Added support for path wildcards of the form "*dllname" in load order
specifications.
Only use wildcard entry for dlls that don't specify an explicit path.
Removed the old DllOverrides syntax support.
Misc cleanups and optimizations.

diff --git a/documentation/wine.conf.man b/documentation/wine.conf.man
index 3c515a9..57921f5 100644
--- a/documentation/wine.conf.man
+++ b/documentation/wine.conf.man
@@ -7,7 +7,7 @@
 expects a configuration file (
 .I $WINEPREFIX/config
 (~/.wine/config)
-), which should conform to the following rules. 
+), which should conform to the following rules.
 A sample configuration file is available as
 .I documentation/samples/config
 in the Wine source distribution.
@@ -33,7 +33,7 @@
 .br
 This section is used to specify the root directory and type of each emulated
 .B DOS
-drive, since most Windows applications require a DOS/MS-Windows based 
+drive, since most Windows applications require a DOS/MS-Windows based
 disk drive & directory scheme, which is either provided by a real
 DOS partition mounted somewhere or by some carefully crafted directory layout
 on a Unix file system ("no-windows fake installation").
@@ -43,10 +43,10 @@
 .br
 default: none
 .br
-If you mounted your dos partition as 
+If you mounted your dos partition as
 .I /dos
-and installed Microsoft Windows in 
-C:\\WINDOWS (thus it shows up as /dos/WINDOWS), then you should specify 
+and installed Microsoft Windows in
+C:\\WINDOWS (thus it shows up as /dos/WINDOWS), then you should specify
 .I """Path""=""/dos"""
 in the
 .I [Drive C]
@@ -125,7 +125,7 @@
 .br
 default: "C:\\\\TEMP"
 .br
-Used to specify a directory where Windows applications can store 
+Used to specify a directory where Windows applications can store
 temporary files. E.g. with a C: drive at /home/user/wine_c, this would be
 the /home/user/wine_c/TEMP directory.
 .PP
@@ -178,11 +178,12 @@
 .I format: """modulename""=""native,so,builtin"""
 .br
 .I modulename
-can be any valid DLL module name, without extension. The specified value
-is a comma separated list of module-types to try to load in that
-specific order. Case is not important and only the first letter of
-each type is enough to identify the type n[ative], s[o],
-b[uiltin]. Also whitespace is ignored. See also commandline option
+can be any valid DLL module name. If no extension is specified .dll is
+assumed. The specified value is a comma separated list of module-types
+to try to load in that specific order. Case is not important and only
+the first letter of each type is enough to identify the type n[ative],
+s[o], b[uiltin]. Also whitespace is ignored. See also commandline
+option
 .I --dll
 for details about the allowable types.
 .br
@@ -202,9 +203,24 @@
 .br
 .I """*""=""builtin,native"""
 .br
-Changing the load order of kernel/kernel32 and gdi/gdi32 to
-anything other than builtin will cause wine to fail because wine cannot
-use native versions for these libraries.
+When the specified module name does not contain a path, it matches
+only dlls loaded from the Windows system directory. If the application
+explicitly loads a dll from a different directory, it has to be
+configured separately. This can be done either by specifying the full
+path in the module name, or by using a path wildcard of the form
+.I """*modulename""".
+.br
+For instance, the following will load the native shell32 when loaded
+from C:\\Program Files, and the builtin when loaded from any other
+directory:
+.br
+.I """C:\\\\\\\\Program Files\\\\\\\\shell32"" = ""native"""
+.br
+.I """*shell32"" = ""builtin"""
+.br
+Changing the load order of low-level dlls like kernel32, gdi32 or
+user32 to anything other than builtin will cause wine to fail because
+wine cannot use native versions for these libraries.
 .br
 Always make sure that you have some kind of strategy in mind when you start
 fiddling with the current defaults and needless to say that you must know
@@ -245,7 +261,7 @@
 .I format: """WineLook""=""<Win31|Win95|Win98>"""
 .br
 default: "Win31"
-.br 
+.br
 Use Win95-like window displays or Win3.1-like window displays.
 .PP
 .B [Registry]
@@ -264,7 +280,7 @@
 .PP
 .I format: """LoadWindowsRegistryFiles""=""<boolean>"""
 .br
-Load Windows registry from the current Windows directory. 
+Load Windows registry from the current Windows directory.
 .PP
 booleans: Y/y/T/t/1 are true, N/n/F/f/0 are false.
 .br
@@ -293,8 +309,8 @@
 .br
 The only sections that support application-specific information at the
 moment are
-.I DllOverrides 
-and 
+.I DllOverrides
+and
 .I x11drv.
 .br
 Make sure to use double backslashes in the section name.
