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:
Casper Hornstrup 2003-12-09 18:44:25 +00:00
parent 6830b8c962
commit 6bb605e497
14 changed files with 7137 additions and 0 deletions

View file

@ -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.

View file

@ -0,0 +1,3 @@
Makefile
winebuild
winebuild.man

View 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:

View 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 */

File diff suppressed because it is too large Load diff

View 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;
}

View 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;
}

File diff suppressed because it is too large Load diff

View 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;
}

View 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;
}

View 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 );
}

View 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 );
}

View 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
}

View 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).