home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / linking / prlink.c < prev   
Encoding:
C/C++ Source or Header  |  1998-04-08  |  23.4 KB  |  955 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "primpl.h"
  20.  
  21. #include <string.h>
  22.  
  23. #ifdef XP_MAC
  24. #include <CodeFragments.h>
  25. #include <TextUtils.h>
  26. #include <Types.h>
  27. #include <Strings.h>
  28. #endif
  29.  
  30. #ifdef XP_UNIX
  31. #ifdef USE_DLFCN
  32. #include <dlfcn.h>
  33. #elif defined(USE_HPSHL)
  34. #include <dl.h>
  35. #endif
  36.  
  37. /* Define this on systems which don't have it (AIX) */
  38. #ifndef RTLD_LAZY
  39. #define RTLD_LAZY RTLD_NOW
  40. #endif
  41. #endif /* XP_UNIX */
  42.  
  43. #ifdef XP_PC
  44. typedef PRStaticLinkTable *NODL_PROC(void);
  45. #endif
  46.  
  47. /************************************************************************/
  48.  
  49. struct PRLibrary {
  50.     char*            name;  /* Our own copy of the name string */
  51.     PRLibrary*            next;
  52.     int                refCount;
  53.     const PRStaticLinkTable*    staticTable;
  54.  
  55. #ifdef XP_PC
  56.     HINSTANCE            dlh;
  57. #endif
  58. #ifdef XP_MAC
  59.     CFragConnectionID        dlh;
  60. #endif
  61.  
  62. #ifdef XP_UNIX
  63. #if defined(USE_HPSHL)
  64.     shl_t            dlh;
  65. #else
  66.     void*            dlh;
  67. #endif 
  68. #endif 
  69. };
  70.  
  71. static PRLibrary *pr_loadmap;
  72. static PRLibrary *pr_exe_loadmap;
  73. static PRMonitor *pr_linker_lock;
  74. static char* _pr_currentLibPath = NULL;
  75.  
  76. /************************************************************************/
  77.  
  78. #if ( !defined(USE_DLFCN) && !defined(HAVE_STRERROR) ) || defined(HPUX) || defined(BSDI) || defined(LINUX)
  79. static char* errStrBuf = NULL;
  80. #define ERR_STR_BUF_LENGTH    20
  81. static char* errno_string(PRIntn oserr)
  82. {
  83.     if (errStrBuf == NULL)
  84.         errStrBuf = PR_MALLOC(ERR_STR_BUF_LENGTH);
  85.     PR_snprintf(errStrBuf, ERR_STR_BUF_LENGTH, "error %ld", oserr);
  86.     return errStrBuf;
  87. }
  88. #endif
  89.  
  90. static void DLLErrorInternal(PRIntn oserr)
  91. /*
  92. ** This whole function, and most of the code in this file, are run
  93. ** with a big hairy lock wrapped around it. Not the best of situations,
  94. ** but will eventually come up with the right answer.
  95. */
  96. {
  97.     const char *error = NULL;
  98. #ifdef HAVE_DLL
  99. #    ifdef USE_DLFCN
  100.         error = dlerror();  /* $$$ That'll be wrong some of the time - AOF */
  101. #    elif defined(USE_HPSHL)
  102. #        ifdef HAVE_STRERROR
  103.             error = strerror(oserr);  /* This should be okay */
  104. #        else
  105.             error = errno_string(oserr);
  106. #        endif /* HAVE_STRERROR */
  107. #    else
  108.         error = errno_string(oserr);
  109. #    endif
  110. #else
  111.     error = errno_string(oserr);
  112. #endif /* HAVE_DLL */
  113.     if (NULL != error)
  114.         PR_SetErrorText(strlen(error), error);
  115. }  /* DLLErrorInternal */
  116.  
  117. void _PR_InitLinker(void)
  118. {
  119. #ifndef XP_MAC
  120.     PRLibrary *lm;
  121. #endif
  122. #if defined(XP_UNIX)
  123.     void *h;
  124. #endif
  125.  
  126.     if (!pr_linker_lock) {
  127.         pr_linker_lock = PR_NewNamedMonitor("linker-lock");
  128.     }
  129.     PR_EnterMonitor(pr_linker_lock);
  130.  
  131. #if defined(XP_PC)
  132.     lm = PR_NEWZAP(PRLibrary);
  133.     lm->name = strdup("Executable");
  134.         /* 
  135.         ** In WIN32, GetProcAddress(...) expects a module handle in order to
  136.         ** get exported symbols from the executable...
  137.         **
  138.         ** However, in WIN16 this is accomplished by passing NULL to 
  139.         ** GetProcAddress(...)
  140.         */
  141. #if defined(_WIN32)
  142.         lm->dlh = GetModuleHandle(NULL);
  143. #else
  144.         lm->dlh = (HINSTANCE)NULL;
  145. #endif /* ! _WIN32 */
  146.  
  147.     lm->refCount    = 1;
  148.     lm->staticTable = NULL;
  149.     pr_exe_loadmap  = lm;
  150.     pr_loadmap      = lm;
  151.  
  152. #elif defined(XP_UNIX)
  153. #ifdef HAVE_DLL
  154. #ifdef USE_DLFCN
  155.     h = dlopen(0, RTLD_LAZY);
  156.     if (!h) {
  157.         char *error;
  158.         
  159.         DLLErrorInternal(_MD_ERRNO());
  160.         error = (char*)PR_MALLOC(PR_GetErrorTextLength());
  161.         (void) PR_GetErrorText(error);
  162.         fprintf(stderr, "failed to initialize shared libraries [%s]\n",
  163.             error);
  164.         PR_DELETE(error);
  165.         abort();/* XXX */
  166.     }
  167. #elif defined(USE_HPSHL)
  168.     h = NULL;
  169.     /* don't abort with this NULL */
  170. #else
  171. #error no dll strategy
  172. #endif /* USE_DLFCN */
  173.  
  174.     lm = PR_NEWZAP(PRLibrary);
  175.     if (lm) {
  176.         lm->name = strdup("a.out");
  177.         lm->refCount = 1;
  178.         lm->dlh = h;
  179.         lm->staticTable = NULL;
  180.     }
  181.     pr_exe_loadmap = lm;
  182.     pr_loadmap = lm;
  183. #endif /* HAVE_DLL */
  184. #endif /* XP_UNIX */
  185.  
  186. #ifndef XP_MAC
  187.     PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (init)", lm?lm->name:"NULL"));
  188. #endif
  189.  
  190.     PR_ExitMonitor(pr_linker_lock);
  191. }
  192.  
  193. #if defined(WIN16)
  194. void _PR_ShutdownLinker(void)
  195. {
  196.     PR_EnterMonitor(pr_linker_lock);
  197.  
  198.     while (pr_loadmap) {
  199.     if (pr_loadmap->refCount > 1) {
  200. #ifdef DEBUG
  201.         fprintf(stderr, "# Forcing library to unload: %s (%d outstanding references)\n",
  202.             pr_loadmap->name, pr_loadmap->refCount);
  203. #endif
  204.         pr_loadmap->refCount = 1;
  205.     }
  206.     PR_UnloadLibrary(pr_loadmap);
  207.     }
  208.     
  209.     PR_ExitMonitor(pr_linker_lock);
  210.  
  211.     PR_DestroyMonitor(pr_linker_lock);
  212.     pr_linker_lock = NULL;
  213. }
  214. #endif
  215.  
  216. /******************************************************************************/
  217.  
  218. PR_IMPLEMENT(PRStatus) PR_SetLibraryPath(const char *path)
  219. {
  220.     PRStatus rv = PR_SUCCESS;
  221.  
  222.     PR_EnterMonitor(pr_linker_lock);
  223.     PR_FREEIF(_pr_currentLibPath);
  224.     if (path) {
  225.         _pr_currentLibPath = strdup(path);
  226.         if (!_pr_currentLibPath) {
  227.             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  228.         rv = PR_FAILURE;
  229.         }
  230.     } else {
  231.         _pr_currentLibPath = 0;
  232.     }
  233.     PR_ExitMonitor(pr_linker_lock);
  234.     return rv;
  235. }
  236.  
  237. /*
  238. ** Return the library path for finding shared libraries.
  239. */
  240. PR_IMPLEMENT(char *) 
  241. PR_GetLibraryPath()
  242. {
  243.     char *ev;
  244.     char *copy = NULL;  /* a copy of _pr_currentLibPath */
  245.  
  246.     PR_EnterMonitor(pr_linker_lock);
  247.     if (_pr_currentLibPath != NULL) {
  248.         goto exit;
  249.     }
  250.  
  251.     /* initialize pr_currentLibPath */
  252.  
  253. #ifdef XP_PC
  254.     ev = getenv("LD_LIBRARY_PATH");
  255.     if (!ev) {
  256.     ev = ".;\\lib";
  257.     }
  258.     ev = strdup(ev);
  259. #endif
  260.  
  261. #ifdef XP_MAC
  262.     {
  263.     char *p;
  264.     int len;
  265.  
  266.     ev = getenv("LD_LIBRARY_PATH");
  267.     
  268.     /* if we couldn't find something make up a default */
  269.     if (!ev)
  270.         ev = "/usr/local/netscape;/usr/local/netscape/java/bin"; /* do we put the classes in here too? */
  271.     
  272.     len = strlen(ev) + 1;        /* +1 for the null */
  273.     p = (char*) PR_MALLOC(len);
  274.     if (p) {
  275.         strcpy(p, ev);
  276.     }
  277.     ev = p;
  278.     }
  279. #endif
  280.  
  281. #ifdef XP_UNIX
  282. #if defined USE_DLFCN
  283.     {
  284.     char *home;
  285.     char *local;
  286.     char *p;
  287.     int len;
  288.  
  289.     ev = getenv("LD_LIBRARY_PATH");
  290.     if (!ev) {
  291.         ev = "/usr/lib:/lib";
  292.     }
  293.     home = getenv("HOME");
  294.  
  295.     /*
  296.     ** Augment the path automatically by adding in ~/.netscape and
  297.     ** /usr/local/netscape
  298.     */
  299.     len = strlen(ev) + 1;        /* +1 for the null */
  300.     if (home && home[0]) {
  301.         len += strlen(home) + 1;    /* +1 for the colon */
  302.     }
  303.  
  304.     local = ":/usr/local/netscape/lib/" PR_LINKER_ARCH;
  305.     len += strlen(local);        /* already got the : */
  306.     p = (char*) PR_MALLOC(len+50);
  307.     if (p) {
  308.         strcpy(p, ev);
  309.         if (home) {
  310.             strcat(p, ":");
  311.             strcat(p, home);
  312.         }
  313.         strcat(p, local);
  314.     }
  315.     ev = p;
  316.     PR_LOG(_pr_io_lm, PR_LOG_NOTICE, ("linker path '%s'", ev));
  317.     }
  318. #else
  319.     /* AFAIK there isn't a library path with the HP SHL interface --Rob */
  320.     ev = strdup("");
  321. #endif
  322. #endif
  323.  
  324.     /*
  325.      * If ev is NULL, we have run out of memory
  326.      */
  327.     _pr_currentLibPath = ev;
  328.  
  329.   exit:
  330.     if (_pr_currentLibPath) {
  331.         copy = strdup(_pr_currentLibPath);
  332.     }
  333.     PR_ExitMonitor(pr_linker_lock);
  334.     if (!copy) {
  335.         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  336.     }
  337.     return copy;
  338. }
  339.  
  340. /*
  341. ** Build library name from path, lib and extensions
  342. */
  343. PR_IMPLEMENT(char*) 
  344. PR_GetLibraryName(const char *path, const char *lib)
  345. {
  346.     char *fullname;
  347.  
  348. #ifdef XP_PC
  349.     if (strstr(lib, PR_DLL_SUFFIX) == NULL)
  350.     {
  351.         fullname = PR_smprintf("%s\\%s%s", path, lib, PR_DLL_SUFFIX);
  352.     } else {
  353.         fullname = PR_smprintf("%s\\%s", path, lib);
  354.     }
  355. #endif /* XP_PC */
  356. #ifdef XP_MAC
  357.     fullname = PR_smprintf("%s%s", path, lib);
  358. #endif
  359. #ifdef XP_UNIX
  360.     if (strstr(lib, PR_DLL_SUFFIX) == NULL)
  361.     {
  362.         fullname = PR_smprintf("%s/lib%s%s", path, lib, PR_DLL_SUFFIX);
  363.     } else {
  364.         fullname = PR_smprintf("%s/%s", path, lib);
  365.     }
  366. #endif /* XP_UNIX */
  367.     return fullname;
  368. }
  369.  
  370. /*
  371. ** Free the memory allocated, for the caller, by PR_GetLibraryName
  372. */
  373. PR_IMPLEMENT(void) 
  374. PR_FreeLibraryName(char *mem)
  375. {
  376.     PR_smprintf_free(mem);
  377. }
  378.  
  379. static PRLibrary* 
  380. pr_UnlockedFindLibrary(const char *name)
  381. {
  382.     PRLibrary* lm = pr_loadmap;
  383.     const char* np = strrchr(name, PR_DIRECTORY_SEPARATOR);
  384.     np = np ? np + 1 : name;
  385.     while (lm) {
  386.     const char* cp = strrchr(lm->name, PR_DIRECTORY_SEPARATOR);
  387.     cp = cp ? cp + 1 : lm->name;
  388. #ifdef XP_PC
  389.         /* Windows DLL names are case insensitive... */
  390.     if (strcmpi(np, cp) == 0) 
  391. #else
  392.     if (strcmp(np, cp)  == 0) 
  393. #endif
  394.     {
  395.         /* found */
  396.         lm->refCount++;
  397.         PR_LOG(_pr_linker_lm, PR_LOG_MIN,
  398.            ("%s incr => %d (find lib)",
  399.             lm->name, lm->refCount));
  400.         return lm;
  401.     }
  402.     lm = lm->next;
  403.     }
  404.     return NULL;
  405. }
  406.  
  407. /*
  408. ** Dynamically load a library. Only load libraries once, so scan the load
  409. ** map first.
  410. */
  411. PR_IMPLEMENT(PRLibrary*) 
  412. PR_LoadLibrary(const char *name)
  413. {
  414.     PRLibrary *lm;
  415.     PRLibrary* result;
  416.  
  417.     if (!_pr_initialized) _PR_ImplicitInitialization();
  418.  
  419.     /* See if library is already loaded */
  420.     PR_EnterMonitor(pr_linker_lock);
  421.  
  422.     result = pr_UnlockedFindLibrary(name);
  423.     if (result != NULL) goto unlock;
  424.  
  425.     lm = PR_NEWZAP(PRLibrary);
  426.     if (lm == NULL) goto unlock;
  427.     lm->staticTable = NULL;
  428.  
  429. #ifdef XP_OS2  /* Why isn't all this stuff in MD code?! */
  430.     {
  431.         NODL_PROC *pfn;
  432.         HMODULE h;
  433.         UCHAR pszError[_MAX_PATH];
  434.         ULONG ulRc = NO_ERROR;
  435.         int first_try = 1;
  436.  
  437.         retry:
  438.               ulRc = DosLoadModule(pszError, _MAX_PATH, (PSZ) name, &h);
  439.           if (ulRc != NO_ERROR) {
  440.               PR_DELETE(lm);
  441.               goto unlock;
  442.           }
  443.           lm->name = strdup(name);
  444.           lm->dlh  = h;
  445.           lm->next = pr_loadmap;
  446.           pr_loadmap = lm;
  447.     }
  448. #endif /* XP_OS2 */
  449.  
  450. #if defined(WIN32) || defined(WIN16)
  451.     {
  452.     HINSTANCE h;
  453.     NODL_PROC *pfn;
  454.  
  455.     h = LoadLibrary(name);
  456.     if (h < (HINSTANCE)HINSTANCE_ERROR) {
  457.         PR_DELETE(lm);
  458.         goto unlock;
  459.     }
  460.     lm->name = strdup(name);
  461.     lm->dlh = h;
  462.     lm->next = pr_loadmap;
  463.     pr_loadmap = lm;
  464.  
  465.         /*
  466.         ** Try to load a table of "static functions" provided by the DLL
  467.         */
  468.  
  469.         pfn = (NODL_PROC *)GetProcAddress(h, "NODL_TABLE");
  470.         if (pfn != NULL) {
  471.             lm->staticTable = (*pfn)();
  472.         }
  473.     }
  474. #endif /* WIN32 || WIN16 */
  475.  
  476. #if defined(XP_MAC) && GENERATINGCFM
  477.     {
  478.     OSErr                err;
  479.     Ptr                    main;
  480.     CFragConnectionID    connectionID;
  481.     Str255                errName;
  482.     Str255                pName;
  483.     char                cName[64];
  484.     const char*                libName;
  485.         
  486.     /*
  487.      * Algorithm: The "name" passed in could be either a shared
  488.      * library name that we should look for in the normal library
  489.      * search paths, or a full path name to a specific library on
  490.      * disk.  Since the full path will always contain a ":"
  491.      * (shortest possible path is "Volume:File"), and since a
  492.      * library name can not contain a ":", we can test for the
  493.      * presence of a ":" to see which type of library we should load.
  494.      * or its a full UNIX path which we for now assume is Java
  495.      * enumerating all the paths (see below)
  496.      */
  497.     if (strchr(name, PR_PATH_SEPARATOR) == NULL)
  498.     {
  499.         if (strchr(name, PR_DIRECTORY_SEPARATOR) == NULL)
  500.     {
  501.         /*
  502.          * The name did not contain a ":", so it must be a
  503.          * library name.  Convert the name to a Pascal string
  504.          * and try to find the library.
  505.          */
  506.         }
  507.         else
  508.         {
  509.             /* name contained a "/" which means we need to suck off the last part */
  510.             /* of the path and pass that on the NSGetSharedLibrary */
  511.             /* this may not be what we really want to do .. because Java could */
  512.             /* be iterating through the whole LD path, and we'll find it if it's */
  513.             /* anywhere on that path -- it appears that's what UNIX and the PC do */
  514.             /* too...so we'll emulate but it could be wrong. */
  515.             name = strrchr(name, PR_DIRECTORY_SEPARATOR) + 1;
  516.         }
  517.         
  518.         PStrFromCStr(name, pName);
  519.     
  520.         err = NSGetSharedLibrary(pName, &connectionID, &main);
  521.         if (err != noErr)
  522.             goto unlock;    
  523.         
  524.         libName = name;
  525.     }
  526.     else    
  527.     {
  528.         /*
  529.          * The name did contain a ":", so it must be a full path name.
  530.          * Now we have to do a lot of work to convert the path name to
  531.          * an FSSpec (silly, since we were probably just called from the
  532.          * MacFE plug-in code that already knew the FSSpec and converted
  533.          * it to a full path just to pass to us).  First we copy out the
  534.          * volume name (the text leading up to the first ":"); then we
  535.          * separate the file name (the text following the last ":") from
  536.          * rest of the path.  After converting the strings to Pascal
  537.          * format we can call GetCatInfo to get the parent directory ID
  538.          * of the file, and then (finally) make an FSSpec and call
  539.          * GetDiskFragment.
  540.          */
  541.         char* cMacPath = NULL;
  542.         char* cFileName = NULL;
  543.         char* position = NULL;
  544.         CInfoPBRec pb;
  545.         FSSpec fileSpec;
  546.         PRUint32 index;
  547.  
  548.         /* Copy the name: we'll change it */
  549.         cMacPath = strdup(name);    
  550.         if (cMacPath == NULL)
  551.             goto unlock;
  552.             
  553.         /* First, get the vRefNum */
  554.         position = strchr(cMacPath, PR_PATH_SEPARATOR);
  555.         if ((position == cMacPath) || (position == NULL))
  556.             fileSpec.vRefNum = 0;        /* Use application relative searching */
  557.         else
  558.         {
  559.             char cVolName[32];
  560.             memset(cVolName, 0, sizeof(cVolName));
  561.             strncpy(cVolName, cMacPath, position-cMacPath);
  562.             fileSpec.vRefNum = GetVolumeRefNumFromName(cVolName);
  563.         }
  564.  
  565.         /* Next, break the path and file name apart */
  566.         index = 0;
  567.         while (cMacPath[index] != 0)
  568.             index++;
  569.         while (cMacPath[index] != PR_PATH_SEPARATOR && index > 0)
  570.             index--;
  571.         if (index == 0 || index == strlen(cMacPath))
  572.         {
  573.             PR_DELETE(cMacPath);
  574.             goto unlock;
  575.         }
  576.         cMacPath[index] = 0;
  577.         cFileName = &(cMacPath[index + 1]);
  578.         
  579.         /* Convert the path and name into Pascal strings */
  580.         strcpy((char*) &pName, cMacPath);
  581.         c2pstr((char*) &pName);
  582.         strcpy((char*) &fileSpec.name, cFileName);
  583.         c2pstr((char*) &fileSpec.name);
  584.         strcpy(cName, cFileName);
  585.         PR_DELETE(cMacPath);
  586.         cMacPath = NULL;
  587.         
  588.         /* Now we can look up the path on the volume */
  589.         pb.dirInfo.ioNamePtr = pName;
  590.         pb.dirInfo.ioVRefNum = fileSpec.vRefNum;
  591.         pb.dirInfo.ioDrDirID = 0;
  592.         pb.dirInfo.ioFDirIndex = 0;
  593.         err = PBGetCatInfoSync(&pb);
  594.         if (err != noErr)
  595.             goto unlock;
  596.         fileSpec.parID = pb.dirInfo.ioDrDirID;
  597.  
  598.         /* Finally, try to load the library */
  599.         err = GetDiskFragment(&fileSpec, 0, kCFragGoesToEOF, fileSpec.name, 
  600.                         kLoadCFrag, &connectionID, &main, errName);
  601.  
  602.         libName = cName;
  603.         if (err != noErr)
  604.             goto unlock;
  605.     }
  606.     
  607.     lm->name = strdup(libName);
  608.     lm->dlh = connectionID;
  609.     lm->next = pr_loadmap;
  610.     pr_loadmap = lm;
  611.     }
  612. #elif defined(XP_MAC) && !GENERATINGCFM
  613.     {
  614.  
  615.     }
  616. #endif
  617.  
  618. #ifdef XP_UNIX
  619. #ifdef HAVE_DLL
  620.     {
  621. #if defined(USE_DLFCN)
  622.     void *h = dlopen(name, RTLD_LAZY);
  623. #elif defined(USE_HPSHL)
  624.     /*
  625.      * Shared libraries built using aCC cannot be dynamically loaded
  626.      * with BIND_DEFERRED, so we have to use the BIND_IMMEDIATE flag.
  627.      */
  628.     shl_t h = shl_load(name, BIND_IMMEDIATE | DYNAMIC_PATH, 0L);
  629. #else
  630. #error Configuration error
  631. #endif
  632.     if (!h) {
  633.         PR_DELETE(lm);
  634.         goto unlock;
  635.     }
  636.     lm->name = strdup(name);
  637.     lm->dlh = h;
  638.     lm->next = pr_loadmap;
  639.     pr_loadmap = lm;
  640.     }
  641. #endif /* HAVE_DLL */
  642. #endif /* XP_UNIX */
  643.  
  644.     lm->refCount = 1;
  645.     result = lm;    /* success */
  646.     PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", lm->name));
  647.  
  648.   unlock:
  649.     if (result == NULL) {
  650.         PR_SetError(PR_LOAD_LIBRARY_ERROR, _MD_ERRNO());
  651.         DLLErrorInternal(_MD_ERRNO());  /* sets error text */
  652.     }
  653.     PR_ExitMonitor(pr_linker_lock);
  654.     return result;
  655. }
  656.  
  657. PR_IMPLEMENT(PRLibrary*) 
  658. PR_FindLibrary(const char *name)
  659. {
  660.     PRLibrary* result;
  661.  
  662.     PR_EnterMonitor(pr_linker_lock);
  663.     result = pr_UnlockedFindLibrary(name);
  664.     PR_ExitMonitor(pr_linker_lock);
  665.     return result;
  666. }
  667.  
  668. /*
  669. ** Unload a shared library which was loaded via PR_LoadLibrary
  670. */
  671. PR_IMPLEMENT(PRStatus) 
  672. PR_UnloadLibrary(PRLibrary *lib)
  673. {
  674.     int result = 0;
  675.     PRStatus status = PR_SUCCESS;
  676.  
  677.     if ((lib == 0) || (lib->refCount <= 0)) {
  678.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  679.         return PR_FAILURE;
  680.     }
  681.  
  682.     PR_EnterMonitor(pr_linker_lock);
  683.     if (--lib->refCount > 0) {
  684.     PR_LOG(_pr_linker_lm, PR_LOG_MIN,
  685.            ("%s decr => %d",
  686.         lib->name, lib->refCount));
  687.     goto done;
  688.     }
  689. #ifdef XP_UNIX
  690. #ifdef HAVE_DLL
  691. #ifdef USE_DLFCN
  692.     result = dlclose(lib->dlh);
  693. #elif defined(USE_HPSHL)
  694.     result = shl_unload(lib->dlh);
  695. #else
  696. #error Configuration error
  697. #endif
  698. #endif /* HAVE_DLL */
  699. #endif /* XP_UNIX */
  700. #ifdef XP_PC
  701.     if (lib->dlh) {
  702.         FreeLibrary((HINSTANCE)(lib->dlh));
  703.         lib->dlh = (HINSTANCE)NULL;
  704.     }
  705. #endif  /* XP_PC */
  706.  
  707. #if defined(XP_MAC) && GENERATINGCFM
  708.     /* Close the connection */
  709.     CloseConnection(&(lib->dlh));
  710. #endif
  711.  
  712.     /* unlink from library search list */
  713.     if (pr_loadmap == lib)
  714.     pr_loadmap = pr_loadmap->next;
  715.     else if (pr_loadmap != NULL) {
  716.     PRLibrary* prev = pr_loadmap;
  717.     PRLibrary* next = pr_loadmap->next;
  718.     while (next != NULL) {
  719.         if (next == lib) {
  720.         prev->next = next->next;
  721.         goto freeLib;
  722.         }
  723.         prev = next;
  724.         next = next->next;
  725.     }
  726.         /*
  727.          * fail (the library is not on the _pr_loadmap list),
  728.          * but don't wipe out an error from dlclose/shl_unload.
  729.          */
  730.         PR_ASSERT(!"_pr_loadmap and lib->refCount inconsistent");
  731.         if (result == 0) {
  732.             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  733.             status = PR_FAILURE;
  734.         }
  735.     }
  736.     /*
  737.      * We free the PRLibrary structure whether dlclose/shl_unload
  738.      * succeeds or not.
  739.      */
  740.  
  741.   freeLib:
  742.     PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Unloaded library %s", lib->name));
  743.     PR_DELETE(lib->name);
  744.     PR_DELETE(lib);
  745.     if (result == -1) {
  746.         PR_SetError(PR_UNLOAD_LIBRARY_ERROR, _MD_ERRNO());
  747.         DLLErrorInternal(_MD_ERRNO());
  748.         status = PR_FAILURE;
  749.     }
  750.  
  751. done:
  752.     PR_ExitMonitor(pr_linker_lock);
  753.     return status;
  754. }
  755.  
  756. static void* 
  757. pr_FindSymbolInLib(PRLibrary *lm, const char *name)
  758. {
  759.     void *f = NULL;
  760.  
  761.     if (lm->staticTable != NULL) {
  762.     const PRStaticLinkTable* tp;
  763.     for (tp = lm->staticTable; tp->name; tp++) {
  764.         if (strcmp(name, tp->name) == 0) {
  765.         return (void*) tp->fp;
  766.         }
  767.     }
  768.         /* 
  769.         ** If the symbol was not found in the static table then check if
  770.         ** the symbol was exported in the DLL... Win16 only!!
  771.         */
  772. #if !defined(WIN16)
  773.         PR_SetError(PR_FIND_SYMBOL_ERROR, 0);
  774.         return (void*)NULL;
  775. #endif
  776.     }
  777.     
  778. #ifdef XP_OS2
  779.     DosQueryProcAddr(lm->dlh, 0, name, (PFN *) &f);
  780. #endif  /* XP_OS2 */
  781.  
  782. #if defined(WIN32) || defined(WIN16)
  783.     f = GetProcAddress(lm->dlh, name);
  784. #endif  /* WIN32 || WIN16 */
  785.  
  786. #ifdef XP_MAC
  787.     {
  788.     Ptr            symAddr;
  789.     CFragSymbolClass    symClass;
  790.     Str255        pName;
  791.             
  792.         PStrFromCStr(name, pName);    
  793.         
  794.         f = (NSFindSymbol(lm->dlh, pName, &symAddr, &symClass) == noErr) ? symAddr : NULL;
  795.     }
  796. #endif /* XP_MAC */
  797.  
  798. #ifdef XP_UNIX
  799. #ifdef HAVE_DLL
  800. #ifdef USE_DLFCN
  801.     f = dlsym(lm->dlh, name);
  802. #elif defined(USE_HPSHL)
  803.     if (shl_findsym(&lm->dlh, name, TYPE_PROCEDURE, &f) == -1)
  804.     f = NULL;
  805. #endif
  806. #endif /* HAVE_DLL */
  807. #endif /* XP_UNIX */
  808.     if (f == NULL) {
  809.         PR_SetError(PR_FIND_SYMBOL_ERROR, _MD_ERRNO());
  810.         DLLErrorInternal(_MD_ERRNO());
  811.     }
  812.     return f;
  813. }
  814.  
  815. /*
  816. ** Called by class loader to resolve missing native's
  817. */
  818. PR_IMPLEMENT(void*) 
  819. PR_FindSymbol(PRLibrary *lib, const char *raw_name)
  820. {
  821.     void *f = NULL;
  822. #if defined(SUNOS4) || defined(WIN16)
  823.     char *name;
  824. #else
  825.     const char *name;
  826. #endif
  827.     /*
  828.     ** Mangle the raw symbol name in any way that is platform specific.
  829.     */
  830. #if defined(SUNOS4)
  831.     /* Need a leading _ */
  832.     name = PR_smprintf("_%s", raw_name);
  833. #elif defined(AIX)
  834.     /*
  835.     ** AIX with the normal linker put's a "." in front of the symbol
  836.     ** name.  When use "svcc" and "svld" then the "." disappears. Go
  837.     ** figure.
  838.     */
  839.     name = raw_name;
  840. #elif defined(WIN16)
  841.     /*
  842.     ** Win16. symbols have a leading '_'
  843.     */
  844.     name = PR_smprintf("_%s", raw_name);
  845. #else
  846.     name = raw_name;
  847. #endif
  848.  
  849.     PR_EnterMonitor(pr_linker_lock);
  850.     PR_ASSERT(lib != NULL);
  851.     f = pr_FindSymbolInLib(lib, name);
  852.  
  853. #if defined(SUNOS4) || defined(WIN16)
  854.     PR_smprintf_free(name);
  855. #endif
  856.  
  857.     PR_ExitMonitor(pr_linker_lock);
  858.     return f;
  859. }
  860.  
  861. PR_IMPLEMENT(void*) 
  862. PR_FindSymbolAndLibrary(const char *raw_name, PRLibrary* *lib)
  863. {
  864.     void *f = NULL;
  865. #if defined(SUNOS4) || defined(WIN16)
  866.     char *name;
  867. #else
  868.     const char *name;
  869. #endif
  870.     PRLibrary* lm;
  871.  
  872.     /*
  873.     ** Mangle the raw symbol name in any way that is platform specific.
  874.     */
  875. #if defined(SUNOS4)
  876.     /* Need a leading _ */
  877.     name = PR_smprintf("_%s", raw_name);
  878. #elif defined(AIX)
  879.     /*
  880.     ** AIX with the normal linker put's a "." in front of the symbol
  881.     ** name.  When use "svcc" and "svld" then the "." disappears. Go
  882.     ** figure.
  883.     */
  884.     name = raw_name;
  885. #elif defined(WIN16)
  886.     /*
  887.     ** Win16. symbols have a leading '_'
  888.     */
  889.     name = PR_smprintf("_%s", raw_name);
  890. #else
  891.     name = raw_name;
  892. #endif
  893.  
  894.     PR_EnterMonitor(pr_linker_lock);
  895.  
  896.     /* search all libraries */
  897.     for (lm = pr_loadmap; lm != NULL; lm = lm->next) {
  898.         f = pr_FindSymbolInLib(lm, name);
  899.         if (f != NULL) {
  900.             *lib = lm;
  901.             lm->refCount++;
  902.             PR_LOG(_pr_linker_lm, PR_LOG_MIN,
  903.                        ("%s incr => %d (for %s)",
  904.                     lm->name, lm->refCount, name));
  905.             break;
  906.         }
  907.     }
  908. #if defined(SUNOS4) || defined(WIN16)
  909.     PR_smprintf_free(name);
  910. #endif
  911.  
  912.     PR_ExitMonitor(pr_linker_lock);
  913.     return f;
  914. }
  915.  
  916. /*
  917. ** Add a static library to the list of loaded libraries. If LoadLibrary
  918. ** is called with the name then we will pretend it was already loaded
  919. */
  920. PR_IMPLEMENT(PRLibrary*) 
  921. PR_LoadStaticLibrary(const char *name, const PRStaticLinkTable *slt)
  922. {
  923.     PRLibrary *lm;
  924.     PRLibrary* result = NULL;
  925.  
  926.     /* See if library is already loaded */
  927.     PR_EnterMonitor(pr_linker_lock);
  928.  
  929.     /* If the lbrary is already loaded, then add the static table information... */
  930.     result = pr_UnlockedFindLibrary(name);
  931.     if (result != NULL) {
  932.         PR_ASSERT( (result->staticTable == NULL) || (result->staticTable == slt) );
  933.         result->staticTable = slt;
  934.         goto unlock;
  935.     }
  936.  
  937.     /* Add library to list...Mark it static */
  938.     lm = PR_NEWZAP(PRLibrary);
  939.     if (lm == NULL) goto unlock;
  940.  
  941.     lm->name = strdup(name);
  942.     lm->refCount    = 1;
  943.     lm->dlh         = pr_exe_loadmap ? pr_exe_loadmap->dlh : 0;
  944.     lm->staticTable = slt;
  945.     lm->next        = pr_loadmap;
  946.     pr_loadmap      = lm;
  947.  
  948.     result = lm;    /* success */
  949.     PR_ASSERT(lm->refCount == 1);
  950.   unlock:
  951.     PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (static lib)", lm->name));
  952.     PR_ExitMonitor(pr_linker_lock);
  953.     return result;
  954. }
  955.