Updated built-in metrics for core PostScript fonts.
[wine] / loader / loadorder.c
1 /*
2  * Module/Library loadorder
3  *
4  * Copyright 1999 Bertho Stultiens
5  */
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <assert.h>
10
11 #include "config.h"
12 #include "windef.h"
13 #include "winreg.h"
14 #include "winerror.h"
15 #include "options.h"
16 #include "loadorder.h"
17 #include "heap.h"
18 #include "file.h"
19 #include "module.h"
20 #include "debugtools.h"
21
22 DEFAULT_DEBUG_CHANNEL(module);
23
24 #define LOADORDER_ALLOC_CLUSTER 32      /* Allocate with 32 entries at a time */
25
26 typedef struct module_loadorder
27 {
28     const char         *modulename;
29     enum loadorder_type loadorder[LOADORDER_NTYPES];
30 } module_loadorder_t;
31
32 struct loadorder_list
33 {
34     int                 count;
35     int                 alloc;
36     module_loadorder_t *order;
37 };
38
39 /* default load-order if nothing specified */
40 /* the list must remain sorted by dll name */
41 static module_loadorder_t default_order_list[] =
42 {
43     { "display",      { LOADORDER_BI,  0,             0, 0 } },
44     { "gdi",          { LOADORDER_BI,  0,             0, 0 } },
45     { "gdi32",        { LOADORDER_BI,  0,             0, 0 } },
46     { "glide2x",      { LOADORDER_SO,  LOADORDER_DLL, 0, 0 } },
47     { "glide3x",      { LOADORDER_SO,  LOADORDER_DLL, 0, 0 } },
48     { "icmp",         { LOADORDER_BI,  0,             0, 0 } },
49     { "kernel",       { LOADORDER_BI,  0,             0, 0 } },
50     { "kernel32",     { LOADORDER_BI,  0,             0, 0 } },
51     { "keyboard",     { LOADORDER_BI,  0,             0, 0 } },
52     { "krnl386",      { LOADORDER_BI,  0,             0, 0 } },
53     { "mmsystem",     { LOADORDER_BI,  0,             0, 0 } },
54     { "mouse",        { LOADORDER_BI,  0,             0, 0 } },
55     { "ntdll",        { LOADORDER_BI,  0,             0, 0 } },
56     { "odbc32",       { LOADORDER_BI,  0,             0, 0 } },
57     { "system",       { LOADORDER_BI,  0,             0, 0 } },
58     { "toolhelp",     { LOADORDER_BI,  0,             0, 0 } },
59     { "ttydrv",       { LOADORDER_BI,  0,             0, 0 } },
60     { "user",         { LOADORDER_BI,  0,             0, 0 } },
61     { "user32",       { LOADORDER_BI,  0,             0, 0 } },
62     { "w32skrnl",     { LOADORDER_BI,  0,             0, 0 } },
63     { "winaspi",      { LOADORDER_BI,  0,             0, 0 } },
64     { "windebug",     { LOADORDER_DLL, LOADORDER_BI,  0, 0 } },
65     { "winedos",      { LOADORDER_BI,  0,             0, 0 } },
66     { "wineps",       { LOADORDER_BI,  0,             0, 0 } },
67     { "wing",         { LOADORDER_BI,  0,             0, 0 } },
68     { "winmm",        { LOADORDER_BI,  0,             0, 0 } },
69     { "winsock",      { LOADORDER_BI,  0,             0, 0 } },
70     { "wnaspi32",     { LOADORDER_BI,  0,             0, 0 } },
71     { "wow32",        { LOADORDER_BI,  0,             0, 0 } },
72     { "wprocs",       { LOADORDER_BI,  0,             0, 0 } },
73     { "ws2_32",       { LOADORDER_BI,  0,             0, 0 } },
74     { "wsock32",      { LOADORDER_BI,  0,             0, 0 } },
75     { "x11drv",       { LOADORDER_BI,  0,             0, 0 } }
76 };
77
78 static const struct loadorder_list default_list =
79 {
80     sizeof(default_order_list)/sizeof(default_order_list[0]),
81     sizeof(default_order_list)/sizeof(default_order_list[0]),
82     default_order_list
83 };
84
85 static struct loadorder_list cmdline_list;
86
87
88 /***************************************************************************
89  *      cmp_sort_func   (internal, static)
90  *
91  * Sorting and comparing function used in sort and search of loadorder
92  * entries.
93  */
94 static int cmp_sort_func(const void *s1, const void *s2)
95 {
96     return FILE_strcasecmp(((module_loadorder_t *)s1)->modulename,
97                            ((module_loadorder_t *)s2)->modulename);
98 }
99
100
101 /***************************************************************************
102  *      get_tok (internal, static)
103  *
104  * strtok wrapper for non-destructive buffer writing.
105  * NOTE: strtok is not reentrant and therefore this code is neither.
106  */
107 static char *get_tok(const char *str, const char *delim)
108 {
109         static char *buf = NULL;
110         char *cptr;
111
112         if(!str && !buf)
113                 return NULL;
114
115         if(str && buf)
116         {
117                 HeapFree(GetProcessHeap(), 0, buf);
118                 buf = NULL;
119         }
120
121         if(str && !buf)
122         {
123                 buf = HEAP_strdupA(GetProcessHeap(), 0, str);
124                 cptr = strtok(buf, delim);
125         }
126         else
127         {
128                 cptr = strtok(NULL, delim);
129         }
130
131         if(!cptr)
132         {
133                 HeapFree(GetProcessHeap(), 0, buf);
134                 buf = NULL;
135         }
136         return cptr;
137 }
138
139
140 /***************************************************************************
141  *      ParseLoadOrder  (internal, static)
142  *
143  * Parses the loadorder options from the configuration and puts it into
144  * a structure.
145  */
146 static BOOL ParseLoadOrder(char *order, enum loadorder_type lo[])
147 {
148     static int warn;
149         char *cptr;
150         int n = 0;
151
152         cptr = get_tok(order, ", \t");
153         while(cptr)
154         {
155             enum loadorder_type type = LOADORDER_INVALID;
156
157                 if(n >= LOADORDER_NTYPES-1)
158                 {
159                         ERR("More than existing %d module-types specified, rest ignored\n", LOADORDER_NTYPES-1);
160                         break;
161                 }
162
163                 switch(*cptr)
164                 {
165                 case 'N':       /* Native */
166                 case 'n': type = LOADORDER_DLL; break;
167
168                 case 'E':       /* Elfdll */
169                 case 'e':
170                     if (!warn++) MESSAGE("Load order 'elfdll' no longer supported, ignored\n");
171                     break;
172                 case 'S':       /* So */
173                 case 's': type = LOADORDER_SO; break;
174
175                 case 'B':       /* Builtin */
176                 case 'b': type = LOADORDER_BI; break;
177
178                 default:
179                         ERR("Invalid load order module-type '%s', ignored\n", cptr);
180                 }
181
182                 if(type != LOADORDER_INVALID) lo[n++] = type;
183                 cptr = get_tok(NULL, ", \t");
184         }
185         lo[n] = LOADORDER_INVALID;
186         return TRUE;
187 }
188
189
190 /***************************************************************************
191  *      AddLoadOrder    (internal, static)
192  *
193  * Adds an entry in the list of command-line overrides.
194  */
195 static BOOL AddLoadOrder(module_loadorder_t *plo)
196 {
197         int i;
198
199         /* TRACE(module, "'%s' -> %08lx\n", plo->modulename, *(DWORD *)(plo->loadorder)); */
200
201         for(i = 0; i < cmdline_list.count; i++)
202         {
203             if(!cmp_sort_func(plo, &cmdline_list.order[i] ))
204             {
205                 /* replace existing option */
206                 memcpy( cmdline_list.order[i].loadorder, plo->loadorder, sizeof(plo->loadorder));
207                 return TRUE;
208             }
209         }
210
211         if (i >= cmdline_list.alloc)
212         {
213                 /* No space in current array, make it larger */
214                 cmdline_list.alloc += LOADORDER_ALLOC_CLUSTER;
215                 cmdline_list.order = HeapReAlloc(GetProcessHeap(), 0, cmdline_list.order,
216                                           cmdline_list.alloc * sizeof(module_loadorder_t));
217                 if(!cmdline_list.order)
218                 {
219                         MESSAGE("Virtual memory exhausted\n");
220                         exit(1);
221                 }
222         }
223         memcpy(cmdline_list.order[i].loadorder, plo->loadorder, sizeof(plo->loadorder));
224         cmdline_list.order[i].modulename = HEAP_strdupA(GetProcessHeap(), 0, plo->modulename);
225         cmdline_list.count++;
226         return TRUE;
227 }
228
229
230 /***************************************************************************
231  *      AddLoadOrderSet (internal, static)
232  *
233  * Adds a set of entries in the list of command-line overrides from the key parameter.
234  */
235 static BOOL AddLoadOrderSet(char *key, char *order)
236 {
237         module_loadorder_t ldo;
238         char *cptr;
239
240         /* Parse the loadorder before the rest because strtok is not reentrant */
241         if(!ParseLoadOrder(order, ldo.loadorder))
242                 return FALSE;
243
244         cptr = get_tok(key, ", \t");
245         while(cptr)
246         {
247                 char *ext = strrchr(cptr, '.');
248                 if(ext)
249                 {
250                         if(strlen(ext) == 4 &&
251                            (!FILE_strcasecmp(ext, ".dll") || !FILE_strcasecmp(ext, ".exe")))
252                                 MESSAGE("Warning: Loadorder override '%s' contains an extension and might not be found during lookup\n", cptr);
253                 }
254
255                 ldo.modulename = cptr;
256                 if(!AddLoadOrder(&ldo)) return FALSE;
257                 cptr = get_tok(NULL, ", \t");
258         }
259         return TRUE;
260 }
261
262
263 /***************************************************************************
264  *      MODULE_AddLoadOrderOption
265  *
266  * The commandline option is in the form:
267  * name[,name,...]=native[,b,...]
268  */
269 void MODULE_AddLoadOrderOption( const char *option )
270 {
271     char *key = HEAP_strdupA(GetProcessHeap(), 0, option);
272     char *value = strchr(key, '=');
273
274     if (!value) goto error;
275     *value++ = '\0';
276
277     TRACE("Commandline override '%s' = '%s'\n", key, value);
278
279     if (!AddLoadOrderSet(key, value)) goto error;
280     HeapFree(GetProcessHeap(), 0, key);
281
282     /* sort the array for quick lookup */
283     qsort(cmdline_list.order, cmdline_list.count, sizeof(cmdline_list.order[0]), cmp_sort_func);
284     return;
285
286  error:
287     MESSAGE( "Syntax: -dll name[,name[,...]]={native|so|builtin}[,{n|s|b}[,...]]\n"
288              "    - 'name' is the name of any dll without extension\n"
289              "    - the order of loading (native, so and builtin) can be abbreviated\n"
290              "      with the first letter\n"
291              "    - the option can be specified multiple times\n"
292              "    Example:\n"
293              "    -dll comdlg32,commdlg=n -dll shell,shell32=b\n" );
294     ExitProcess(1);
295 }
296
297
298 /***************************************************************************
299  *      set_registry_keys
300  *
301  * Set individual registry keys for a multiple dll specification
302  * Helper for MODULE_InitLoadOrder().
303  */
304 inline static void set_registry_keys( HKEY hkey, char *module, const char *buffer )
305 {
306     static int warn;
307     char *p = get_tok( module, ", \t" );
308
309     TRACE( "converting \"%s\" = \"%s\"\n", module, buffer );
310
311     if (!warn)
312         MESSAGE( "Warning: setting multiple modules in a single DllOverrides entry is no longer\n"
313                  "recommended. It is suggested that you rewrite the configuration file entry:\n\n"
314                  "\"%s\" = \"%s\"\n\n"
315                  "into something like:\n\n", module, buffer );
316     while (p)
317     {
318         if (!warn) MESSAGE( "\"%s\" = \"%s\"\n", p, buffer );
319         /* only set it if not existing already */
320         if (RegQueryValueExA( hkey, p, 0, NULL, NULL, NULL ) == ERROR_FILE_NOT_FOUND)
321             RegSetValueExA( hkey, p, 0, REG_SZ, buffer, strlen(buffer)+1 );
322         p = get_tok( NULL, ", \t" );
323     }
324     if (!warn) MESSAGE( "\n" );
325     warn = 1;
326 }
327
328
329 /***************************************************************************
330  *      MODULE_InitLoadOrder
331  *
332  * Convert entries containing multiple dll names (old syntax) to the
333  * new one dll module per entry syntax
334  */
335 void MODULE_InitLoadOrder(void)
336 {
337     char module[80];
338     char buffer[1024];
339     char *p;
340     HKEY hkey;
341     DWORD index = 0;
342
343     if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\DllOverrides", &hkey ))
344         return;
345
346     for (;;)
347     {
348         DWORD type, count = sizeof(buffer), name_len = sizeof(module);
349
350         if (RegEnumValueA( hkey, index, module, &name_len, NULL, &type, buffer, &count )) break;
351         p = module;
352         while (isspace(*p)) p++;
353         p += strcspn( p, ", \t" );
354         while (isspace(*p)) p++;
355         if (*p)
356         {
357             RegDeleteValueA( hkey, module );
358             set_registry_keys( hkey, module, buffer );
359         }
360         else index++;
361     }
362     RegCloseKey( hkey );
363 }
364
365
366 /***************************************************************************
367  *      get_list_load_order
368  *
369  * Get the load order for a given module from the command-line or
370  * default lists.
371  */
372 static BOOL get_list_load_order( const char *module, const struct loadorder_list *list,
373                                  enum loadorder_type lo[] )
374 {
375     module_loadorder_t tmp, *res;
376
377     tmp.modulename = module;
378     if ((res = bsearch(&tmp, list->order, list->count, sizeof(list->order[0]), cmp_sort_func)))
379         memcpy( lo, res->loadorder, sizeof(res->loadorder) );
380     return (res != NULL);
381 }
382
383
384 /***************************************************************************
385  *      get_app_load_order
386  *
387  * Get the load order for a given module from the app-specific DllOverrides list.
388  * Also look for default '*' key if no module key found.
389  */
390 static BOOL get_app_load_order( const char *module, enum loadorder_type lo[], BOOL *got_default )
391 {
392     HKEY hkey, appkey;
393     DWORD count, type, res;
394     char buffer[MAX_PATH+16], *appname, *p;
395
396     if (!GetModuleFileName16( GetCurrentTask(), buffer, MAX_PATH ) &&
397         !GetModuleFileNameA( 0, buffer, MAX_PATH ))
398     {
399         WARN( "could not get module file name loading %s\n", module );
400         return FALSE;
401     }
402     appname = buffer;
403     if ((p = strrchr( appname, '/' ))) appname = p + 1;
404     if ((p = strrchr( appname, '\\' ))) appname = p + 1;
405
406     TRACE( "searching '%s' in AppDefaults\\%s\\DllOverrides\n", module, appname );
407
408     if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\AppDefaults", &hkey ))
409         return FALSE;
410
411     /* open AppDefaults\\appname\\DllOverrides key */
412     strcat( appname, "\\DllOverrides" );
413     res = RegOpenKeyA( hkey, appname, &appkey );
414     RegCloseKey( hkey );
415     if (res) return FALSE;
416
417     count = sizeof(buffer);
418     if ((res = RegQueryValueExA( appkey, module, NULL, &type, buffer, &count )))
419     {
420         if (!(res = RegQueryValueExA( appkey, "*", NULL, &type, buffer, &count )))
421             *got_default = TRUE;
422     }
423     else TRACE( "got app loadorder '%s' for '%s'\n", buffer, module );
424     RegCloseKey( appkey );
425     if (res) return FALSE;
426     return ParseLoadOrder( buffer, lo );
427 }
428
429
430 /***************************************************************************
431  *      get_standard_load_order
432  *
433  * Get the load order for a given module from the main DllOverrides list
434  * Also look for default '*' key if no module key found.
435  */
436 static BOOL get_standard_load_order( const char *module, enum loadorder_type lo[],
437                                      BOOL *got_default )
438 {
439     HKEY hkey;
440     DWORD count, type, res;
441     char buffer[80];
442
443     if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\DllOverrides", &hkey ))
444         return FALSE;
445
446     count = sizeof(buffer);
447     if ((res = RegQueryValueExA( hkey, module, NULL, &type, buffer, &count )))
448     {
449         if (!(res = RegQueryValueExA( hkey, "*", NULL, &type, buffer, &count )))
450             *got_default = TRUE;
451     }
452     else TRACE( "got standard loadorder '%s' for '%s'\n", buffer, module );
453     RegCloseKey( hkey );
454     if (res) return FALSE;
455     return ParseLoadOrder( buffer, lo );
456 }
457
458
459 /***************************************************************************
460  *      get_default_load_order
461  *
462  * Get the default load order if nothing specified for a given dll.
463  */
464 static void get_default_load_order( enum loadorder_type lo[] )
465 {
466     DWORD res;
467     static enum loadorder_type default_loadorder[LOADORDER_NTYPES];
468     static int loaded;
469
470     if (!loaded)
471     {
472         char buffer[80];
473         HKEY hkey;
474
475         if (!(res = RegOpenKeyA( HKEY_LOCAL_MACHINE,
476                                  "Software\\Wine\\Wine\\Config\\DllDefaults", &hkey )))
477         {
478             DWORD type, count = sizeof(buffer);
479
480             res = RegQueryValueExA( hkey, "DefaultLoadOrder", NULL, &type, buffer, &count );
481             RegCloseKey( hkey );
482         }
483         if (res) strcpy( buffer, "n,b,s" );
484         ParseLoadOrder( buffer, default_loadorder );
485         loaded = 1;
486         TRACE( "got default loadorder '%s'\n", buffer );
487     }
488     memcpy( lo, default_loadorder, sizeof(default_loadorder) );
489 }
490
491
492 /***************************************************************************
493  *      MODULE_GetLoadOrder     (internal)
494  *
495  * Locate the loadorder of a module.
496  * Any path is stripped from the path-argument and so are the extension
497  * '.dll' and '.exe'. A lookup in the table can yield an override for
498  * the specific dll. Otherwise the default load order is returned.
499  */
500 void MODULE_GetLoadOrder( enum loadorder_type loadorder[], const char *path, BOOL win32 )
501 {
502         char fname[256];
503         char sysdir[MAX_PATH+1];
504         char *cptr;
505         char *name;
506         int len;
507         BOOL got_app_default = FALSE, got_std_default = FALSE;
508         enum loadorder_type lo_default[LOADORDER_NTYPES];
509
510         TRACE("looking for %s\n", path);
511
512         if ( ! GetSystemDirectoryA ( sysdir, MAX_PATH ) ) goto done;
513
514         /* Strip path information for 16 bit modules or if the module 
515            resides in the system directory */
516         if ( !win32 || !FILE_strncasecmp ( sysdir, path, strlen (sysdir) ) )
517         {
518         
519             cptr = strrchr(path, '\\');
520             if(!cptr)
521                 name = strrchr(path, '/');
522             else
523                 name = strrchr(cptr, '/');
524             
525             if(!name)
526                 name = cptr ? cptr+1 : (char *)path;
527             else
528                 name++;
529             
530             if((cptr = strchr(name, ':')) != NULL)      /* Also strip drive if in format 'C:MODULE.DLL' */
531                 name = cptr+1;
532         }
533         else 
534           name = (char *)path;
535     
536         len = strlen(name);
537         if(len >= sizeof(fname) || len <= 0)
538         {
539             WARN("Path '%s' -> '%s' reduces to zilch or just too large...\n", path, name);
540             goto done;
541         }
542
543         strcpy(fname, name);
544         if(len >= 4 && (!FILE_strcasecmp(fname+len-4, ".dll") || !FILE_strcasecmp(fname+len-4, ".exe")))
545                 fname[len-4] = '\0';
546
547         /* check command-line first */
548         if (get_list_load_order( fname, &cmdline_list, loadorder )) return;
549
550         /* then app-specific config */
551         if (get_app_load_order( fname, loadorder, &got_app_default ))
552         {
553             if (!got_app_default) return;
554             /* save the default value for later on */
555             memcpy( lo_default, loadorder, sizeof(lo_default) );
556         }
557
558         /* then standard config */
559         if (get_standard_load_order( fname, loadorder, &got_std_default ))
560         {
561             if (!got_std_default) return;
562             /* save the default value for later on */
563             if (!got_app_default) memcpy( lo_default, loadorder, sizeof(lo_default) );
564         }
565
566         /* then compiled-in defaults */
567         if (get_list_load_order( fname, &default_list, loadorder )) return;
568
569  done:
570         /* last, return the default */
571         if (got_app_default || got_std_default)
572             memcpy( loadorder, lo_default, sizeof(lo_default) );
573         else
574             get_default_load_order( loadorder );
575 }