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: