Added support for building a dll from a .def file for cases where we
don't want to write a full .spec.
Renamed --spec option to --dll for consistency.
diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h
index c7da34d..9e6d387 100644
--- a/tools/winebuild/build.h
+++ b/tools/winebuild/build.h
@@ -68,7 +68,6 @@
typedef struct
{
- int n_args;
char arg_types[21];
} ORD_FUNCTION;
@@ -170,6 +169,9 @@
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 int remove_stdcall_decoration( char *name );
+extern DLLSPEC *alloc_dll_spec(void);
+extern void free_dll_spec( DLLSPEC *spec );
extern const char *make_c_identifier( const char *str );
extern int get_alignment(int alignBoundary);
@@ -184,7 +186,6 @@
extern int output_res16_data( FILE *outfile, DLLSPEC *spec );
extern int output_res16_directory( unsigned char *buffer, DLLSPEC *spec );
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 );
@@ -192,7 +193,10 @@
extern void BuildSpec32File( FILE *outfile, DLLSPEC *spec );
extern void BuildDef32File( FILE *outfile, DLLSPEC *spec );
extern void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv );
-extern int ParseTopLevel( FILE *file, DLLSPEC *spec );
+
+extern int parse_spec_file( FILE *file, DLLSPEC *spec );
+extern int parse_def_file( FILE *file, DLLSPEC *spec );
+extern int parse_debug_channels( const char *srcdir, const char *filename );
/* global variables */
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c
index a8f367c..996e0b1 100644
--- a/tools/winebuild/import.c
+++ b/tools/winebuild/import.c
@@ -1,8 +1,8 @@
/*
* DLL imports support
*
- * Copyright 2000 Alexandre Julliard
- * 2000 Eric Pouech
+ * Copyright 2000, 2004 Alexandre Julliard
+ * Copyright 2000 Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -32,20 +32,13 @@
#include "build.h"
-struct func
-{
- char *name; /* function name */
- int ordinal; /* function ordinal */
- int ord_only; /* non-zero if function is imported by ordinal */
-};
-
struct import
{
- char *dll; /* dll name */
+ DLLSPEC *spec; /* description of the imported dll */
int delay; /* delay or not dll loading ? */
- struct func *exports; /* functions exported from this dll */
+ ORDDEF **exports; /* functions exported from this dll */
int nb_exports; /* number of exported functions */
- struct func *imports; /* functions we want to import from this dll */
+ ORDDEF **imports; /* functions we want to import from this dll */
int nb_imports; /* number of imported functions */
};
@@ -143,7 +136,10 @@
/* compare function names; helper for resolve_imports */
static int func_cmp( const void *func1, const void *func2 )
{
- return strcmp( ((struct func *)func1)->name, ((struct func *)func2)->name );
+ const ORDDEF *odp1 = *(const ORDDEF **)func1;
+ const ORDDEF *odp2 = *(const ORDDEF **)func2;
+ return strcmp( odp1->name ? odp1->name : odp1->export_name,
+ odp2->name ? odp2->name : odp2->export_name );
}
/* locate a symbol in a (sorted) list */
@@ -159,14 +155,15 @@
}
/* locate an export in a (sorted) export list */
-inline static struct func *find_export( const char *name, struct func *table, int size )
+inline static ORDDEF *find_export( const char *name, ORDDEF **table, int size )
{
- struct func func, *res = NULL;
+ ORDDEF func, *odp, **res = NULL;
func.name = (char *)name;
func.ordinal = -1;
- if (table) res = bsearch( &func, table, size, sizeof(*table), func_cmp );
- return res;
+ odp = &func;
+ if (table) res = bsearch( &odp, table, size, sizeof(*table), func_cmp );
+ return res ? *res : NULL;
}
/* sort a symbol table */
@@ -179,13 +176,9 @@
/* free an import structure */
static void free_imports( struct import *imp )
{
- int i;
-
- for (i = 0; i < imp->nb_exports; i++) free( imp->exports[i].name );
- for (i = 0; i < imp->nb_imports; i++) free( imp->imports[i].name );
free( imp->exports );
free( imp->imports );
- free( imp->dll );
+ free_dll_spec( imp->spec );
free( imp );
}
@@ -202,7 +195,7 @@
for (i = 0; i < nb_imports; i++)
{
- if (!strcmp( dll_imports[i]->dll, name )) return 1;
+ if (!strcmp( dll_imports[i]->spec->file_name, name )) return 1;
}
return 0;
}
@@ -241,152 +234,40 @@
return fullname;
}
-/* skip whitespace until the next token */
-static char *skip_whitespace( char *p )
-{
- while (*p && isspace(*p)) p++;
- if (!*p || *p == ';') p = NULL;
- return p;
-}
-
-/* skip to the start of the next token, null terminating the current one */
-static char *next_token( char *p )
-{
- while (*p && !isspace(*p)) p++;
- if (*p) *p++ = 0;
- return skip_whitespace( p );
-}
-
-/* remove the @nn suffix from stdcall names */
-static char *remove_stdcall_decoration( char *buffer )
-{
- char *p = buffer + strlen(buffer) - 1;
- while (p > buffer && isdigit(*p)) p--;
- if (p > buffer && *p == '@') *p = 0;
- return buffer;
-}
-
/* read in the list of exported symbols of an import library */
static int read_import_lib( const char *name, struct import *imp )
{
FILE *f;
- char buffer[1024];
char *fullname;
- int size;
+ int i, ret;
+ DLLSPEC *spec = imp->spec;
imp->exports = NULL;
- imp->nb_exports = size = 0;
+ imp->nb_exports = 0;
fullname = open_library( name );
f = open_input_file( NULL, fullname );
free( fullname );
- while (fgets( buffer, sizeof(buffer), f ))
- {
- char *name, *flags;
- int ordinal = 0, ord_only = 0;
-
- char *p = buffer + strlen(buffer) - 1;
- if (p < buffer) goto next;
- if (*p == '\n') *p-- = 0;
-
- p = buffer;
- if (!(p = skip_whitespace(p))) goto next;
- name = p;
- p = next_token( name );
-
- if (!strcmp( name, "LIBRARY" ))
- {
- if (!p)
- {
- error( "Expected name after LIBRARY\n" );
- goto next;
- }
- name = p;
- p = next_token( name );
- if (p)
- {
- error( "Garbage after LIBRARY statement\n" );
- goto next;
- }
- if (is_already_imported( name ))
- {
- close_input_file( f );
- return 0; /* ignore this dll */
- }
- free( imp->dll );
- imp->dll = xstrdup( name );
- goto next;
- }
- if (!strcmp( name, "EXPORTS" )) goto next;
-
- /* check for ordinal */
- if (!p)
- {
- error( "Expected ordinal after function name\n" );
- goto next;
- }
- if (*p != '@' || !isdigit(p[1]))
- {
- error( "Expected ordinal after function name '%s'\n", name );
- goto next;
- }
- ordinal = strtol( p+1, &p, 10 );
- if (ordinal >= MAX_ORDINALS)
- {
- error( "Invalid ordinal number %d\n", ordinal );
- goto next;
- }
-
- /* check for optional flags */
- while (p && (p = skip_whitespace(p)))
- {
- flags = p;
- p = next_token( flags );
- if (!strcmp( flags, "NONAME" ))
- {
- ord_only = 1;
- if (!ordinal)
- {
- error( "Invalid ordinal number %d\n", ordinal );
- goto next;
- }
- }
- else if (!strcmp( flags, "CONSTANT" ) || !strcmp( flags, "DATA" ))
- {
- /* we don't support importing non-function entry points */
- goto next;
- }
- else if (!strcmp( flags, "PRIVATE" ))
- {
- /* function must not be imported */
- goto next;
- }
- else
- {
- error( "Garbage after ordinal declaration\n" );
- goto next;
- }
- }
-
- if (imp->nb_exports == size)
- {
- size += 128;
- imp->exports = xrealloc( imp->exports, size * sizeof(*imp->exports) );
- }
- if ((p = strchr( name, '=' ))) *p = 0;
- remove_stdcall_decoration( name );
- imp->exports[imp->nb_exports].name = xstrdup( name );
- imp->exports[imp->nb_exports].ordinal = ordinal;
- imp->exports[imp->nb_exports].ord_only = ord_only;
- imp->nb_exports++;
- next:
- current_line++;
- }
+ ret = parse_def_file( f, spec );
close_input_file( f );
+ if (!ret) return 0;
+ if (is_already_imported( spec->file_name )) return 0;
+
+ imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) );
+
+ for (i = 0; i < spec->nb_entry_points; i++)
+ {
+ ORDDEF *odp = &spec->entry_points[i];
+
+ if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL) continue;
+ if (odp->flags & FLAG_PRIVATE) continue;
+ imp->exports[imp->nb_exports++] = odp;
+ }
+ imp->exports = xrealloc( imp->exports, imp->nb_exports * sizeof(*imp->exports) );
if (imp->nb_exports)
qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
- return !nb_errors;
+ return 1;
}
/* add a dll to the list of imports */
@@ -407,11 +288,11 @@
}
imp = xmalloc( sizeof(*imp) );
- imp->dll = fullname;
- imp->delay = delay;
- imp->imports = NULL;
- imp->nb_imports = 0;
-
+ imp->spec = alloc_dll_spec();
+ imp->spec->file_name = fullname;
+ imp->delay = delay;
+ imp->imports = NULL;
+ imp->nb_imports = 0;
if (delay) nb_delayed++;
if (read_import_lib( name, imp ))
@@ -489,13 +370,10 @@
}
/* add a function to the list of imports from a given dll */
-static void add_import_func( struct import *imp, const struct func *func )
+static void add_import_func( struct import *imp, ORDDEF *func )
{
imp->imports = xrealloc( imp->imports, (imp->nb_imports+1) * sizeof(*imp->imports) );
- imp->imports[imp->nb_imports].name = xstrdup( func->name );
- imp->imports[imp->nb_imports].ordinal = func->ordinal;
- imp->imports[imp->nb_imports].ord_only = func->ord_only;
- imp->nb_imports++;
+ imp->imports[imp->nb_imports++] = func;
total_imports++;
if (imp->delay) total_delayed++;
}
@@ -613,15 +491,16 @@
static int check_unused( const struct import* imp, const DLLSPEC *spec )
{
int i;
- size_t len = strlen(imp->dll);
- const char *p = strchr( imp->dll, '.' );
- if (p && !strcasecmp( p, ".dll" )) len = p - imp->dll;
+ const char *file_name = imp->spec->file_name;
+ size_t len = strlen( file_name );
+ const char *p = strchr( file_name, '.' );
+ if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
for (i = spec->base; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
- if (!strncasecmp( odp->link_name, imp->dll, len ) &&
+ if (!strncasecmp( odp->link_name, file_name, len ) &&
odp->link_name[len] == '.')
return 0; /* found a forward, it is used */
}
@@ -724,10 +603,10 @@
for (j = 0; j < nb_undef_symbols; j++)
{
- struct func *func = find_export( undef_symbols[j], imp->exports, imp->nb_exports );
- if (func)
+ ORDDEF *odp = find_export( undef_symbols[j], imp->exports, imp->nb_exports );
+ if (odp)
{
- add_import_func( imp, func );
+ add_import_func( imp, odp );
free( undef_symbols[j] );
undef_symbols[j] = NULL;
}
@@ -736,7 +615,7 @@
if (!remove_symbol_holes() && check_unused( imp, spec ))
{
/* the dll is not used, get rid of it */
- warning( "%s imported but no symbols used\n", imp->dll );
+ warning( "%s imported but no symbols used\n", imp->spec->file_name );
remove_import_dll( i );
i--;
}
@@ -772,7 +651,7 @@
{
if (dll_imports[i]->delay) continue;
fprintf( outfile, " { 0, 0, 0, \"%s\", &imports.data[%d] },\n",
- dll_imports[i]->dll, j );
+ dll_imports[i]->spec->file_name, j );
j += dll_imports[i]->nb_imports + 1;
}
@@ -784,18 +663,18 @@
for (i = 0; i < nb_imports; i++)
{
if (dll_imports[i]->delay) continue;
- fprintf( outfile, " /* %s */\n", dll_imports[i]->dll );
+ fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
for (j = 0; j < dll_imports[i]->nb_imports; j++)
{
- struct func *import = &dll_imports[i]->imports[j];
- if (!import->ord_only)
+ ORDDEF *odp = dll_imports[i]->imports[j];
+ if (!(odp->flags & FLAG_NONAME))
{
- unsigned short ord = import->ordinal;
+ unsigned short ord = odp->ordinal;
fprintf( outfile, " \"\\%03o\\%03o%s\",\n",
- *(unsigned char *)&ord, *((unsigned char *)&ord + 1), import->name );
+ *(unsigned char *)&ord, *((unsigned char *)&ord + 1), odp->name );
}
else
- fprintf( outfile, " (char *)%d,\n", import->ordinal );
+ fprintf( outfile, " (char *)%d,\n", odp->ordinal );
}
fprintf( outfile, " 0,\n" );
}
@@ -811,13 +690,14 @@
if (dll_imports[i]->delay) continue;
for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
{
- struct func *import = &dll_imports[i]->imports[j];
- fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", import->name );
- fprintf( outfile, " \"\\t.globl " __ASM_NAME("%s") "\\n\"\n", import->name );
- fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\\t", import->name);
+ ORDDEF *odp = dll_imports[i]->imports[j];
+ const char *name = odp->name ? odp->name : odp->export_name;
+ fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", name );
+ fprintf( outfile, " \"\\t.globl " __ASM_NAME("%s") "\\n\"\n", name );
+ fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\\t", name);
#if defined(__i386__)
- if (strstr( import->name, "__wine_call_from_16" ))
+ if (strstr( name, "__wine_call_from_16" ))
fprintf( outfile, ".byte 0x2e\\n\\tjmp *(imports+%d)\\n\\tnop\\n", pos );
else
fprintf( outfile, "jmp *(imports+%d)\\n\\tmovl %%esi,%%esi\\n", pos );
@@ -886,8 +766,9 @@
fprintf( outfile, "static void *__wine_delay_imp_%d_hmod;\n", i);
for (j = 0; j < dll_imports[i]->nb_imports; j++)
{
- fprintf( outfile, "void __wine_delay_imp_%d_%s();\n",
- i, dll_imports[i]->imports[j].name );
+ ORDDEF *odp = dll_imports[i]->imports[j];
+ const char *name = odp->name ? odp->name : odp->export_name;
+ fprintf( outfile, "void __wine_delay_imp_%d_%s();\n", i, name );
}
}
fprintf( outfile, "\n" );
@@ -910,31 +791,33 @@
{
if (!dll_imports[i]->delay) continue;
fprintf( outfile, " { 0, \"%s\", &__wine_delay_imp_%d_hmod, &delay_imports.IAT[%d], &delay_imports.INT[%d], 0, 0, 0 },\n",
- dll_imports[i]->dll, i, j, j );
+ dll_imports[i]->spec->file_name, i, j, j );
j += dll_imports[i]->nb_imports;
}
fprintf( outfile, " },\n {\n" );
for (i = 0; i < nb_imports; i++)
{
if (!dll_imports[i]->delay) continue;
- fprintf( outfile, " /* %s */\n", dll_imports[i]->dll );
+ fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
for (j = 0; j < dll_imports[i]->nb_imports; j++)
{
- fprintf( outfile, " &__wine_delay_imp_%d_%s,\n", i, dll_imports[i]->imports[j].name);
+ ORDDEF *odp = dll_imports[i]->imports[j];
+ const char *name = odp->name ? odp->name : odp->export_name;
+ fprintf( outfile, " &__wine_delay_imp_%d_%s,\n", i, name );
}
}
fprintf( outfile, " },\n {\n" );
for (i = 0; i < nb_imports; i++)
{
if (!dll_imports[i]->delay) continue;
- fprintf( outfile, " /* %s */\n", dll_imports[i]->dll );
+ fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
for (j = 0; j < dll_imports[i]->nb_imports; j++)
{
- struct func *import = &dll_imports[i]->imports[j];
- if (import->ord_only)
- fprintf( outfile, " (char *)%d,\n", import->ordinal );
+ ORDDEF *odp = dll_imports[i]->imports[j];
+ if (!odp->name)
+ fprintf( outfile, " (char *)%d,\n", odp->ordinal );
else
- fprintf( outfile, " \"%s\",\n", import->name );
+ fprintf( outfile, " \"%s\",\n", odp->name );
}
}
fprintf( outfile, " }\n};\n\n" );
@@ -1059,7 +942,10 @@
for (j = 0; j < dll_imports[i]->nb_imports; j++)
{
char buffer[128];
- sprintf( buffer, "__wine_delay_imp_%d_%s", i, dll_imports[i]->imports[j].name );
+ ORDDEF *odp = dll_imports[i]->imports[j];
+ const char *name = odp->name ? odp->name : odp->export_name;
+
+ sprintf( buffer, "__wine_delay_imp_%d_%s", i, name );
fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", buffer );
fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\"\n", buffer );
#if defined(__i386__)
@@ -1088,12 +974,14 @@
if (!dll_imports[i]->delay) continue;
for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
{
- struct func *import = &dll_imports[i]->imports[j];
- fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", import->name );
- fprintf( outfile, " \"\\t.globl " __ASM_NAME("%s") "\\n\"\n", import->name );
- fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\\t\"", import->name);
+ ORDDEF *odp = dll_imports[i]->imports[j];
+ const char *name = odp->name ? odp->name : odp->export_name;
+
+ fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", name );
+ fprintf( outfile, " \"\\t.globl " __ASM_NAME("%s") "\\n\"\n", name );
+ fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\\t\"", name );
#if defined(__i386__)
- if (strstr( import->name, "__wine_call_from_16" ))
+ if (strstr( name, "__wine_call_from_16" ))
fprintf( outfile, "\".byte 0x2e\\n\\tjmp *(delay_imports+%d)\\n\\tnop\\n\"", pos );
else
fprintf( outfile, "\"jmp *(delay_imports+%d)\\n\\tmovl %%esi,%%esi\\n\"", pos );
diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c
index edddd7c..2050979 100644
--- a/tools/winebuild/main.c
+++ b/tools/winebuild/main.c
@@ -56,17 +56,17 @@
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;
+static char *spec_file_name;
/* execution mode */
enum exec_mode_values
{
MODE_NONE,
- MODE_SPEC,
+ MODE_DLL,
MODE_EXE,
MODE_DEF,
MODE_DEBUG,
@@ -87,7 +87,10 @@
if ((p = strrchr( name, '/' ))) name = p + 1;
spec->file_name = xmalloc( strlen(name) + 5 );
strcpy( spec->file_name, name );
- if ((p = strrchr( spec->file_name, '.' )) && !strcmp( p, ".spec" )) *p = 0;
+ if ((p = strrchr( spec->file_name, '.' )))
+ {
+ if (!strcmp( p, ".spec" ) || !strcmp( p, ".def" )) *p = 0;
+ }
if (!strchr( spec->file_name, '.' )) strcat( spec->file_name, ".dll" );
}
@@ -126,7 +129,7 @@
" --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"
+" --dll=FILE Build a .c file from a .spec or .def 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"
@@ -136,7 +139,7 @@
enum long_options_values
{
- LONG_OPT_SPEC = 1,
+ LONG_OPT_DLL = 1,
LONG_OPT_DEF,
LONG_OPT_EXE,
LONG_OPT_DEBUG,
@@ -149,13 +152,14 @@
static const struct option long_options[] =
{
- { "spec", 1, 0, LONG_OPT_SPEC },
+ { "dll", 1, 0, LONG_OPT_DLL },
{ "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 },
+ { "spec", 1, 0, LONG_OPT_DLL }, /* for backwards compatibility */
/* aliases for short options */
{ "source-dir", 1, 0, 'C' },
{ "delay-lib", 1, 0, 'd' },
@@ -287,14 +291,14 @@
case 'w':
display_warnings = 1;
break;
- case LONG_OPT_SPEC:
- set_exec_mode( MODE_SPEC );
- input_file = open_input_file( NULL, optarg );
+ case LONG_OPT_DLL:
+ set_exec_mode( MODE_DLL );
+ spec_file_name = xstrdup( optarg );
set_dll_file_name( optarg, spec );
break;
case LONG_OPT_DEF:
set_exec_mode( MODE_DEF );
- input_file = open_input_file( NULL, optarg );
+ spec_file_name = xstrdup( optarg );
set_dll_file_name( optarg, spec );
break;
case LONG_OPT_EXE:
@@ -357,65 +361,59 @@
}
}
+static int parse_input_file( DLLSPEC *spec )
+{
+ FILE *input_file = open_input_file( NULL, spec_file_name );
+ char *extension = strrchr( spec_file_name, '.' );
+
+ if (extension && !strcmp( extension, ".def" ))
+ return parse_def_file( input_file, spec );
+ else
+ return parse_spec_file( input_file, spec );
+ close_input_file( input_file );
+}
+
+
/*******************************************************************
* main
*/
int main(int argc, char **argv)
{
- DLLSPEC spec;
-
- spec.file_name = NULL;
- spec.dll_name = NULL;
- spec.owner_name = NULL;
- spec.init_func = NULL;
- spec.type = SPEC_WIN32;
- spec.mode = SPEC_MODE_DLL;
- spec.base = MAX_ORDINALS;
- spec.limit = 0;
- spec.stack_size = 0;
- spec.heap_size = 0;
- spec.nb_entry_points = 0;
- spec.alloc_entry_points = 0;
- spec.nb_names = 0;
- spec.nb_resources = 0;
- spec.entry_points = NULL;
- spec.names = NULL;
- spec.ordinals = NULL;
- spec.resources = NULL;
+ DLLSPEC *spec = alloc_dll_spec();
output_file = stdout;
- argv = parse_options( argc, argv, &spec );
+ argv = parse_options( argc, argv, spec );
switch(exec_mode)
{
- case MODE_SPEC:
- load_resources( argv, &spec );
- if (!ParseTopLevel( input_file, &spec )) break;
- switch (spec.type)
+ case MODE_DLL:
+ load_resources( argv, spec );
+ if (!parse_input_file( spec )) break;
+ switch (spec->type)
{
case SPEC_WIN16:
if (argv[0])
fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
- BuildSpec16File( output_file, &spec );
+ BuildSpec16File( output_file, spec );
break;
case SPEC_WIN32:
read_undef_symbols( argv );
- BuildSpec32File( output_file, &spec );
+ BuildSpec32File( output_file, spec );
break;
default: assert(0);
}
break;
case MODE_EXE:
- if (spec.type == SPEC_WIN16) fatal_error( "Cannot build 16-bit exe files\n" );
- load_resources( argv, &spec );
+ if (spec->type == SPEC_WIN16) fatal_error( "Cannot build 16-bit exe files\n" );
+ load_resources( argv, spec );
read_undef_symbols( argv );
- BuildSpec32File( output_file, &spec );
+ BuildSpec32File( output_file, spec );
break;
case MODE_DEF:
if (argv[0]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
- if (spec.type == SPEC_WIN16) fatal_error( "Cannot yet build .def file for 16-bit dlls\n" );
- if (!ParseTopLevel( input_file, &spec )) break;
- BuildDef32File( output_file, &spec );
+ if (spec->type == SPEC_WIN16) fatal_error( "Cannot yet build .def file for 16-bit dlls\n" );
+ if (!parse_input_file( spec )) break;
+ BuildDef32File( output_file, spec );
break;
case MODE_DEBUG:
BuildDebugFile( output_file, current_src_dir, argv );
diff --git a/tools/winebuild/parser.c b/tools/winebuild/parser.c
index 49b42a9..652826f 100644
--- a/tools/winebuild/parser.c
+++ b/tools/winebuild/parser.c
@@ -3,7 +3,7 @@
*
* Copyright 1993 Robert J. Amstadt
* Copyright 1995 Martin von Loewis
- * Copyright 1995, 1996, 1997 Alexandre Julliard
+ * Copyright 1995, 1996, 1997, 2004 Alexandre Julliard
* Copyright 1997 Eric Youngdale
* Copyright 1999 Ulrich Weigand
*
@@ -43,6 +43,9 @@
static char *ParseNext = ParseBuffer;
static FILE *input_file;
+static const char *separator_chars;
+static const char *comment_chars;
+
static const char * const TypeNames[TYPE_NBTYPES] =
{
"variable", /* TYPE_VARIABLE */
@@ -76,7 +79,12 @@
inline static int is_token_separator( char ch )
{
- return (ch == '(' || ch == ')' || ch == '-');
+ return strchr( separator_chars, ch ) != NULL;
+}
+
+inline static int is_token_comment( char ch )
+{
+ return strchr( comment_chars, ch ) != NULL;
}
/* get the next line from the input file, or return 0 if at eof */
@@ -109,7 +117,7 @@
else break;
}
- if ((*p == '\0') || (*p == '#'))
+ if ((*p == '\0') || is_token_comment(*p))
{
if (!allow_eol) error( "Declaration not terminated properly\n" );
return NULL;
@@ -146,11 +154,11 @@
}
/*******************************************************************
- * ParseVariable
+ * parse_spec_variable
*
- * Parse a variable definition.
+ * Parse a variable definition in a .spec file.
*/
-static int ParseVariable( ORDDEF *odp, DLLSPEC *spec )
+static int parse_spec_variable( ORDDEF *odp, DLLSPEC *spec )
{
char *endptr;
int *value_array;
@@ -208,11 +216,11 @@
/*******************************************************************
- * ParseExportFunction
+ * parse_spec_export
*
- * Parse a function definition.
+ * Parse an exported function definition in a .spec file.
*/
-static int ParseExportFunction( ORDDEF *odp, DLLSPEC *spec )
+static int parse_spec_export( ORDDEF *odp, DLLSPEC *spec )
{
const char *token;
unsigned int i;
@@ -330,11 +338,11 @@
/*******************************************************************
- * ParseEquate
+ * parse_spec_equate
*
- * Parse an 'equate' definition.
+ * Parse an 'equate' definition in a .spec file.
*/
-static int ParseEquate( ORDDEF *odp, DLLSPEC *spec )
+static int parse_spec_equate( ORDDEF *odp, DLLSPEC *spec )
{
char *endptr;
int value;
@@ -358,11 +366,11 @@
/*******************************************************************
- * ParseStub
+ * parse_spec_stub
*
- * Parse a 'stub' definition.
+ * Parse a 'stub' definition in a .spec file
*/
-static int ParseStub( ORDDEF *odp, DLLSPEC *spec )
+static int parse_spec_stub( ORDDEF *odp, DLLSPEC *spec )
{
odp->u.func.arg_types[0] = '\0';
odp->link_name = xstrdup("");
@@ -371,11 +379,11 @@
/*******************************************************************
- * ParseExtern
+ * parse_spec_extern
*
- * Parse an 'extern' definition.
+ * Parse an 'extern' definition in a .spec file.
*/
-static int ParseExtern( ORDDEF *odp, DLLSPEC *spec )
+static int parse_spec_extern( ORDDEF *odp, DLLSPEC *spec )
{
const char *token;
@@ -403,11 +411,11 @@
/*******************************************************************
- * ParseFlags
+ * parse_spec_flags
*
- * Parse the optional flags for an entry point
+ * Parse the optional flags for an entry point in a .spec file.
*/
-static const char *ParseFlags( ORDDEF *odp )
+static const char *parse_spec_flags( ORDDEF *odp )
{
unsigned int i;
const char *token;
@@ -429,26 +437,13 @@
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_spec_ordinal
*
- * Parse an ordinal definition.
+ * Parse an ordinal definition in a .spec file.
*/
-static int ParseOrdinal( int ordinal, DLLSPEC *spec )
+static int parse_spec_ordinal( int ordinal, DLLSPEC *spec )
{
const char *token;
@@ -468,32 +463,32 @@
}
if (!(token = GetToken(0))) goto error;
- if (*token == '-' && !(token = ParseFlags( odp ))) goto error;
+ if (*token == '-' && !(token = parse_spec_flags( odp ))) goto error;
odp->name = xstrdup( token );
- fix_export_name( odp->name );
+ remove_stdcall_decoration( odp->name );
odp->lineno = current_line;
odp->ordinal = ordinal;
switch(odp->type)
{
case TYPE_VARIABLE:
- if (!ParseVariable( odp, spec )) goto error;
+ if (!parse_spec_variable( odp, spec )) goto error;
break;
case TYPE_PASCAL:
case TYPE_STDCALL:
case TYPE_VARARGS:
case TYPE_CDECL:
- if (!ParseExportFunction( odp, spec )) goto error;
+ if (!parse_spec_export( odp, spec )) goto error;
break;
case TYPE_ABS:
- if (!ParseEquate( odp, spec )) goto error;
+ if (!parse_spec_equate( odp, spec )) goto error;
break;
case TYPE_STUB:
- if (!ParseStub( odp, spec )) goto error;
+ if (!parse_spec_stub( odp, spec )) goto error;
break;
case TYPE_EXTERN:
- if (!ParseExtern( odp, spec )) goto error;
+ if (!parse_spec_extern( odp, spec )) goto error;
break;
default:
assert( 0 );
@@ -641,17 +636,20 @@
/*******************************************************************
- * ParseTopLevel
+ * parse_spec_file
*
- * Parse a spec file.
+ * Parse a .spec file.
*/
-int ParseTopLevel( FILE *file, DLLSPEC *spec )
+int parse_spec_file( FILE *file, DLLSPEC *spec )
{
const char *token;
input_file = file;
current_line = 0;
+ comment_chars = "#;";
+ separator_chars = "()-";
+
while (get_next_line())
{
if (!(token = GetToken(1))) continue;
@@ -662,11 +660,11 @@
error( "'@' ordinals not supported for Win16\n" );
continue;
}
- if (!ParseOrdinal( -1, spec )) continue;
+ if (!parse_spec_ordinal( -1, spec )) continue;
}
else if (IsNumberString(token))
{
- if (!ParseOrdinal( atoi(token), spec )) continue;
+ if (!parse_spec_ordinal( atoi(token), spec )) continue;
}
else
{
@@ -684,6 +682,243 @@
/*******************************************************************
+ * parse_def_library
+ *
+ * Parse a LIBRARY declaration in a .def file.
+ */
+static int parse_def_library( DLLSPEC *spec )
+{
+ const char *token = GetToken(1);
+
+ if (!token) return 1;
+ if (strcmp( token, "BASE" ))
+ {
+ free( spec->file_name );
+ spec->file_name = xstrdup( token );
+ if (!(token = GetToken(1))) return 1;
+ }
+ if (strcmp( token, "BASE" ))
+ {
+ error( "Expected library name or BASE= declaration, got '%s'\n", token );
+ return 0;
+ }
+ if (!(token = GetToken(0))) return 0;
+ if (strcmp( token, "=" ))
+ {
+ error( "Expected '=' after BASE, got '%s'\n", token );
+ return 0;
+ }
+ if (!(token = GetToken(0))) return 0;
+ /* FIXME: do something with base address */
+
+ return 1;
+}
+
+
+/*******************************************************************
+ * parse_def_stack_heap_size
+ *
+ * Parse a STACKSIZE or HEAPSIZE declaration in a .def file.
+ */
+static int parse_def_stack_heap_size( int is_stack, DLLSPEC *spec )
+{
+ const char *token = GetToken(0);
+ char *end;
+ unsigned long size;
+
+ if (!token) return 0;
+ size = strtoul( token, &end, 0 );
+ if (*end)
+ {
+ error( "Invalid number '%s'\n", token );
+ return 0;
+ }
+ if (is_stack) spec->stack_size = size / 1024;
+ else spec->heap_size = size / 1024;
+ if (!(token = GetToken(1))) return 1;
+ if (strcmp( token, "," ))
+ {
+ error( "Expected ',' after size, got '%s'\n", token );
+ return 0;
+ }
+ if (!(token = GetToken(0))) return 0;
+ /* FIXME: do something with reserve size */
+ return 1;
+}
+
+
+/*******************************************************************
+ * parse_def_export
+ *
+ * Parse an export declaration in a .def file.
+ */
+static int parse_def_export( char *name, DLLSPEC *spec )
+{
+ int i, args;
+ const char *token = GetToken(1);
+
+ ORDDEF *odp = add_entry_point( spec );
+ memset( odp, 0, sizeof(*odp) );
+
+ odp->lineno = current_line;
+ odp->ordinal = -1;
+ odp->name = name;
+ args = remove_stdcall_decoration( odp->name );
+ if (args == -1) odp->type = TYPE_CDECL;
+ else
+ {
+ odp->type = TYPE_STDCALL;
+ args /= sizeof(int);
+ if (args >= sizeof(odp->u.func.arg_types))
+ {
+ error( "Too many arguments in stdcall function '%s'\n", odp->name );
+ return 0;
+ }
+ for (i = 0; i < args; i++) odp->u.func.arg_types[i] = 'l';
+ }
+
+ /* check for optional internal name */
+
+ if (token && !strcmp( token, "=" ))
+ {
+ if (!(token = GetToken(0))) goto error;
+ odp->link_name = xstrdup( token );
+ remove_stdcall_decoration( odp->link_name );
+ token = GetToken(1);
+ }
+
+ /* check for optional ordinal */
+
+ if (token && token[0] == '@')
+ {
+ int ordinal;
+
+ if (!IsNumberString( token+1 ))
+ {
+ error( "Expected number after '@', got '%s'\n", token+1 );
+ goto error;
+ }
+ ordinal = atoi( token+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 > spec->limit) spec->limit = ordinal;
+ if (ordinal < spec->base) spec->base = ordinal;
+ odp->ordinal = ordinal;
+ token = GetToken(1);
+ }
+
+ /* check for other optional keywords */
+
+ if (token && !strcmp( token, "NONAME" ))
+ {
+ if (odp->ordinal == -1)
+ {
+ error( "NONAME requires an ordinal\n" );
+ goto error;
+ }
+ odp->export_name = odp->name;
+ odp->name = NULL;
+ odp->flags |= FLAG_NONAME;
+ token = GetToken(1);
+ }
+ if (token && !strcmp( token, "PRIVATE" ))
+ {
+ odp->flags |= FLAG_PRIVATE;
+ token = GetToken(1);
+ }
+ if (token && !strcmp( token, "DATA" ))
+ {
+ odp->type = TYPE_EXTERN;
+ token = GetToken(1);
+ }
+ if (token)
+ {
+ error( "Garbage text '%s' found at end of export declaration\n", token );
+ goto error;
+ }
+ return 1;
+
+error:
+ spec->nb_entry_points--;
+ free( odp->name );
+ return 0;
+}
+
+
+/*******************************************************************
+ * parse_def_file
+ *
+ * Parse a .def file.
+ */
+int parse_def_file( FILE *file, DLLSPEC *spec )
+{
+ const char *token;
+ int in_exports = 0;
+
+ input_file = file;
+ current_line = 0;
+
+ comment_chars = ";";
+ separator_chars = ",=";
+
+ while (get_next_line())
+ {
+ if (!(token = GetToken(1))) continue;
+
+ if (!strcmp( token, "LIBRARY" ) || !strcmp( token, "NAME" ))
+ {
+ if (!parse_def_library( spec )) continue;
+ goto end_of_line;
+ }
+ else if (!strcmp( token, "STACKSIZE" ))
+ {
+ if (!parse_def_stack_heap_size( 1, spec )) continue;
+ goto end_of_line;
+ }
+ else if (!strcmp( token, "HEAPSIZE" ))
+ {
+ if (!parse_def_stack_heap_size( 0, spec )) continue;
+ goto end_of_line;
+ }
+ else if (!strcmp( token, "EXPORTS" ))
+ {
+ in_exports = 1;
+ if (!(token = GetToken(1))) continue;
+ }
+ else if (!strcmp( token, "IMPORTS" ))
+ {
+ in_exports = 0;
+ if (!(token = GetToken(1))) continue;
+ }
+ else if (!strcmp( token, "SECTIONS" ))
+ {
+ in_exports = 0;
+ if (!(token = GetToken(1))) continue;
+ }
+
+ if (!in_exports) continue; /* ignore this line */
+ if (!parse_def_export( xstrdup(token), spec )) continue;
+
+ end_of_line:
+ if ((token = GetToken(1))) error( "Syntax error near '%s'\n", token );
+ }
+
+ current_line = 0; /* no longer parsing the input file */
+ assign_names( spec );
+ assign_ordinals( spec );
+ return !nb_errors;
+}
+
+
+/*******************************************************************
* add_debug_channel
*/
static void add_debug_channel( const char *name )
diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c
index 2736ba0..cd7d56a 100644
--- a/tools/winebuild/utils.c
+++ b/tools/winebuild/utils.c
@@ -210,6 +210,83 @@
/*******************************************************************
+ * remove_stdcall_decoration
+ *
+ * Remove a possible @xx suffix from a function name.
+ * Return the numerical value of the suffix, or -1 if none.
+ */
+int remove_stdcall_decoration( char *name )
+{
+ char *p, *end = strrchr( name, '@' );
+ if (!end || !end[1] || end == name) return -1;
+ /* make sure all the rest is digits */
+ for (p = end + 1; *p; p++) if (!isdigit(*p)) return -1;
+ *end = 0;
+ return atoi( end + 1 );
+}
+
+
+/*******************************************************************
+ * alloc_dll_spec
+ *
+ * Create a new dll spec file descriptor
+ */
+DLLSPEC *alloc_dll_spec(void)
+{
+ DLLSPEC *spec;
+
+ spec = xmalloc( sizeof(*spec) );
+ spec->file_name = NULL;
+ spec->dll_name = NULL;
+ spec->owner_name = NULL;
+ spec->init_func = NULL;
+ spec->type = SPEC_WIN32;
+ spec->mode = SPEC_MODE_DLL;
+ spec->base = MAX_ORDINALS;
+ spec->limit = 0;
+ spec->stack_size = 0;
+ spec->heap_size = 0;
+ spec->nb_entry_points = 0;
+ spec->alloc_entry_points = 0;
+ spec->nb_names = 0;
+ spec->nb_resources = 0;
+ spec->entry_points = NULL;
+ spec->names = NULL;
+ spec->ordinals = NULL;
+ spec->resources = NULL;
+ return spec;
+}
+
+
+/*******************************************************************
+ * free_dll_spec
+ *
+ * Free dll spec file descriptor
+ */
+void free_dll_spec( DLLSPEC *spec )
+{
+ int i;
+
+ for (i = 0; i < spec->nb_entry_points; i++)
+ {
+ ORDDEF *odp = &spec->entry_points[i];
+ free( odp->name );
+ free( odp->export_name );
+ free( odp->link_name );
+ }
+ free( spec->file_name );
+ free( spec->dll_name );
+ free( spec->owner_name );
+ free( spec->init_func );
+ free( spec->entry_points );
+ free( spec->names );
+ free( spec->ordinals );
+ free( spec->resources );
+ free( spec );
+}
+
+
+/*******************************************************************
* make_c_identifier
*
* Map a string to a valid C identifier.
diff --git a/tools/winebuild/winebuild.man.in b/tools/winebuild/winebuild.man.in
index d7cb76a..9e68474 100644
--- a/tools/winebuild/winebuild.man.in
+++ b/tools/winebuild/winebuild.man.in
@@ -19,10 +19,11 @@
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.
+.BI \--dll=\ filename
+Build a C file from a .spec file (see \fBSPEC FILE SYNTAX\fR for
+details), or from a standard Windows .def file. 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
@@ -34,7 +35,7 @@
.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,
+the --dll 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
@@ -130,7 +131,7 @@
.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.
+meaningful in \fB--dll\fR mode.
.TP
.BI \-m,\ --mode= mode
Set the executable or dll mode, which can be one of the following: