diff --git a/include/elfdll.h b/include/elfdll.h new file mode 100644 index 00000000000..134b1118f43 --- /dev/null +++ b/include/elfdll.h @@ -0,0 +1,8 @@ +#ifndef __WINE_ELFDLL_H +#define __WINE_ELFDLL_H + +WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR libname, DWORD flags, DWORD *err); +HINSTANCE16 ELFDLL_LoadModule16(LPCSTR libname, BOOL implicit); +void ELFDLL_UnloadLibrary(WINE_MODREF *wm); + +#endif diff --git a/include/loadorder.h b/include/loadorder.h new file mode 100644 index 00000000000..9b8313389a2 --- /dev/null +++ b/include/loadorder.h @@ -0,0 +1,26 @@ +/* + * Module/Library loadorder + * + * Copyright 1999 Bertho Stultiens + */ + +#ifndef __WINE_LOADORDER_H +#define __WINE_LOADORDER_H + +#define MODULE_LOADORDER_INVALID 0 /* Must be 0 */ +#define MODULE_LOADORDER_DLL 1 /* Native DLLs */ +#define MODULE_LOADORDER_ELFDLL 2 /* Elf-dlls */ +#define MODULE_LOADORDER_SO 3 /* Native .so libraries */ +#define MODULE_LOADORDER_BI 4 /* Built-in modules */ +#define MODULE_LOADORDER_NTYPES 4 + +typedef struct module_loadorder { + char *modulename; + char loadorder[MODULE_LOADORDER_NTYPES]; +} module_loadorder_t; + +BOOL MODULE_InitLoadOrder(void); +module_loadorder_t *MODULE_GetLoadOrder(const char *path); + +#endif + diff --git a/loader/elfdll.c b/loader/elfdll.c new file mode 100644 index 00000000000..62b0eac4f91 --- /dev/null +++ b/loader/elfdll.c @@ -0,0 +1,314 @@ +/* + * Elf-dll loader functions + * + * Copyright 1999 Bertho A. Stultiens + */ + +#include +#include + +#include "config.h" +#include "windef.h" +#include "global.h" +#include "process.h" +#include "module.h" +#include "neexe.h" +#include "heap.h" +#include "wine/winbase16.h" +#include "elfdll.h" +#include "debug.h" +#include "winerror.h" + +#if defined(HAVE_LIBDL) && defined(HAVE_DLFCN_H) +#include + +/*------------------ HACKS -----------------*/ +#ifndef elfdll +#define elfdll win32 +#endif + +extern DWORD fixup_imports(WINE_MODREF *wm); +/*---------------- END HACKS ---------------*/ + +struct elfdll_image +{ + HMODULE pe_module_start; + DWORD pe_module_size; + NE_MODULE *ne_module_start; + DWORD ne_module_size; +}; + + +/**************************************************************************** + * get_sobasename (internal) + * + */ +static LPSTR get_sobasename(LPCSTR path, LPSTR name) +{ + char *cptr; + + /* Strip the path from the library name */ + if((cptr = strrchr(path, '/'))) + { + char *cp = strrchr(cptr+1, '\\'); + if(cp && cp > cptr) + cptr = cp+1; + else + cptr++; + } + else + cptr = strrchr(path, '\\'); + + if(!cptr) + cptr = (char *)path; /* No '/' nor '\\' in path */ + else + cptr++; + + strcpy(name, cptr); + cptr = strrchr(name, '.'); + if(cptr) + *cptr = '\0'; /* Strip extension */ + + /* Convert to lower case. + * This must be done manually because it is not sure that + * other modules are accessible. + */ + for(cptr = name; *cptr; cptr++) + *cptr = tolower(*cptr); + + return name; +} + + +/**************************************************************************** + * ELFDLL_CreateModref (internal) + * + * INPUT + * hModule - the header from the elf-dll's data-segment + * path - requested path from original call + * + * OUTPUT + * A WINE_MODREF pointer to the new object + * + * BUGS + * - Does not handle errors due to dependencies correctly + * - path can be wrong + */ +#define RVA(base, va) (((DWORD)base) + ((DWORD)va)) + +static WINE_MODREF *ELFDLL_CreateModref(HMODULE hModule, LPCSTR path) +{ + IMAGE_NT_HEADERS *nt = PE_HEADER(hModule); + IMAGE_DATA_DIRECTORY *dir; + IMAGE_IMPORT_DESCRIPTOR *pe_import = NULL; + WINE_MODREF *wm; + int len; + HANDLE procheap = GetProcessHeap(); + + wm = (WINE_MODREF *)HeapAlloc(procheap, HEAP_ZERO_MEMORY, sizeof(*wm)); + if(!wm) + return NULL; + + wm->module = hModule; + wm->type = MODULE32_PE; /* FIXME */ + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_EXPORT; + if(dir->Size) + wm->binfmt.pe.pe_export = (PIMAGE_EXPORT_DIRECTORY)RVA(hModule, dir->VirtualAddress); + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_IMPORT; + if(dir->Size) + pe_import = wm->binfmt.pe.pe_import = (PIMAGE_IMPORT_DESCRIPTOR)RVA(hModule, dir->VirtualAddress); + + dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_RESOURCE; + if(dir->Size) + wm->binfmt.pe.pe_resource = (PIMAGE_RESOURCE_DIRECTORY)RVA(hModule, dir->VirtualAddress); + + wm->modname = HEAP_strdupA(procheap, 0, (char *)RVA(hModule, wm->binfmt.pe.pe_export->Name)); + + len = GetLongPathNameA(path, NULL, 0); + wm->longname = (char *)HeapAlloc(procheap, 0, len+1); + GetLongPathNameA(path, wm->longname, len+1); + + wm->shortname = HEAP_strdupA(procheap, 0, path); + + /* Link MODREF into process list */ + wm->next = PROCESS_Current()->modref_list; + PROCESS_Current()->modref_list = wm; + + if(!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL)) + { + if(PROCESS_Current()->exe_modref) + FIXME(win32, "overwriting old exe_modref... arrgh\n"); + PROCESS_Current()->exe_modref = wm; + } + + /* Fixup Imports */ + if(pe_import && fixup_imports(wm)) + { + /* Error in this module or its dependencies + * remove entry from modref chain + */ + WINE_MODREF **xwm; + for(xwm = &(PROCESS_Current()->modref_list); *xwm; xwm = &((*xwm)->next)) + { + if ( *xwm == wm ) + { + *xwm = wm->next; + break; + } + } + if(wm == PROCESS_Current()->exe_modref) + ERR(win32, "Have to delete current exe_modref. Expect crash now\n"); + HeapFree(procheap, 0, wm->shortname); + HeapFree(procheap, 0, wm->longname); + HeapFree(procheap, 0, wm->modname); + HeapFree(procheap, 0, wm); + return NULL; + + /* FIXME: We should traverse back in the recursion + * with an error to unload everything that got loaded + * before this error occurred. + * Too dificult for now though and we don't care at the + * moment. But, it *MUST* be implemented someday because + * we won't be able to map the elf-dll twice in this + * address-space which can cause some unexpected and + * weird problems later on. + */ + } + + return wm; +} + + +/*********************************************************************** + * ELFDLL_CreateNEModule + * + * Create a dummy NE module for the win32 elf-dll based on the supplied + * NE header in the elf-dll. + */ +static HMODULE16 ELFDLL_CreateNEModule(NE_MODULE *ne_image, DWORD size) +{ + HMODULE16 hModule = GLOBAL_CreateBlock(GMEM_MOVEABLE, ne_image, size, 0, + FALSE, FALSE, FALSE, NULL); + if(!hModule) + return (HMODULE16)0; + + FarSetOwner16(hModule, hModule); + NE_RegisterModule(ne_image); + return hModule; +} + + +/**************************************************************************** + * ELFDLL_LoadLibraryExA (internal) + * + * Implementation of elf-dll loading for PE modules + */ +WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR path, DWORD flags, DWORD *err) +{ + LPVOID dlhandle; + struct elfdll_image *image; + char name[129]; + char soname[129]; + HMODULE16 hmod16; + WINE_MODREF *wm; + + get_sobasename(path, name); + strcpy(soname, name); + strcat(soname, ".so"); + + /* Try to open the elf-dll. + * The dlopen will search the correct path and our extended + * LD_LIBRARY as well. + */ + dlhandle = dlopen(soname, RTLD_LAZY); + if(!dlhandle) + { + WARN(elfdll, "Could not load %s (%s)\n", soname, dlerror()); + *err = ERROR_FILE_NOT_FOUND; + return NULL; + } + + /* Get the 'dllname_elfdll_image' variable */ + strcpy(soname, name); + strcat(soname, "_elfdll_image"); + image = (struct elfdll_image *)dlsym(dlhandle, soname); + if(!image) + { + ERR(elfdll, "Could not get elfdll image descriptor %s (%s)\n", soname, dlerror()); + dlclose(dlhandle); + *err = ERROR_BAD_FORMAT; + return NULL; + } + + /* Create a win16 dummy module */ + hmod16 = ELFDLL_CreateNEModule(image->ne_module_start, image->ne_module_size); + if(!hmod16) + { + ERR(elfdll, "Could not create win16 dummy module for %s\n", path); + dlclose(dlhandle); + *err = ERROR_OUTOFMEMORY; + return NULL; + } + + image->ne_module_start->module32 = image->pe_module_start; + + wm = ELFDLL_CreateModref(image->pe_module_start, path); + if(!wm) + { + ERR(elfdll, "Could not create WINE_MODREF for %s\n", path); + GLOBAL_FreeBlock((HGLOBAL16)hmod16); + dlclose(dlhandle); + *err = ERROR_OUTOFMEMORY; + return NULL; + } + + *err = 0; + return wm; +} + + +/**************************************************************************** + * ELFDLL_UnloadLibrary (internal) + * + * Unload an elf-dll completely from memory and deallocate the modref + */ +void ELFDLL_UnloadLibrary(WINE_MODREF *wm) +{ +} + + +/**************************************************************************** + * ELFDLL_LoadModule16 (internal) + * + * Implementation of elf-dll loading for NE modules + */ +HINSTANCE16 ELFDLL_LoadModule16(LPCSTR libname, BOOL implicit) +{ + return (HINSTANCE16)ERROR_FILE_NOT_FOUND; +} + +#else + +/* + * No elfdlls possible + * Just put stubs in here. + */ + +WINE_MODREF *ELFDLL_LoadLibraryExA(LPCSTR libname, DWORD flags, DWORD *err) +{ + *err = ERROR_FILE_NOT_FOUND; + return NULL; +} + +void ELFDLL_UnloadLibrary(WINE_MODREF *wm) +{ +} + +HINSTANCE16 ELFDLL_LoadModule16(LPCSTR libname, BOOL implicit) +{ + return (HINSTANCE16)ERROR_FILE_NOT_FOUND; +} + +#endif diff --git a/loader/loadorder.c b/loader/loadorder.c new file mode 100644 index 00000000000..2dbd14dcd53 --- /dev/null +++ b/loader/loadorder.c @@ -0,0 +1,543 @@ +/* + * Module/Library loadorder + * + * Copyright 1999 Bertho Stultiens + */ + +#include +#include +#include + +#include "windef.h" +#include "options.h" +#include "debug.h" +#include "loadorder.h" +#include "heap.h" +#include "options.h" + + +/* #define DEBUG_LOADORDER */ + +#define LOADORDER_ALLOC_CLUSTER 32 /* Allocate with 32 entries at a time */ + +static module_loadorder_t default_loadorder; +static module_loadorder_t *module_loadorder = NULL; +static int nmodule_loadorder = 0; +static int nmodule_loadorder_alloc = 0; + +/*************************************************************************** + * cmp_sort_func (internal, static) + * + * Sorting and comparing function used in sort and search of loadorder + * entries. + */ +static int cmp_sort_func(const void *s1, const void *s2) +{ + return strcasecmp(((module_loadorder_t *)s1)->modulename, ((module_loadorder_t *)s2)->modulename); +} + + +/*************************************************************************** + * get_tok (internal, static) + * + * strtok wrapper for non-destructive buffer writing. + * NOTE: strtok is not reentrant and therefore this code is neither. + */ +static char *get_tok(const char *str, const char *delim) +{ + static char *buf = NULL; + char *cptr; + + if(!str && (!buf || !index)) + return NULL; + + if(str && buf) + { + HeapFree(SystemHeap, 0, buf); + buf = NULL; + } + + if(str && !buf) + { + buf = HEAP_strdupA(SystemHeap, 0, str); + cptr = strtok(buf, delim); + } + else + { + cptr = strtok(NULL, delim); + } + + if(!cptr) + { + HeapFree(SystemHeap, 0, buf); + buf = NULL; + } + return cptr; +} + + +/*************************************************************************** + * ParseLoadOrder (internal, static) + * + * Parses the loadorder options from the configuration and puts it into + * a structure. + */ +static BOOL ParseLoadOrder(char *order, module_loadorder_t *mlo) +{ + char *cptr; + int n = 0; + + memset(mlo->loadorder, 0, sizeof(mlo->loadorder)); + + cptr = get_tok(order, ", \t"); + while(cptr) + { + char type = MODULE_LOADORDER_INVALID; + + if(n >= MODULE_LOADORDER_NTYPES) + { + ERR(module, "More than existing %d module-types specified, rest ignored", MODULE_LOADORDER_NTYPES); + break; + } + + switch(*cptr) + { + case 'N': /* Native */ + case 'n': type = MODULE_LOADORDER_DLL; break; + + case 'E': /* Elfdll */ + case 'e': type = MODULE_LOADORDER_ELFDLL; break; + + case 'S': /* So */ + case 's': type = MODULE_LOADORDER_SO; break; + + case 'B': /* Builtin */ + case 'b': type = MODULE_LOADORDER_BI; break; + + default: + ERR(module, "Invalid load order module-type '%s', ignored\n", cptr); + } + + if(type != MODULE_LOADORDER_INVALID) + { + mlo->loadorder[n++] = type; + } + cptr = get_tok(NULL, ", \t"); + } + return TRUE; +} + + +/*************************************************************************** + * AddLoadOrder (internal, static) + * + * Adds an entry in the list of overrides. If the entry exists then the + * override parameter determines whether it will be overwriten. + */ +static BOOL AddLoadOrder(module_loadorder_t *plo, BOOL override) +{ + int i; + + /* TRACE(module, "'%s' -> %08lx\n", plo->modulename, *(DWORD *)(plo->loadorder)); */ + + for(i = 0; i < nmodule_loadorder; i++) + { + if(!cmp_sort_func(plo, &module_loadorder[i])) + { + if(!override) + ERR(module, "Module '%s' is already in the list of overrides, using first definition\n", plo->modulename); + else + memcpy(module_loadorder[i].loadorder, plo->loadorder, sizeof(plo->loadorder)); + return TRUE; + } + } + + if(nmodule_loadorder >= nmodule_loadorder_alloc) + { + /* No space in current array, make it larger */ + nmodule_loadorder_alloc += LOADORDER_ALLOC_CLUSTER; + module_loadorder = (module_loadorder_t *)HeapReAlloc(SystemHeap, + 0, + module_loadorder, + nmodule_loadorder_alloc * sizeof(module_loadorder_t)); + if(!module_loadorder) + { + MSG("Virtual memory exhausted\n"); + exit(1); + } + } + memcpy(module_loadorder[nmodule_loadorder].loadorder, plo->loadorder, sizeof(plo->loadorder)); + module_loadorder[nmodule_loadorder].modulename = HEAP_strdupA(SystemHeap, 0, plo->modulename); + nmodule_loadorder++; + return TRUE; +} + + +/*************************************************************************** + * AddLoadOrderSet (internal, static) + * + * Adds an set of entries in the list of overrides from the key parameter. + * If the entry exists then the override parameter determines whether it + * will be overwriten. + */ +static BOOL AddLoadOrderSet(char *key, char *order, BOOL override) +{ + module_loadorder_t ldo; + char *cptr; + + /* Parse the loadorder before the rest because strtok is not reentrant */ + if(!ParseLoadOrder(order, &ldo)) + return FALSE; + + cptr = get_tok(key, ", \t"); + while(cptr) + { + if(strchr(cptr, '.')) + MSG("Warning: Loadorder override '%s' contains an extension and might not be found during lookup\n", cptr); + + ldo.modulename = cptr; + if(!AddLoadOrder(&ldo, override)) + return FALSE; + cptr = get_tok(NULL, ", \t"); + } + return TRUE; +} + + +/*************************************************************************** + * ParseCommandlineOverrides (internal, static) + * + * The commandline is in the form: + * name[,name,...]=native[,b,...][:...] + */ +static BOOL ParseCommandlineOverrides(void) +{ + char *cpy; + char *key; + char *next; + char *value; + BOOL retval = TRUE; + + if(!Options.dllFlags) + return TRUE; + + cpy = HEAP_strdupA(SystemHeap, 0, Options.dllFlags); + key = cpy; + next = key; + for(; next; key = next) + { + next = strchr(key, ':'); + if(next) + { + *next = '\0'; + next++; + } + value = strchr(key, '='); + if(!value) + { + retval = FALSE; + goto endit; + } + *value = '\0'; + value++; + + TRACE(module, "Commandline override '%s' = '%s'\n", key, value); + + if(!AddLoadOrderSet(key, value, TRUE)) + { + retval = FALSE; + goto endit; + } + } +endit: + HeapFree(SystemHeap, 0, cpy); + return retval;; +} + + +/*************************************************************************** + * MODULE_InitLoadOrder (internal) + * + * Initialize the load order from the wine.conf file. + * The section has tyhe following format: + * Section: + * [DllDefaults] + * + * Keys: + * EXTRA_LD_LIBRARY_PATH=/usr/local/lib/wine[:/more/path/to/search[:...]] + * The path will be appended to any existing LD_LIBRARY_PATH from the + * environment (see note in code below). + * + * DefaultLoadOrder=native,elfdll,so,builtin + * A comma seperated list of module-types to try to load in that specific + * order. The DefaultLoadOrder key is used as a fallback when a module is + * not specified explicitely. If the DefaultLoadOrder key is not found, + * then the order "dll,elfdll,so,bi" is used + * The possible module-types are: + * - native Native windows dll files + * - elfdll Dlls encapsulated in .so libraries + * - so Native .so libraries mapped to dlls + * - builtin Built-in modules + * + * Case is not important and only the first letter of each type is enough to + * identify the type n[ative], e[lfdll], s[o], b[uiltin]. Also whitespace is + * ignored. + * E.g.: + * n,el ,s , b + * is equal to: + * native,elfdll,so,builtin + * + * Section: + * [DllOverrides] + * + * Keys: + * There are no explicit keys defined other than module/library names. A comma + * separated list of modules is followed by an assignment of the load-order + * for these specific modules. See above for possible types. You should not + * specify an extension. + * Examples: + * kernel32, gdi32, user32 = builtin + * kernel, gdi, user = builtin + * comdlg32 = elfdll, native, builtin + * commdlg = native, builtin + * version, ver = elfdll, native, builtin + * + * Section: + * [DllPairs] + * + * Keys: + * This is a simple pairing in the form 'name1 = name2'. It is supposed to + * identify the dlls that cannot live without eachother unless they are + * loaded in the same format. Examples are common dialogs and controls, + * shell, kernel, gdi, user, etc... + * The code will issue a warning if the loadorder of these pairs are different + * and might cause hard-to-find bugs due to incompatible pairs loaded at + * run-time. Note that this pairing gives *no* guarantee that the pairs + * actually get loaded as the same type, nor that the correct versions are + * loaded (might be implemented later). It merely notes obvious trouble. + * Examples: + * kernel = kernel32 + * commdlg = comdlg32 + * + */ + +#define BUFFERSIZE 1024 + +BOOL MODULE_InitLoadOrder(void) +{ + char buffer[BUFFERSIZE]; + int nbuffer; + + /* Get/set the new LD_LIBRARY_PATH */ + nbuffer = PROFILE_GetWineIniString("DllDefaults", "EXTRA_LD_LIBRARY_PATH", "", buffer, sizeof(buffer)); + + if(nbuffer) + { + extern char *_dl_library_path; + char *ld_lib_path = getenv("LD_LIBRARY_PATH"); + if(ld_lib_path) + { + /* + * Append new path to current + */ + char *tmp = HEAP_strdupA(SystemHeap, 0, buffer); + sprintf(buffer, "%s:%s", ld_lib_path, tmp); + free(tmp); + } + + TRACE(module, "Setting new LD_LIBRARY_PATH=%s\n", buffer); + + setenv("LD_LIBRARY_PATH", buffer, 1); + + /* + * This is a cruel hack required to have libdl check this path. + * The problem is that libdl caches the environment variable + * and we won't get our modifications applied. We ensure the + * the correct search path by explicitely modifying the libdl + * internal variable which holds the path. + */ + _dl_library_path = HEAP_strdupA(SystemHeap, 0, buffer); + } + + /* Get the default load order */ + nbuffer = PROFILE_GetWineIniString("DllDefaults", "DefaultLoadOrder", "n,e,s,b", buffer, sizeof(buffer)); + if(!nbuffer) + { + MSG("MODULE_InitLoadOrder: misteriously read nothing from default loadorder\n"); + return FALSE; + } + + TRACE(module, "Setting default loadorder=%s\n", buffer); + + if(!ParseLoadOrder(buffer, &default_loadorder)) + return FALSE; + default_loadorder.modulename = ""; + + /* Read the explicitely defined orders for specific modules as an entire section */ + nbuffer = PROFILE_GetWineIniString("DllOverrides", NULL, "", buffer, sizeof(buffer)); + if(nbuffer == BUFFERSIZE-2) + { + ERR(module, "BUFFERSIZE %d is too small to read [DllOverrides]. Needs to grow in the source\n", BUFFERSIZE); + return FALSE; + } + if(nbuffer) + { + /* We only have the keys in the buffer, not the values */ + char *key; + char value[BUFFERSIZE]; + char *next; + + for(key = buffer; *key; key = next) + { + next = key + strlen(key) + 1; + + nbuffer = PROFILE_GetWineIniString("DllOverrides", key, "", value, sizeof(value)); + if(!nbuffer) + { + ERR(module, "Module(s) '%s' will always fail to load. Are you sure you want this?\n", key); + value[0] = '\0'; /* Just in case */ + } + if(nbuffer == BUFFERSIZE-2) + { + ERR(module, "BUFFERSIZE %d is too small to read [DllOverrides] key '%s'. Needs to grow in the source\n", BUFFERSIZE, key); + return FALSE; + } + + TRACE(module, "Key '%s' uses override '%s'\n", key, value); + + if(!AddLoadOrderSet(key, value, FALSE)) + return FALSE; + } + } + + /* Add the commandline overrides to the pool */ + if(!ParseCommandlineOverrides()) + { + MSG( "Syntax: -dll name[,name[,...]]={native|elfdll|so|builtin}[,{n|e|s|b}[,...]][:...]\n" + " - 'name' is the name of any dll without extension\n" + " - the order of loading (native, elfdll, so and builtin) can be abbreviated\n" + " with the first letter\n" + " - different loadorders for different dlls can be specified by seperating the\n" + " commandline entries with a ':'\n" + " Example:\n" + " -dll comdlg32,commdlg=n:shell,shell32=b\n" + ); + return FALSE; + } + + /* Sort the array for quick lookup */ + qsort(module_loadorder, nmodule_loadorder, sizeof(module_loadorder[0]), cmp_sort_func); + + /* Check the pairs of dlls */ + nbuffer = PROFILE_GetWineIniString("DllPairs", NULL, "", buffer, sizeof(buffer)); + if(nbuffer == BUFFERSIZE-2) + { + ERR(module, "BUFFERSIZE %d is too small to read [DllPairs]. Needs to grow in the source\n", BUFFERSIZE); + return FALSE; + } + if(nbuffer) + { + /* We only have the keys in the buffer, not the values */ + char *key; + char value[BUFFERSIZE]; + char *next; + + for(key = buffer; *key; key = next) + { + module_loadorder_t *plo1, *plo2; + + next = key + strlen(key) + 1; + + nbuffer = PROFILE_GetWineIniString("DllPairs", key, "", value, sizeof(value)); + if(!nbuffer) + { + ERR(module, "Module pair '%s' is not associated with another module?\n", key); + continue; + } + if(nbuffer == BUFFERSIZE-2) + { + ERR(module, "BUFFERSIZE %d is too small to read [DllPairs] key '%s'. Needs to grow in the source\n", BUFFERSIZE, key); + return FALSE; + } + + plo1 = MODULE_GetLoadOrder(key); + plo2 = MODULE_GetLoadOrder(value); + assert(plo1 && plo2); + + if(memcmp(plo1->loadorder, plo2->loadorder, sizeof(plo1->loadorder))) + MSG("Warning: Modules '%s' and '%s' have different loadorder which may cause trouble\n", key, value); + } + } + + if(TRACE_ON(module)) + { + int i, j; + static char types[6] = "-NESB"; + + for(i = 0; i < nmodule_loadorder; i++) + { + DPRINTF("%3d: %-12s:", i, module_loadorder[i].modulename); + for(j = 0; j < MODULE_LOADORDER_NTYPES; j++) + DPRINTF(" %c", types[module_loadorder[i].loadorder[j] % (MODULE_LOADORDER_NTYPES+1)]); + DPRINTF("\n"); + } + } + + return TRUE; +} + + +/*************************************************************************** + * MODULE_GetLoadOrder (internal) + * + * Locate the loadorder of a module. + * Any path is stripped from the path-argument and so are the extension + * '.dll' and '.exe'. A lookup in the table can yield an override for the + * specific dll. Otherwise the default load order is returned. + */ +module_loadorder_t *MODULE_GetLoadOrder(const char *path) +{ + module_loadorder_t lo, *tmp; + char fname[256]; + char *cptr; + char *name; + int len; + + assert(path != NULL); + + /* Strip path information */ + cptr = strrchr(path, '\\'); + if(!cptr) + name = strrchr(path, '/'); + else + name = strrchr(cptr, '/'); + + if(!name) + name = cptr ? cptr+1 : (char *)path; + else + name++; + + if((cptr = strchr(name, ':')) != NULL) /* Also strip drive if in format 'C:MODULE.DLL' */ + name = cptr+1; + + len = strlen(name); + if(len >= sizeof(fname) || len <= 0) + { + ERR(module, "Path '%s' -> '%s' reduces to zilch or just too large...\n", path, name); + return &default_loadorder; + } + + strcpy(fname, name); + if(len >= 4 && (!lstrcmpiA(fname+len-4, ".dll") || !lstrcmpiA(fname+len-4, ".exe"))) + fname[len-4] = '\0'; + + lo.modulename = fname; + tmp = bsearch(&lo, module_loadorder, nmodule_loadorder, sizeof(module_loadorder[0]), cmp_sort_func); + + TRACE(module, "Looking for '%s' (%s), found '%s'\n", path, fname, tmp ? tmp->modulename : ""); + + if(!tmp) + return &default_loadorder; + return tmp; +} +