Raise an exception for unimplemented 16-bit entry points too.
Added check for duplicate names in 16-bit spec files.

diff --git a/dlls/kernel/kernel.spec b/dlls/kernel/kernel.spec
index 3f57447..fad93d7 100644
--- a/dlls/kernel/kernel.spec
+++ b/dlls/kernel/kernel.spec
@@ -422,7 +422,7 @@
 #508 stub WOWFAILEDEXEC # conflict with 507 ! (something broken here ?)
 508 stub WOWCLOSECOMPORT
 #509 stub WOWCLOSECOMPORT # conflict with 508 !
-509 stub WOWKILLREMOTETASK
+#509 stub WOWKILLREMOTETASK
 511 stub WOWKILLREMOTETASK
 512 stub WOWQUERYDEBUG
 513 pascal LoadLibraryEx32W(ptr long long) LoadLibraryEx32W16   # Both NT/95
@@ -482,12 +482,16 @@
 602 pascal16 GetDummyModuleHandleDS() GetDummyModuleHandleDS16
 603 stub KERNEL_603  # OutputDebugString (?)
 604 register CBClientGlueSL() CBClientGlueSL
-605 pascal AllocSLThunkletCallback(long long) AllocSLThunkletCallback16
-606 pascal AllocLSThunkletCallback(segptr long) AllocLSThunkletCallback16
+# FIXME: 605 is duplicate of 562
+605 pascal AllocSLThunkletCallback_dup(long long) AllocSLThunkletCallback16
+# FIXME: 606 is duplicate of 561
+606 pascal AllocLSThunkletCallback_dup(segptr long) AllocLSThunkletCallback16
 607 pascal AllocLSThunkletSysthunk(segptr long long) AllocLSThunkletSysthunk16
 608 pascal AllocSLThunkletSysthunk(long segptr long) AllocSLThunkletSysthunk16
-609 pascal FindLSThunkletCallback(segptr long) FindLSThunkletCallback
-610 pascal FindSLThunkletCallback(long long) FindSLThunkletCallback
+# FIXME: 609 is duplicate of 563
+609 pascal FindLSThunkletCallback_dup(segptr long) FindLSThunkletCallback
+# FIXME: 610 is duplicate of 562
+610 pascal FindSLThunkletCallback_dup(long long) FindSLThunkletCallback
 611 pascal16 FreeThunklet(long long) FreeThunklet16
 612 pascal16 IsSLThunklet(ptr) IsSLThunklet16
 613 stub HugeMapLS
diff --git a/dlls/ole32/compobj.spec b/dlls/ole32/compobj.spec
index ef6e5fc..606f7a6 100644
--- a/dlls/ole32/compobj.spec
+++ b/dlls/ole32/compobj.spec
@@ -169,14 +169,16 @@
 166 stub OPDELETE16
 167 stub ?GETSIZEVALUE@CARRAYFVALUE@@RFCHXZ
 168 stub ?PROXY1632ADDREF@@ZAKPEVCPROXY1632@@@Z
-169 stub REMLOOKUPSHUNK
+# FIXME: 169 is a duplicate of 97
+169 stub REMLOOKUPSHUNK_dup
 170 stub ?ISEMPTY@CMAPKEYTOVALUE@@RFCHXZ
 171 stub ?FREE@CSTDMALLOC@@VEAXPEX@Z
 172 stub CALLTHKMGRINITIALIZE
 173 stub ?REALLOC@CSTDMALLOC@@VEAPEXPEXK@Z
 174 stub ?SM16RHQI@@ZAPEXPEVCSM16RELEASEHANDLER@@AFUGUID@@PEPEX@Z
 175 stub ?PROXY1632METHOD10@@ZAKPEVCPROXY1632@@@Z
-176 stub ___EXPORTEDSTUB
+# FIXME: 176 is a duplicate of 154
+176 stub ___EXPORTEDSTUB_dup
 177 stub ?PROXY1632METHOD20@@ZAKPEVCPROXY1632@@@Z
 178 stub ?PROXY1632METHOD11@@ZAKPEVCPROXY1632@@@Z
 179 stub ?PROXY1632METHOD30@@ZAKPEVCPROXY1632@@@Z