@@ -308,7 +324,7 @@
 .I ~/.wine/config
 User-specific configuration file
 .SH ENVIRONMENT VARIABLES
-.TP 
+.TP
 .I WINEPREFIX
 Specifies the directory that contains the per-user
 .I config
diff --git a/include/module.h b/include/module.h
index 44e2df9..bd7da2d 100644
--- a/include/module.h
+++ b/include/module.h
@@ -265,7 +265,6 @@
 extern DWORD PE_fixup_imports(WINE_MODREF *wm);
 
 /* loader/loadorder.c */
-extern void MODULE_InitLoadOrder(void);
 extern void MODULE_GetLoadOrder( enum loadorder_type plo[], const char *path, BOOL win32 );
 extern void MODULE_AddLoadOrderOption( const char *option );
 
diff --git a/loader/loadorder.c b/loader/loadorder.c
index 6b35877..054d419 100644
--- a/loader/loadorder.c
+++ b/loader/loadorder.c
@@ -94,6 +94,12 @@
     default_order_list
 };
 
+/* default if nothing else specified */
+static const enum loadorder_type default_loadorder[LOADORDER_NTYPES] =
+{
+    LOADORDER_DLL, LOADORDER_BI, 0, 0
+};
+
 static struct loadorder_list cmdline_list;
 
 
@@ -151,6 +157,49 @@
 
 
 /***************************************************************************
+ *	get_basename
+ *
+ * Return the base name of a file name (i.e. remove the path components).
+ */
+static const char *get_basename( const char *name )
+{
+    const char *ptr;
+
+    if (name[0] && name[1] == ':') name += 2;  /* strip drive specification */
+    if ((ptr = strrchr( name, '\\' ))) name = ptr + 1;
+    if ((ptr = strrchr( name, '/' ))) name = ptr + 1;
+    return name;
+}
+
+
+/***************************************************************************
+ *	debugstr_loadorder
+ *
+ * Return a loadorder in printable form.
+ */
+static const char *debugstr_loadorder( enum loadorder_type lo[] )
+{
+    int i;
+    char buffer[LOADORDER_NTYPES*3+1];
+
+    buffer[0] = 0;
+    for(i = 0; i < LOADORDER_NTYPES; i++)
+    {
+        if (lo[i] == LOADORDER_INVALID) break;
+        switch(lo[i])
+        {
+        case LOADORDER_DLL: strcat( buffer, "n," ); break;
+        case LOADORDER_SO:  strcat( buffer, "s," ); break;
+        case LOADORDER_BI:  strcat( buffer, "b," ); break;
+        default:            strcat( buffer, "?," ); break;
+        }
+    }
+    if (buffer[0]) buffer[strlen(buffer)-1] = 0;
+    return debugstr_a(buffer);
+}
+
+
+/***************************************************************************
  *	ParseLoadOrder	(internal, static)
  *
  * Parses the loadorder options from the configuration and puts it into
@@ -304,74 +353,6 @@
 
 
 /***************************************************************************
- *	set_registry_keys
- *
- * Set individual registry keys for a multiple dll specification
- * Helper for MODULE_InitLoadOrder().
- */
-inline static void set_registry_keys( HKEY hkey, char *module, const char *buffer )
-{
-    static int warn;
-    char *p = get_tok( module, ", \t" );
-
-    TRACE( "converting \"%s\" = \"%s\"\n", module, buffer );
-
-    if (!warn)
-        MESSAGE( "Warning: setting multiple modules in a single DllOverrides entry is no longer\n"
-                 "recommended. It is suggested that you rewrite the configuration file entry:\n\n"
-                 "\"%s\" = \"%s\"\n\n"
-                 "into something like:\n\n", module, buffer );
-    while (p)
-    {
-        if (!warn) MESSAGE( "\"%s\" = \"%s\"\n", p, buffer );
-        /* only set it if not existing already */
-        if (RegQueryValueExA( hkey, p, 0, NULL, NULL, NULL ) == ERROR_FILE_NOT_FOUND)
-            RegSetValueExA( hkey, p, 0, REG_SZ, buffer, strlen(buffer)+1 );
-        p = get_tok( NULL, ", \t" );
-    }
-    if (!warn) MESSAGE( "\n" );
-    warn = 1;
-}
-
-
-/***************************************************************************
- *	MODULE_InitLoadOrder
- *
- * Convert entries containing multiple dll names (old syntax) to the
- * new one dll module per entry syntax
- */
-void MODULE_InitLoadOrder(void)
-{
-    char module[80];
-    char buffer[1024];
-    char *p;
-    HKEY hkey;
-    DWORD index = 0;
-
-    if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\DllOverrides", &hkey ))
-        return;
-
-    for (;;)
-    {
-        DWORD type, count = sizeof(buffer), name_len = sizeof(module);
-
-        if (RegEnumValueA( hkey, index, module, &name_len, NULL, &type, buffer, &count )) break;
-        p = module;
-        while (isspace(*p)) p++;
-        p += strcspn( p, ", \t" );
-        while (isspace(*p)) p++;
-        if (*p)
-        {
-            RegDeleteValueA( hkey, module );
-            set_registry_keys( hkey, module, buffer );
-        }
-        else index++;
-    }
-    RegCloseKey( hkey );
-}
-
-
-/***************************************************************************
  *	get_list_load_order
  *
  * Get the load order for a given module from the command-line or
@@ -391,114 +372,53 @@
 
 
 /***************************************************************************
- *	get_app_load_order
+ *	open_app_key
  *
- * Get the load order for a given module from the app-specific DllOverrides list.
- * Also look for default '*' key if no module key found.
+ * Open the registry key to the app-specific DllOverrides list.
  */
