mirror of
https://github.com/reactos/reactos.git
synced 2024-07-02 02:34:53 +00:00
2003-12-09 Casper S. Hornstrup <chorns@users.sourceforge.net>
* tools/winebuild: Import winebuild from Wine (D20031208). svn path=/trunk/; revision=6931
This commit is contained in:
parent
6830b8c962
commit
6bb605e497
|
@ -1,3 +1,7 @@
|
|||
2003-12-09 Casper S. Hornstrup <chorns@users.sourceforge.net>
|
||||
|
||||
* tools/winebuild: Import winebuild from Wine (D20031208).
|
||||
|
||||
2003-12-08 Casper S. Hornstrup <chorns@users.sourceforge.net>
|
||||
|
||||
* include/win32k/text.h (NtGdiExtTextOut): Follow ExtTextOut prototype.
|
||||
|
|
3
reactos/tools/winebuild/.cvsignore
Normal file
3
reactos/tools/winebuild/.cvsignore
Normal file
|
@ -0,0 +1,3 @@
|
|||
Makefile
|
||||
winebuild
|
||||
winebuild.man
|
42
reactos/tools/winebuild/Makefile.in
Normal file
42
reactos/tools/winebuild/Makefile.in
Normal file
|
@ -0,0 +1,42 @@
|
|||
TOPSRCDIR = @top_srcdir@
|
||||
TOPOBJDIR = ../..
|
||||
SRCDIR = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
EXEEXT = @EXEEXT@
|
||||
|
||||
PROGRAMS = winebuild$(EXEEXT)
|
||||
MODULE = none
|
||||
|
||||
C_SRCS = \
|
||||
import.c \
|
||||
main.c \
|
||||
parser.c \
|
||||
relay.c \
|
||||
res16.c \
|
||||
res32.c \
|
||||
spec16.c \
|
||||
spec32.c \
|
||||
utils.c
|
||||
|
||||
all: $(PROGRAMS) winebuild.man
|
||||
|
||||
@MAKE_RULES@
|
||||
|
||||
winebuild$(EXEEXT): $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBPORT) $(LDFLAGS)
|
||||
|
||||
winebuild.man: winebuild.man.in
|
||||
sed -e 's,@PACKAGE_STRING\@,@PACKAGE_STRING@,g' $(SRCDIR)/winebuild.man.in >$@ || ($(RM) $@ && false)
|
||||
|
||||
install:: $(PROGRAMS) winebuild.man
|
||||
$(MKINSTALLDIRS) $(bindir) $(mandir)/man$(prog_manext)
|
||||
$(INSTALL_PROGRAM) winebuild$(EXEEXT) $(bindir)/winebuild$(EXEEXT)
|
||||
$(INSTALL_DATA) winebuild.man $(mandir)/man$(prog_manext)/winebuild.$(prog_manext)
|
||||
|
||||
uninstall::
|
||||
$(RM) $(bindir)/winebuild$(EXEEXT) $(mandir)/man$(prog_manext)/winebuild.$(prog_manext)
|
||||
|
||||
clean::
|
||||
$(RM) winebuild.man
|
||||
|
||||
### Dependencies:
|
206
reactos/tools/winebuild/build.h
Normal file
206
reactos/tools/winebuild/build.h
Normal file
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Copyright 1993 Robert J. Amstadt
|
||||
* Copyright 1995 Martin von Loewis
|
||||
* Copyright 1995, 1996, 1997 Alexandre Julliard
|
||||
* Copyright 1997 Eric Youngdale
|
||||
* Copyright 1999 Ulrich Weigand
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __WINE_BUILD_H
|
||||
#define __WINE_BUILD_H
|
||||
|
||||
#ifndef __WINE_CONFIG_H
|
||||
# error You must include config.h to use this header
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TYPE_VARIABLE, /* variable */
|
||||
TYPE_PASCAL, /* pascal function (Win16) */
|
||||
TYPE_ABS, /* absolute value (Win16) */
|
||||
TYPE_STUB, /* unimplemented stub */
|
||||
TYPE_STDCALL, /* stdcall function (Win32) */
|
||||
TYPE_CDECL, /* cdecl function (Win32) */
|
||||
TYPE_VARARGS, /* varargs function (Win32) */
|
||||
TYPE_EXTERN, /* external symbol (Win32) */
|
||||
TYPE_NBTYPES
|
||||
} ORD_TYPE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SPEC_WIN16,
|
||||
SPEC_WIN32
|
||||
} SPEC_TYPE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SPEC_MODE_DLL,
|
||||
SPEC_MODE_GUIEXE,
|
||||
SPEC_MODE_CUIEXE,
|
||||
SPEC_MODE_GUIEXE_UNICODE,
|
||||
SPEC_MODE_CUIEXE_UNICODE
|
||||
} SPEC_MODE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int n_values;
|
||||
int *values;
|
||||
} ORD_VARIABLE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int n_args;
|
||||
char arg_types[21];
|
||||
} ORD_FUNCTION;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int value;
|
||||
} ORD_ABS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ORD_TYPE type;
|
||||
int ordinal;
|
||||
int offset;
|
||||
int lineno;
|
||||
int flags;
|
||||
char *name; /* public name of this function */
|
||||
char *link_name; /* name of the C symbol to link to */
|
||||
char *export_name; /* name exported under for noname exports */
|
||||
union
|
||||
{
|
||||
ORD_VARIABLE var;
|
||||
ORD_FUNCTION func;
|
||||
ORD_ABS abs;
|
||||
} u;
|
||||
} ORDDEF;
|
||||
|
||||
/* entry point flags */
|
||||
#define FLAG_NORELAY 0x01 /* don't use relay debugging for this function */
|
||||
#define FLAG_NONAME 0x02 /* don't import function by name */
|
||||
#define FLAG_RET16 0x04 /* function returns a 16-bit value */
|
||||
#define FLAG_RET64 0x08 /* function returns a 64-bit value */
|
||||
#define FLAG_I386 0x10 /* function is i386 only */
|
||||
#define FLAG_REGISTER 0x20 /* use register calling convention */
|
||||
#define FLAG_INTERRUPT 0x40 /* function is an interrupt handler */
|
||||
#define FLAG_PRIVATE 0x80 /* function is private (cannot be imported) */
|
||||
|
||||
#define FLAG_FORWARD 0x100 /* function is a forwarded name */
|
||||
|
||||
/* Offset of a structure field relative to the start of the struct */
|
||||
#define STRUCTOFFSET(type,field) ((int)&((type *)0)->field)
|
||||
|
||||
/* Offset of register relative to the start of the CONTEXT struct */
|
||||
#define CONTEXTOFFSET(reg) STRUCTOFFSET(CONTEXT86,reg)
|
||||
|
||||
/* Offset of register relative to the start of the STACK16FRAME struct */
|
||||
#define STACK16OFFSET(reg) STRUCTOFFSET(STACK16FRAME,reg)
|
||||
|
||||
/* Offset of register relative to the start of the STACK32FRAME struct */
|
||||
#define STACK32OFFSET(reg) STRUCTOFFSET(STACK32FRAME,reg)
|
||||
|
||||
/* Offset of the stack pointer relative to %fs:(0) */
|
||||
#define STACKOFFSET (STRUCTOFFSET(TEB,cur_stack))
|
||||
|
||||
|
||||
#define MAX_ORDINALS 65535
|
||||
|
||||
/* global functions */
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define __attribute__(X)
|
||||
#endif
|
||||
|
||||
extern void *xmalloc (size_t size);
|
||||
extern void *xrealloc (void *ptr, size_t size);
|
||||
extern char *xstrdup( const char *str );
|
||||
extern char *strupper(char *s);
|
||||
extern void fatal_error( const char *msg, ... )
|
||||
__attribute__ ((__format__ (__printf__, 1, 2)));
|
||||
extern void fatal_perror( const char *msg, ... )
|
||||
__attribute__ ((__format__ (__printf__, 1, 2)));
|
||||
extern void error( const char *msg, ... )
|
||||
__attribute__ ((__format__ (__printf__, 1, 2)));
|
||||
extern void warning( const char *msg, ... )
|
||||
__attribute__ ((__format__ (__printf__, 1, 2)));
|
||||
extern void output_standard_file_header( FILE *outfile );
|
||||
extern FILE *open_input_file( const char *srcdir, const char *name );
|
||||
extern void close_input_file( FILE *file );
|
||||
extern void dump_bytes( FILE *outfile, const unsigned char *data, int len,
|
||||
const char *label, int constant );
|
||||
extern const char *make_c_identifier( const char *str );
|
||||
extern int get_alignment(int alignBoundary);
|
||||
|
||||
extern void add_import_dll( const char *name, int delay );
|
||||
extern void add_ignore_symbol( const char *name );
|
||||
extern void read_undef_symbols( char **argv );
|
||||
extern int resolve_imports( void );
|
||||
extern int output_imports( FILE *outfile );
|
||||
extern int load_res32_file( const char *name );
|
||||
extern int output_resources( FILE *outfile );
|
||||
extern void load_res16_file( const char *name );
|
||||
extern int output_res16_data( FILE *outfile );
|
||||
extern int output_res16_directory( unsigned char *buffer );
|
||||
extern void output_dll_init( FILE *outfile, const char *constructor, const char *destructor );
|
||||
extern int parse_debug_channels( const char *srcdir, const char *filename );
|
||||
|
||||
extern void BuildRelays16( FILE *outfile );
|
||||
extern void BuildRelays32( FILE *outfile );
|
||||
extern void BuildSpec16File( FILE *outfile );
|
||||
extern void BuildSpec32File( FILE *outfile );
|
||||
extern void BuildDef32File( FILE *outfile );
|
||||
extern void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv );
|
||||
extern int ParseTopLevel( FILE *file );
|
||||
|
||||
/* global variables */
|
||||
|
||||
extern int current_line;
|
||||
extern int nb_entry_points;
|
||||
extern int nb_names;
|
||||
extern int Base;
|
||||
extern int Limit;
|
||||
extern int DLLHeapSize;
|
||||
extern int UsePIC;
|
||||
extern int debugging;
|
||||
extern int stack_size;
|
||||
extern int nb_debug_channels;
|
||||
extern int nb_lib_paths;
|
||||
extern int nb_errors;
|
||||
extern int display_warnings;
|
||||
extern int kill_at;
|
||||
|
||||
extern char *owner_name;
|
||||
extern char *dll_name;
|
||||
extern char *dll_file_name;
|
||||
extern const char *init_func;
|
||||
extern char *input_file_name;
|
||||
extern const char *output_file_name;
|
||||
extern char **debug_channels;
|
||||
extern char **lib_path;
|
||||
|
||||
extern ORDDEF *EntryPoints[MAX_ORDINALS];
|
||||
extern ORDDEF *Ordinals[MAX_ORDINALS];
|
||||
extern ORDDEF *Names[MAX_ORDINALS];
|
||||
extern SPEC_MODE SpecMode;
|
||||
extern SPEC_TYPE SpecType;
|
||||
|
||||
#endif /* __WINE_BUILD_H */
|
1160
reactos/tools/winebuild/import.c
Normal file
1160
reactos/tools/winebuild/import.c
Normal file
File diff suppressed because it is too large
Load diff
436
reactos/tools/winebuild/main.c
Normal file
436
reactos/tools/winebuild/main.c
Normal file
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
* Main function
|
||||
*
|
||||
* Copyright 1993 Robert J. Amstadt
|
||||
* Copyright 1995 Martin von Loewis
|
||||
* Copyright 1995, 1996, 1997 Alexandre Julliard
|
||||
* Copyright 1997 Eric Youngdale
|
||||
* Copyright 1999 Ulrich Weigand
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#ifdef HAVE_GETOPT_H
|
||||
# include <getopt.h>
|
||||
#endif
|
||||
|
||||
#include "build.h"
|
||||
|
||||
ORDDEF *EntryPoints[MAX_ORDINALS];
|
||||
ORDDEF *Ordinals[MAX_ORDINALS];
|
||||
ORDDEF *Names[MAX_ORDINALS];
|
||||
|
||||
SPEC_MODE SpecMode = SPEC_MODE_DLL;
|
||||
SPEC_TYPE SpecType = SPEC_WIN32;
|
||||
|
||||
int Base = MAX_ORDINALS;
|
||||
int Limit = 0;
|
||||
int DLLHeapSize = 0;
|
||||
int UsePIC = 0;
|
||||
int stack_size = 0;
|
||||
int nb_entry_points = 0;
|
||||
int nb_names = 0;
|
||||
int nb_debug_channels = 0;
|
||||
int nb_lib_paths = 0;
|
||||
int nb_errors = 0;
|
||||
int display_warnings = 0;
|
||||
int kill_at = 0;
|
||||
|
||||
/* we only support relay debugging on i386 */
|
||||
#if defined(__i386__) && !defined(NO_TRACE_MSGS)
|
||||
int debugging = 1;
|
||||
#else
|
||||
int debugging = 0;
|
||||
#endif
|
||||
|
||||
char *owner_name = NULL;
|
||||
char *dll_name = NULL;
|
||||
char *dll_file_name = NULL;
|
||||
const char *init_func = NULL;
|
||||
char **debug_channels = NULL;
|
||||
char **lib_path = NULL;
|
||||
|
||||
char *input_file_name = NULL;
|
||||
const char *output_file_name = NULL;
|
||||
|
||||
static FILE *input_file;
|
||||
static FILE *output_file;
|
||||
static const char *current_src_dir;
|
||||
static int nb_res_files;
|
||||
static char **res_files;
|
||||
|
||||
/* execution mode */
|
||||
enum exec_mode_values
|
||||
{
|
||||
MODE_NONE,
|
||||
MODE_SPEC,
|
||||
MODE_EXE,
|
||||
MODE_DEF,
|
||||
MODE_DEBUG,
|
||||
MODE_RELAY16,
|
||||
MODE_RELAY32
|
||||
};
|
||||
|
||||
static enum exec_mode_values exec_mode = MODE_NONE;
|
||||
|
||||
/* set the dll file name from the input file name */
|
||||
static void set_dll_file_name( const char *name )
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (dll_file_name) return;
|
||||
|
||||
if ((p = strrchr( name, '\\' ))) name = p + 1;
|
||||
if ((p = strrchr( name, '/' ))) name = p + 1;
|
||||
dll_file_name = xmalloc( strlen(name) + 5 );
|
||||
strcpy( dll_file_name, name );
|
||||
if ((p = strrchr( dll_file_name, '.' )) && !strcmp( p, ".spec" )) *p = 0;
|
||||
if (!strchr( dll_file_name, '.' )) strcat( dll_file_name, ".dll" );
|
||||
}
|
||||
|
||||
/* cleanup on program exit */
|
||||
static void cleanup(void)
|
||||
{
|
||||
if (output_file_name) unlink( output_file_name );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* command-line option handling
|
||||
*/
|
||||
static const char usage_str[] =
|
||||
"Usage: winebuild [OPTIONS] [FILES]\n\n"
|
||||
"Options:\n"
|
||||
" -C --source-dir=DIR Look for source files in DIR\n"
|
||||
" -d --delay-lib=LIB Import the specified library in delayed mode\n"
|
||||
" -D SYM Ignored for C flags compatibility\n"
|
||||
" -e --entry=FUNC Set the DLL entry point function (default: DllMain)\n"
|
||||
" -f FLAGS Compiler flags (only -fPIC is supported)\n"
|
||||
" -F --filename=DLLFILE Set the DLL filename (default: from input file name)\n"
|
||||
" -h --help Display this help message\n"
|
||||
" -H --heap=SIZE Set the heap size for a Win16 dll\n"
|
||||
" -i --ignore=SYM[,SYM] Ignore specified symbols when resolving imports\n"
|
||||
" -I DIR Ignored for C flags compatibility\n"
|
||||
" -k --kill-at Kill stdcall decorations in generated .def files\n"
|
||||
" -K FLAGS Compiler flags (only -KPIC is supported)\n"
|
||||
" -l --library=LIB Import the specified library\n"
|
||||
" -L --library-path=DIR Look for imports libraries in DIR\n"
|
||||
" -m --exe-mode=MODE Set the executable mode (cui|gui|cuiw|guiw)\n"
|
||||
" -M --main-module=MODULE Set the name of the main module for a Win16 dll\n"
|
||||
" -N --dll-name=DLLNAME Set the DLL name (default: from input file name)\n"
|
||||
" -o --output=NAME Set the output file name (default: stdout)\n"
|
||||
" -r --res=RSRC.RES Load resources from RSRC.RES\n"
|
||||
" --version Print the version and exit\n"
|
||||
" -w --warnings Turn on warnings\n"
|
||||
"\nMode options:\n"
|
||||
" --spec=FILE.SPEC Build a .c file from a spec file\n"
|
||||
" --def=FILE.SPEC Build a .def file from a spec file\n"
|
||||
" --exe=NAME Build a .c file for the named executable\n"
|
||||
" --debug [FILES] Build a .c file with the debug channels declarations\n"
|
||||
" --relay16 Build the 16-bit relay assembly routines\n"
|
||||
" --relay32 Build the 32-bit relay assembly routines\n\n"
|
||||
"The mode options are mutually exclusive; you must specify one and only one.\n\n";
|
||||
|
||||
enum long_options_values
|
||||
{
|
||||
LONG_OPT_SPEC = 1,
|
||||
LONG_OPT_DEF,
|
||||
LONG_OPT_EXE,
|
||||
LONG_OPT_DEBUG,
|
||||
LONG_OPT_RELAY16,
|
||||
LONG_OPT_RELAY32,
|
||||
LONG_OPT_VERSION
|
||||
};
|
||||
|
||||
static const char short_options[] = "C:D:F:H:I:K:L:M:N:d:e:f:hi:kl:m:o:r:w";
|
||||
|
||||
static const struct option long_options[] =
|
||||
{
|
||||
{ "spec", 1, 0, LONG_OPT_SPEC },
|
||||
{ "def", 1, 0, LONG_OPT_DEF },
|
||||
{ "exe", 1, 0, LONG_OPT_EXE },
|
||||
{ "debug", 0, 0, LONG_OPT_DEBUG },
|
||||
{ "relay16", 0, 0, LONG_OPT_RELAY16 },
|
||||
{ "relay32", 0, 0, LONG_OPT_RELAY32 },
|
||||
{ "version", 0, 0, LONG_OPT_VERSION },
|
||||
/* aliases for short options */
|
||||
{ "source-dir", 1, 0, 'C' },
|
||||
{ "delay-lib", 1, 0, 'd' },
|
||||
{ "entry", 1, 0, 'e' },
|
||||
{ "filename", 1, 0, 'F' },
|
||||
{ "help", 0, 0, 'h' },
|
||||
{ "heap", 1, 0, 'H' },
|
||||
{ "ignore", 1, 0, 'i' },
|
||||
{ "kill-at", 0, 0, 'k' },
|
||||
{ "library", 1, 0, 'l' },
|
||||
{ "library-path", 1, 0, 'L' },
|
||||
{ "exe-mode", 1, 0, 'm' },
|
||||
{ "main-module", 1, 0, 'M' },
|
||||
{ "dll-name", 1, 0, 'N' },
|
||||
{ "output", 1, 0, 'o' },
|
||||
{ "res", 1, 0, 'r' },
|
||||
{ "warnings", 0, 0, 'w' },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static void usage( int exit_code )
|
||||
{
|
||||
fprintf( stderr, "%s", usage_str );
|
||||
exit( exit_code );
|
||||
}
|
||||
|
||||
static void set_exec_mode( enum exec_mode_values mode )
|
||||
{
|
||||
if (exec_mode != MODE_NONE) usage(1);
|
||||
exec_mode = mode;
|
||||
}
|
||||
|
||||
/* parse options from the argv array and remove all the recognized ones */
|
||||
static char **parse_options( int argc, char **argv )
|
||||
{
|
||||
char *p;
|
||||
int optc;
|
||||
|
||||
while ((optc = getopt_long( argc, argv, short_options, long_options, NULL )) != -1)
|
||||
{
|
||||
switch(optc)
|
||||
{
|
||||
case 'C':
|
||||
current_src_dir = optarg;
|
||||
break;
|
||||
case 'D':
|
||||
/* ignored */
|
||||
break;
|
||||
case 'F':
|
||||
dll_file_name = xstrdup( optarg );
|
||||
break;
|
||||
case 'H':
|
||||
if (!isdigit(optarg[0]))
|
||||
fatal_error( "Expected number argument with -H option instead of '%s'\n", optarg );
|
||||
DLLHeapSize = atoi(optarg);
|
||||
if (DLLHeapSize > 65535)
|
||||
fatal_error( "Invalid heap size %d, maximum is 65535\n", DLLHeapSize );
|
||||
break;
|
||||
case 'I':
|
||||
/* ignored */
|
||||
break;
|
||||
case 'K':
|
||||
/* ignored, because cc generates correct code. */
|
||||
break;
|
||||
case 'L':
|
||||
lib_path = xrealloc( lib_path, (nb_lib_paths+1) * sizeof(*lib_path) );
|
||||
lib_path[nb_lib_paths++] = xstrdup( optarg );
|
||||
break;
|
||||
case 'M':
|
||||
owner_name = xstrdup( optarg );
|
||||
SpecType = SPEC_WIN16;
|
||||
break;
|
||||
case 'N':
|
||||
dll_name = xstrdup( optarg );
|
||||
break;
|
||||
case 'd':
|
||||
add_import_dll( optarg, 1 );
|
||||
break;
|
||||
case 'e':
|
||||
init_func = xstrdup( optarg );
|
||||
if ((p = strchr( init_func, '@' ))) *p = 0; /* kill stdcall decoration */
|
||||
break;
|
||||
case 'f':
|
||||
if (!strcmp( optarg, "PIC") || !strcmp( optarg, "pic")) UsePIC = 1;
|
||||
/* ignore all other flags */
|
||||
break;
|
||||
case 'h':
|
||||
usage(0);
|
||||
break;
|
||||
case 'i':
|
||||
{
|
||||
char *str = xstrdup( optarg );
|
||||
char *token = strtok( str, "," );
|
||||
while (token)
|
||||
{
|
||||
add_ignore_symbol( token );
|
||||
token = strtok( NULL, "," );
|
||||
}
|
||||
free( str );
|
||||
}
|
||||
break;
|
||||
case 'k':
|
||||
kill_at = 1;
|
||||
break;
|
||||
case 'l':
|
||||
add_import_dll( optarg, 0 );
|
||||
break;
|
||||
case 'm':
|
||||
if (!strcmp( optarg, "gui" )) SpecMode = SPEC_MODE_GUIEXE;
|
||||
else if (!strcmp( optarg, "cui" )) SpecMode = SPEC_MODE_CUIEXE;
|
||||
else if (!strcmp( optarg, "guiw" )) SpecMode = SPEC_MODE_GUIEXE_UNICODE;
|
||||
else if (!strcmp( optarg, "cuiw" )) SpecMode = SPEC_MODE_CUIEXE_UNICODE;
|
||||
else usage(1);
|
||||
break;
|
||||
case 'o':
|
||||
if (unlink( optarg ) == -1 && errno != ENOENT)
|
||||
fatal_error( "Unable to create output file '%s'\n", optarg );
|
||||
if (!(output_file = fopen( optarg, "w" )))
|
||||
fatal_error( "Unable to create output file '%s'\n", optarg );
|
||||
output_file_name = xstrdup(optarg);
|
||||
atexit( cleanup ); /* make sure we remove the output file on exit */
|
||||
break;
|
||||
case 'r':
|
||||
res_files = xrealloc( res_files, (nb_res_files+1) * sizeof(*res_files) );
|
||||
res_files[nb_res_files++] = xstrdup( optarg );
|
||||
break;
|
||||
case 'w':
|
||||
display_warnings = 1;
|
||||
break;
|
||||
case LONG_OPT_SPEC:
|
||||
set_exec_mode( MODE_SPEC );
|
||||
input_file = open_input_file( NULL, optarg );
|
||||
set_dll_file_name( optarg );
|
||||
break;
|
||||
case LONG_OPT_DEF:
|
||||
set_exec_mode( MODE_DEF );
|
||||
input_file = open_input_file( NULL, optarg );
|
||||
set_dll_file_name( optarg );
|
||||
break;
|
||||
case LONG_OPT_EXE:
|
||||
set_exec_mode( MODE_EXE );
|
||||
if ((p = strrchr( optarg, '/' ))) p++;
|
||||
else p = optarg;
|
||||
dll_file_name = xmalloc( strlen(p) + 5 );
|
||||
strcpy( dll_file_name, p );
|
||||
if (!strchr( dll_file_name, '.' )) strcat( dll_file_name, ".exe" );
|
||||
if (SpecMode == SPEC_MODE_DLL) SpecMode = SPEC_MODE_GUIEXE;
|
||||
break;
|
||||
case LONG_OPT_DEBUG:
|
||||
set_exec_mode( MODE_DEBUG );
|
||||
break;
|
||||
case LONG_OPT_RELAY16:
|
||||
set_exec_mode( MODE_RELAY16 );
|
||||
break;
|
||||
case LONG_OPT_RELAY32:
|
||||
set_exec_mode( MODE_RELAY32 );
|
||||
break;
|
||||
case LONG_OPT_VERSION:
|
||||
printf( "winebuild version " PACKAGE_VERSION "\n" );
|
||||
exit(0);
|
||||
case '?':
|
||||
usage(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return &argv[optind];
|
||||
}
|
||||
|
||||
|
||||
/* load all specified resource files */
|
||||
static void load_resources( char *argv[] )
|
||||
{
|
||||
int i;
|
||||
char **ptr, **last;
|
||||
|
||||
switch (SpecType)
|
||||
{
|
||||
case SPEC_WIN16:
|
||||
for (i = 0; i < nb_res_files; i++) load_res16_file( res_files[i] );
|
||||
break;
|
||||
|
||||
case SPEC_WIN32:
|
||||
for (i = 0; i < nb_res_files; i++)
|
||||
{
|
||||
if (!load_res32_file( res_files[i] ))
|
||||
fatal_error( "%s is not a valid Win32 resource file\n", res_files[i] );
|
||||
}
|
||||
|
||||
/* load any resource file found in the remaining arguments */
|
||||
for (ptr = last = argv; *ptr; ptr++)
|
||||
{
|
||||
if (!load_res32_file( *ptr ))
|
||||
*last++ = *ptr; /* not a resource file, keep it in the list */
|
||||
}
|
||||
*last = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* main
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
output_file = stdout;
|
||||
argv = parse_options( argc, argv );
|
||||
|
||||
switch(exec_mode)
|
||||
{
|
||||
case MODE_SPEC:
|
||||
load_resources( argv );
|
||||
if (!ParseTopLevel( input_file )) break;
|
||||
switch (SpecType)
|
||||
{
|
||||
case SPEC_WIN16:
|
||||
if (argv[0])
|
||||
fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
|
||||
BuildSpec16File( output_file );
|
||||
break;
|
||||
case SPEC_WIN32:
|
||||
read_undef_symbols( argv );
|
||||
BuildSpec32File( output_file );
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
break;
|
||||
case MODE_EXE:
|
||||
if (SpecType == SPEC_WIN16) fatal_error( "Cannot build 16-bit exe files\n" );
|
||||
load_resources( argv );
|
||||
read_undef_symbols( argv );
|
||||
BuildSpec32File( output_file );
|
||||
break;
|
||||
case MODE_DEF:
|
||||
if (argv[0]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
|
||||
if (SpecType == SPEC_WIN16) fatal_error( "Cannot yet build .def file for 16-bit dlls\n" );
|
||||
if (!ParseTopLevel( input_file )) break;
|
||||
BuildDef32File( output_file );
|
||||
break;
|
||||
case MODE_DEBUG:
|
||||
BuildDebugFile( output_file, current_src_dir, argv );
|
||||
break;
|
||||
case MODE_RELAY16:
|
||||
if (argv[0]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
|
||||
BuildRelays16( output_file );
|
||||
break;
|
||||
case MODE_RELAY32:
|
||||
if (argv[0]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
|
||||
BuildRelays32( output_file );
|
||||
break;
|
||||
default:
|
||||
usage(1);
|
||||
break;
|
||||
}
|
||||
if (nb_errors) exit(1);
|
||||
if (output_file_name)
|
||||
{
|
||||
fclose( output_file );
|
||||
output_file_name = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
703
reactos/tools/winebuild/parser.c
Normal file
703
reactos/tools/winebuild/parser.c
Normal file
|
@ -0,0 +1,703 @@
|
|||
/*
|
||||
* Spec file parser
|
||||
*
|
||||
* Copyright 1993 Robert J. Amstadt
|
||||
* Copyright 1995 Martin von Loewis
|
||||
* Copyright 1995, 1996, 1997 Alexandre Julliard
|
||||
* Copyright 1997 Eric Youngdale
|
||||
* Copyright 1999 Ulrich Weigand
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "build.h"
|
||||
|
||||
int current_line = 0;
|
||||
|
||||
static char ParseBuffer[512];
|
||||
static char TokenBuffer[512];
|
||||
static char *ParseNext = ParseBuffer;
|
||||
static FILE *input_file;
|
||||
|
||||
static const char * const TypeNames[TYPE_NBTYPES] =
|
||||
{
|
||||
"variable", /* TYPE_VARIABLE */
|
||||
"pascal", /* TYPE_PASCAL */
|
||||
"equate", /* TYPE_ABS */
|
||||
"stub", /* TYPE_STUB */
|
||||
"stdcall", /* TYPE_STDCALL */
|
||||
"cdecl", /* TYPE_CDECL */
|
||||
"varargs", /* TYPE_VARARGS */
|
||||
"extern" /* TYPE_EXTERN */
|
||||
};
|
||||
|
||||
static const char * const FlagNames[] =
|
||||
{
|
||||
"norelay", /* FLAG_NORELAY */
|
||||
"noname", /* FLAG_NONAME */
|
||||
"ret16", /* FLAG_RET16 */
|
||||
"ret64", /* FLAG_RET64 */
|
||||
"i386", /* FLAG_I386 */
|
||||
"register", /* FLAG_REGISTER */
|
||||
"interrupt", /* FLAG_INTERRUPT */
|
||||
"private", /* FLAG_PRIVATE */
|
||||
NULL
|
||||
};
|
||||
|
||||
static int IsNumberString(const char *s)
|
||||
{
|
||||
while (*s) if (!isdigit(*s++)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline static int is_token_separator( char ch )
|
||||
{
|
||||
return (ch == '(' || ch == ')' || ch == '-');
|
||||
}
|
||||
|
||||
/* get the next line from the input file, or return 0 if at eof */
|
||||
static int get_next_line(void)
|
||||
{
|
||||
ParseNext = ParseBuffer;
|
||||
current_line++;
|
||||
return (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) != NULL);
|
||||
}
|
||||
|
||||
static const char * GetToken( int allow_eol )
|
||||
{
|
||||
char *p = ParseNext;
|
||||
char *token = TokenBuffer;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* remove initial white space */
|
||||
p = ParseNext;
|
||||
while (isspace(*p)) p++;
|
||||
|
||||
if (*p == '\\' && p[1] == '\n') /* line continuation */
|
||||
{
|
||||
if (!get_next_line())
|
||||
{
|
||||
if (!allow_eol) error( "Unexpected end of file\n" );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
if ((*p == '\0') || (*p == '#'))
|
||||
{
|
||||
if (!allow_eol) error( "Declaration not terminated properly\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find end of token.
|
||||
*/
|
||||
if (is_token_separator(*p))
|
||||
{
|
||||
/* a separator is always a complete token */
|
||||
*token++ = *p++;
|
||||
}
|
||||
else while (*p != '\0' && !is_token_separator(*p) && !isspace(*p))
|
||||
{
|
||||
if (*p == '\\') p++;
|
||||
if (*p) *token++ = *p++;
|
||||
}
|
||||
*token = '\0';
|
||||
ParseNext = p;
|
||||
return TokenBuffer;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* ParseVariable
|
||||
*
|
||||
* Parse a variable definition.
|
||||
*/
|
||||
static int ParseVariable( ORDDEF *odp )
|
||||
{
|
||||
char *endptr;
|
||||
int *value_array;
|
||||
int n_values;
|
||||
int value_array_size;
|
||||
const char *token;
|
||||
|
||||
if (SpecType == SPEC_WIN32)
|
||||
{
|
||||
error( "'variable' not supported in Win32, use 'extern' instead\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(token = GetToken(0))) return 0;
|
||||
if (*token != '(')
|
||||
{
|
||||
error( "Expected '(' got '%s'\n", token );
|
||||
return 0;
|
||||
}
|
||||
|
||||
n_values = 0;
|
||||
value_array_size = 25;
|
||||
value_array = xmalloc(sizeof(*value_array) * value_array_size);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!(token = GetToken(0)))
|
||||
{
|
||||
free( value_array );
|
||||
return 0;
|
||||
}
|
||||
if (*token == ')')
|
||||
break;
|
||||
|
||||
value_array[n_values++] = strtol(token, &endptr, 0);
|
||||
if (n_values == value_array_size)
|
||||
{
|
||||
value_array_size += 25;
|
||||
value_array = xrealloc(value_array,
|
||||
sizeof(*value_array) * value_array_size);
|
||||
}
|
||||
|
||||
if (endptr == NULL || *endptr != '\0')
|
||||
{
|
||||
error( "Expected number value, got '%s'\n", token );
|
||||
free( value_array );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
odp->u.var.n_values = n_values;
|
||||
odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* ParseExportFunction
|
||||
*
|
||||
* Parse a function definition.
|
||||
*/
|
||||
static int ParseExportFunction( ORDDEF *odp )
|
||||
{
|
||||
const char *token;
|
||||
unsigned int i;
|
||||
|
||||
switch(SpecType)
|
||||
{
|
||||
case SPEC_WIN16:
|
||||
if (odp->type == TYPE_STDCALL)
|
||||
{
|
||||
error( "'stdcall' not supported for Win16\n" );
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case SPEC_WIN32:
|
||||
if (odp->type == TYPE_PASCAL)
|
||||
{
|
||||
error( "'pascal' not supported for Win32\n" );
|
||||
return 0;
|
||||
}
|
||||
if (odp->flags & FLAG_INTERRUPT)
|
||||
{
|
||||
error( "'interrupt' not supported for Win32\n" );
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(token = GetToken(0))) return 0;
|
||||
if (*token != '(')
|
||||
{
|
||||
error( "Expected '(' got '%s'\n", token );
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(odp->u.func.arg_types); i++)
|
||||
{
|
||||
if (!(token = GetToken(0))) return 0;
|
||||
if (*token == ')')
|
||||
break;
|
||||
|
||||
if (!strcmp(token, "word"))
|
||||
odp->u.func.arg_types[i] = 'w';
|
||||
else if (!strcmp(token, "s_word"))
|
||||
odp->u.func.arg_types[i] = 's';
|
||||
else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
|
||||
odp->u.func.arg_types[i] = 'l';
|
||||
else if (!strcmp(token, "ptr"))
|
||||
odp->u.func.arg_types[i] = 'p';
|
||||
else if (!strcmp(token, "str"))
|
||||
odp->u.func.arg_types[i] = 't';
|
||||
else if (!strcmp(token, "wstr"))
|
||||
odp->u.func.arg_types[i] = 'W';
|
||||
else if (!strcmp(token, "segstr"))
|
||||
odp->u.func.arg_types[i] = 'T';
|
||||
else if (!strcmp(token, "double"))
|
||||
{
|
||||
odp->u.func.arg_types[i++] = 'l';
|
||||
if (i < sizeof(odp->u.func.arg_types)) odp->u.func.arg_types[i] = 'l';
|
||||
}
|
||||
else
|
||||
{
|
||||
error( "Unknown argument type '%s'\n", token );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (SpecType == SPEC_WIN32)
|
||||
{
|
||||
if (strcmp(token, "long") &&
|
||||
strcmp(token, "ptr") &&
|
||||
strcmp(token, "str") &&
|
||||
strcmp(token, "wstr") &&
|
||||
strcmp(token, "double"))
|
||||
{
|
||||
error( "Type '%s' not supported for Win32\n", token );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
|
||||
{
|
||||
error( "Too many arguments\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
odp->u.func.arg_types[i] = '\0';
|
||||
if (odp->type == TYPE_VARARGS)
|
||||
odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */
|
||||
|
||||
if (!(token = GetToken(1)))
|
||||
{
|
||||
if (!strcmp( odp->name, "@" ))
|
||||
{
|
||||
error( "Missing handler name for anonymous function\n" );
|
||||
return 0;
|
||||
}
|
||||
odp->link_name = xstrdup( odp->name );
|
||||
}
|
||||
else
|
||||
{
|
||||
odp->link_name = xstrdup( token );
|
||||
if (strchr( odp->link_name, '.' ))
|
||||
{
|
||||
if (SpecType == SPEC_WIN16)
|
||||
{
|
||||
error( "Forwarded functions not supported for Win16\n" );
|
||||
return 0;
|
||||
}
|
||||
odp->flags |= FLAG_FORWARD;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* ParseEquate
|
||||
*
|
||||
* Parse an 'equate' definition.
|
||||
*/
|
||||
static int ParseEquate( ORDDEF *odp )
|
||||
{
|
||||
char *endptr;
|
||||
int value;
|
||||
const char *token;
|
||||
|
||||
if (SpecType == SPEC_WIN32)
|
||||
{
|
||||
error( "'equate' not supported for Win32\n" );
|
||||
return 0;
|
||||
}
|
||||
if (!(token = GetToken(0))) return 0;
|
||||
value = strtol(token, &endptr, 0);
|
||||
if (endptr == NULL || *endptr != '\0')
|
||||
{
|
||||
error( "Expected number value, got '%s'\n", token );
|
||||
return 0;
|
||||
}
|
||||
odp->u.abs.value = value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* ParseStub
|
||||
*
|
||||
* Parse a 'stub' definition.
|
||||
*/
|
||||
static int ParseStub( ORDDEF *odp )
|
||||
{
|
||||
odp->u.func.arg_types[0] = '\0';
|
||||
odp->link_name = xstrdup("");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* ParseExtern
|
||||
*
|
||||
* Parse an 'extern' definition.
|
||||
*/
|
||||
static int ParseExtern( ORDDEF *odp )
|
||||
{
|
||||
const char *token;
|
||||
|
||||
if (SpecType == SPEC_WIN16)
|
||||
{
|
||||
error( "'extern' not supported for Win16, use 'variable' instead\n" );
|
||||
return 0;
|
||||
}
|
||||
if (!(token = GetToken(1)))
|
||||
{
|
||||
if (!strcmp( odp->name, "@" ))
|
||||
{
|
||||
error( "Missing handler name for anonymous extern\n" );
|
||||
return 0;
|
||||
}
|
||||
odp->link_name = xstrdup( odp->name );
|
||||
}
|
||||
else
|
||||
{
|
||||
odp->link_name = xstrdup( token );
|
||||
if (strchr( odp->link_name, '.' )) odp->flags |= FLAG_FORWARD;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* ParseFlags
|
||||
*
|
||||
* Parse the optional flags for an entry point
|
||||
*/
|
||||
static const char *ParseFlags( ORDDEF *odp )
|
||||
{
|
||||
unsigned int i;
|
||||
const char *token;
|
||||
|
||||
do
|
||||
{
|
||||
if (!(token = GetToken(0))) break;
|
||||
for (i = 0; FlagNames[i]; i++)
|
||||
if (!strcmp( FlagNames[i], token )) break;
|
||||
if (!FlagNames[i])
|
||||
{
|
||||
error( "Unknown flag '%s'\n", token );
|
||||
return NULL;
|
||||
}
|
||||
odp->flags |= 1 << i;
|
||||
token = GetToken(0);
|
||||
} while (token && *token == '-');
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* fix_export_name
|
||||
*
|
||||
* Fix an exported function name by removing a possible @xx suffix
|
||||
*/
|
||||
static void fix_export_name( char *name )
|
||||
{
|
||||
char *p, *end = strrchr( name, '@' );
|
||||
if (!end || !end[1] || end == name) return;
|
||||
/* make sure all the rest is digits */
|
||||
for (p = end + 1; *p; p++) if (!isdigit(*p)) return;
|
||||
*end = 0;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* ParseOrdinal
|
||||
*
|
||||
* Parse an ordinal definition.
|
||||
*/
|
||||
static int ParseOrdinal(int ordinal)
|
||||
{
|
||||
const char *token;
|
||||
|
||||
ORDDEF *odp = xmalloc( sizeof(*odp) );
|
||||
memset( odp, 0, sizeof(*odp) );
|
||||
EntryPoints[nb_entry_points++] = odp;
|
||||
|
||||
if (!(token = GetToken(0))) goto error;
|
||||
|
||||
for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
|
||||
if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
|
||||
break;
|
||||
|
||||
if (odp->type >= TYPE_NBTYPES)
|
||||
{
|
||||
error( "Expected type after ordinal, found '%s' instead\n", token );
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(token = GetToken(0))) goto error;
|
||||
if (*token == '-' && !(token = ParseFlags( odp ))) goto error;
|
||||
|
||||
odp->name = xstrdup( token );
|
||||
fix_export_name( odp->name );
|
||||
odp->lineno = current_line;
|
||||
odp->ordinal = ordinal;
|
||||
|
||||
switch(odp->type)
|
||||
{
|
||||
case TYPE_VARIABLE:
|
||||
if (!ParseVariable( odp )) goto error;
|
||||
break;
|
||||
case TYPE_PASCAL:
|
||||
case TYPE_STDCALL:
|
||||
case TYPE_VARARGS:
|
||||
case TYPE_CDECL:
|
||||
if (!ParseExportFunction( odp )) goto error;
|
||||
break;
|
||||
case TYPE_ABS:
|
||||
if (!ParseEquate( odp )) goto error;
|
||||
break;
|
||||
case TYPE_STUB:
|
||||
if (!ParseStub( odp )) goto error;
|
||||
break;
|
||||
case TYPE_EXTERN:
|
||||
if (!ParseExtern( odp )) goto error;
|
||||
break;
|
||||
default:
|
||||
assert( 0 );
|
||||
}
|
||||
|
||||
#ifndef __i386__
|
||||
if (odp->flags & FLAG_I386)
|
||||
{
|
||||
/* ignore this entry point on non-Intel archs */
|
||||
EntryPoints[--nb_entry_points] = NULL;
|
||||
free( odp );
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ordinal != -1)
|
||||
{
|
||||
if (!ordinal)
|
||||
{
|
||||
error( "Ordinal 0 is not valid\n" );
|
||||
goto error;
|
||||
}
|
||||
if (ordinal >= MAX_ORDINALS)
|
||||
{
|
||||
error( "Ordinal number %d too large\n", ordinal );
|
||||
goto error;
|
||||
}
|
||||
if (ordinal > Limit) Limit = ordinal;
|
||||
if (ordinal < Base) Base = ordinal;
|
||||
odp->ordinal = ordinal;
|
||||
if (Ordinals[ordinal])
|
||||
{
|
||||
error( "Duplicate ordinal %d\n", ordinal );
|
||||
goto error;
|
||||
}
|
||||
Ordinals[ordinal] = odp;
|
||||
}
|
||||
|
||||
if (!strcmp( odp->name, "@" ) || odp->flags & FLAG_NONAME)
|
||||
{
|
||||
if (ordinal == -1)
|
||||
{
|
||||
error( "Nameless function needs an explicit ordinal number\n" );
|
||||
goto error;
|
||||
}
|
||||
if (SpecType != SPEC_WIN32)
|
||||
{
|
||||
error( "Nameless functions not supported for Win16\n" );
|
||||
goto error;
|
||||
}
|
||||
if (!strcmp( odp->name, "@" )) free( odp->name );
|
||||
else odp->export_name = odp->name;
|
||||
odp->name = NULL;
|
||||
}
|
||||
else Names[nb_names++] = odp;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
EntryPoints[--nb_entry_points] = NULL;
|
||||
free( odp->name );
|
||||
free( odp );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int name_compare( const void *name1, const void *name2 )
|
||||
{
|
||||
ORDDEF *odp1 = *(ORDDEF **)name1;
|
||||
ORDDEF *odp2 = *(ORDDEF **)name2;
|
||||
return strcmp( odp1->name, odp2->name );
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* sort_names
|
||||
*
|
||||
* Sort the name array and catch duplicates.
|
||||
*/
|
||||
static void sort_names(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!nb_names) return;
|
||||
|
||||
/* sort the list of names */
|
||||
qsort( Names, nb_names, sizeof(Names[0]), name_compare );
|
||||
|
||||
/* check for duplicate names */
|
||||
for (i = 0; i < nb_names - 1; i++)
|
||||
{
|
||||
if (!strcmp( Names[i]->name, Names[i+1]->name ))
|
||||
{
|
||||
current_line = max( Names[i]->lineno, Names[i+1]->lineno );
|
||||
error( "'%s' redefined\n%s:%d: First defined here\n",
|
||||
Names[i]->name, input_file_name,
|
||||
min( Names[i]->lineno, Names[i+1]->lineno ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* ParseTopLevel
|
||||
*
|
||||
* Parse a spec file.
|
||||
*/
|
||||
int ParseTopLevel( FILE *file )
|
||||
{
|
||||
const char *token;
|
||||
|
||||
input_file = file;
|
||||
current_line = 0;
|
||||
|
||||
while (get_next_line())
|
||||
{
|
||||
if (!(token = GetToken(1))) continue;
|
||||
if (strcmp(token, "@") == 0)
|
||||
{
|
||||
if (SpecType != SPEC_WIN32)
|
||||
{
|
||||
error( "'@' ordinals not supported for Win16\n" );
|
||||
continue;
|
||||
}
|
||||
if (!ParseOrdinal( -1 )) continue;
|
||||
}
|
||||
else if (IsNumberString(token))
|
||||
{
|
||||
if (!ParseOrdinal( atoi(token) )) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
error( "Expected ordinal declaration, got '%s'\n", token );
|
||||
continue;
|
||||
}
|
||||
if ((token = GetToken(1))) error( "Syntax error near '%s'\n", token );
|
||||
}
|
||||
|
||||
current_line = 0; /* no longer parsing the input file */
|
||||
sort_names();
|
||||
return !nb_errors;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* add_debug_channel
|
||||
*/
|
||||
static void add_debug_channel( const char *name )
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nb_debug_channels; i++)
|
||||
if (!strcmp( debug_channels[i], name )) return;
|
||||
|
||||
debug_channels = xrealloc( debug_channels, (nb_debug_channels + 1) * sizeof(*debug_channels));
|
||||
debug_channels[nb_debug_channels++] = xstrdup(name);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* parse_debug_channels
|
||||
*
|
||||
* Parse a source file and extract the debug channel definitions.
|
||||
*/
|
||||
int parse_debug_channels( const char *srcdir, const char *filename )
|
||||
{
|
||||
FILE *file;
|
||||
int eol_seen = 1;
|
||||
|
||||
file = open_input_file( srcdir, filename );
|
||||
while (fgets( ParseBuffer, sizeof(ParseBuffer), file ))
|
||||
{
|
||||
char *channel, *end, *p = ParseBuffer;
|
||||
|
||||
p = ParseBuffer + strlen(ParseBuffer) - 1;
|
||||
if (!eol_seen) /* continuation line */
|
||||
{
|
||||
eol_seen = (*p == '\n');
|
||||
continue;
|
||||
}
|
||||
if ((eol_seen = (*p == '\n'))) *p = 0;
|
||||
|
||||
p = ParseBuffer;
|
||||
while (isspace(*p)) p++;
|
||||
if (!memcmp( p, "WINE_DECLARE_DEBUG_CHANNEL", 26 ) ||
|
||||
!memcmp( p, "WINE_DEFAULT_DEBUG_CHANNEL", 26 ))
|
||||
{
|
||||
p += 26;
|
||||
while (isspace(*p)) p++;
|
||||
if (*p != '(')
|
||||
{
|
||||
error( "invalid debug channel specification '%s'\n", ParseBuffer );
|
||||
goto next;
|
||||
}
|
||||
p++;
|
||||
while (isspace(*p)) p++;
|
||||
if (!isalpha(*p))
|
||||
{
|
||||
error( "invalid debug channel specification '%s'\n", ParseBuffer );
|
||||
goto next;
|
||||
}
|
||||
channel = p;
|
||||
while (isalnum(*p) || *p == '_') p++;
|
||||
end = p;
|
||||
while (isspace(*p)) p++;
|
||||
if (*p != ')')
|
||||
{
|
||||
error( "invalid debug channel specification '%s'\n", ParseBuffer );
|
||||
goto next;
|
||||
}
|
||||
*end = 0;
|
||||
add_debug_channel( channel );
|
||||
}
|
||||
next:
|
||||
current_line++;
|
||||
}
|
||||
close_input_file( file );
|
||||
return !nb_errors;
|
||||
}
|
1188
reactos/tools/winebuild/relay.c
Normal file
1188
reactos/tools/winebuild/relay.c
Normal file
File diff suppressed because it is too large
Load diff
346
reactos/tools/winebuild/res16.c
Normal file
346
reactos/tools/winebuild/res16.c
Normal file
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* Builtin dlls resource support
|
||||
*
|
||||
* Copyright 2000 Alexandre Julliard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "build.h"
|
||||
|
||||
#define ALIGNMENT 2 /* alignment for resource data */
|
||||
#define ALIGN_MASK ((1 << ALIGNMENT) - 1)
|
||||
|
||||
/* Unicode string or integer id */
|
||||
struct string_id
|
||||
{
|
||||
char *str; /* ptr to string */
|
||||
WORD id; /* integer id if str is NULL */
|
||||
};
|
||||
|
||||
/* descriptor for a resource */
|
||||
struct resource
|
||||
{
|
||||
struct string_id type;
|
||||
struct string_id name;
|
||||
const void *data;
|
||||
unsigned int data_size;
|
||||
WORD memopt;
|
||||
};
|
||||
|
||||
/* type level of the resource tree */
|
||||
struct res_type
|
||||
{
|
||||
const struct string_id *type; /* type name */
|
||||
const struct resource *res; /* first resource of this type */
|
||||
unsigned int nb_names; /* total number of names */
|
||||
};
|
||||
|
||||
static struct resource *resources;
|
||||
static int nb_resources;
|
||||
|
||||
static struct res_type *res_types;
|
||||
static int nb_types; /* total number of types */
|
||||
|
||||
static const unsigned char *file_pos; /* current position in resource file */
|
||||
static const unsigned char *file_end; /* end of resource file */
|
||||
static const char *file_name; /* current resource file name */
|
||||
|
||||
|
||||
inline static struct resource *add_resource(void)
|
||||
{
|
||||
resources = xrealloc( resources, (nb_resources + 1) * sizeof(*resources) );
|
||||
return &resources[nb_resources++];
|
||||
}
|
||||
|
||||
static struct res_type *add_type( const struct resource *res )
|
||||
{
|
||||
struct res_type *type;
|
||||
res_types = xrealloc( res_types, (nb_types + 1) * sizeof(*res_types) );
|
||||
type = &res_types[nb_types++];
|
||||
type->type = &res->type;
|
||||
type->res = res;
|
||||
type->nb_names = 0;
|
||||
return type;
|
||||
}
|
||||
|
||||
/* get the next byte from the current resource file */
|
||||
static unsigned char get_byte(void)
|
||||
{
|
||||
unsigned char ret = *file_pos++;
|
||||
if (file_pos > file_end) fatal_error( "%s is a truncated/corrupted file\n", file_name );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* get the next word from the current resource file */
|
||||
static WORD get_word(void)
|
||||
{
|
||||
/* might not be aligned */
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
unsigned char high = get_byte();
|
||||
unsigned char low = get_byte();
|
||||
#else
|
||||
unsigned char low = get_byte();
|
||||
unsigned char high = get_byte();
|
||||
#endif
|
||||
return low | (high << 8);
|
||||
}
|
||||
|
||||
/* get the next dword from the current resource file */
|
||||
static DWORD get_dword(void)
|
||||
{
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
WORD high = get_word();
|
||||
WORD low = get_word();
|
||||
#else
|
||||
WORD low = get_word();
|
||||
WORD high = get_word();
|
||||
#endif
|
||||
return low | (high << 16);
|
||||
}
|
||||
|
||||
/* get a string from the current resource file */
|
||||
static void get_string( struct string_id *str )
|
||||
{
|
||||
if (*file_pos == 0xff)
|
||||
{
|
||||
get_byte(); /* skip the 0xff */
|
||||
str->str = NULL;
|
||||
str->id = get_word();
|
||||
}
|
||||
else
|
||||
{
|
||||
char *p = xmalloc( (strlen(file_pos) + 1) );
|
||||
str->str = p;
|
||||
str->id = 0;
|
||||
while ((*p++ = get_byte()));
|
||||
}
|
||||
}
|
||||
|
||||
/* load the next resource from the current file */
|
||||
static void load_next_resource(void)
|
||||
{
|
||||
struct resource *res = add_resource();
|
||||
|
||||
get_string( &res->type );
|
||||
get_string( &res->name );
|
||||
res->memopt = get_word();
|
||||
res->data_size = get_dword();
|
||||
res->data = file_pos;
|
||||
file_pos += res->data_size;
|
||||
if (file_pos > file_end) fatal_error( "%s is a truncated/corrupted file\n", file_name );
|
||||
}
|
||||
|
||||
/* load a Win16 .res file */
|
||||
void load_res16_file( const char *name )
|
||||
{
|
||||
int fd;
|
||||
void *base;
|
||||
struct stat st;
|
||||
|
||||
if ((fd = open( name, O_RDONLY )) == -1) fatal_perror( "Cannot open %s", name );
|
||||
if ((fstat( fd, &st ) == -1)) fatal_perror( "Cannot stat %s", name );
|
||||
if (!st.st_size) fatal_error( "%s is an empty file\n", name );
|
||||
#ifdef HAVE_MMAP
|
||||
if ((base = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 )) == (void*)-1)
|
||||
#endif /* HAVE_MMAP */
|
||||
{
|
||||
base = xmalloc( st.st_size );
|
||||
if (read( fd, base, st.st_size ) != st.st_size)
|
||||
fatal_error( "Cannot read %s\n", name );
|
||||
}
|
||||
|
||||
file_name = name;
|
||||
file_pos = base;
|
||||
file_end = file_pos + st.st_size;
|
||||
while (file_pos < file_end) load_next_resource();
|
||||
}
|
||||
|
||||
/* compare two strings/ids */
|
||||
static int cmp_string( const struct string_id *str1, const struct string_id *str2 )
|
||||
{
|
||||
if (!str1->str)
|
||||
{
|
||||
if (!str2->str) return str1->id - str2->id;
|
||||
return 1; /* an id compares larger than a string */
|
||||
}
|
||||
if (!str2->str) return -1;
|
||||
return strcasecmp( str1->str, str2->str );
|
||||
}
|
||||
|
||||
/* compare two resources for sorting the resource directory */
|
||||
/* resources are stored first by type, then by name */
|
||||
static int cmp_res( const void *ptr1, const void *ptr2 )
|
||||
{
|
||||
const struct resource *res1 = ptr1;
|
||||
const struct resource *res2 = ptr2;
|
||||
int ret;
|
||||
|
||||
if ((ret = cmp_string( &res1->type, &res2->type ))) return ret;
|
||||
return cmp_string( &res1->name, &res2->name );
|
||||
}
|
||||
|
||||
/* build the 2-level (type,name) resource tree */
|
||||
static void build_resource_tree(void)
|
||||
{
|
||||
int i;
|
||||
struct res_type *type = NULL;
|
||||
|
||||
qsort( resources, nb_resources, sizeof(*resources), cmp_res );
|
||||
|
||||
for (i = 0; i < nb_resources; i++)
|
||||
{
|
||||
if (!i || cmp_string( &resources[i].type, &resources[i-1].type )) /* new type */
|
||||
type = add_type( &resources[i] );
|
||||
type->nb_names++;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void put_byte( unsigned char **buffer, unsigned char val )
|
||||
{
|
||||
*(*buffer)++ = val;
|
||||
}
|
||||
|
||||
inline static void put_word( unsigned char **buffer, WORD val )
|
||||
{
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
put_byte( buffer, HIBYTE(val) );
|
||||
put_byte( buffer, LOBYTE(val) );
|
||||
#else
|
||||
put_byte( buffer, LOBYTE(val) );
|
||||
put_byte( buffer, HIBYTE(val) );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* output a string preceded by its length */
|
||||
static void output_string( unsigned char **buffer, const char *str )
|
||||
{
|
||||
int len = strlen(str);
|
||||
put_byte( buffer, len );
|
||||
while (len--) put_byte( buffer, *str++ );
|
||||
}
|
||||
|
||||
/* output the resource data */
|
||||
int output_res16_data( FILE *outfile )
|
||||
{
|
||||
const struct resource *res;
|
||||
unsigned char *buffer, *p;
|
||||
int i, total;
|
||||
|
||||
if (!nb_resources) return 0;
|
||||
|
||||
for (i = total = 0, res = resources; i < nb_resources; i++, res++)
|
||||
total += (res->data_size + ALIGN_MASK) & ~ALIGN_MASK;
|
||||
|
||||
buffer = p = xmalloc( total );
|
||||
for (i = 0, res = resources; i < nb_resources; i++, res++)
|
||||
{
|
||||
memcpy( p, res->data, res->data_size );
|
||||
p += res->data_size;
|
||||
while ((int)p & ALIGN_MASK) *p++ = 0;
|
||||
}
|
||||
dump_bytes( outfile, buffer, total, "resource_data", 1 );
|
||||
free( buffer );
|
||||
return total;
|
||||
}
|
||||
|
||||
/* output the resource definitions */
|
||||
int output_res16_directory( unsigned char *buffer )
|
||||
{
|
||||
int i, offset, res_offset = 0;
|
||||
unsigned int j;
|
||||
const struct res_type *type;
|
||||
const struct resource *res;
|
||||
unsigned char *start = buffer;
|
||||
|
||||
build_resource_tree();
|
||||
|
||||
offset = 4; /* alignment + terminator */
|
||||
offset += nb_types * 8; /* typeinfo structures */
|
||||
offset += nb_resources * 12; /* nameinfo structures */
|
||||
|
||||
put_word( &buffer, ALIGNMENT );
|
||||
|
||||
/* type and name structures */
|
||||
|
||||
for (i = 0, type = res_types; i < nb_types; i++, type++)
|
||||
{
|
||||
if (type->type->str)
|
||||
{
|
||||
put_word( &buffer, offset );
|
||||
offset += strlen(type->type->str) + 1;
|
||||
}
|
||||
else
|
||||
put_word( &buffer, type->type->id | 0x8000 );
|
||||
|
||||
put_word( &buffer, type->nb_names );
|
||||
put_word( &buffer, 0 );
|
||||
put_word( &buffer, 0 );
|
||||
|
||||
for (j = 0, res = type->res; j < type->nb_names; j++, res++)
|
||||
{
|
||||
put_word( &buffer, res_offset >> ALIGNMENT );
|
||||
put_word( &buffer, (res->data_size + ALIGN_MASK) >> ALIGNMENT );
|
||||
put_word( &buffer, res->memopt );
|
||||
if (res->name.str)
|
||||
{
|
||||
put_word( &buffer, offset );
|
||||
offset += strlen(res->name.str) + 1;
|
||||
}
|
||||
else
|
||||
put_word( &buffer, res->name.id | 0x8000 );
|
||||
put_word( &buffer, 0 );
|
||||
put_word( &buffer, 0 );
|
||||
res_offset += (res->data_size + ALIGN_MASK) & ~ALIGN_MASK;
|
||||
}
|
||||
}
|
||||
put_word( &buffer, 0 ); /* terminator */
|
||||
|
||||
/* name strings */
|
||||
|
||||
for (i = 0, type = res_types; i < nb_types; i++, type++)
|
||||
{
|
||||
if (type->type->str) output_string( &buffer, type->type->str );
|
||||
for (j = 0, res = type->res; j < type->nb_names; j++, res++)
|
||||
{
|
||||
if (res->name.str) output_string( &buffer, res->name.str );
|
||||
}
|
||||
}
|
||||
put_byte( &buffer, 0 ); /* names terminator */
|
||||
if ((buffer - start) & 1) put_byte( &buffer, 0 ); /* align on word boundary */
|
||||
|
||||
return buffer - start;
|
||||
}
|
452
reactos/tools/winebuild/res32.c
Normal file
452
reactos/tools/winebuild/res32.c
Normal file
|
@ -0,0 +1,452 @@
|
|||
/*
|
||||
* Builtin dlls resource support
|
||||
*
|
||||
* Copyright 2000 Alexandre Julliard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "build.h"
|
||||
|
||||
/* Unicode string or integer id */
|
||||
struct string_id
|
||||
{
|
||||
WCHAR *str; /* ptr to Unicode string */
|
||||
WORD id; /* integer id if str is NULL */
|
||||
};
|
||||
|
||||
/* descriptor for a resource */
|
||||
struct resource
|
||||
{
|
||||
struct string_id type;
|
||||
struct string_id name;
|
||||
const void *data;
|
||||
unsigned int data_size;
|
||||
WORD lang;
|
||||
};
|
||||
|
||||
/* name level of the resource tree */
|
||||
struct res_name
|
||||
{
|
||||
const struct string_id *name; /* name */
|
||||
const struct resource *res; /* resource */
|
||||
int nb_languages; /* number of languages */
|
||||
};
|
||||
|
||||
/* type level of the resource tree */
|
||||
struct res_type
|
||||
{
|
||||
const struct string_id *type; /* type name */
|
||||
struct res_name *names; /* names array */
|
||||
unsigned int nb_names; /* total number of names */
|
||||
unsigned int nb_id_names; /* number of names that have a numeric id */
|
||||
};
|
||||
|
||||
static struct resource *resources;
|
||||
static int nb_resources;
|
||||
|
||||
static struct res_type *res_types;
|
||||
static int nb_types; /* total number of types */
|
||||
static int nb_id_types; /* number of types that have a numeric id */
|
||||
|
||||
static const unsigned char *file_pos; /* current position in resource file */
|
||||
static const unsigned char *file_end; /* end of resource file */
|
||||
static const char *file_name; /* current resource file name */
|
||||
|
||||
|
||||
inline static struct resource *add_resource(void)
|
||||
{
|
||||
resources = xrealloc( resources, (nb_resources + 1) * sizeof(*resources) );
|
||||
return &resources[nb_resources++];
|
||||
}
|
||||
|
||||
static inline unsigned int strlenW( const WCHAR *str )
|
||||
{
|
||||
const WCHAR *s = str;
|
||||
while (*s) s++;
|
||||
return s - str;
|
||||
}
|
||||
|
||||
static inline int strcmpW( const WCHAR *str1, const WCHAR *str2 )
|
||||
{
|
||||
while (*str1 && (*str1 == *str2)) { str1++; str2++; }
|
||||
return *str1 - *str2;
|
||||
}
|
||||
|
||||
static struct res_name *add_name( struct res_type *type, const struct resource *res )
|
||||
{
|
||||
struct res_name *name;
|
||||
type->names = xrealloc( type->names, (type->nb_names + 1) * sizeof(*type->names) );
|
||||
name = &type->names[type->nb_names++];
|
||||
name->name = &res->name;
|
||||
name->res = res;
|
||||
name->nb_languages = 1;
|
||||
if (!name->name->str) type->nb_id_names++;
|
||||
return name;
|
||||
}
|
||||
|
||||
static struct res_type *add_type( const struct resource *res )
|
||||
{
|
||||
struct res_type *type;
|
||||
res_types = xrealloc( res_types, (nb_types + 1) * sizeof(*res_types) );
|
||||
type = &res_types[nb_types++];
|
||||
type->type = &res->type;
|
||||
type->names = NULL;
|
||||
type->nb_names = 0;
|
||||
type->nb_id_names = 0;
|
||||
if (!type->type->str) nb_id_types++;
|
||||
return type;
|
||||
}
|
||||
|
||||
/* get the next word from the current resource file */
|
||||
static WORD get_word(void)
|
||||
{
|
||||
WORD ret = *(WORD *)file_pos;
|
||||
file_pos += sizeof(WORD);
|
||||
if (file_pos > file_end) fatal_error( "%s is a truncated file\n", file_name );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* get the next dword from the current resource file */
|
||||
static DWORD get_dword(void)
|
||||
{
|
||||
DWORD ret = *(DWORD *)file_pos;
|
||||
file_pos += sizeof(DWORD);
|
||||
if (file_pos > file_end) fatal_error( "%s is a truncated file\n", file_name );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* get a string from the current resource file */
|
||||
static void get_string( struct string_id *str )
|
||||
{
|
||||
if (*(WCHAR *)file_pos == 0xffff)
|
||||
{
|
||||
get_word(); /* skip the 0xffff */
|
||||
str->str = NULL;
|
||||
str->id = get_word();
|
||||
}
|
||||
else
|
||||
{
|
||||
WCHAR *p = xmalloc( (strlenW((WCHAR*)file_pos) + 1) * sizeof(WCHAR) );
|
||||
str->str = p;
|
||||
str->id = 0;
|
||||
while ((*p++ = get_word()));
|
||||
}
|
||||
}
|
||||
|
||||
/* check the file header */
|
||||
/* all values must be zero except header size */
|
||||
static int check_header(void)
|
||||
{
|
||||
if (get_dword()) return 0; /* data size */
|
||||
if (get_dword() != 32) return 0; /* header size */
|
||||
if (get_word() != 0xffff || get_word()) return 0; /* type, must be id 0 */
|
||||
if (get_word() != 0xffff || get_word()) return 0; /* name, must be id 0 */
|
||||
if (get_dword()) return 0; /* data version */
|
||||
if (get_word()) return 0; /* mem options */
|
||||
if (get_word()) return 0; /* language */
|
||||
if (get_dword()) return 0; /* version */
|
||||
if (get_dword()) return 0; /* characteristics */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* load the next resource from the current file */
|
||||
static void load_next_resource(void)
|
||||
{
|
||||
DWORD hdr_size;
|
||||
struct resource *res = add_resource();
|
||||
|
||||
res->data_size = (get_dword() + 3) & ~3;
|
||||
hdr_size = get_dword();
|
||||
if (hdr_size & 3) fatal_error( "%s header size not aligned\n", file_name );
|
||||
|
||||
res->data = file_pos - 2*sizeof(DWORD) + hdr_size;
|
||||
get_string( &res->type );
|
||||
get_string( &res->name );
|
||||
if ((int)file_pos & 2) get_word(); /* align to dword boundary */
|
||||
get_dword(); /* skip data version */
|
||||
get_word(); /* skip mem options */
|
||||
res->lang = get_word();
|
||||
get_dword(); /* skip version */
|
||||
get_dword(); /* skip characteristics */
|
||||
|
||||
file_pos = (char *)res->data + res->data_size;
|
||||
if (file_pos > file_end) fatal_error( "%s is a truncated file\n", file_name );
|
||||
}
|
||||
|
||||
/* load a Win32 .res file */
|
||||
int load_res32_file( const char *name )
|
||||
{
|
||||
int fd, ret;
|
||||
void *base;
|
||||
struct stat st;
|
||||
|
||||
if ((fd = open( name, O_RDONLY )) == -1) fatal_perror( "Cannot open %s", name );
|
||||
if ((fstat( fd, &st ) == -1)) fatal_perror( "Cannot stat %s", name );
|
||||
if (!st.st_size) fatal_error( "%s is an empty file\n", name );
|
||||
#ifdef HAVE_MMAP
|
||||
if ((base = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 )) == (void*)-1)
|
||||
#endif /* HAVE_MMAP */
|
||||
{
|
||||
base = xmalloc( st.st_size );
|
||||
if (read( fd, base, st.st_size ) != st.st_size)
|
||||
fatal_error( "Cannot read %s\n", name );
|
||||
}
|
||||
|
||||
file_name = name;
|
||||
file_pos = base;
|
||||
file_end = file_pos + st.st_size;
|
||||
if ((ret = check_header()))
|
||||
{
|
||||
while (file_pos < file_end) load_next_resource();
|
||||
}
|
||||
close( fd );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* compare two unicode strings/ids */
|
||||
static int cmp_string( const struct string_id *str1, const struct string_id *str2 )
|
||||
{
|
||||
if (!str1->str)
|
||||
{
|
||||
if (!str2->str) return str1->id - str2->id;
|
||||
return 1; /* an id compares larger than a string */
|
||||
}
|
||||
if (!str2->str) return -1;
|
||||
return strcmpW( str1->str, str2->str );
|
||||
}
|
||||
|
||||
/* compare two resources for sorting the resource directory */
|
||||
/* resources are stored first by type, then by name, then by language */
|
||||
static int cmp_res( const void *ptr1, const void *ptr2 )
|
||||
{
|
||||
const struct resource *res1 = ptr1;
|
||||
const struct resource *res2 = ptr2;
|
||||
int ret;
|
||||
|
||||
if ((ret = cmp_string( &res1->type, &res2->type ))) return ret;
|
||||
if ((ret = cmp_string( &res1->name, &res2->name ))) return ret;
|
||||
return res1->lang - res2->lang;
|
||||
}
|
||||
|
||||
/* build the 3-level (type,name,language) resource tree */
|
||||
static void build_resource_tree(void)
|
||||
{
|
||||
int i;
|
||||
struct res_type *type = NULL;
|
||||
struct res_name *name = NULL;
|
||||
|
||||
qsort( resources, nb_resources, sizeof(*resources), cmp_res );
|
||||
|
||||
for (i = 0; i < nb_resources; i++)
|
||||
{
|
||||
if (!i || cmp_string( &resources[i].type, &resources[i-1].type )) /* new type */
|
||||
{
|
||||
type = add_type( &resources[i] );
|
||||
name = add_name( type, &resources[i] );
|
||||
}
|
||||
else if (cmp_string( &resources[i].name, &resources[i-1].name )) /* new name */
|
||||
{
|
||||
name = add_name( type, &resources[i] );
|
||||
}
|
||||
else name->nb_languages++;
|
||||
}
|
||||
}
|
||||
|
||||
/* output a Unicode string */
|
||||
static void output_string( FILE *outfile, const WCHAR *name )
|
||||
{
|
||||
int i, len = strlenW(name);
|
||||
fprintf( outfile, "0x%04x", len );
|
||||
for (i = 0; i < len; i++) fprintf( outfile, ", 0x%04x", name[i] );
|
||||
fprintf( outfile, " /* " );
|
||||
for (i = 0; i < len; i++) fprintf( outfile, "%c", isprint((char)name[i]) ? (char)name[i] : '?' );
|
||||
fprintf( outfile, " */" );
|
||||
}
|
||||
|
||||
/* output the resource definitions */
|
||||
int output_resources( FILE *outfile )
|
||||
{
|
||||
int i, j, k;
|
||||
unsigned int n;
|
||||
const struct res_type *type;
|
||||
const struct res_name *name;
|
||||
const struct resource *res;
|
||||
|
||||
if (!nb_resources) return 0;
|
||||
|
||||
build_resource_tree();
|
||||
|
||||
/* resource data */
|
||||
|
||||
for (i = 0, res = resources; i < nb_resources; i++, res++)
|
||||
{
|
||||
const unsigned int *p = res->data;
|
||||
int size = res->data_size / 4;
|
||||
/* dump data as ints to ensure correct alignment */
|
||||
fprintf( outfile, "static const unsigned int res_%d[%d] = {\n ", i, size );
|
||||
for (j = 0; j < size - 1; j++, p++)
|
||||
{
|
||||
fprintf( outfile, "0x%08x,", *p );
|
||||
if ((j % 8) == 7) fprintf( outfile, "\n " );
|
||||
}
|
||||
fprintf( outfile, "0x%08x\n};\n\n", *p );
|
||||
}
|
||||
|
||||
/* directory structures */
|
||||
|
||||
fprintf( outfile, "struct res_dir {\n" );
|
||||
fprintf( outfile, " unsigned int Characteristics;\n" );
|
||||
fprintf( outfile, " unsigned int TimeDateStamp;\n" );
|
||||
fprintf( outfile, " unsigned short MajorVersion, MinorVersion;\n" );
|
||||
fprintf( outfile, " unsigned short NumerOfNamedEntries, NumberOfIdEntries;\n};\n\n" );
|
||||
fprintf( outfile, "struct res_dir_entry {\n" );
|
||||
fprintf( outfile, " unsigned int Name;\n" );
|
||||
fprintf( outfile, " unsigned int OffsetToData;\n};\n\n" );
|
||||
fprintf( outfile, "struct res_data_entry {\n" );
|
||||
fprintf( outfile, " const unsigned int *OffsetToData;\n" );
|
||||
fprintf( outfile, " unsigned int Size;\n" );
|
||||
fprintf( outfile, " unsigned int CodePage;\n" );
|
||||
fprintf( outfile, " unsigned int ResourceHandle;\n};\n\n" );
|
||||
|
||||
/* resource directory definition */
|
||||
|
||||
fprintf( outfile, "#define OFFSETOF(field) ((char*)&((struct res_struct *)0)->field - (char*)((struct res_struct *) 0))\n" );
|
||||
fprintf( outfile, "static struct res_struct{\n" );
|
||||
fprintf( outfile, " struct res_dir type_dir;\n" );
|
||||
fprintf( outfile, " struct res_dir_entry type_entries[%d];\n", nb_types );
|
||||
|
||||
for (i = 0, type = res_types; i < nb_types; i++, type++)
|
||||
{
|
||||
fprintf( outfile, " struct res_dir name_%d_dir;\n", i );
|
||||
fprintf( outfile, " struct res_dir_entry name_%d_entries[%d];\n", i, type->nb_names );
|
||||
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
|
||||
{
|
||||
fprintf( outfile, " struct res_dir lang_%d_%d_dir;\n", i, n );
|
||||
fprintf( outfile, " struct res_dir_entry lang_%d_%d_entries[%d];\n",
|
||||
i, n, name->nb_languages );
|
||||
}
|
||||
}
|
||||
|
||||
fprintf( outfile, " struct res_data_entry data_entries[%d];\n", nb_resources );
|
||||
|
||||
for (i = 0, type = res_types; i < nb_types; i++, type++)
|
||||
{
|
||||
if (type->type->str)
|
||||
fprintf( outfile, " unsigned short type_%d_name[%d];\n",
|
||||
i, strlenW(type->type->str)+1 );
|
||||
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
|
||||
{
|
||||
if (name->name->str)
|
||||
fprintf( outfile, " unsigned short name_%d_%d_name[%d];\n",
|
||||
i, n, strlenW(name->name->str)+1 );
|
||||
}
|
||||
}
|
||||
|
||||
/* resource directory contents */
|
||||
|
||||
fprintf( outfile, "} resources = {\n" );
|
||||
fprintf( outfile, " { 0, 0, 0, 0, %d, %d },\n", nb_types - nb_id_types, nb_id_types );
|
||||
|
||||
/* dump the type directory */
|
||||
fprintf( outfile, " {\n" );
|
||||
for (i = 0, type = res_types; i < nb_types; i++, type++)
|
||||
{
|
||||
if (!type->type->str)
|
||||
fprintf( outfile, " { 0x%04x, OFFSETOF(name_%d_dir) | 0x80000000 },\n",
|
||||
type->type->id, i );
|
||||
else
|
||||
fprintf( outfile, " { OFFSETOF(type_%d_name) | 0x80000000, OFFSETOF(name_%d_dir) | 0x80000000 },\n",
|
||||
i, i );
|
||||
}
|
||||
fprintf( outfile, " },\n" );
|
||||
|
||||
/* dump the names and languages directories */
|
||||
for (i = 0, type = res_types; i < nb_types; i++, type++)
|
||||
{
|
||||
fprintf( outfile, " { 0, 0, 0, 0, %d, %d }, /* name_%d_dir */\n {\n",
|
||||
type->nb_names - type->nb_id_names, type->nb_id_names, i );
|
||||
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
|
||||
{
|
||||
if (!name->name->str)
|
||||
fprintf( outfile, " { 0x%04x, OFFSETOF(lang_%d_%d_dir) | 0x80000000 },\n",
|
||||
name->name->id, i, n );
|
||||
else
|
||||
fprintf( outfile, " { OFFSETOF(name_%d_%d_name) | 0x80000000, OFFSETOF(lang_%d_%d_dir) | 0x80000000 },\n",
|
||||
i, n, i, n );
|
||||
}
|
||||
fprintf( outfile, " },\n" );
|
||||
|
||||
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
|
||||
{
|
||||
fprintf( outfile, " { 0, 0, 0, 0, 0, %d }, /* lang_%d_%d_dir */\n {\n",
|
||||
name->nb_languages, i, n );
|
||||
for (k = 0, res = name->res; k < name->nb_languages; k++, res++)
|
||||
{
|
||||
fprintf( outfile, " { 0x%04x, OFFSETOF(data_entries[%d]) },\n",
|
||||
res->lang, res - resources );
|
||||
}
|
||||
fprintf( outfile, " },\n" );
|
||||
}
|
||||
}
|
||||
|
||||
/* dump the resource data entries */
|
||||
fprintf( outfile, " {\n" );
|
||||
for (i = 0, res = resources; i < nb_resources; i++, res++)
|
||||
{
|
||||
fprintf( outfile, " { res_%d, sizeof(res_%d), 0, 0 },\n", i, i );
|
||||
}
|
||||
|
||||
/* dump the name strings */
|
||||
for (i = 0, type = res_types; i < nb_types; i++, type++)
|
||||
{
|
||||
if (type->type->str)
|
||||
{
|
||||
fprintf( outfile, " },\n { " );
|
||||
output_string( outfile, type->type->str );
|
||||
}
|
||||
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
|
||||
{
|
||||
if (name->name->str)
|
||||
{
|
||||
fprintf( outfile, " },\n { " );
|
||||
output_string( outfile, name->name->str );
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf( outfile, " }\n};\n#undef OFFSETOF\n\n" );
|
||||
return nb_resources;
|
||||
}
|
841
reactos/tools/winebuild/spec16.c
Normal file
841
reactos/tools/winebuild/spec16.c
Normal file
|
@ -0,0 +1,841 @@
|
|||
/*
|
||||
* 16-bit spec files
|
||||
*
|
||||
* Copyright 1993 Robert J. Amstadt
|
||||
* Copyright 1995 Martin von Loewis
|
||||
* Copyright 1995, 1996, 1997 Alexandre Julliard
|
||||
* Copyright 1997 Eric Youngdale
|
||||
* Copyright 1999 Ulrich Weigand
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "wine/exception.h"
|
||||
#include "stackframe.h"
|
||||
#include "builtin16.h"
|
||||
#include "module.h"
|
||||
|
||||
#include "build.h"
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* get_cs
|
||||
*/
|
||||
#ifdef __i386__
|
||||
static inline unsigned short get_cs(void)
|
||||
{
|
||||
unsigned short res;
|
||||
#ifdef __GNUC__
|
||||
__asm__("movw %%cs,%w0" : "=r"(res));
|
||||
#elif defined(_MSC_VER)
|
||||
__asm { mov res, cs }
|
||||
#else
|
||||
res = 0;
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
#endif /* __i386__ */
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* output_file_header
|
||||
*
|
||||
* Output a file header with the common declarations we need.
|
||||
*/
|
||||
static void output_file_header( FILE *outfile )
|
||||
{
|
||||
output_standard_file_header( outfile );
|
||||
fprintf( outfile, "extern struct\n{\n" );
|
||||
fprintf( outfile, " void *base[8192];\n" );
|
||||
fprintf( outfile, " unsigned long limit[8192];\n" );
|
||||
fprintf( outfile, " unsigned char flags[8192];\n" );
|
||||
fprintf( outfile, "} wine_ldt_copy;\n\n" );
|
||||
#ifdef __i386__
|
||||
fprintf( outfile, "#define __stdcall __attribute__((__stdcall__))\n\n" );
|
||||
#else
|
||||
fprintf( outfile, "#define __stdcall\n\n" );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* StoreVariableCode
|
||||
*
|
||||
* Store a list of ints into a byte array.
|
||||
*/
|
||||
static int StoreVariableCode( unsigned char *buffer, int size, ORDDEF *odp )
|
||||
{
|
||||
int i;
|
||||
|
||||
switch(size)
|
||||
{
|
||||
case 1:
|
||||
for (i = 0; i < odp->u.var.n_values; i++)
|
||||
buffer[i] = odp->u.var.values[i];
|
||||
break;
|
||||
case 2:
|
||||
for (i = 0; i < odp->u.var.n_values; i++)
|
||||
((unsigned short *)buffer)[i] = odp->u.var.values[i];
|
||||
break;
|
||||
case 4:
|
||||
for (i = 0; i < odp->u.var.n_values; i++)
|
||||
((unsigned int *)buffer)[i] = odp->u.var.values[i];
|
||||
break;
|
||||
}
|
||||
return odp->u.var.n_values * size;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* BuildModule16
|
||||
*
|
||||
* Build the in-memory representation of a 16-bit NE module, and dump it
|
||||
* as a byte stream into the assembly code.
|
||||
*/
|
||||
static int BuildModule16( FILE *outfile, int max_code_offset,
|
||||
int max_data_offset )
|
||||
{
|
||||
int i;
|
||||
char *buffer;
|
||||
NE_MODULE *pModule;
|
||||
SEGTABLEENTRY *pSegment;
|
||||
OFSTRUCT *pFileInfo;
|
||||
BYTE *pstr;
|
||||
ET_BUNDLE *bundle = 0;
|
||||
ET_ENTRY entry;
|
||||
|
||||
/* Module layout:
|
||||
* NE_MODULE Module
|
||||
* OFSTRUCT File information
|
||||
* SEGTABLEENTRY Segment 1 (code)
|
||||
* SEGTABLEENTRY Segment 2 (data)
|
||||
* WORD[2] Resource table (empty)
|
||||
* BYTE[2] Imported names (empty)
|
||||
* BYTE[n] Resident names table
|
||||
* BYTE[n] Entry table
|
||||
*/
|
||||
|
||||
buffer = xmalloc( 0x10000 );
|
||||
memset( buffer, 0, 0x10000 );
|
||||
|
||||
pModule = (NE_MODULE *)buffer;
|
||||
pModule->magic = IMAGE_OS2_SIGNATURE;
|
||||
pModule->count = 1;
|
||||
pModule->next = 0;
|
||||
pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN | NE_FFLAGS_LIBMODULE;
|
||||
pModule->dgroup = 2;
|
||||
pModule->heap_size = DLLHeapSize;
|
||||
pModule->stack_size = 0;
|
||||
pModule->ip = 0;
|
||||
pModule->cs = 0;
|
||||
pModule->sp = 0;
|
||||
pModule->ss = 0;
|
||||
pModule->seg_count = 2;
|
||||
pModule->modref_count = 0;
|
||||
pModule->nrname_size = 0;
|
||||
pModule->modref_table = 0;
|
||||
pModule->nrname_fpos = 0;
|
||||
pModule->moveable_entries = 0;
|
||||
pModule->alignment = 0;
|
||||
pModule->truetype = 0;
|
||||
pModule->os_flags = NE_OSFLAGS_WINDOWS;
|
||||
pModule->misc_flags = 0;
|
||||
pModule->dlls_to_init = 0;
|
||||
pModule->nrname_handle = 0;
|
||||
pModule->min_swap_area = 0;
|
||||
pModule->expected_version = 0;
|
||||
pModule->module32 = 0;
|
||||
pModule->self = 0;
|
||||
pModule->self_loading_sel = 0;
|
||||
|
||||
/* File information */
|
||||
|
||||
pFileInfo = (OFSTRUCT *)(pModule + 1);
|
||||
pModule->fileinfo = (int)pFileInfo - (int)pModule;
|
||||
memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) );
|
||||
pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName)
|
||||
+ strlen(dll_file_name);
|
||||
strcpy( pFileInfo->szPathName, dll_file_name );
|
||||
pstr = (char *)pFileInfo + pFileInfo->cBytes + 1;
|
||||
|
||||
/* Segment table */
|
||||
|
||||
pstr = (char *)(((long)pstr + 3) & ~3);
|
||||
pSegment = (SEGTABLEENTRY *)pstr;
|
||||
pModule->seg_table = (int)pSegment - (int)pModule;
|
||||
pSegment->filepos = 0;
|
||||
pSegment->size = max_code_offset;
|
||||
pSegment->flags = 0;
|
||||
pSegment->minsize = max_code_offset;
|
||||
pSegment->hSeg = 0;
|
||||
pSegment++;
|
||||
|
||||
pModule->dgroup_entry = (int)pSegment - (int)pModule;
|
||||
pSegment->filepos = 0;
|
||||
pSegment->size = max_data_offset;
|
||||
pSegment->flags = NE_SEGFLAGS_DATA;
|
||||
pSegment->minsize = max_data_offset;
|
||||
pSegment->hSeg = 0;
|
||||
pSegment++;
|
||||
|
||||
/* Resource table */
|
||||
|
||||
pstr = (char *)pSegment;
|
||||
pstr = (char *)(((long)pstr + 3) & ~3);
|
||||
pModule->res_table = (int)pstr - (int)pModule;
|
||||
pstr += output_res16_directory( pstr );
|
||||
|
||||
/* Imported names table */
|
||||
|
||||
pstr = (char *)(((long)pstr + 3) & ~3);
|
||||
pModule->import_table = (int)pstr - (int)pModule;
|
||||
*pstr++ = 0;
|
||||
*pstr++ = 0;
|
||||
|
||||
/* Resident names table */
|
||||
|
||||
pstr = (char *)(((long)pstr + 3) & ~3);
|
||||
pModule->name_table = (int)pstr - (int)pModule;
|
||||
/* First entry is module name */
|
||||
*pstr = strlen( dll_name );
|
||||
strcpy( pstr + 1, dll_name );
|
||||
strupper( pstr + 1 );
|
||||
pstr += *pstr + 1;
|
||||
*pstr++ = 0;
|
||||
*pstr++ = 0;
|
||||
/* Store all ordinals */
|
||||
for (i = 1; i <= Limit; i++)
|
||||
{
|
||||
ORDDEF *odp = Ordinals[i];
|
||||
WORD ord = i;
|
||||
if (!odp || !odp->name[0]) continue;
|
||||
*pstr = strlen( odp->name );
|
||||
strcpy( pstr + 1, odp->name );
|
||||
strupper( pstr + 1 );
|
||||
pstr += *pstr + 1;
|
||||
memcpy( pstr, &ord, sizeof(WORD) );
|
||||
pstr += sizeof(WORD);
|
||||
}
|
||||
*pstr++ = 0;
|
||||
|
||||
/* Entry table */
|
||||
|
||||
pstr = (char *)(((long)pstr + 3) & ~3);
|
||||
pModule->entry_table = (int)pstr - (int)pModule;
|
||||
for (i = 1; i <= Limit; i++)
|
||||
{
|
||||
int selector = 0;
|
||||
ORDDEF *odp = Ordinals[i];
|
||||
if (!odp) continue;
|
||||
|
||||
switch (odp->type)
|
||||
{
|
||||
case TYPE_CDECL:
|
||||
case TYPE_PASCAL:
|
||||
case TYPE_VARARGS:
|
||||
case TYPE_STUB:
|
||||
selector = 1; /* Code selector */
|
||||
break;
|
||||
|
||||
case TYPE_VARIABLE:
|
||||
selector = 2; /* Data selector */
|
||||
break;
|
||||
|
||||
case TYPE_ABS:
|
||||
selector = 0xfe; /* Constant selector */
|
||||
break;
|
||||
|
||||
default:
|
||||
selector = 0; /* Invalid selector */
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !selector )
|
||||
continue;
|
||||
|
||||
if ( bundle && bundle->last+1 == i )
|
||||
bundle->last++;
|
||||
else
|
||||
{
|
||||
pstr = (char *)(((long)pstr + 1) & ~1);
|
||||
if ( bundle )
|
||||
bundle->next = (char *)pstr - (char *)pModule;
|
||||
|
||||
bundle = (ET_BUNDLE *)pstr;
|
||||
bundle->first = i-1;
|
||||
bundle->last = i;
|
||||
bundle->next = 0;
|
||||
pstr += sizeof(ET_BUNDLE);
|
||||
}
|
||||
|
||||
/* FIXME: is this really correct ?? */
|
||||
entry.type = 0xff; /* movable */
|
||||
entry.flags = 3; /* exported & public data */
|
||||
entry.segnum = selector;
|
||||
entry.offs = odp->offset;
|
||||
memcpy( pstr, &entry, sizeof(ET_ENTRY) );
|
||||
pstr += sizeof(ET_ENTRY);
|
||||
}
|
||||
*pstr++ = 0;
|
||||
|
||||
/* Dump the module content */
|
||||
|
||||
pstr = (char *)(((long)pstr + 3) & ~3);
|
||||
dump_bytes( outfile, (char *)pModule, (int)pstr - (int)pModule, "Module", 0 );
|
||||
return (int)pstr - (int)pModule;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* BuildCallFrom16Func
|
||||
*
|
||||
* Build a 16-bit-to-Wine callback glue function.
|
||||
*
|
||||
* The generated routines are intended to be used as argument conversion
|
||||
* routines to be called by the CallFrom16... core. Thus, the prototypes of
|
||||
* the generated routines are (see also CallFrom16):
|
||||
*
|
||||
* extern WORD WINAPI PREFIX_CallFrom16_C_word_xxx( FARPROC func, LPBYTE args );
|
||||
* extern LONG WINAPI PREFIX_CallFrom16_C_long_xxx( FARPROC func, LPBYTE args );
|
||||
* extern void WINAPI PREFIX_CallFrom16_C_regs_xxx( FARPROC func, LPBYTE args,
|
||||
* CONTEXT86 *context );
|
||||
* extern void WINAPI PREFIX_CallFrom16_C_intr_xxx( FARPROC func, LPBYTE args,
|
||||
* CONTEXT86 *context );
|
||||
*
|
||||
* where 'C' is the calling convention ('p' for pascal or 'c' for cdecl),
|
||||
* and each 'x' is an argument ('w'=word, 's'=signed word, 'l'=long,
|
||||
* 'p'=linear pointer, 't'=linear pointer to null-terminated string,
|
||||
* 'T'=segmented pointer to null-terminated string).
|
||||
*
|
||||
* The generated routines fetch the arguments from the 16-bit stack (pointed
|
||||
* to by 'args'); the offsets of the single argument values are computed
|
||||
* according to the calling convention and the argument types. Then, the
|
||||
* 32-bit entry point is called with these arguments.
|
||||
*
|
||||
* For register functions, the arguments (if present) are converted just
|
||||
* the same as for normal functions, but in addition the CONTEXT86 pointer
|
||||
* filled with the current register values is passed to the 32-bit routine.
|
||||
* (An 'intr' interrupt handler routine is treated exactly like a register
|
||||
* routine, except that upon return, the flags word pushed onto the stack
|
||||
* by the interrupt is removed by the 16-bit call stub.)
|
||||
*
|
||||
*/
|
||||
static void BuildCallFrom16Func( FILE *outfile, const char *profile, const char *prefix )
|
||||
{
|
||||
int i, pos, argsize = 0;
|
||||
int short_ret = 0;
|
||||
int reg_func = 0;
|
||||
int usecdecl = 0;
|
||||
int varargs = 0;
|
||||
const char *args = profile + 7;
|
||||
const char *ret_type;
|
||||
|
||||
/* Parse function type */
|
||||
|
||||
if (!strncmp( "c_", profile, 2 )) usecdecl = 1;
|
||||
else if (!strncmp( "v_", profile, 2 )) varargs = usecdecl = 1;
|
||||
else if (strncmp( "p_", profile, 2 ))
|
||||
{
|
||||
fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strncmp( "word_", profile + 2, 5 )) short_ret = 1;
|
||||
else if (!strncmp( "regs_", profile + 2, 5 )) reg_func = 1;
|
||||
else if (!strncmp( "intr_", profile + 2, 5 )) reg_func = 2;
|
||||
else if (strncmp( "long_", profile + 2, 5 ))
|
||||
{
|
||||
fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
|
||||
return;
|
||||
}
|
||||
|
||||
for ( i = 0; args[i]; i++ )
|
||||
switch ( args[i] )
|
||||
{
|
||||
case 'w': /* word */
|
||||
case 's': /* s_word */
|
||||
argsize += 2;
|
||||
break;
|
||||
case 'l': /* long or segmented pointer */
|
||||
case 'T': /* segmented pointer to null-terminated string */
|
||||
case 'p': /* linear pointer */
|
||||
case 't': /* linear pointer to null-terminated string */
|
||||
argsize += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
ret_type = reg_func? "void" : short_ret ? "unsigned short" : "unsigned int";
|
||||
|
||||
fprintf( outfile, "typedef %s (%s*proc_%s_t)( ",
|
||||
ret_type, usecdecl ? "" : "__stdcall ", profile );
|
||||
args = profile + 7;
|
||||
for ( i = 0; args[i]; i++ )
|
||||
{
|
||||
if ( i ) fprintf( outfile, ", " );
|
||||
switch (args[i])
|
||||
{
|
||||
case 'w': fprintf( outfile, "unsigned short" ); break;
|
||||
case 's': fprintf( outfile, "short" ); break;
|
||||
case 'l': case 'T': fprintf( outfile, "unsigned int" ); break;
|
||||
case 'p': case 't': fprintf( outfile, "void *" ); break;
|
||||
}
|
||||
}
|
||||
if (reg_func || varargs)
|
||||
fprintf( outfile, "%svoid *", i? ", " : "" );
|
||||
else if ( !i )
|
||||
fprintf( outfile, "void" );
|
||||
fprintf( outfile, " );\n" );
|
||||
|
||||
fprintf( outfile, "static %s __stdcall __wine_%s_CallFrom16_%s( proc_%s_t proc, unsigned char *args%s )\n",
|
||||
ret_type, make_c_identifier(prefix), profile, profile,
|
||||
reg_func? ", void *context" : "" );
|
||||
|
||||
fprintf( outfile, "{\n %sproc(\n", reg_func ? "" : "return " );
|
||||
args = profile + 7;
|
||||
pos = !usecdecl? argsize : 0;
|
||||
for ( i = 0; args[i]; i++ )
|
||||
{
|
||||
if ( i ) fprintf( outfile, ",\n" );
|
||||
fprintf( outfile, " " );
|
||||
switch (args[i])
|
||||
{
|
||||
case 'w': /* word */
|
||||
if ( !usecdecl ) pos -= 2;
|
||||
fprintf( outfile, "*(unsigned short *)(args+%d)", pos );
|
||||
if ( usecdecl ) pos += 2;
|
||||
break;
|
||||
|
||||
case 's': /* s_word */
|
||||
if ( !usecdecl ) pos -= 2;
|
||||
fprintf( outfile, "*(short *)(args+%d)", pos );
|
||||
if ( usecdecl ) pos += 2;
|
||||
break;
|
||||
|
||||
case 'l': /* long or segmented pointer */
|
||||
case 'T': /* segmented pointer to null-terminated string */
|
||||
if ( !usecdecl ) pos -= 4;
|
||||
fprintf( outfile, "*(unsigned int *)(args+%d)", pos );
|
||||
if ( usecdecl ) pos += 4;
|
||||
break;
|
||||
|
||||
case 'p': /* linear pointer */
|
||||
case 't': /* linear pointer to null-terminated string */
|
||||
if ( !usecdecl ) pos -= 4;
|
||||
fprintf( outfile, "((char*)wine_ldt_copy.base[*(unsigned short*)(args+%d) >> 3] + *(unsigned short*)(args+%d))",
|
||||
pos + 2, pos );
|
||||
if ( usecdecl ) pos += 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf( stderr, "Unknown arg type '%c'\n", args[i] );
|
||||
}
|
||||
}
|
||||
if ( reg_func )
|
||||
fprintf( outfile, "%s context", i? ",\n" : "" );
|
||||
else if (varargs)
|
||||
fprintf( outfile, "%s args + %d", i? ",\n" : "", argsize );
|
||||
fprintf( outfile, " );\n}\n\n" );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* get_function_name
|
||||
*/
|
||||
static const char *get_function_name( const ORDDEF *odp )
|
||||
{
|
||||
static char buffer[80];
|
||||
|
||||
sprintf( buffer, "%s_%s_%s",
|
||||
(odp->type == TYPE_PASCAL) ? "p" :
|
||||
(odp->type == TYPE_VARARGS) ? "v" : "c",
|
||||
(odp->flags & FLAG_REGISTER) ? "regs" :
|
||||
(odp->flags & FLAG_INTERRUPT) ? "intr" :
|
||||
(odp->flags & FLAG_RET16) ? "word" : "long",
|
||||
odp->u.func.arg_types );
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* Spec16TypeCompare
|
||||
*/
|
||||
static int Spec16TypeCompare( const void *e1, const void *e2 )
|
||||
{
|
||||
const ORDDEF *odp1 = *(const ORDDEF **)e1;
|
||||
const ORDDEF *odp2 = *(const ORDDEF **)e2;
|
||||
int retval;
|
||||
int type1 = odp1->type;
|
||||
int type2 = odp2->type;
|
||||
|
||||
if (type1 == TYPE_STUB) type1 = TYPE_CDECL;
|
||||
if (type2 == TYPE_STUB) type2 = TYPE_CDECL;
|
||||
|
||||
if ((retval = type1 - type2) != 0) return retval;
|
||||
|
||||
type1 = odp1->flags & (FLAG_RET16|FLAG_REGISTER|FLAG_INTERRUPT);
|
||||
type2 = odp2->flags & (FLAG_RET16|FLAG_REGISTER|FLAG_INTERRUPT);
|
||||
|
||||
if ((retval = type1 - type2) != 0) return retval;
|
||||
|
||||
return strcmp( odp1->u.func.arg_types, odp2->u.func.arg_types );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* output_stub_funcs
|
||||
*
|
||||
* Output the functions for stub entry points
|
||||
*/
|
||||
static void output_stub_funcs( FILE *outfile )
|
||||
{
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
for (i = 0; i <= Limit; i++)
|
||||
{
|
||||
ORDDEF *odp = Ordinals[i];
|
||||
if (!odp || odp->type != TYPE_STUB) continue;
|
||||
fprintf( outfile, "#ifdef __GNUC__\n" );
|
||||
fprintf( outfile, "static void __wine_unimplemented( const char *func ) __attribute__((noreturn));\n" );
|
||||
fprintf( outfile, "#endif\n" );
|
||||
fprintf( outfile, "static void __wine_unimplemented( const char *func )\n{\n" );
|
||||
fprintf( outfile, " struct exc_record {\n" );
|
||||
fprintf( outfile, " unsigned int code, flags;\n" );
|
||||
fprintf( outfile, " void *rec, *addr;\n" );
|
||||
fprintf( outfile, " unsigned int params;\n" );
|
||||
fprintf( outfile, " const void *info[15];\n" );
|
||||
fprintf( outfile, " } rec;\n\n" );
|
||||
fprintf( outfile, " extern void __stdcall RtlRaiseException( struct exc_record * );\n\n" );
|
||||
fprintf( outfile, " rec.code = 0x%08x;\n", EXCEPTION_WINE_STUB );
|
||||
fprintf( outfile, " rec.flags = %d;\n", EH_NONCONTINUABLE );
|
||||
fprintf( outfile, " rec.rec = 0;\n" );
|
||||
fprintf( outfile, " rec.params = 2;\n" );
|
||||
fprintf( outfile, " rec.info[0] = \"%s\";\n", dll_file_name );
|
||||
fprintf( outfile, " rec.info[1] = func;\n" );
|
||||
fprintf( outfile, "#ifdef __GNUC__\n" );
|
||||
fprintf( outfile, " rec.addr = __builtin_return_address(1);\n" );
|
||||
fprintf( outfile, "#else\n" );
|
||||
fprintf( outfile, " rec.addr = 0;\n" );
|
||||
fprintf( outfile, "#endif\n" );
|
||||
fprintf( outfile, " for (;;) RtlRaiseException( &rec );\n}\n\n" );
|
||||
break;
|
||||
}
|
||||
for (i = 0; i <= Limit; i++)
|
||||
{
|
||||
ORDDEF *odp = Ordinals[i];
|
||||
if (!odp || odp->type != TYPE_STUB) continue;
|
||||
odp->link_name = xrealloc( odp->link_name, strlen(odp->name) + 13 );
|
||||
strcpy( odp->link_name, "__wine_stub_" );
|
||||
strcat( odp->link_name, odp->name );
|
||||
for (p = odp->link_name; *p; p++) if (!isalnum(*p)) *p = '_';
|
||||
fprintf( outfile, "static void %s(void) { __wine_unimplemented(\"%s\"); }\n",
|
||||
odp->link_name, odp->name );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* BuildSpec16File
|
||||
*
|
||||
* Build a Win16 assembly file from a spec file.
|
||||
*/
|
||||
void BuildSpec16File( FILE *outfile )
|
||||
{
|
||||
ORDDEF **type, **typelist;
|
||||
int i, nFuncs, nTypes;
|
||||
int code_offset, data_offset, module_size, res_size;
|
||||
unsigned char *data;
|
||||
char constructor[100], destructor[100];
|
||||
#ifdef __i386__
|
||||
unsigned short code_selector = get_cs();
|
||||
#endif
|
||||
|
||||
/* File header */
|
||||
|
||||
output_file_header( outfile );
|
||||
fprintf( outfile, "extern unsigned short __wine_call_from_16_word();\n" );
|
||||
fprintf( outfile, "extern unsigned int __wine_call_from_16_long();\n" );
|
||||
fprintf( outfile, "extern void __wine_call_from_16_regs();\n" );
|
||||
fprintf( outfile, "extern void __wine_call_from_16_thunk();\n" );
|
||||
|
||||
data = (unsigned char *)xmalloc( 0x10000 );
|
||||
memset( data, 0, 16 );
|
||||
data_offset = 16;
|
||||
|
||||
if (!dll_name) /* set default name from file name */
|
||||
{
|
||||
char *p;
|
||||
dll_name = xstrdup( dll_file_name );
|
||||
if ((p = strrchr( dll_name, '.' ))) *p = 0;
|
||||
}
|
||||
|
||||
output_stub_funcs( outfile );
|
||||
|
||||
/* Build sorted list of all argument types, without duplicates */
|
||||
|
||||
typelist = (ORDDEF **)calloc( Limit+1, sizeof(ORDDEF *) );
|
||||
|
||||
for (i = nFuncs = 0; i <= Limit; i++)
|
||||
{
|
||||
ORDDEF *odp = Ordinals[i];
|
||||
if (!odp) continue;
|
||||
switch (odp->type)
|
||||
{
|
||||
case TYPE_CDECL:
|
||||
case TYPE_PASCAL:
|
||||
case TYPE_VARARGS:
|
||||
case TYPE_STUB:
|
||||
typelist[nFuncs++] = odp;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qsort( typelist, nFuncs, sizeof(ORDDEF *), Spec16TypeCompare );
|
||||
|
||||
i = nTypes = 0;
|
||||
while ( i < nFuncs )
|
||||
{
|
||||
typelist[nTypes++] = typelist[i++];
|
||||
while ( i < nFuncs && Spec16TypeCompare( typelist + i, typelist + nTypes-1 ) == 0 )
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Output CallFrom16 routines needed by this .spec file */
|
||||
#ifdef __i386__
|
||||
for ( i = 0; i < nTypes; i++ )
|
||||
{
|
||||
char profile[101];
|
||||
|
||||
strcpy( profile, get_function_name( typelist[i] ));
|
||||
BuildCallFrom16Func( outfile, profile, dll_file_name );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Output the DLL functions prototypes */
|
||||
|
||||
for (i = 0; i <= Limit; i++)
|
||||
{
|
||||
ORDDEF *odp = Ordinals[i];
|
||||
if (!odp) continue;
|
||||
switch(odp->type)
|
||||
{
|
||||
case TYPE_CDECL:
|
||||
case TYPE_PASCAL:
|
||||
case TYPE_VARARGS:
|
||||
fprintf( outfile, "extern void %s();\n", odp->link_name );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Output code segment */
|
||||
|
||||
fprintf( outfile, "\n#include \"pshpack1.h\"\n" );
|
||||
fprintf( outfile, "\nstatic struct code_segment\n{\n" );
|
||||
fprintf( outfile, " struct {\n" );
|
||||
#ifdef __i386__
|
||||
fprintf( outfile, " unsigned char pushl;\n" ); /* pushl $relay */
|
||||
fprintf( outfile, " void *relay;\n" );
|
||||
fprintf( outfile, " unsigned char lcall;\n" ); /* lcall __FLATCS__:glue */
|
||||
fprintf( outfile, " void *glue;\n" );
|
||||
fprintf( outfile, " unsigned short flatcs;\n" );
|
||||
#endif
|
||||
fprintf( outfile, " unsigned short lret;\n" ); /* lret $args */
|
||||
fprintf( outfile, " unsigned short args;\n" );
|
||||
fprintf( outfile, " unsigned int arg_types[2];\n" );
|
||||
fprintf( outfile, " } call[%d];\n", nTypes );
|
||||
fprintf( outfile, " struct {\n" );
|
||||
#ifdef __i386__
|
||||
fprintf( outfile, " unsigned short pushw_bp;\n" ); /* pushw %bp */
|
||||
fprintf( outfile, " unsigned char pushl;\n" ); /* pushl $target */
|
||||
#endif
|
||||
fprintf( outfile, " void (*target)();\n" );
|
||||
fprintf( outfile, " unsigned short call;\n" ); /* call CALLFROM16 */
|
||||
fprintf( outfile, " short callfrom16;\n" );
|
||||
fprintf( outfile, " } entry[%d];\n", nFuncs );
|
||||
fprintf( outfile, "} code_segment =\n{\n {\n" );
|
||||
|
||||
code_offset = 0;
|
||||
|
||||
for ( i = 0; i < nTypes; i++ )
|
||||
{
|
||||
char profile[101], *arg;
|
||||
unsigned int arg_types[2];
|
||||
int j, argsize = 0;
|
||||
|
||||
strcpy( profile, get_function_name( typelist[i] ));
|
||||
if ( typelist[i]->type == TYPE_PASCAL )
|
||||
for ( arg = typelist[i]->u.func.arg_types; *arg; arg++ )
|
||||
switch ( *arg )
|
||||
{
|
||||
case 'w': /* word */
|
||||
case 's': /* s_word */
|
||||
argsize += 2;
|
||||
break;
|
||||
case 'l': /* long or segmented pointer */
|
||||
case 'T': /* segmented pointer to null-terminated string */
|
||||
case 'p': /* linear pointer */
|
||||
case 't': /* linear pointer to null-terminated string */
|
||||
argsize += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (typelist[i]->flags & FLAG_INTERRUPT) argsize += 2;
|
||||
|
||||
/* build the arg types bit fields */
|
||||
arg_types[0] = arg_types[1] = 0;
|
||||
for (j = 0; typelist[i]->u.func.arg_types[j]; j++)
|
||||
{
|
||||
int type = 0;
|
||||
switch(typelist[i]->u.func.arg_types[j])
|
||||
{
|
||||
case 'w': type = ARG_WORD; break;
|
||||
case 's': type = ARG_SWORD; break;
|
||||
case 'l': type = ARG_LONG; break;
|
||||
case 'p': type = ARG_PTR; break;
|
||||
case 't': type = ARG_STR; break;
|
||||
case 'T': type = ARG_SEGSTR; break;
|
||||
}
|
||||
arg_types[j / 10] |= type << (3 * (j % 10));
|
||||
}
|
||||
if (typelist[i]->flags & (FLAG_REGISTER|FLAG_INTERRUPT)) arg_types[0] |= ARG_REGISTER;
|
||||
if (typelist[i]->flags & FLAG_RET16) arg_types[0] |= ARG_RET16;
|
||||
|
||||
#ifdef __i386__
|
||||
fprintf( outfile, " { 0x68, __wine_%s_CallFrom16_%s, 0x9a, __wine_call_from_16_%s,\n",
|
||||
make_c_identifier(dll_file_name), profile,
|
||||
(typelist[i]->flags & (FLAG_REGISTER|FLAG_INTERRUPT)) ? "regs":
|
||||
(typelist[i]->flags & FLAG_RET16) ? "word" : "long" );
|
||||
if (argsize)
|
||||
fprintf( outfile, " 0x%04x, 0xca66, %d, { 0x%08x, 0x%08x } },\n",
|
||||
code_selector, argsize, arg_types[0], arg_types[1] );
|
||||
else
|
||||
fprintf( outfile, " 0x%04x, 0xcb66, 0x9090, { 0x%08x, 0x%08x } },\n",
|
||||
code_selector, arg_types[0], arg_types[1] );
|
||||
#else
|
||||
if (argsize)
|
||||
fprintf( outfile, " { 0xca66, %d, { 0x%08x, 0x%08x } },\n",
|
||||
argsize, arg_types[0], arg_types[1] );
|
||||
else
|
||||
fprintf( outfile, " { 0xcb66, 0x9090, { 0x%08x, 0x%08x } },\n",
|
||||
arg_types[0], arg_types[1] );
|
||||
#endif
|
||||
code_offset += sizeof(CALLFROM16);
|
||||
}
|
||||
fprintf( outfile, " },\n {\n" );
|
||||
|
||||
for (i = 0; i <= Limit; i++)
|
||||
{
|
||||
ORDDEF *odp = Ordinals[i];
|
||||
if (!odp) continue;
|
||||
switch (odp->type)
|
||||
{
|
||||
case TYPE_ABS:
|
||||
odp->offset = LOWORD(odp->u.abs.value);
|
||||
break;
|
||||
|
||||
case TYPE_VARIABLE:
|
||||
odp->offset = data_offset;
|
||||
data_offset += StoreVariableCode( data + data_offset, 4, odp);
|
||||
break;
|
||||
|
||||
case TYPE_CDECL:
|
||||
case TYPE_PASCAL:
|
||||
case TYPE_VARARGS:
|
||||
case TYPE_STUB:
|
||||
type = bsearch( &odp, typelist, nTypes, sizeof(ORDDEF *), Spec16TypeCompare );
|
||||
assert( type );
|
||||
|
||||
fprintf( outfile, " /* %s.%d */ ", dll_name, i );
|
||||
#ifdef __i386__
|
||||
fprintf( outfile, "{ 0x5566, 0x68, %s, 0xe866, %d /* %s */ },\n",
|
||||
#else
|
||||
fprintf( outfile, "{ %s, 0xe866, %d, /* %s */ },\n",
|
||||
#endif
|
||||
odp->link_name,
|
||||
(type-typelist)*sizeof(CALLFROM16) -
|
||||
(code_offset + sizeof(ENTRYPOINT16)),
|
||||
get_function_name( odp ) );
|
||||
|
||||
odp->offset = code_offset;
|
||||
code_offset += sizeof(ENTRYPOINT16);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr,"build: function type %d not available for Win16\n",
|
||||
odp->type);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf( outfile, " }\n};\n" );
|
||||
|
||||
/* Output data segment */
|
||||
|
||||
dump_bytes( outfile, data, data_offset, "Data_Segment", 0 );
|
||||
|
||||
/* Build the module */
|
||||
|
||||
module_size = BuildModule16( outfile, code_offset, data_offset );
|
||||
res_size = output_res16_data( outfile );
|
||||
|
||||
/* Output the DLL descriptor */
|
||||
|
||||
fprintf( outfile, "#include \"poppack.h\"\n\n" );
|
||||
|
||||
fprintf( outfile, "static const struct dll_descriptor\n{\n" );
|
||||
fprintf( outfile, " unsigned char *module_start;\n" );
|
||||
fprintf( outfile, " int module_size;\n" );
|
||||
fprintf( outfile, " struct code_segment *code_start;\n" );
|
||||
fprintf( outfile, " unsigned char *data_start;\n" );
|
||||
fprintf( outfile, " const char *owner;\n" );
|
||||
fprintf( outfile, " const unsigned char *rsrc;\n" );
|
||||
fprintf( outfile, "} descriptor =\n{\n" );
|
||||
fprintf( outfile, " Module,\n" );
|
||||
fprintf( outfile, " sizeof(Module),\n" );
|
||||
fprintf( outfile, " &code_segment,\n" );
|
||||
fprintf( outfile, " Data_Segment,\n" );
|
||||
fprintf( outfile, " \"%s\",\n", owner_name );
|
||||
fprintf( outfile, " %s\n", res_size ? "resource_data" : "0" );
|
||||
fprintf( outfile, "};\n" );
|
||||
|
||||
/* Output the DLL constructor */
|
||||
|
||||
sprintf( constructor, "__wine_spec_%s_init", make_c_identifier(dll_file_name) );
|
||||
sprintf( destructor, "__wine_spec_%s_fini", make_c_identifier(dll_file_name) );
|
||||
output_dll_init( outfile, constructor, destructor );
|
||||
|
||||
fprintf( outfile,
|
||||
"void %s(void)\n"
|
||||
"{\n"
|
||||
" extern void __wine_register_dll_16( const struct dll_descriptor *descr );\n"
|
||||
" __wine_register_dll_16( &descriptor );\n"
|
||||
"}\n", constructor );
|
||||
fprintf( outfile,
|
||||
"void %s(void)\n"
|
||||
"{\n"
|
||||
" extern void __wine_unregister_dll_16( const struct dll_descriptor *descr );\n"
|
||||
" __wine_unregister_dll_16( &descriptor );\n"
|
||||
"}\n", destructor );
|
||||
}
|
996
reactos/tools/winebuild/spec32.c
Normal file
996
reactos/tools/winebuild/spec32.c
Normal file
|
@ -0,0 +1,996 @@
|
|||
/*
|
||||
* 32-bit spec files
|
||||
*
|
||||
* Copyright 1993 Robert J. Amstadt
|
||||
* Copyright 1995 Martin von Loewis
|
||||
* Copyright 1995, 1996, 1997 Alexandre Julliard
|
||||
* Copyright 1997 Eric Youngdale
|
||||
* Copyright 1999 Ulrich Weigand
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wine/exception.h"
|
||||
#include "build.h"
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
# define __ASM_SKIP ".space"
|
||||
#else
|
||||
# define __ASM_SKIP ".skip"
|
||||
#endif
|
||||
|
||||
static int string_compare( const void *ptr1, const void *ptr2 )
|
||||
{
|
||||
const char * const *str1 = ptr1;
|
||||
const char * const *str2 = ptr2;
|
||||
return strcmp( *str1, *str2 );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* make_internal_name
|
||||
*
|
||||
* Generate an internal name for an entry point. Used for stubs etc.
|
||||
*/
|
||||
static const char *make_internal_name( const ORDDEF *odp, const char *prefix )
|
||||
{
|
||||
static char buffer[256];
|
||||
if (odp->name || odp->export_name)
|
||||
{
|
||||
char *p;
|
||||
sprintf( buffer, "__wine_%s_%s_%s", prefix, dll_file_name,
|
||||
odp->name ? odp->name : odp->export_name );
|
||||
/* make sure name is a legal C identifier */
|
||||
for (p = buffer; *p; p++) if (!isalnum(*p) && *p != '_') break;
|
||||
if (!*p) return buffer;
|
||||
}
|
||||
sprintf( buffer, "__wine_%s_%s_%d", prefix, make_c_identifier(dll_file_name), odp->ordinal );
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
* AssignOrdinals
|
||||
*
|
||||
* Assign ordinals to all entry points.
|
||||
*/
|
||||
static void AssignOrdinals(void)
|
||||
{
|
||||
int i, ordinal;
|
||||
|
||||
if ( !nb_names ) return;
|
||||
|
||||
/* start assigning from Base, or from 1 if no ordinal defined yet */
|
||||
if (Base == MAX_ORDINALS) Base = 1;
|
||||
for (i = 0, ordinal = Base; i < nb_names; i++)
|
||||
{
|
||||
if (Names[i]->ordinal != -1) continue; /* already has an ordinal */
|
||||
while (Ordinals[ordinal]) ordinal++;
|
||||
if (ordinal >= MAX_ORDINALS)
|
||||
{
|
||||
current_line = Names[i]->lineno;
|
||||
fatal_error( "Too many functions defined (max %d)\n", MAX_ORDINALS );
|
||||
}
|
||||
Names[i]->ordinal = ordinal;
|
||||
Ordinals[ordinal] = Names[i];
|
||||
}
|
||||
if (ordinal > Limit) Limit = ordinal;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* output_debug
|
||||
*
|
||||
* Output the debug channels.
|
||||
*/
|
||||
static int output_debug( FILE *outfile )
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!nb_debug_channels) return 0;
|
||||
qsort( debug_channels, nb_debug_channels, sizeof(debug_channels[0]), string_compare );
|
||||
|
||||
for (i = 0; i < nb_debug_channels; i++)
|
||||
fprintf( outfile, "char __wine_dbch_%s[] = \"\\003%s\";\n",
|
||||
debug_channels[i], debug_channels[i] );
|
||||
|
||||
fprintf( outfile, "\nstatic char * const debug_channels[%d] =\n{\n", nb_debug_channels );
|
||||
for (i = 0; i < nb_debug_channels; i++)
|
||||
{
|
||||
fprintf( outfile, " __wine_dbch_%s", debug_channels[i] );
|
||||
if (i < nb_debug_channels - 1) fprintf( outfile, ",\n" );
|
||||
}
|
||||
fprintf( outfile, "\n};\n\n" );
|
||||
fprintf( outfile, "static void *debug_registration;\n\n" );
|
||||
|
||||
return nb_debug_channels;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* output_exports
|
||||
*
|
||||
* Output the export table for a Win32 module.
|
||||
*/
|
||||
static int output_exports( FILE *outfile, int nr_exports )
|
||||
{
|
||||
int i, fwd_size = 0, total_size = 0;
|
||||
|
||||
if (!nr_exports) return 0;
|
||||
|
||||
fprintf( outfile, "asm(\".data\\n\"\n" );
|
||||
fprintf( outfile, " \"\\t.align %d\\n\"\n", get_alignment(4) );
|
||||
fprintf( outfile, " \"" __ASM_NAME("__wine_spec_exports") ":\\n\"\n" );
|
||||
|
||||
/* export directory header */
|
||||
|
||||
fprintf( outfile, " \"\\t.long 0\\n\"\n" ); /* Characteristics */
|
||||
fprintf( outfile, " \"\\t.long 0\\n\"\n" ); /* TimeDateStamp */
|
||||
fprintf( outfile, " \"\\t.long 0\\n\"\n" ); /* MajorVersion/MinorVersion */
|
||||
fprintf( outfile, " \"\\t.long __wine_spec_exp_names\\n\"\n" ); /* Name */
|
||||
fprintf( outfile, " \"\\t.long %d\\n\"\n", Base ); /* Base */
|
||||
fprintf( outfile, " \"\\t.long %d\\n\"\n", nr_exports ); /* NumberOfFunctions */
|
||||
fprintf( outfile, " \"\\t.long %d\\n\"\n", nb_names ); /* NumberOfNames */
|
||||
fprintf( outfile, " \"\\t.long __wine_spec_exports_funcs\\n\"\n" ); /* AddressOfFunctions */
|
||||
if (nb_names)
|
||||
{
|
||||
fprintf( outfile, " \"\\t.long __wine_spec_exp_name_ptrs\\n\"\n" ); /* AddressOfNames */
|
||||
fprintf( outfile, " \"\\t.long __wine_spec_exp_ordinals\\n\"\n" ); /* AddressOfNameOrdinals */
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf( outfile, " \"\\t.long 0\\n\"\n" ); /* AddressOfNames */
|
||||
fprintf( outfile, " \"\\t.long 0\\n\"\n" ); /* AddressOfNameOrdinals */
|
||||
}
|
||||
total_size += 10 * sizeof(int);
|
||||
|
||||
/* output the function pointers */
|
||||
|
||||
fprintf( outfile, " \"__wine_spec_exports_funcs:\\n\"\n" );
|
||||
for (i = Base; i <= Limit; i++)
|
||||
{
|
||||
ORDDEF *odp = Ordinals[i];
|
||||
if (!odp) fprintf( outfile, " \"\\t.long 0\\n\"\n" );
|
||||
else switch(odp->type)
|
||||
{
|
||||
case TYPE_EXTERN:
|
||||
case TYPE_STDCALL:
|
||||
case TYPE_VARARGS:
|
||||
case TYPE_CDECL:
|
||||
if (!(odp->flags & FLAG_FORWARD))
|
||||
{
|
||||
fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") "\\n\"\n",
|
||||
(odp->flags & FLAG_REGISTER) ? make_internal_name(odp,"regs") : odp->link_name );
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf( outfile, " \"\\t.long __wine_spec_forwards+%d\\n\"\n", fwd_size );
|
||||
fwd_size += strlen(odp->link_name) + 1;
|
||||
}
|
||||
break;
|
||||
case TYPE_STUB:
|
||||
fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") "\\n\"\n", make_internal_name( odp, "stub" ) );
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
total_size += (Limit - Base + 1) * sizeof(int);
|
||||
|
||||
if (nb_names)
|
||||
{
|
||||
/* output the function name pointers */
|
||||
|
||||
int namepos = strlen(dll_file_name) + 1;
|
||||
|
||||
fprintf( outfile, " \"__wine_spec_exp_name_ptrs:\\n\"\n" );
|
||||
for (i = 0; i < nb_names; i++)
|
||||
{
|
||||
fprintf( outfile, " \"\\t.long __wine_spec_exp_names+%d\\n\"\n", namepos );
|
||||
namepos += strlen(Names[i]->name) + 1;
|
||||
}
|
||||
total_size += nb_names * sizeof(int);
|
||||
}
|
||||
|
||||
/* output the function names */
|
||||
|
||||
fprintf( outfile, " \"\\t.text\\n\"\n" );
|
||||
fprintf( outfile, " \"__wine_spec_exp_names:\\n\"\n" );
|
||||
fprintf( outfile, " \"\\t" __ASM_STRING " \\\"%s\\\"\\n\"\n", dll_file_name );
|
||||
for (i = 0; i < nb_names; i++)
|
||||
fprintf( outfile, " \"\\t" __ASM_STRING " \\\"%s\\\"\\n\"\n", Names[i]->name );
|
||||
fprintf( outfile, " \"\\t.data\\n\"\n" );
|
||||
|
||||
if (nb_names)
|
||||
{
|
||||
/* output the function ordinals */
|
||||
|
||||
fprintf( outfile, " \"__wine_spec_exp_ordinals:\\n\"\n" );
|
||||
for (i = 0; i < nb_names; i++)
|
||||
{
|
||||
fprintf( outfile, " \"\\t" __ASM_SHORT " %d\\n\"\n", Names[i]->ordinal - Base );
|
||||
}
|
||||
total_size += nb_names * sizeof(short);
|
||||
if (nb_names % 2)
|
||||
{
|
||||
fprintf( outfile, " \"\\t" __ASM_SHORT " 0\\n\"\n" );
|
||||
total_size += sizeof(short);
|
||||
}
|
||||
}
|
||||
|
||||
/* output forward strings */
|
||||
|
||||
if (fwd_size)
|
||||
{
|
||||
fprintf( outfile, " \"__wine_spec_forwards:\\n\"\n" );
|
||||
for (i = Base; i <= Limit; i++)
|
||||
{
|
||||
ORDDEF *odp = Ordinals[i];
|
||||
if (odp && (odp->flags & FLAG_FORWARD))
|
||||
fprintf( outfile, " \"\\t" __ASM_STRING " \\\"%s\\\"\\n\"\n", odp->link_name );
|
||||
}
|
||||
fprintf( outfile, " \"\\t.align %d\\n\"\n", get_alignment(4) );
|
||||
total_size += (fwd_size + 3) & ~3;
|
||||
}
|
||||
|
||||
/* output relays */
|
||||
|
||||
if (debugging)
|
||||
{
|
||||
for (i = Base; i <= Limit; i++)
|
||||
{
|
||||
ORDDEF *odp = Ordinals[i];
|
||||
unsigned int j, args, mask = 0;
|
||||
const char *name;
|
||||
|
||||
/* skip non-existent entry points */
|
||||
if (!odp) goto ignore;
|
||||
/* skip non-functions */
|
||||
if ((odp->type != TYPE_STDCALL) && (odp->type != TYPE_CDECL)) goto ignore;
|
||||
/* skip norelay and forward entry points */
|
||||
if (odp->flags & (FLAG_NORELAY|FLAG_FORWARD)) goto ignore;
|
||||
|
||||
for (j = 0; odp->u.func.arg_types[j]; j++)
|
||||
{
|
||||
if (odp->u.func.arg_types[j] == 't') mask |= 1<< (j*2);
|
||||
if (odp->u.func.arg_types[j] == 'W') mask |= 2<< (j*2);
|
||||
}
|
||||
if ((odp->flags & FLAG_RET64) && (j < 16)) mask |= 0x80000000;
|
||||
|
||||
name = odp->link_name;
|
||||
args = strlen(odp->u.func.arg_types) * sizeof(int);
|
||||
if (odp->flags & FLAG_REGISTER) name = make_internal_name( odp, "regs" );
|
||||
|
||||
switch(odp->type)
|
||||
{
|
||||
case TYPE_STDCALL:
|
||||
fprintf( outfile, " \"\\tjmp " __ASM_NAME("%s") "\\n\"\n", name );
|
||||
fprintf( outfile, " \"\\tret $%d\\n\"\n", args );
|
||||
fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") ",0x%08x\\n\"\n", name, mask );
|
||||
break;
|
||||
case TYPE_CDECL:
|
||||
fprintf( outfile, " \"\\tjmp " __ASM_NAME("%s") "\\n\"\n", name );
|
||||
fprintf( outfile, " \"\\tret\\n\"\n" );
|
||||
fprintf( outfile, " \"\\t" __ASM_SHORT " %d\\n\"\n", args );
|
||||
fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") ",0x%08x\\n\"\n", name, mask );
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
continue;
|
||||
|
||||
ignore:
|
||||
fprintf( outfile, " \"\\t.long 0,0,0,0\\n\"\n" );
|
||||
}
|
||||
}
|
||||
|
||||
fprintf( outfile, " \"\\t.text\\n\"\n" );
|
||||
fprintf( outfile, " \"\\t.align %d\\n\"\n", get_alignment(4) );
|
||||
fprintf( outfile, ");\n\n" );
|
||||
|
||||
return total_size;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* output_stub_funcs
|
||||
*
|
||||
* Output the functions for stub entry points
|
||||
*/
|
||||
static void output_stub_funcs( FILE *outfile )
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nb_entry_points; i++)
|
||||
{
|
||||
ORDDEF *odp = EntryPoints[i];
|
||||
if (odp->type != TYPE_STUB) continue;
|
||||
fprintf( outfile, "#ifdef __GNUC__\n" );
|
||||
fprintf( outfile, "static void __wine_unimplemented( const char *func ) __attribute__((noreturn));\n" );
|
||||
fprintf( outfile, "#endif\n\n" );
|
||||
fprintf( outfile, "struct exc_record {\n" );
|
||||
fprintf( outfile, " unsigned int code, flags;\n" );
|
||||
fprintf( outfile, " void *rec, *addr;\n" );
|
||||
fprintf( outfile, " unsigned int params;\n" );
|
||||
fprintf( outfile, " const void *info[15];\n" );
|
||||
fprintf( outfile, "};\n\n" );
|
||||
fprintf( outfile, "extern void __stdcall RtlRaiseException( struct exc_record * );\n\n" );
|
||||
fprintf( outfile, "static void __wine_unimplemented( const char *func )\n{\n" );
|
||||
fprintf( outfile, " struct exc_record rec;\n" );
|
||||
fprintf( outfile, " rec.code = 0x%08x;\n", EXCEPTION_WINE_STUB );
|
||||
fprintf( outfile, " rec.flags = %d;\n", EH_NONCONTINUABLE );
|
||||
fprintf( outfile, " rec.rec = 0;\n" );
|
||||
fprintf( outfile, " rec.params = 2;\n" );
|
||||
fprintf( outfile, " rec.info[0] = \"%s\";\n", dll_file_name );
|
||||
fprintf( outfile, " rec.info[1] = func;\n" );
|
||||
fprintf( outfile, "#ifdef __GNUC__\n" );
|
||||
fprintf( outfile, " rec.addr = __builtin_return_address(1);\n" );
|
||||
fprintf( outfile, "#else\n" );
|
||||
fprintf( outfile, " rec.addr = 0;\n" );
|
||||
fprintf( outfile, "#endif\n" );
|
||||
fprintf( outfile, " for (;;) RtlRaiseException( &rec );\n}\n\n" );
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < nb_entry_points; i++)
|
||||
{
|
||||
ORDDEF *odp = EntryPoints[i];
|
||||
if (odp->type != TYPE_STUB) continue;
|
||||
fprintf( outfile, "void %s(void) ", make_internal_name( odp, "stub" ) );
|
||||
if (odp->name)
|
||||
fprintf( outfile, "{ __wine_unimplemented(\"%s\"); }\n", odp->name );
|
||||
else if (odp->export_name)
|
||||
fprintf( outfile, "{ __wine_unimplemented(\"%s\"); }\n", odp->export_name );
|
||||
else
|
||||
fprintf( outfile, "{ __wine_unimplemented(\"%d\"); }\n", odp->ordinal );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* output_register_funcs
|
||||
*
|
||||
* Output the functions for register entry points
|
||||
*/
|
||||
static void output_register_funcs( FILE *outfile )
|
||||
{
|
||||
const char *name;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nb_entry_points; i++)
|
||||
{
|
||||
ORDDEF *odp = EntryPoints[i];
|
||||
if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL) continue;
|
||||
if (!(odp->flags & FLAG_REGISTER)) continue;
|
||||
if (odp->flags & FLAG_FORWARD) continue;
|
||||
name = make_internal_name( odp, "regs" );
|
||||
fprintf( outfile,
|
||||
"asm(\".align %d\\n\\t\"\n"
|
||||
" \"" __ASM_FUNC("%s") "\\n\\t\"\n"
|
||||
" \"" __ASM_NAME("%s") ":\\n\\t\"\n"
|
||||
" \"call " __ASM_NAME("__wine_call_from_32_regs") "\\n\\t\"\n"
|
||||
" \".long " __ASM_NAME("%s") "\\n\\t\"\n"
|
||||
" \".byte %d,%d\");\n",
|
||||
get_alignment(4),
|
||||
name, name, odp->link_name,
|
||||
strlen(odp->u.func.arg_types) * sizeof(int),
|
||||
(odp->type == TYPE_CDECL) ? 0 : (strlen(odp->u.func.arg_types) * sizeof(int)) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* output_dll_init
|
||||
*
|
||||
* Output code for calling a dll constructor and destructor.
|
||||
*/
|
||||
void output_dll_init( FILE *outfile, const char *constructor, const char *destructor )
|
||||
{
|
||||
fprintf( outfile, "#ifndef __GNUC__\n" );
|
||||
fprintf( outfile, "static void __asm__dummy_dll_init(void) {\n" );
|
||||
fprintf( outfile, "#endif\n" );
|
||||
|
||||
#if defined(__i386__)
|
||||
if (constructor)
|
||||
{
|
||||
fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
|
||||
fprintf( outfile, " \"\\tcall " __ASM_NAME("%s") "\\n\"\n", constructor );
|
||||
fprintf( outfile, " \"\\t.section\\t\\\".text\\\"\\n\");\n" );
|
||||
}
|
||||
if (destructor)
|
||||
{
|
||||
fprintf( outfile, "asm(\"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
|
||||
fprintf( outfile, " \"\\tcall " __ASM_NAME("%s") "\\n\"\n", destructor );
|
||||
fprintf( outfile, " \"\\t.section\\t\\\".text\\\"\\n\");\n" );
|
||||
}
|
||||
#elif defined(__sparc__)
|
||||
if (constructor)
|
||||
{
|
||||
fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
|
||||
fprintf( outfile, " \"\\tcall " __ASM_NAME("%s") "\\n\"\n", constructor );
|
||||
fprintf( outfile, " \"\\tnop\\n\"\n" );
|
||||
fprintf( outfile, " \"\\t.section\\t\\\".text\\\"\\n\");\n" );
|
||||
}
|
||||
if (destructor)
|
||||
{
|
||||
fprintf( outfile, "asm(\"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
|
||||
fprintf( outfile, " \"\\tcall " __ASM_NAME("%s") "\\n\"\n", destructor );
|
||||
fprintf( outfile, " \"\\tnop\\n\"\n" );
|
||||
fprintf( outfile, " \"\\t.section\\t\\\".text\\\"\\n\");\n" );
|
||||
}
|
||||
#elif defined(__powerpc__)
|
||||
# ifdef __APPLE__
|
||||
/* Mach-O doesn't have an init section */
|
||||
if (constructor)
|
||||
{
|
||||
fprintf( outfile, "asm(\"\\t.mod_init_func\\n\"\n" );
|
||||
fprintf( outfile, " \"\\t.align 2\\n\"\n" );
|
||||
fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") "\\n\"\n", constructor );
|
||||
fprintf( outfile, " \"\\t.text\\n\");\n" );
|
||||
}
|
||||
if (destructor)
|
||||
{
|
||||
fprintf( outfile, "asm(\"\\t.mod_term_func\\n\"\n" );
|
||||
fprintf( outfile, " \"\\t.align 2\\n\"\n" );
|
||||
fprintf( outfile, " \"\\t.long " __ASM_NAME("%s") "\\n\"\n", destructor );
|
||||
fprintf( outfile, " \"\\t.text\\n\");\n" );
|
||||
}
|
||||
# else /* __APPLE__ */
|
||||
if (constructor)
|
||||
{
|
||||
fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
|
||||
fprintf( outfile, " \"\\tbl " __ASM_NAME("%s") "\\n\"\n", constructor );
|
||||
fprintf( outfile, " \"\\t.section\\t\\\".text\\\"\\n\");\n" );
|
||||
}
|
||||
if (destructor)
|
||||
{
|
||||
fprintf( outfile, "asm(\"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
|
||||
fprintf( outfile, " \"\\tbl " __ASM_NAME("%s") "\\n\"\n", destructor );
|
||||
fprintf( outfile, " \"\\t.section\\t\\\".text\\\"\\n\");\n" );
|
||||
}
|
||||
# endif /* __APPLE__ */
|
||||
#else
|
||||
#error You need to define the DLL constructor for your architecture
|
||||
#endif
|
||||
fprintf( outfile, "#ifndef __GNUC__\n" );
|
||||
fprintf( outfile, "}\n" );
|
||||
fprintf( outfile, "#endif\n" );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* BuildSpec32File
|
||||
*
|
||||
* Build a Win32 C file from a spec file.
|
||||
*/
|
||||
void BuildSpec32File( FILE *outfile )
|
||||
{
|
||||
int exports_size = 0;
|
||||
int nr_exports, nr_imports, nr_resources;
|
||||
int characteristics, subsystem;
|
||||
DWORD page_size;
|
||||
char constructor[100];
|
||||
|
||||
#ifdef HAVE_GETPAGESIZE
|
||||
page_size = getpagesize();
|
||||
#elif defined(__svr4__)
|
||||
page_size = sysconf(_SC_PAGESIZE);
|
||||
#elif defined(_WINDOWS)
|
||||
{
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
page_size = si.dwPageSize;
|
||||
}
|
||||
#else
|
||||
# error Cannot get the page size on this platform
|
||||
#endif
|
||||
|
||||
AssignOrdinals();
|
||||
nr_exports = Base <= Limit ? Limit - Base + 1 : 0;
|
||||
|
||||
resolve_imports();
|
||||
output_standard_file_header( outfile );
|
||||
|
||||
/* Reserve some space for the PE header */
|
||||
|
||||
fprintf( outfile, "extern char __wine_spec_pe_header[];\n" );
|
||||
fprintf( outfile, "#ifndef __GNUC__\n" );
|
||||
fprintf( outfile, "static void __asm__dummy_header(void) {\n" );
|
||||
fprintf( outfile, "#endif\n" );
|
||||
fprintf( outfile, "asm(\".text\\n\\t\"\n" );
|
||||
fprintf( outfile, " \".align %d\\n\"\n", get_alignment(page_size) );
|
||||
fprintf( outfile, " \"" __ASM_NAME("__wine_spec_pe_header") ":\\t" __ASM_SKIP " 65536\\n\\t\"\n" );
|
||||
fprintf( outfile, " \".data\\n\\t\"\n" );
|
||||
fprintf( outfile, " \".align %d\\n\"\n", get_alignment(4) );
|
||||
fprintf( outfile, " \"" __ASM_NAME("__wine_spec_data_start") ":\\t.long 1\");\n" );
|
||||
fprintf( outfile, "#ifndef __GNUC__\n" );
|
||||
fprintf( outfile, "}\n" );
|
||||
fprintf( outfile, "#endif\n" );
|
||||
|
||||
fprintf( outfile, "extern char _end[];\n" );
|
||||
fprintf( outfile, "extern int __wine_spec_data_start[], __wine_spec_exports[];\n\n" );
|
||||
|
||||
#ifdef __i386__
|
||||
fprintf( outfile, "#define __stdcall __attribute__((__stdcall__))\n\n" );
|
||||
#else
|
||||
fprintf( outfile, "#define __stdcall\n\n" );
|
||||
#endif
|
||||
|
||||
if (nr_exports)
|
||||
{
|
||||
/* Output the stub functions */
|
||||
|
||||
output_stub_funcs( outfile );
|
||||
|
||||
fprintf( outfile, "#ifndef __GNUC__\n" );
|
||||
fprintf( outfile, "static void __asm__dummy(void) {\n" );
|
||||
fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" );
|
||||
|
||||
/* Output code for all register functions */
|
||||
|
||||
output_register_funcs( outfile );
|
||||
|
||||
/* Output the exports and relay entry points */
|
||||
|
||||
exports_size = output_exports( outfile, nr_exports );
|
||||
|
||||
fprintf( outfile, "#ifndef __GNUC__\n" );
|
||||
fprintf( outfile, "}\n" );
|
||||
fprintf( outfile, "#endif /* !defined(__GNUC__) */\n" );
|
||||
}
|
||||
|
||||
/* Output the DLL imports */
|
||||
|
||||
nr_imports = output_imports( outfile );
|
||||
|
||||
/* Output the resources */
|
||||
|
||||
nr_resources = output_resources( outfile );
|
||||
|
||||
/* Output LibMain function */
|
||||
|
||||
characteristics = subsystem = 0;
|
||||
switch(SpecMode)
|
||||
{
|
||||
case SPEC_MODE_DLL:
|
||||
if (init_func) fprintf( outfile, "extern void %s();\n", init_func );
|
||||
else
|
||||
{
|
||||
fprintf( outfile, "#ifdef __GNUC__\n" );
|
||||
fprintf( outfile, "# ifdef __APPLE__\n" );
|
||||
fprintf( outfile, "extern void DllMain() __attribute__((weak_import));\n" );
|
||||
fprintf( outfile, "# else\n" );
|
||||
fprintf( outfile, "extern void DllMain() __attribute__((weak));\n" );
|
||||
fprintf( outfile, "# endif\n" );
|
||||
fprintf( outfile, "#else\n" );
|
||||
fprintf( outfile, "extern void DllMain();\n" );
|
||||
fprintf( outfile, "static void __asm__dummy_dllmain(void)" );
|
||||
fprintf( outfile, " { asm(\".weak " __ASM_NAME("DllMain") "\"); }\n" );
|
||||
fprintf( outfile, "#endif\n" );
|
||||
}
|
||||
characteristics = IMAGE_FILE_DLL;
|
||||
break;
|
||||
case SPEC_MODE_GUIEXE:
|
||||
if (!init_func) init_func = "WinMain";
|
||||
fprintf( outfile,
|
||||
"\ntypedef struct {\n"
|
||||
" unsigned int cb;\n"
|
||||
" char *lpReserved, *lpDesktop, *lpTitle;\n"
|
||||
" unsigned int dwX, dwY, dwXSize, dwYSize;\n"
|
||||
" unsigned int dwXCountChars, dwYCountChars, dwFillAttribute, dwFlags;\n"
|
||||
" unsigned short wShowWindow, cbReserved2;\n"
|
||||
" char *lpReserved2;\n"
|
||||
" void *hStdInput, *hStdOutput, *hStdError;\n"
|
||||
"} STARTUPINFOA;\n"
|
||||
"int _ARGC;\n"
|
||||
"char **_ARGV;\n"
|
||||
"extern int __stdcall %s(void *,void *,char *,int);\n"
|
||||
"extern char * __stdcall GetCommandLineA(void);\n"
|
||||
"extern void * __stdcall GetModuleHandleA(char *);\n"
|
||||
"extern void __stdcall GetStartupInfoA(STARTUPINFOA *);\n"
|
||||
"extern void __stdcall ExitProcess(unsigned int);\n"
|
||||
"static void __wine_exe_main(void)\n"
|
||||
"{\n"
|
||||
" extern int __wine_main_argc;\n"
|
||||
" extern char **__wine_main_argv;\n"
|
||||
" STARTUPINFOA info;\n"
|
||||
" char *cmdline = GetCommandLineA();\n"
|
||||
" int bcount=0, in_quotes=0;\n"
|
||||
" while (*cmdline) {\n"
|
||||
" if ((*cmdline=='\\t' || *cmdline==' ') && !in_quotes) break;\n"
|
||||
" else if (*cmdline=='\\\\') bcount++;\n"
|
||||
" else if (*cmdline=='\\\"') {\n"
|
||||
" if ((bcount & 1)==0) in_quotes=!in_quotes;\n"
|
||||
" bcount=0;\n"
|
||||
" }\n"
|
||||
" else bcount=0;\n"
|
||||
" cmdline++;\n"
|
||||
" }\n"
|
||||
" while (*cmdline=='\\t' || *cmdline==' ') cmdline++;\n"
|
||||
" GetStartupInfoA( &info );\n"
|
||||
" if (!(info.dwFlags & 1)) info.wShowWindow = 1;\n"
|
||||
" _ARGC = __wine_main_argc;\n"
|
||||
" _ARGV = __wine_main_argv;\n"
|
||||
" ExitProcess( %s( GetModuleHandleA(0), 0, cmdline, info.wShowWindow ) );\n"
|
||||
"}\n\n", init_func, init_func );
|
||||
init_func = "__wine_exe_main";
|
||||
subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
|
||||
break;
|
||||
case SPEC_MODE_GUIEXE_UNICODE:
|
||||
if (!init_func) init_func = "WinMain";
|
||||
fprintf( outfile,
|
||||
"\ntypedef unsigned short WCHAR;\n"
|
||||
"typedef struct {\n"
|
||||
" unsigned int cb;\n"
|
||||
" char *lpReserved, *lpDesktop, *lpTitle;\n"
|
||||
" unsigned int dwX, dwY, dwXSize, dwYSize;\n"
|
||||
" unsigned int dwXCountChars, dwYCountChars, dwFillAttribute, dwFlags;\n"
|
||||
" unsigned short wShowWindow, cbReserved2;\n"
|
||||
" char *lpReserved2;\n"
|
||||
" void *hStdInput, *hStdOutput, *hStdError;\n"
|
||||
"} STARTUPINFOA;\n"
|
||||
"int _ARGC;\n"
|
||||
"WCHAR **_ARGV;\n"
|
||||
"extern int __stdcall %s(void *,void *,char *,int);\n"
|
||||
"extern char * __stdcall GetCommandLineA(void);\n"
|
||||
"extern void * __stdcall GetModuleHandleA(char *);\n"
|
||||
"extern void __stdcall GetStartupInfoA(STARTUPINFOA *);\n"
|
||||
"extern void __stdcall ExitProcess(unsigned int);\n"
|
||||
"static void __wine_exe_main(void)\n"
|
||||
"{\n"
|
||||
" extern int __wine_main_argc;\n"
|
||||
" extern WCHAR **__wine_main_wargv;\n"
|
||||
" STARTUPINFOA info;\n"
|
||||
" char *cmdline = GetCommandLineA();\n"
|
||||
" int bcount=0, in_quotes=0;\n"
|
||||
" while (*cmdline) {\n"
|
||||
" if ((*cmdline=='\\t' || *cmdline==' ') && !in_quotes) break;\n"
|
||||
" else if (*cmdline=='\\\\') bcount++;\n"
|
||||
" else if (*cmdline=='\\\"') {\n"
|
||||
" if ((bcount & 1)==0) in_quotes=!in_quotes;\n"
|
||||
" bcount=0;\n"
|
||||
" }\n"
|
||||
" else bcount=0;\n"
|
||||
" cmdline++;\n"
|
||||
" }\n"
|
||||
" while (*cmdline=='\\t' || *cmdline==' ') cmdline++;\n"
|
||||
" GetStartupInfoA( &info );\n"
|
||||
" if (!(info.dwFlags & 1)) info.wShowWindow = 1;\n"
|
||||
" _ARGC = __wine_main_argc;\n"
|
||||
" _ARGV = __wine_main_wargv;\n"
|
||||
" ExitProcess( %s( GetModuleHandleA(0), 0, cmdline, info.wShowWindow ) );\n"
|
||||
"}\n\n", init_func, init_func );
|
||||
init_func = "__wine_exe_main";
|
||||
subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
|
||||
break;
|
||||
case SPEC_MODE_CUIEXE:
|
||||
if (!init_func) init_func = "main";
|
||||
fprintf( outfile,
|
||||
"\nint _ARGC;\n"
|
||||
"char **_ARGV;\n"
|
||||
"extern void __stdcall ExitProcess(int);\n"
|
||||
"static void __wine_exe_main(void)\n"
|
||||
"{\n"
|
||||
" extern int %s( int argc, char *argv[] );\n"
|
||||
" extern int __wine_main_argc;\n"
|
||||
" extern char **__wine_main_argv;\n"
|
||||
" _ARGC = __wine_main_argc;\n"
|
||||
" _ARGV = __wine_main_argv;\n"
|
||||
" ExitProcess( %s( _ARGC, _ARGV ) );\n"
|
||||
"}\n\n", init_func, init_func );
|
||||
init_func = "__wine_exe_main";
|
||||
subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
|
||||
break;
|
||||
case SPEC_MODE_CUIEXE_UNICODE:
|
||||
if (!init_func) init_func = "wmain";
|
||||
fprintf( outfile,
|
||||
"\ntypedef unsigned short WCHAR;\n"
|
||||
"int _ARGC;\n"
|
||||
"WCHAR **_ARGV;\n"
|
||||
"extern void __stdcall ExitProcess(int);\n"
|
||||
"static void __wine_exe_main(void)\n"
|
||||
"{\n"
|
||||
" extern int %s( int argc, WCHAR *argv[] );\n"
|
||||
" extern int __wine_main_argc;\n"
|
||||
" extern WCHAR **__wine_main_wargv;\n"
|
||||
" _ARGC = __wine_main_argc;\n"
|
||||
" _ARGV = __wine_main_wargv;\n"
|
||||
" ExitProcess( %s( _ARGC, _ARGV ) );\n"
|
||||
"}\n\n", init_func, init_func );
|
||||
init_func = "__wine_exe_main";
|
||||
subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Output the NT header */
|
||||
|
||||
/* this is the IMAGE_NT_HEADERS structure, but we cannot include winnt.h here */
|
||||
fprintf( outfile, "static const struct image_nt_headers\n{\n" );
|
||||
fprintf( outfile, " int Signature;\n" );
|
||||
fprintf( outfile, " struct file_header {\n" );
|
||||
fprintf( outfile, " short Machine;\n" );
|
||||
fprintf( outfile, " short NumberOfSections;\n" );
|
||||
fprintf( outfile, " int TimeDateStamp;\n" );
|
||||
fprintf( outfile, " void *PointerToSymbolTable;\n" );
|
||||
fprintf( outfile, " int NumberOfSymbols;\n" );
|
||||
fprintf( outfile, " short SizeOfOptionalHeader;\n" );
|
||||
fprintf( outfile, " short Characteristics;\n" );
|
||||
fprintf( outfile, " } FileHeader;\n" );
|
||||
fprintf( outfile, " struct opt_header {\n" );
|
||||
fprintf( outfile, " short Magic;\n" );
|
||||
fprintf( outfile, " char MajorLinkerVersion, MinorLinkerVersion;\n" );
|
||||
fprintf( outfile, " int SizeOfCode;\n" );
|
||||
fprintf( outfile, " int SizeOfInitializedData;\n" );
|
||||
fprintf( outfile, " int SizeOfUninitializedData;\n" );
|
||||
fprintf( outfile, " void *AddressOfEntryPoint;\n" );
|
||||
fprintf( outfile, " void *BaseOfCode;\n" );
|
||||
fprintf( outfile, " void *BaseOfData;\n" );
|
||||
fprintf( outfile, " void *ImageBase;\n" );
|
||||
fprintf( outfile, " int SectionAlignment;\n" );
|
||||
fprintf( outfile, " int FileAlignment;\n" );
|
||||
fprintf( outfile, " short MajorOperatingSystemVersion;\n" );
|
||||
fprintf( outfile, " short MinorOperatingSystemVersion;\n" );
|
||||
fprintf( outfile, " short MajorImageVersion;\n" );
|
||||
fprintf( outfile, " short MinorImageVersion;\n" );
|
||||
fprintf( outfile, " short MajorSubsystemVersion;\n" );
|
||||
fprintf( outfile, " short MinorSubsystemVersion;\n" );
|
||||
fprintf( outfile, " int Win32VersionValue;\n" );
|
||||
fprintf( outfile, " void *SizeOfImage;\n" );
|
||||
fprintf( outfile, " int SizeOfHeaders;\n" );
|
||||
fprintf( outfile, " int CheckSum;\n" );
|
||||
fprintf( outfile, " short Subsystem;\n" );
|
||||
fprintf( outfile, " short DllCharacteristics;\n" );
|
||||
fprintf( outfile, " int SizeOfStackReserve;\n" );
|
||||
fprintf( outfile, " int SizeOfStackCommit;\n" );
|
||||
fprintf( outfile, " int SizeOfHeapReserve;\n" );
|
||||
fprintf( outfile, " int SizeOfHeapCommit;\n" );
|
||||
fprintf( outfile, " int LoaderFlags;\n" );
|
||||
fprintf( outfile, " int NumberOfRvaAndSizes;\n" );
|
||||
fprintf( outfile, " struct { const void *VirtualAddress; int Size; } DataDirectory[%d];\n",
|
||||
IMAGE_NUMBEROF_DIRECTORY_ENTRIES );
|
||||
fprintf( outfile, " } OptionalHeader;\n" );
|
||||
fprintf( outfile, "} nt_header = {\n" );
|
||||
fprintf( outfile, " 0x%04x,\n", IMAGE_NT_SIGNATURE ); /* Signature */
|
||||
#ifdef __i386__
|
||||
fprintf( outfile, " { 0x%04x,\n", IMAGE_FILE_MACHINE_I386 ); /* Machine */
|
||||
#elif defined(__powerpc__)
|
||||
fprintf( outfile, " { 0x%04x,\n", IMAGE_FILE_MACHINE_POWERPC ); /* Machine */
|
||||
#else
|
||||
fprintf( outfile, " { 0x%04x,\n", IMAGE_FILE_MACHINE_UNKNOWN ); /* Machine */
|
||||
#endif
|
||||
fprintf( outfile, " 0, 0, 0, 0,\n" );
|
||||
fprintf( outfile, " sizeof(nt_header.OptionalHeader),\n" ); /* SizeOfOptionalHeader */
|
||||
fprintf( outfile, " 0x%04x },\n", characteristics ); /* Characteristics */
|
||||
|
||||
fprintf( outfile, " { 0x%04x,\n", IMAGE_NT_OPTIONAL_HDR_MAGIC ); /* Magic */
|
||||
fprintf( outfile, " 0, 0,\n" ); /* Major/MinorLinkerVersion */
|
||||
fprintf( outfile, " 0, 0, 0,\n" ); /* SizeOfCode/Data */
|
||||
fprintf( outfile, " %s,\n", init_func ? init_func : "DllMain" ); /* AddressOfEntryPoint */
|
||||
fprintf( outfile, " 0, __wine_spec_data_start,\n" ); /* BaseOfCode/Data */
|
||||
fprintf( outfile, " __wine_spec_pe_header,\n" ); /* ImageBase */
|
||||
fprintf( outfile, " %ld,\n", page_size ); /* SectionAlignment */
|
||||
fprintf( outfile, " %ld,\n", page_size ); /* FileAlignment */
|
||||
fprintf( outfile, " 1, 0,\n" ); /* Major/MinorOperatingSystemVersion */
|
||||
fprintf( outfile, " 0, 0,\n" ); /* Major/MinorImageVersion */
|
||||
fprintf( outfile, " 4, 0,\n" ); /* Major/MinorSubsystemVersion */
|
||||
fprintf( outfile, " 0,\n" ); /* Win32VersionValue */
|
||||
fprintf( outfile, " _end,\n" ); /* SizeOfImage */
|
||||
fprintf( outfile, " %ld,\n", page_size ); /* SizeOfHeaders */
|
||||
fprintf( outfile, " 0,\n" ); /* CheckSum */
|
||||
fprintf( outfile, " 0x%04x,\n", subsystem ); /* Subsystem */
|
||||
fprintf( outfile, " 0,\n" ); /* DllCharacteristics */
|
||||
fprintf( outfile, " %d, %ld,\n", /* SizeOfStackReserve/Commit */
|
||||
(stack_size ? stack_size : 1024) * 1024, page_size );
|
||||
fprintf( outfile, " %d, %ld,\n", /* SizeOfHeapReserve/Commit */
|
||||
(DLLHeapSize ? DLLHeapSize : 1024) * 1024, page_size );
|
||||
fprintf( outfile, " 0,\n" ); /* LoaderFlags */
|
||||
fprintf( outfile, " %d,\n", IMAGE_NUMBEROF_DIRECTORY_ENTRIES ); /* NumberOfRvaAndSizes */
|
||||
fprintf( outfile, " {\n" );
|
||||
fprintf( outfile, " { %s, %d },\n", /* IMAGE_DIRECTORY_ENTRY_EXPORT */
|
||||
exports_size ? "__wine_spec_exports" : "0", exports_size );
|
||||
fprintf( outfile, " { %s, %s },\n", /* IMAGE_DIRECTORY_ENTRY_IMPORT */
|
||||
nr_imports ? "&imports" : "0", nr_imports ? "sizeof(imports)" : "0" );
|
||||
fprintf( outfile, " { %s, %s },\n", /* IMAGE_DIRECTORY_ENTRY_RESOURCE */
|
||||
nr_resources ? "&resources" : "0", nr_resources ? "sizeof(resources)" : "0" );
|
||||
fprintf( outfile, " }\n }\n};\n\n" );
|
||||
|
||||
/* Output the DLL constructor */
|
||||
|
||||
sprintf( constructor, "__wine_spec_%s_init", make_c_identifier(dll_file_name) );
|
||||
output_dll_init( outfile, constructor, NULL );
|
||||
|
||||
fprintf( outfile,
|
||||
"void %s(void)\n"
|
||||
"{\n"
|
||||
" extern void __wine_dll_register( const struct image_nt_headers *, const char * );\n"
|
||||
" extern void *__wine_dbg_register( char * const *, int );\n"
|
||||
" __wine_dll_register( &nt_header, \"%s\" );\n"
|
||||
"}\n",
|
||||
constructor, dll_file_name );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* BuildDef32File
|
||||
*
|
||||
* Build a Win32 def file from a spec file.
|
||||
*/
|
||||
void BuildDef32File(FILE *outfile)
|
||||
{
|
||||
const char *name;
|
||||
int i;
|
||||
|
||||
AssignOrdinals();
|
||||
|
||||
fprintf(outfile, "; File generated automatically from %s; do not edit!\n\n",
|
||||
input_file_name );
|
||||
|
||||
fprintf(outfile, "LIBRARY %s\n\n", dll_file_name);
|
||||
|
||||
fprintf(outfile, "EXPORTS\n");
|
||||
|
||||
/* Output the exports and relay entry points */
|
||||
|
||||
for(i = 0; i < nb_entry_points; i++)
|
||||
{
|
||||
ORDDEF *odp = EntryPoints[i];
|
||||
int is_data = 0;
|
||||
|
||||
if (!odp) continue;
|
||||
if (odp->flags & FLAG_REGISTER) continue;
|
||||
if (odp->type == TYPE_STUB) continue;
|
||||
|
||||
if (odp->name) name = odp->name;
|
||||
else if (odp->export_name) name = odp->export_name;
|
||||
else continue;
|
||||
|
||||
fprintf(outfile, " %s", name);
|
||||
|
||||
switch(odp->type)
|
||||
{
|
||||
case TYPE_EXTERN:
|
||||
is_data = 1;
|
||||
/* fall through */
|
||||
case TYPE_VARARGS:
|
||||
case TYPE_CDECL:
|
||||
/* try to reduce output */
|
||||
if(strcmp(name, odp->link_name) || (odp->flags & FLAG_FORWARD))
|
||||
fprintf(outfile, "=%s", odp->link_name);
|
||||
break;
|
||||
case TYPE_STDCALL:
|
||||
{
|
||||
int at_param = strlen(odp->u.func.arg_types) * sizeof(int);
|
||||
if (!kill_at) fprintf(outfile, "@%d", at_param);
|
||||
if (odp->flags & FLAG_FORWARD)
|
||||
{
|
||||
fprintf(outfile, "=%s", odp->link_name);
|
||||
}
|
||||
else if (strcmp(name, odp->link_name)) /* try to reduce output */
|
||||
{
|
||||
fprintf(outfile, "=%s", odp->link_name);
|
||||
if (!kill_at) fprintf(outfile, "@%d", at_param);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
fprintf( outfile, " @%d", odp->ordinal );
|
||||
if (!odp->name) fprintf( outfile, " NONAME" );
|
||||
if (is_data) fprintf( outfile, " DATA" );
|
||||
if (odp->flags & FLAG_PRIVATE) fprintf( outfile, " PRIVATE" );
|
||||
fprintf( outfile, "\n" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* BuildDebugFile
|
||||
*
|
||||
* Build the debugging channels source file.
|
||||
*/
|
||||
void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv )
|
||||
{
|
||||
int nr_debug;
|
||||
char *prefix, *p;
|
||||
|
||||
while (*argv)
|
||||
{
|
||||
if (!parse_debug_channels( srcdir, *argv++ )) exit(1);
|
||||
}
|
||||
|
||||
output_standard_file_header( outfile );
|
||||
nr_debug = output_debug( outfile );
|
||||
if (!nr_debug)
|
||||
{
|
||||
fprintf( outfile, "/* no debug channels found for this module */\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if (output_file_name)
|
||||
{
|
||||
if ((p = strrchr( output_file_name, '/' ))) p++;
|
||||
prefix = xstrdup( p ? p : output_file_name );
|
||||
if ((p = strchr( prefix, '.' ))) *p = 0;
|
||||
strcpy( p, make_c_identifier(p) );
|
||||
}
|
||||
else prefix = xstrdup( "_" );
|
||||
|
||||
/* Output the DLL constructor */
|
||||
|
||||
fprintf( outfile,
|
||||
"#ifdef __GNUC__\n"
|
||||
"static void __wine_dbg_%s_init(void) __attribute__((constructor));\n"
|
||||
"static void __wine_dbg_%s_fini(void) __attribute__((destructor));\n"
|
||||
"#else\n"
|
||||
"static void __asm__dummy_dll_init(void) {\n",
|
||||
prefix, prefix );
|
||||
|
||||
#if defined(__i386__)
|
||||
fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
|
||||
fprintf( outfile, " \"\\tcall " __ASM_NAME("__wine_dbg_%s_init") "\\n\"\n", prefix );
|
||||
fprintf( outfile, " \"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
|
||||
fprintf( outfile, " \"\\tcall " __ASM_NAME("__wine_dbg_%s_fini") "\\n\"\n", prefix );
|
||||
fprintf( outfile, " \"\\t.section\\t\\\".text\\\"\\n\");\n" );
|
||||
#elif defined(__sparc__)
|
||||
fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
|
||||
fprintf( outfile, " \"\\tcall " __ASM_NAME("__wine_dbg_%s_init") "\\n\"\n", prefix );
|
||||
fprintf( outfile, " \"\\tnop\\n\"\n" );
|
||||
fprintf( outfile, " \"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
|
||||
fprintf( outfile, " \"\\tcall " __ASM_NAME("__wine_dbg_%s_fini") "\\n\"\n", prefix );
|
||||
fprintf( outfile, " \"\\tnop\\n\"\n" );
|
||||
fprintf( outfile, " \"\\t.section\t\\\".text\\\"\\n\");\n" );
|
||||
#elif defined(__powerpc__)
|
||||
fprintf( outfile, "asm(\"\\t.section\\t\\\".init\\\" ,\\\"ax\\\"\\n\"\n" );
|
||||
fprintf( outfile, " \"\\tbl " __ASM_NAME("__wine_dbg_%s_init") "\\n\"\n", prefix );
|
||||
fprintf( outfile, " \"\\t.section\\t\\\".fini\\\" ,\\\"ax\\\"\\n\"\n" );
|
||||
fprintf( outfile, " \"\\tbl " __ASM_NAME("__wine_dbg_%s_fini") "\\n\"\n", prefix );
|
||||
fprintf( outfile, " \"\\t.text\\n\");\n" );
|
||||
#else
|
||||
#error You need to define the DLL constructor for your architecture
|
||||
#endif
|
||||
fprintf( outfile, "}\n#endif /* defined(__GNUC__) */\n" );
|
||||
|
||||
fprintf( outfile,
|
||||
"\n#ifdef __GNUC__\n"
|
||||
"static\n"
|
||||
"#endif\n"
|
||||
"void __wine_dbg_%s_init(void)\n"
|
||||
"{\n"
|
||||
" extern void *__wine_dbg_register( char * const *, int );\n"
|
||||
" debug_registration = __wine_dbg_register( debug_channels, %d );\n"
|
||||
"}\n", prefix, nr_debug );
|
||||
fprintf( outfile,
|
||||
"\n#ifdef __GNUC__\n"
|
||||
"static\n"
|
||||
"#endif\n"
|
||||
"void __wine_dbg_%s_fini(void)\n"
|
||||
"{\n"
|
||||
" extern void __wine_dbg_unregister( void* );\n"
|
||||
" __wine_dbg_unregister( debug_registration );\n"
|
||||
"}\n", prefix );
|
||||
|
||||
free( prefix );
|
||||
}
|
331
reactos/tools/winebuild/utils.c
Normal file
331
reactos/tools/winebuild/utils.c
Normal file
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* Small utility functions for winebuild
|
||||
*
|
||||
* Copyright 2000 Alexandre Julliard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "build.h"
|
||||
|
||||
void *xmalloc (size_t size)
|
||||
{
|
||||
void *res;
|
||||
|
||||
res = malloc (size ? size : 1);
|
||||
if (res == NULL)
|
||||
{
|
||||
fprintf (stderr, "Virtual memory exhausted.\n");
|
||||
exit (1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void *xrealloc (void *ptr, size_t size)
|
||||
{
|
||||
void *res = realloc (ptr, size);
|
||||
if (res == NULL)
|
||||
{
|
||||
fprintf (stderr, "Virtual memory exhausted.\n");
|
||||
exit (1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
char *xstrdup( const char *str )
|
||||
{
|
||||
char *res = strdup( str );
|
||||
if (!res)
|
||||
{
|
||||
fprintf (stderr, "Virtual memory exhausted.\n");
|
||||
exit (1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
char *strupper(char *s)
|
||||
{
|
||||
char *p;
|
||||
for (p = s; *p; p++) *p = toupper(*p);
|
||||
return s;
|
||||
}
|
||||
|
||||
void fatal_error( const char *msg, ... )
|
||||
{
|
||||
va_list valist;
|
||||
va_start( valist, msg );
|
||||
if (input_file_name)
|
||||
{
|
||||
fprintf( stderr, "%s:", input_file_name );
|
||||
if (current_line)
|
||||
fprintf( stderr, "%d:", current_line );
|
||||
fputc( ' ', stderr );
|
||||
}
|
||||
vfprintf( stderr, msg, valist );
|
||||
va_end( valist );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void fatal_perror( const char *msg, ... )
|
||||
{
|
||||
va_list valist;
|
||||
va_start( valist, msg );
|
||||
if (input_file_name)
|
||||
{
|
||||
fprintf( stderr, "%s:", input_file_name );
|
||||
if (current_line)
|
||||
fprintf( stderr, "%d:", current_line );
|
||||
fputc( ' ', stderr );
|
||||
}
|
||||
vfprintf( stderr, msg, valist );
|
||||
perror( " " );
|
||||
va_end( valist );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void error( const char *msg, ... )
|
||||
{
|
||||
va_list valist;
|
||||
va_start( valist, msg );
|
||||
if (input_file_name)
|
||||
{
|
||||
fprintf( stderr, "%s:", input_file_name );
|
||||
if (current_line)
|
||||
fprintf( stderr, "%d:", current_line );
|
||||
fputc( ' ', stderr );
|
||||
}
|
||||
vfprintf( stderr, msg, valist );
|
||||
va_end( valist );
|
||||
nb_errors++;
|
||||
}
|
||||
|
||||
void warning( const char *msg, ... )
|
||||
{
|
||||
va_list valist;
|
||||
|
||||
if (!display_warnings) return;
|
||||
va_start( valist, msg );
|
||||
if (input_file_name)
|
||||
{
|
||||
fprintf( stderr, "%s:", input_file_name );
|
||||
if (current_line)
|
||||
fprintf( stderr, "%d:", current_line );
|
||||
fputc( ' ', stderr );
|
||||
}
|
||||
fprintf( stderr, "warning: " );
|
||||
vfprintf( stderr, msg, valist );
|
||||
va_end( valist );
|
||||
}
|
||||
|
||||
/* output a standard header for generated files */
|
||||
void output_standard_file_header( FILE *outfile )
|
||||
{
|
||||
if (input_file_name)
|
||||
fprintf( outfile, "/* File generated automatically from %s; do not edit! */\n",
|
||||
input_file_name );
|
||||
else
|
||||
fprintf( outfile, "/* File generated automatically; do not edit! */\n" );
|
||||
fprintf( outfile,
|
||||
"/* This file can be copied, modified and distributed without restriction. */\n\n" );
|
||||
}
|
||||
|
||||
/* dump a byte stream into the assembly code */
|
||||
void dump_bytes( FILE *outfile, const unsigned char *data, int len,
|
||||
const char *label, int constant )
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf( outfile, "\nstatic %sunsigned char %s[%d] = {",
|
||||
constant ? "const " : "", label, len );
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (!(i & 7)) fprintf( outfile, "\n " );
|
||||
fprintf( outfile, "0x%02x", *data++ );
|
||||
if (i < len - 1) fprintf( outfile, "," );
|
||||
}
|
||||
fprintf( outfile, "\n};\n" );
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* open_input_file
|
||||
*
|
||||
* Open a file in the given srcdir and set the input_file_name global variable.
|
||||
*/
|
||||
FILE *open_input_file( const char *srcdir, const char *name )
|
||||
{
|
||||
char *fullname;
|
||||
FILE *file = fopen( name, "r" );
|
||||
|
||||
if (!file && srcdir)
|
||||
{
|
||||
fullname = xmalloc( strlen(srcdir) + strlen(name) + 2 );
|
||||
strcpy( fullname, srcdir );
|
||||
strcat( fullname, "/" );
|
||||
strcat( fullname, name );
|
||||
file = fopen( fullname, "r" );
|
||||
}
|
||||
else fullname = xstrdup( name );
|
||||
|
||||
if (!file) fatal_error( "Cannot open file '%s'\n", fullname );
|
||||
input_file_name = fullname;
|
||||
current_line = 1;
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* close_input_file
|
||||
*
|
||||
* Close the current input file (must have been opened with open_input_file).
|
||||
*/
|
||||
void close_input_file( FILE *file )
|
||||
{
|
||||
fclose( file );
|
||||
free( input_file_name );
|
||||
input_file_name = NULL;
|
||||
current_line = 0;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* make_c_identifier
|
||||
*
|
||||
* Map a string to a valid C identifier.
|
||||
*/
|
||||
const char *make_c_identifier( const char *str )
|
||||
{
|
||||
static char buffer[256];
|
||||
char *p;
|
||||
|
||||
for (p = buffer; *str && p < buffer+sizeof(buffer)-1; p++, str++)
|
||||
{
|
||||
if (isalnum(*str)) *p = *str;
|
||||
else *p = '_';
|
||||
}
|
||||
*p = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
* Function: get_alignment
|
||||
*
|
||||
* Description:
|
||||
* According to the info page for gas, the .align directive behaves
|
||||
* differently on different systems. On some architectures, the
|
||||
* argument of a .align directive is the number of bytes to pad to, so
|
||||
* to align on an 8-byte boundary you'd say
|
||||
* .align 8
|
||||
* On other systems, the argument is "the number of low-order zero bits
|
||||
* that the location counter must have after advancement." So to
|
||||
* align on an 8-byte boundary you'd say
|
||||
* .align 3
|
||||
*
|
||||
* The reason gas is written this way is that it's trying to mimick
|
||||
* native assemblers for the various architectures it runs on. gas
|
||||
* provides other directives that work consistantly across
|
||||
* architectures, but of course we want to work on all arches with or
|
||||
* without gas. Hence this function.
|
||||
*
|
||||
*
|
||||
* Parameters:
|
||||
* alignBoundary -- the number of bytes to align to.
|
||||
* If we're on an architecture where
|
||||
* the assembler requires a 'number
|
||||
* of low-order zero bits' as a
|
||||
* .align argument, then this number
|
||||
* must be a power of 2.
|
||||
*
|
||||
*/
|
||||
int get_alignment(int alignBoundary)
|
||||
{
|
||||
#if defined(__powerpc__) || defined(__ALPHA__)
|
||||
|
||||
int n = 0;
|
||||
|
||||
switch(alignBoundary)
|
||||
{
|
||||
case 2:
|
||||
n = 1;
|
||||
break;
|
||||
case 4:
|
||||
n = 2;
|
||||
break;
|
||||
case 8:
|
||||
n = 3;
|
||||
break;
|
||||
case 16:
|
||||
n = 4;
|
||||
break;
|
||||
case 32:
|
||||
n = 5;
|
||||
break;
|
||||
case 64:
|
||||
n = 6;
|
||||
break;
|
||||
case 128:
|
||||
n = 7;
|
||||
break;
|
||||
case 256:
|
||||
n = 8;
|
||||
break;
|
||||
case 512:
|
||||
n = 9;
|
||||
break;
|
||||
case 1024:
|
||||
n = 10;
|
||||
break;
|
||||
case 2048:
|
||||
n = 11;
|
||||
break;
|
||||
case 4096:
|
||||
n = 12;
|
||||
break;
|
||||
case 8192:
|
||||
n = 13;
|
||||
break;
|
||||
case 16384:
|
||||
n = 14;
|
||||
break;
|
||||
case 32768:
|
||||
n = 15;
|
||||
break;
|
||||
case 65536:
|
||||
n = 16;
|
||||
break;
|
||||
default:
|
||||
fatal_error("Alignment to %d-byte boundary not supported on this architecture.\n",
|
||||
alignBoundary);
|
||||
}
|
||||
return n;
|
||||
|
||||
#elif defined(__i386__) || defined(__sparc__)
|
||||
|
||||
return alignBoundary;
|
||||
|
||||
#else
|
||||
#error "How does the '.align' assembler directive work on your architecture?"
|
||||
#endif
|
||||
}
|
429
reactos/tools/winebuild/winebuild.man.in
Normal file
429
reactos/tools/winebuild/winebuild.man.in
Normal file
|
@ -0,0 +1,429 @@
|
|||
.\" -*- nroff -*-
|
||||
.TH WINEBUILD 1 "March 2003" "@PACKAGE_STRING@" "Wine dll builder"
|
||||
.SH NAME
|
||||
winebuild \- Wine dll builder
|
||||
.SH SYNOPSIS
|
||||
.BI winebuild\ [options]\ [input\ files]
|
||||
.SH DESCRIPTION
|
||||
.B winebuild
|
||||
generates the C and assembly files that are necessary to build a Wine
|
||||
dll, which is basically a Win32 dll encapsulated inside a Unix
|
||||
library.
|
||||
.PP
|
||||
.B winebuild
|
||||
has different modes, depending on what kind of file it is asked to
|
||||
generate. The mode is specified by one of the mode options specified
|
||||
below. In addition to the mode option, various other command-line
|
||||
option can be specified, as described in the \fBOPTIONS\fR section.
|
||||
.SH "MODE OPTIONS"
|
||||
You have to specify exactly one of the following options, depending on
|
||||
what you want winebuild to generate.
|
||||
.TP
|
||||
.BI \--spec=\ file.spec
|
||||
Build a C file from a spec file (see \fBSPEC FILE SYNTAX\fR for
|
||||
details). The resulting C file must be compiled and linked to the
|
||||
other object files to build a working Wine dll.
|
||||
.br
|
||||
In that mode, the
|
||||
.I input files
|
||||
should be the list of all object files that will be linked into the
|
||||
final dll, to allow
|
||||
.B winebuild
|
||||
to get the list of all undefined symbols that need to be imported from
|
||||
other dlls.
|
||||
.TP
|
||||
.BI \--exe=\ name
|
||||
Build a C file for the named executable. This is basically the same as
|
||||
the --spec mode except that it doesn't require a .spec file as input,
|
||||
since an executable doesn't export functions. The resulting C file
|
||||
must be compiled and linked to the other object files to build a
|
||||
working Wine executable, and all the other object files must be listed
|
||||
as
|
||||
.I input files.
|
||||
.TP
|
||||
.BI \--def=\ file.spec
|
||||
Build a .def file from a spec file. This is used when building dlls
|
||||
with a PE (Win32) compiler.
|
||||
.TP
|
||||
.B \--debug
|
||||
Build a C file containing the definitions for debugging channels. In
|
||||
that mode the
|
||||
.I input files
|
||||
should be a list of C files to search for debug channel
|
||||
definitions. The resulting C file must be compiled and linked with the
|
||||
dll.
|
||||
.TP
|
||||
.B \--relay16
|
||||
Generate the assembly code for the 16-bit relay routines. This is for
|
||||
Wine internal usage only, you should never need to use this option.
|
||||
.TP
|
||||
.B \--relay32
|
||||
Generate the assembly code for the 32-bit relay routines. This is for
|
||||
Wine internal usage only, you should never need to use this option.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BI \-C,\ --source-dir= directory
|
||||
Change to the specified directory before reading source files. Only
|
||||
meaningful in
|
||||
.BR \--debug\ mode.
|
||||
.TP
|
||||
.BI \-D\ symbol
|
||||
Ignored for compatibility with the C compiler.
|
||||
.TP
|
||||
.BI \-e,\ --entry= function
|
||||
Specify the module entry point function; if not specified, the default
|
||||
is
|
||||
.B DllMain
|
||||
for dlls, and
|
||||
.B main
|
||||
or
|
||||
.B WinMain
|
||||
for CUI or GUI executables respectively. This is only valid for Win32
|
||||
modules.
|
||||
.TP
|
||||
.BI \-f\ flags
|
||||
Ignored for compatibility with the C compiler.
|
||||
.TP
|
||||
.BI \-F,\ --filename= filename
|
||||
Set the file name of the module. The default is to use the base name
|
||||
of the spec file (without any extension).
|
||||
.TP
|
||||
.B \-h, --help
|
||||
Display a usage message and exit.
|
||||
.TP
|
||||
.BI \-H,\ --heap= size
|
||||
Specify the size of the module local heap in bytes (only valid for
|
||||
Win16 modules); default is no local heap.
|
||||
.TP
|
||||
.BI \-i,\ --ignore= [-]symbol[,[-]symbol]
|
||||
Specify a list of symbols that should be ignored when resolving
|
||||
undefined symbols against the imported libraries. This forces these
|
||||
symbols to be resolved from the Unix C library (or from another Unix
|
||||
library linked with the application). If a symbol is prefixed by '-'
|
||||
it is removed from the list instead of being added; a stand-alone '-'
|
||||
clears the whole list.
|
||||
.TP
|
||||
.BI \-I\ directory
|
||||
Ignored for compatibility with the C compiler.
|
||||
.TP
|
||||
.B \-k, --kill-at
|
||||
Remove the stdcall decorations from the symbol names in the
|
||||
generated .def file. Only meaningful in \fB--def\fR mode.
|
||||
.TP
|
||||
.BI \-K\ flags
|
||||
Ignored for compatibility with the C compiler.
|
||||
.TP
|
||||
.BI \-L,\ --library-path= directory
|
||||
Append the specified directory to the list of directories that are
|
||||
searched for import libraries.
|
||||
.TP
|
||||
.BI \-l,\ --library= name
|
||||
Import the specified library, looking for a corresponding
|
||||
\fIlibname.def\fR file in the directories specified with the \fB-L\fR
|
||||
option.
|
||||
.TP
|
||||
.BI \-d,\ --delay-lib= name
|
||||
Same as the \fB-l\fR option, but import the specified library in
|
||||
delayed mode (i.e. the library won't be loaded until a function
|
||||
imported from it is actually called).
|
||||
.TP
|
||||
.BI \-M,\ --main-module= module
|
||||
Specify that we are building a 16-bit dll, that will ultimately be
|
||||
linked together with the 32-bit dll specified in \fImodule\fR. Only
|
||||
meaningful in \fB--spec\fR mode.
|
||||
.TP
|
||||
.BI \-m,\ --exe-mode= mode
|
||||
Set the executable mode, which can be one of the following:
|
||||
.br
|
||||
.B cui
|
||||
for a command line ASCII executable,
|
||||
.br
|
||||
.B gui
|
||||
for a graphical ASCII executable,
|
||||
.br
|
||||
.B cuiw
|
||||
for a command line Unicode executable,
|
||||
.br
|
||||
.B guiw
|
||||
for a graphical Unicode executable.
|
||||
.br
|
||||
A command line executable entry point is a normal C \fBmain\fR
|
||||
function. A graphical executable has a \fBWinMain\fR entry point
|
||||
instead. The ASCII/Unicode distinction applies to the strings that are
|
||||
passed to the entry point.
|
||||
.br
|
||||
This option is only meaningful in \fB--exe\fR mode.
|
||||
.TP
|
||||
.BI \-N,\ --dll-name= dllname
|
||||
Set the internal name of the module. It is only used in Win16
|
||||
modules. The default is to use the base name of the spec file (without
|
||||
any extension). This is used for KERNEL, since it lives in
|
||||
KRNL386.EXE. It shouldn't be needed otherwise.
|
||||
.TP
|
||||
.BI \-o,\ --output= file
|
||||
Set the name of the output file (default is standard output).
|
||||
.TP
|
||||
.BI \-r,\ --res= rsrc.res
|
||||
Load resources from the specified binary resource file. The
|
||||
\fIrsrc.res\fR can be produced from a source resource file with
|
||||
.BR wrc(1)
|
||||
(or with a Windows resource compiler).
|
||||
.br
|
||||
This option is only necessary for Win16 resource files, the Win32 ones
|
||||
can simply listed as
|
||||
.I input files
|
||||
and will automatically be handled correctly (though the
|
||||
.B \-r
|
||||
option will also work for Win32 files).
|
||||
.TP
|
||||
.B \--version
|
||||
Display the program version and exit.
|
||||
.TP
|
||||
.B \-w, --warnings
|
||||
Turn on warnings.
|
||||
.SH "SPEC FILE SYNTAX"
|
||||
.SS "General syntax"
|
||||
A spec file should contain a list of ordinal declarations. The general
|
||||
syntax is the following:
|
||||
.PP
|
||||
.I ordinal functype
|
||||
.RI [ flags ]\ exportname \ \fB(\fR\ [ args... ] \ \fB) \ [ handler ]
|
||||
.br
|
||||
.IB ordinal\ variable
|
||||
.RI [ flags ]\ exportname \ \fB(\fR\ [ data... ] \ \fB)
|
||||
.br
|
||||
.IB ordinal\ extern
|
||||
.RI [ flags ]\ exportname \ [ symbolname ]
|
||||
.br
|
||||
.IB ordinal\ stub
|
||||
.RI [ flags ]\ exportname
|
||||
.br
|
||||
.IB ordinal\ equate
|
||||
.RI [ flags ]\ exportname\ data
|
||||
.br
|
||||
.BI #\ comments
|
||||
.PP
|
||||
Declarations must fit on a single line, except if the end of line is
|
||||
escaped using a backslash character. The
|
||||
.B #
|
||||
character anywhere in a line causes the rest of the line to be ignored
|
||||
as a comment.
|
||||
.PP
|
||||
.I ordinal
|
||||
specifies the ordinal number corresponding to the entry point, or '@'
|
||||
for automatic ordinal allocation (Win32 only).
|
||||
.PP
|
||||
.I flags
|
||||
is a series of optional flags, preceded by a '-' character. The
|
||||
supported flags are:
|
||||
.RS
|
||||
.TP
|
||||
.B -norelay
|
||||
The entry point is not displayed in relay debugging traces (Win32
|
||||
only).
|
||||
.TP
|
||||
.B -noname
|
||||
The entry point will be imported by ordinal instead of by name.
|
||||
.TP
|
||||
.B -ret16
|
||||
The function returns a 16-bit value (Win16 only).
|
||||
.TP
|
||||
.B -ret64
|
||||
The function returns a 64-bit value (Win32 only).
|
||||
.TP
|
||||
.B -i386
|
||||
The entry point is only available on i386 platforms.
|
||||
.TP
|
||||
.B -register
|
||||
The function uses CPU register to pass arguments.
|
||||
.TP
|
||||
.B -interrupt
|
||||
The function is an interrupt handler routine.
|
||||
.TP
|
||||
.B -private
|
||||
The function cannot be imported from other dlls, it can only be
|
||||
accessed through GetProcAddress.
|
||||
.SS "Function ordinals"
|
||||
Syntax:
|
||||
.br
|
||||
.I ordinal functype
|
||||
.RI [ flags ]\ exportname \ \fB(\fR\ [ args... ] \ \fB) \ [ handler ]
|
||||
.br
|
||||
|
||||
This declaration defines a function entry point. The prototype defined by
|
||||
.IR exportname \ \fB(\fR\ [ args... ] \ \fB)
|
||||
specifies the name available for dynamic linking and the format of the
|
||||
arguments. '@' can be used instead of
|
||||
.I exportname
|
||||
for ordinal-only exports.
|
||||
.PP
|
||||
.I functype
|
||||
should be one of:
|
||||
.RS
|
||||
.TP
|
||||
.B stdcall
|
||||
for a normal Win32 function
|
||||
.TP
|
||||
.B pascal
|
||||
for a normal Win16 function
|
||||
.TP
|
||||
.B cdecl
|
||||
for a Win16 or Win32 function using the C calling convention
|
||||
.TP
|
||||
.B varargs
|
||||
for a Win16 or Win32 function using the C calling convention with a
|
||||
variable number of arguments
|
||||
.RE
|
||||
.PP
|
||||
.I args
|
||||
should be one or several of:
|
||||
.RS
|
||||
.TP
|
||||
.B word
|
||||
(16-bit unsigned value)
|
||||
.TP
|
||||
.B s_word
|
||||
(16-bit signed word)
|
||||
.TP
|
||||
.B long
|
||||
(32-bit value)
|
||||
.TP
|
||||
.B double
|
||||
(64-bit value)
|
||||
.TP
|
||||
.B ptr
|
||||
(linear pointer)
|
||||
.TP
|
||||
.B str
|
||||
(linear pointer to a null-terminated ASCII string)
|
||||
.TP
|
||||
.B wstr
|
||||
(linear pointer to a null-terminated Unicode string)
|
||||
.TP
|
||||
.B segptr
|
||||
(segmented pointer)
|
||||
.TP
|
||||
.B segstr
|
||||
(segmented pointer to a null-terminated ASCII string).
|
||||
.HP
|
||||
.RB Only\ ptr ,\ str ,\ wstr ,\ long\ and\ double
|
||||
are valid for Win32 functions.
|
||||
.RE
|
||||
.PP
|
||||
.I handler
|
||||
is the name of the actual C function that will implement that entry
|
||||
point in 32-bit mode. The handler can also be specified as
|
||||
.IB dllname . function
|
||||
to define a forwarded function (one whose implementation is in another
|
||||
dll). If
|
||||
.I handler
|
||||
is not specified, it is assumed to be identical to
|
||||
.I exportname.
|
||||
.PP
|
||||
This first example defines an entry point for the 32-bit GetFocus()
|
||||
call:
|
||||
.IP
|
||||
@ stdcall GetFocus() GetFocus
|
||||
.PP
|
||||
This second example defines an entry point for the 16-bit
|
||||
CreateWindow() call (the ordinal 100 is just an example); it also
|
||||
shows how long lines can be split using a backslash:
|
||||
.IP
|
||||
100 pascal CreateWindow(ptr ptr long s_word s_word s_word \\
|
||||
s_word word word word ptr) WIN_CreateWindow
|
||||
.PP
|
||||
To declare a function using a variable number of arguments, specify
|
||||
the function as
|
||||
.B varargs
|
||||
and declare it in the C file with a '...' parameter for a Win32
|
||||
function, or with an extra VA_LIST16 argument for a Win16 function.
|
||||
See the wsprintf* functions in user.exe.spec and user32.spec for an
|
||||
example.
|
||||
.SS "Variable ordinals"
|
||||
Syntax:
|
||||
.br
|
||||
.IB ordinal\ variable
|
||||
.RI [ flags ]\ exportname \ \fB(\fR\ [ data... ] \ \fB)
|
||||
.PP
|
||||
This declaration defines data storage as 32-bit words at the ordinal
|
||||
specified.
|
||||
.I exportname
|
||||
will be the name available for dynamic
|
||||
linking.
|
||||
.I data
|
||||
can be a decimal number or a hex number preceeded by "0x". The
|
||||
following example defines the variable VariableA at ordinal 2 and
|
||||
containing 4 ints:
|
||||
.IP
|
||||
2 variable VariableA(-1 0xff 0 0)
|
||||
.PP
|
||||
This declaration only works in Win16 spec files. In Win32 you should
|
||||
use
|
||||
.B extern
|
||||
instead (see below).
|
||||
.SS "Extern ordinals"
|
||||
Syntax:
|
||||
.br
|
||||
.IB ordinal\ extern
|
||||
.RI [ flags ]\ exportname \ [ symbolname ]
|
||||
.PP
|
||||
This declaration defines an entry that simply maps to a C symbol
|
||||
(variable or function). It only works in Win32 spec files.
|
||||
.I exportname
|
||||
will point to the symbol
|
||||
.I symbolname
|
||||
that must be defined in the C code. Alternatively, it can be of the
|
||||
form
|
||||
.IB dllname . symbolname
|
||||
to define a forwarded symbol (one whose implementation is in another
|
||||
dll). If
|
||||
.I symbolname
|
||||
is not specified, it is assumed to be identical to
|
||||
.I exportname.
|
||||
.SS "Stub ordinals"
|
||||
Syntax:
|
||||
.br
|
||||
.IB ordinal\ stub
|
||||
.RI [ flags ]\ exportname
|
||||
.PP
|
||||
This declaration defines a stub function. It makes the name and
|
||||
ordinal available for dynamic linking, but will terminate execution
|
||||
with an error message if the function is ever called.
|
||||
.SS "Equate ordinals"
|
||||
Syntax:
|
||||
.br
|
||||
.IB ordinal\ equate
|
||||
.RI [ flags ]\ exportname\ data
|
||||
.PP
|
||||
This declaration defines an ordinal as an absolute value.
|
||||
.I exportname
|
||||
will be the name available for dynamic linking.
|
||||
.I data
|
||||
can be a decimal number or a hex number preceeded by "0x".
|
||||
.SH AUTHORS
|
||||
.B winebuild
|
||||
has been worked on by many people over the years. The main authors are
|
||||
Robert J. Amstadt, Alexandre Julliard, Martin von Loewis, Ulrich
|
||||
Weigand and Eric Youngdale. Many other Wine developers have
|
||||
contributed, please check the file Changelog in the Wine distribution
|
||||
for the complete details.
|
||||
.SH BUGS
|
||||
It is not yet possible to use a PE-format dll in an import
|
||||
specification; only Wine dlls can be imported.
|
||||
.PP
|
||||
If you find a bug, please submit a bug report at
|
||||
.UR http://bugs.winehq.org
|
||||
.B http://bugs.winehq.org.
|
||||
.UE
|
||||
.SH AVAILABILITY
|
||||
.B winebuild
|
||||
is part of the wine distribution, which is available through WineHQ,
|
||||
the
|
||||
.B wine
|
||||
development headquarters, at
|
||||
.UR http://www.winehq.org/
|
||||
.B http://www.winehq.org/.
|
||||
.UE
|
||||
.SH "SEE ALSO"
|
||||
.BR wine (1),
|
||||
.BR wrc (1).
|
Loading…
Reference in a new issue