diff --git a/if1632/relay.c b/if1632/relay.c
index f4ecb65..2892091 100644
--- a/if1632/relay.c
+++ b/if1632/relay.c
@@ -263,24 +263,6 @@
 
 
 /***********************************************************************
- *           RELAY_Unimplemented16
- *
- * This function is called for unimplemented 16-bit entry points (declared
- * as 'stub' in the spec file).
- */
-void RELAY_Unimplemented16(void)
-{
-    WORD ordinal;
-    char name[80];
-    STACK16FRAME *frame = CURRENT_STACK16;
-    BUILTIN_GetEntryPoint16( frame, name, &ordinal );
-    MESSAGE("FATAL: No handler for Win16 routine %s (called from %04x:%04x)\n",
-            name, frame->cs, frame->ip );
-    ExitProcess(1);
-}
-
-
-/***********************************************************************
  *           RELAY_DebugCallTo16
  *
  * 'target' contains either the function to call (normal CallTo16)
diff --git a/loader/task.c b/loader/task.c
index e6bafa0..3924fad 100644
--- a/loader/task.c
+++ b/loader/task.c
@@ -409,7 +409,6 @@
     if (!nTaskCount || (nTaskCount == 1 && hFirstTask == initial_task))
     {
         TRACE("this is the last task, exiting\n" );
-        ERR("done\n");
         ExitKernel16();
     }
 
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c
index 60d2045..0f5ae4c 100644
--- a/tools/winebuild/import.c
+++ b/tools/winebuild/import.c
@@ -21,7 +21,8 @@
 };
 
 static char **undef_symbols;  /* list of undefined symbols */
-static int nb_undef_symbols, undef_size;
+static int nb_undef_symbols = -1;
+static int undef_size;
 
 static struct import **dll_imports = NULL;
 static int nb_imports = 0;  /* number of imported dlls */
@@ -223,7 +224,7 @@
     int i, j, off;
     char **p;
 
-    if (!nb_undef_symbols) return 0; /* no symbol file specified */
+    if (nb_undef_symbols == -1) return 0; /* no symbol file specified */
 
     add_extra_undef_symbols();
 
diff --git a/tools/winebuild/parser.c b/tools/winebuild/parser.c
index 19085a4..d4b6d43 100644
--- a/tools/winebuild/parser.c
+++ b/tools/winebuild/parser.c
@@ -15,6 +15,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "winbase.h"
 #include "build.h"
 
 int current_line = 0;
@@ -45,9 +46,6 @@
     "forward"       /* TYPE_FORWARD */
 };
 
-/* callback function used for stub functions */
-#define STUB_CALLBACK \
-  ((SpecType == SPEC_WIN16) ? "RELAY_Unimplemented16": "RELAY_Unimplemented32")
 
 static int IsNumberString(char *s)
 {
@@ -280,7 +278,7 @@
 static void ParseStub( ORDDEF *odp )
 {
     odp->u.func.arg_types[0] = '\0';
-    strcpy( odp->u.func.link_name, STUB_CALLBACK );
+    odp->u.func.link_name[0] = '\0';
 }
 
 
@@ -438,6 +436,40 @@
 }
 
 
+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 );
+            fatal_error( "'%s' redefined (previous definition at line %d)\n",
+                         Names[i]->name, min( Names[i]->lineno, Names[i+1]->lineno ) );
+        }
+    }
+}
+
+
 /*******************************************************************
  *         ParseTopLevel
  *
@@ -543,5 +575,6 @@
         fatal_error( "'owner' not specified for Win16 dll\n" );
 
     current_line = 0;  /* no longer parsing the input file */
+    sort_names();
     return SpecType;
 }
diff --git a/tools/winebuild/spec16.c b/tools/winebuild/spec16.c
index da94cff..a113ecb 100644
--- a/tools/winebuild/spec16.c
+++ b/tools/winebuild/spec16.c
@@ -11,6 +11,7 @@
 #include <assert.h>
 #include <ctype.h>
 
+#include "wine/exception.h"
 #include "builtin16.h"
 #include "module.h"
 #include "neexe.h"
@@ -494,6 +495,58 @@
 
 
 /*******************************************************************
+ *         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" );
+        fprintf( outfile, "  extern void 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] = dllname;\n" );
+        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;
+        strcpy( odp->u.func.link_name, "__stub_" );
+        strcat( odp->u.func.link_name, odp->name );
+        for (p = odp->u.func.link_name; *p; p++) if (!isalnum(*p)) *p = '_';
+        fprintf( outfile, "static void %s(void) { __wine_unimplemented(\"%s\"); }\n",
+                 odp->u.func.link_name, odp->name );
+    }
+}
+
+
+/*******************************************************************
  *         BuildSpec16File
  *
  * Build a Win16 assembly file from a spec file.
@@ -519,6 +572,9 @@
     data_offset = 16;
     strupper( DLLName );
 
+    fprintf( outfile, "static const char dllname[] = \"%s\";\n\n", DLLName );
+    output_stub_funcs( outfile );
+
     /* Build sorted list of all argument types, without duplicates */
 
     typelist = (ORDDEF **)calloc( Limit+1, sizeof(ORDDEF *) );