-static BOOL get_app_load_order( const char *module, enum loadorder_type lo[], BOOL *got_default )
+static HKEY open_app_key( const char *module )
 {
     HKEY hkey, appkey;
-    DWORD count, type, res;
-    char buffer[MAX_PATH+16], *appname, *p;
+    char buffer[MAX_PATH+16], *appname;
 
     if (!GetModuleFileName16( GetCurrentTask(), buffer, MAX_PATH ) &&
         !GetModuleFileNameA( 0, buffer, MAX_PATH ))
     {
         WARN( "could not get module file name loading %s\n", module );
-        return FALSE;
+        return 0;
     }
-    appname = buffer;
-    if ((p = strrchr( appname, '/' ))) appname = p + 1;
-    if ((p = strrchr( appname, '\\' ))) appname = p + 1;
+    appname = (char *)get_basename( buffer );
 
     TRACE( "searching '%s' in AppDefaults\\%s\\DllOverrides\n", module, appname );
 
     if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\AppDefaults", &hkey ))
-        return FALSE;
+        return 0;
 
     /* open AppDefaults\\appname\\DllOverrides key */
     strcat( appname, "\\DllOverrides" );
-    res = RegOpenKeyA( hkey, appname, &appkey );
+    if (RegOpenKeyA( hkey, appname, &appkey )) appkey = 0;
     RegCloseKey( hkey );
-    if (res) return FALSE;
-
-    count = sizeof(buffer);
-    if ((res = RegQueryValueExA( appkey, module, NULL, &type, buffer, &count )))
-    {
-        if (!(res = RegQueryValueExA( appkey, "*", NULL, &type, buffer, &count )))
-            *got_default = TRUE;
-    }
-    else TRACE( "got app loadorder '%s' for '%s'\n", buffer, module );
-    RegCloseKey( appkey );
-    if (res) return FALSE;
-    return ParseLoadOrder( buffer, lo );
+    return appkey;
 }
 
 
 /***************************************************************************
- *	get_standard_load_order
+ *	get_registry_value
  *
- * Get the load order for a given module from the main DllOverrides list
- * Also look for default '*' key if no module key found.
+ * Load the registry loadorder value for a given module.
  */