@@ -615,7 +671,6 @@
                 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 */
@@ -679,24 +734,23 @@
 
             fprintf( outfile, "    /* %s.%d */ ", DLLName, i );
             fprintf( outfile, "{ 0x5566, 0x68, %s, 0xe866, %d  /* %s_%s_%s */ },\n",
-                              odp->u.func.link_name,
-                              (type-typelist)*sizeof(CALLFROM16) - 
-                              (code_offset + sizeof(ENTRYPOINT16)),
-                              (odp->type == TYPE_CDECL) ? "c" : "p",
-                              (odp->type == TYPE_REGISTER) ? "regs" :
-                              (odp->type == TYPE_INTERRUPT) ? "intr" :
-                              (odp->type == TYPE_PASCAL_16) ? "word" : "long",
-                              odp->u.func.arg_types );
-                                 
+                     odp->u.func.link_name,
+                     (type-typelist)*sizeof(CALLFROM16) -
+                     (code_offset + sizeof(ENTRYPOINT16)),
+                     (odp->type == TYPE_CDECL) ? "c" : "p",
+                     (odp->type == TYPE_REGISTER) ? "regs" :
+                     (odp->type == TYPE_INTERRUPT) ? "intr" :
+                     (odp->type == TYPE_PASCAL_16) ? "word" : "long",
+                     odp->u.func.arg_types );
             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" );
diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c
index 1629be6..77ee24c 100644
--- a/tools/winebuild/spec32.c
+++ b/tools/winebuild/spec32.c
@@ -17,13 +17,6 @@
 #include "build.h"
 
 
-static int name_compare( const void *name1, const void *name2 )
-{
-    ORDDEF *odp1 = *(ORDDEF **)name1;
-    ORDDEF *odp2 = *(ORDDEF **)name2;
-    return strcmp( odp1->name, odp2->name );
-}
-
 static int string_compare( const void *ptr1, const void *ptr2 )
 {
     const char * const *str1 = ptr1;
@@ -42,20 +35,6 @@
 
     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 );
-            fatal_error( "'%s' redefined (previous definition at line %d)\n",
-                         Names[i]->name, min( Names[i]->lineno, Names[i+1]->lineno ) );
-        }
-    }
-
     /* 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++)
@@ -318,6 +297,58 @@
 
 
 /*******************************************************************
+ *         output_stub_funcs
+ *
+ * Output the functions for stub entry points
+*/
+static void output_stub_funcs( FILE *outfile )
+{
+    int i;
+    ORDDEF *odp;
+
+    for (i = 0, odp = EntryPoints; i < nb_entry_points; i++, odp++)
+    {
+        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" );
+        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" );
+        fprintf( outfile, "  extern void 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] = dllname;\n" );
+        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, odp = EntryPoints; i < nb_entry_points; i++, odp++)
+    {
+        if (odp->type != TYPE_STUB) continue;
+        if (odp->name[0])
+            fprintf( outfile, "static void __stub_%s(void) { __wine_unimplemented(\"%s\"); }\n",
+                     odp->name, odp->name );
+        else
+            fprintf( outfile, "static void __stub_%d(void) { __wine_unimplemented(\"%d\"); }\n",
+                     odp->ordinal, odp->ordinal );
+    }
+}
+
+
+/*******************************************************************
  *         BuildSpec32File
  *
  * Build a Win32 C file from a spec file.
@@ -356,36 +387,9 @@
 
     fprintf( outfile, "static const char dllname[] = \"%s\";\n\n", DLLName );
 
-    /* Output the stub function if necessary */
+    /* Output the stub functions */
 
-    for (i = 0, odp = EntryPoints; i < nb_entry_points; i++, odp++)
-    {
-        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" );
-        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" );
-        fprintf( outfile, "  extern void 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] = dllname;\n" );
-        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;
-    }
+    output_stub_funcs( outfile );
 
     /* Output the DLL functions prototypes */
 
@@ -410,14 +414,6 @@
             have_regs = TRUE;
             break;
         case TYPE_STUB:
-            if (odp->name[0])
-                fprintf( outfile,
-                         "static void __stub_%s() { __wine_unimplemented(\"%s\"); }\n",
-                         odp->name, odp->name );
-            else
-                fprintf( outfile,
-                         "static void __stub_%d() { __wine_unimplemented(\"%d\"); }\n",
-                         odp->ordinal, odp->ordinal );
             break;
         default:
             fprintf(stderr,"build: function type %d not available for Win32\n",