-static BOOL get_standard_load_order( const char *module, enum loadorder_type lo[],
-                                     BOOL *got_default )
+static BOOL get_registry_value( HKEY hkey, const char *module, enum loadorder_type lo[] )
 {
-    HKEY hkey;
-    DWORD count, type, res;
     char buffer[80];
-
-    if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\DllOverrides", &hkey ))
-        return FALSE;
+    DWORD count, type;
 
     count = sizeof(buffer);
-    if ((res = RegQueryValueExA( hkey, module, NULL, &type, buffer, &count )))
-    {
-        if (!(res = RegQueryValueExA( hkey, "*", NULL, &type, buffer, &count )))
-            *got_default = TRUE;
-    }
-    else TRACE( "got standard loadorder '%s' for '%s'\n", buffer, module );
-    RegCloseKey( hkey );
-    if (res) return FALSE;
+    if (RegQueryValueExA( hkey, module, NULL, &type, buffer, &count )) return FALSE;
     return ParseLoadOrder( buffer, lo );
 }
 
 
 /***************************************************************************
- *	get_default_load_order
- *
- * Get the default load order if nothing specified for a given dll.
- */
-static void get_default_load_order( enum loadorder_type lo[] )
-{
-    DWORD res;
-    static enum loadorder_type default_loadorder[LOADORDER_NTYPES];
-    static int loaded;
-
-    if (!loaded)
-    {
-        char buffer[80];
-        HKEY hkey;
-
-        if (!(res = RegOpenKeyA( HKEY_LOCAL_MACHINE,
-                                 "Software\\Wine\\Wine\\Config\\DllDefaults", &hkey )))
-        {
-            DWORD type, count = sizeof(buffer);
-
-            res = RegQueryValueExA( hkey, "DefaultLoadOrder", NULL, &type, buffer, &count );
-            RegCloseKey( hkey );
-        }
-        if (res) strcpy( buffer, "n,b,s" );
-        ParseLoadOrder( buffer, default_loadorder );
-        loaded = 1;
-        TRACE( "got default loadorder '%s'\n", buffer );
-    }
-    memcpy( lo, default_loadorder, sizeof(default_loadorder) );
-}
-
-
-/***************************************************************************
  *	MODULE_GetLoadOrder	(internal)
  *
  * Locate the loadorder of a module.
@@ -508,76 +428,119 @@
  */
 void MODULE_GetLoadOrder( enum loadorder_type loadorder[], const char *path, BOOL win32 )
 {
-	char fname[256];
-	char sysdir[MAX_PATH+1];
-	char *cptr;
-	char *name;
-	int len;
-        BOOL got_app_default = FALSE, got_std_default = FALSE;
-        enum loadorder_type lo_default[LOADORDER_NTYPES];
+    static HKEY std_key = (HKEY)-1;  /* key to standard section, cached */
+    HKEY app_key = 0;
+    char *module, *basename;
+    int len;
 
-	TRACE("looking for %s\n", path);
+    TRACE("looking for %s\n", path);
 
-        if ( ! GetSystemDirectoryA ( sysdir, MAX_PATH ) ) goto done;
+    loadorder[0] = LOADORDER_INVALID;  /* in case something bad happens below */
 
-	/* Strip path information for 16 bit modules or if the module
-	   resides in the system directory */
-	if ( !win32 || !FILE_strncasecmp ( sysdir, path, strlen (sysdir) ) )
-	{
+    /* Strip path information for 16 bit modules or if the module
+     * resides in the system directory */
+    if (!win32) path = get_basename( path );
+    else
+    {
+        char sysdir[MAX_PATH+1];
+        if (!GetSystemDirectoryA( sysdir, MAX_PATH )) return;
+        if (!FILE_strncasecmp( sysdir, path, strlen (sysdir) ))
+        {
+            path += strlen(sysdir);
+            while (*path == '\\' || *path == '/') path++;
+        }
+    }
 
-	    cptr = strrchr(path, '\\');
-	    if(!cptr)
-	        name = strrchr(path, '/');
-	    else
-	        name = strrchr(cptr, '/');
+    if (!(len = strlen(path))) return;
+    if (!(module = HeapAlloc( GetProcessHeap(), 0, len + 2 ))) return;
+    strcpy( module+1, path );  /* reserve module[0] for the wildcard char */
 
-	    if(!name)
-	        name = cptr ? cptr+1 : (char *)path;
-	    else
-	        name++;
+    if (len >= 4)
+    {
+        char *ext = module + 1 + len - 4;
+        if (!FILE_strcasecmp( ext, ".dll" )) *ext = 0;
+    }
 
-	    if((cptr = strchr(name, ':')) != NULL)	/* Also strip drive if in format 'C:MODULE.DLL' */
-	        name = cptr+1;
-	}
-	else
-	  name = (char *)path;
+    /* check command-line first */
+    if (get_list_load_order( module+1, &cmdline_list, loadorder ))
+    {
+        TRACE( "got cmdline %s for %s\n",
+               debugstr_loadorder(loadorder), debugstr_a(path) );
+        goto done;
+    }
 
-	len = strlen(name);
-	if(len >= sizeof(fname) || len <= 0)
-	{
-            WARN("Path '%s' -> '%s' reduces to zilch or just too large...\n", path, name);
+    /* then explicit module name in AppDefaults */
+    app_key = open_app_key( module+1 );
+    if (app_key && get_registry_value( app_key, module+1, loadorder ))
+    {
+        TRACE( "got app defaults %s for %s\n",
+               debugstr_loadorder(loadorder), debugstr_a(path) );
+        goto done;
+    }
+
+    /* then explicit module name in standard section */
+    if (std_key == (HKEY)-1)
+        RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\DllOverrides", &std_key );
+
+    if (std_key && get_registry_value( std_key, module+1, loadorder ))
+    {
+        TRACE( "got standard entry %s for %s\n",
+               debugstr_loadorder(loadorder), debugstr_a(path) );
+        goto done;
+    }
+
+    /* then module basename preceded by '*' in AppDefaults */
+    basename = (char *)get_basename( module+1 );
+    basename[-1] = '*';
+    if (app_key && get_registry_value( app_key, basename-1, loadorder ))
+    {
+        TRACE( "got app defaults basename %s for %s\n",
+               debugstr_loadorder(loadorder), debugstr_a(path) );
+        goto done;
+    }
+
+    /* then module name preceded by '*' in standard section */
+    if (std_key && get_registry_value( std_key, basename-1, loadorder ))
+    {
+        TRACE( "got standard base name %s for %s\n",
+               debugstr_loadorder(loadorder), debugstr_a(path) );
+        goto done;
+    }
+
+    /* then base name matching compiled-in defaults */
+    if (get_list_load_order( basename, &default_list, loadorder ))
+    {
+        TRACE( "got compiled-in default %s for %s\n",
+               debugstr_loadorder(loadorder), debugstr_a(path) );
+        goto done;
+    }
+
+    if (basename == module+1)
+    {
+        /* then wildcard entry in AppDefaults (only if no explicit path) */
+        if (app_key && get_registry_value( app_key, "*", loadorder ))
+        {
+            TRACE( "got app defaults wildcard %s for %s\n",
+                   debugstr_loadorder(loadorder), debugstr_a(path) );
             goto done;
-	}
-
-	strcpy(fname, name);
-	if(len >= 4 && !FILE_strcasecmp(fname+len-4, ".dll")) fname[len-4] = '\0';
-
-        /* check command-line first */
-        if (get_list_load_order( fname, &cmdline_list, loadorder )) return;
-
-        /* then app-specific config */
-        if (get_app_load_order( fname, loadorder, &got_app_default ))
-        {
-            if (!got_app_default) return;
-            /* save the default value for later on */
-            memcpy( lo_default, loadorder, sizeof(lo_default) );
         }
 
-        /* then standard config */
-        if (get_standard_load_order( fname, loadorder, &got_std_default ))
+        /* then wildcard entry in standard section (only if no explicit path) */
+        if (std_key && get_registry_value( std_key, "*", loadorder ))
         {
-            if (!got_std_default) return;
-            /* save the default value for later on */
-            if (!got_app_default) memcpy( lo_default, loadorder, sizeof(lo_default) );
+            TRACE( "got standard wildcard %s for %s\n",
+                   debugstr_loadorder(loadorder), debugstr_a(path) );
+            goto done;
         }
+    }
 
-        /* then compiled-in defaults */
-        if (get_list_load_order( fname, &default_list, loadorder )) return;
+    /* and last the hard-coded default */
+    memcpy( loadorder, default_loadorder, sizeof(default_loadorder) );
+    TRACE( "got hardcoded default %s for %s\n",
+           debugstr_loadorder(loadorder), debugstr_a(path) );
+
 
  done:
-        /* last, return the default */
-        if (got_app_default || got_std_default)
-            memcpy( loadorder, lo_default, sizeof(lo_default) );
-        else
-            get_default_load_order( loadorder );
+    if (app_key) RegCloseKey( app_key );
+    HeapFree( GetProcessHeap(), 0, module );
 }
diff --git a/loader/main.c b/loader/main.c
index 95531be..b54271f 100644
--- a/loader/main.c
+++ b/loader/main.c
@@ -34,7 +34,6 @@
 #include "drive.h"
 #include "file.h"
 #include "options.h"
-#include "module.h"
 #include "wine/debug.h"
 #include "wine/server.h"
 
@@ -75,9 +74,6 @@
     /* Registry initialisation */
     SHELL_LoadRegistry();
 
-    /* Initialize module loadorder */
-    if (CLIENT_IsBootThread()) MODULE_InitLoadOrder();
-
     /* Global boot finished, the rest is process-local */
     CLIENT_BootDone( TRACE_ON(server) );
 
diff --git a/loader/module.c b/loader/module.c
index 52e4f7e..f3a9a64 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -1425,6 +1425,10 @@
 			MODULE_modref_list = wm->next;
 
                 TRACE(" unloading %s\n", wm->filename);
+                if (!TRACE_ON(module))
+                    TRACE_(loaddll)("Unloaded module '%s' : %s\n", wm->filename,
+                                    wm->dlhandle ? "builtin" : "native" );
+
                 if (wm->dlhandle) wine_dll_unload( wm->dlhandle );
                 else UnmapViewOfFile( (LPVOID)wm->module );
                 FreeLibrary16(wm->hDummyMod);