tclLoad.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:20k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclLoad.c --
  3.  *
  4.  * This file provides the generic portion (those that are the same
  5.  * on all platforms) of Tcl's dynamic loading facilities.
  6.  *
  7.  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * RCS: @(#) $Id: tclLoad.c,v 1.9 2003/02/01 23:37:29 kennykb Exp $
  13.  */
  14. #include "tclInt.h"
  15. /*
  16.  * The following structure describes a package that has been loaded
  17.  * either dynamically (with the "load" command) or statically (as
  18.  * indicated by a call to TclGetLoadedPackages).  All such packages
  19.  * are linked together into a single list for the process.  Packages
  20.  * are never unloaded, until the application exits, when 
  21.  * TclFinalizeLoad is called, and these structures are freed.
  22.  */
  23. typedef struct LoadedPackage {
  24.     char *fileName; /* Name of the file from which the
  25.  * package was loaded.  An empty string
  26.  * means the package is loaded statically.
  27.  * Malloc-ed. */
  28.     char *packageName; /* Name of package prefix for the package,
  29.  * properly capitalized (first letter UC,
  30.  * others LC), no "_", as in "Net". 
  31.  * Malloc-ed. */
  32.     Tcl_LoadHandle loadHandle; /* Token for the loaded file which should be
  33.  * passed to (*unLoadProcPtr)() when the file
  34.  * is no longer needed.  If fileName is NULL,
  35.  * then this field is irrelevant. */
  36.     Tcl_PackageInitProc *initProc;
  37. /* Initialization procedure to call to
  38.  * incorporate this package into a trusted
  39.  * interpreter. */
  40.     Tcl_PackageInitProc *safeInitProc;
  41. /* Initialization procedure to call to
  42.  * incorporate this package into a safe
  43.  * interpreter (one that will execute
  44.  * untrusted scripts).   NULL means the
  45.  * package can't be used in unsafe
  46.  * interpreters. */
  47.     Tcl_FSUnloadFileProc *unLoadProcPtr;
  48. /* Procedure to use to unload this package.
  49.  * If NULL, then we do not attempt to unload
  50.  * the package.  If fileName is NULL, then
  51.  * this field is irrelevant. */
  52.     struct LoadedPackage *nextPtr;
  53. /* Next in list of all packages loaded into
  54.  * this application process.  NULL means
  55.  * end of list. */
  56. } LoadedPackage;
  57. /*
  58.  * TCL_THREADS
  59.  * There is a global list of packages that is anchored at firstPackagePtr.
  60.  * Access to this list is governed by a mutex.
  61.  */
  62. static LoadedPackage *firstPackagePtr = NULL;
  63. /* First in list of all packages loaded into
  64.  * this process. */
  65. TCL_DECLARE_MUTEX(packageMutex)
  66. /*
  67.  * The following structure represents a particular package that has
  68.  * been incorporated into a particular interpreter (by calling its
  69.  * initialization procedure).  There is a list of these structures for
  70.  * each interpreter, with an AssocData value (key "load") for the
  71.  * interpreter that points to the first package (if any).
  72.  */
  73. typedef struct InterpPackage {
  74.     LoadedPackage *pkgPtr; /* Points to detailed information about
  75.  * package. */
  76.     struct InterpPackage *nextPtr;
  77. /* Next package in this interpreter, or
  78.  * NULL for end of list. */
  79. } InterpPackage;
  80. /*
  81.  * Prototypes for procedures that are private to this file:
  82.  */
  83. static void LoadCleanupProc _ANSI_ARGS_((ClientData clientData,
  84.     Tcl_Interp *interp));
  85. /*
  86.  *----------------------------------------------------------------------
  87.  *
  88.  * Tcl_LoadObjCmd --
  89.  *
  90.  * This procedure is invoked to process the "load" Tcl command.
  91.  * See the user documentation for details on what it does.
  92.  *
  93.  * Results:
  94.  * A standard Tcl result.
  95.  *
  96.  * Side effects:
  97.  * See the user documentation.
  98.  *
  99.  *----------------------------------------------------------------------
  100.  */
  101. int
  102. Tcl_LoadObjCmd(dummy, interp, objc, objv)
  103.     ClientData dummy; /* Not used. */
  104.     Tcl_Interp *interp; /* Current interpreter. */
  105.     int objc; /* Number of arguments. */
  106.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  107. {
  108.     Tcl_Interp *target;
  109.     LoadedPackage *pkgPtr, *defaultPtr;
  110.     Tcl_DString pkgName, tmp, initName, safeInitName;
  111.     Tcl_PackageInitProc *initProc, *safeInitProc;
  112.     InterpPackage *ipFirstPtr, *ipPtr;
  113.     int code, namesMatch, filesMatch;
  114.     char *p, *fullFileName, *packageName;
  115.     Tcl_LoadHandle loadHandle;
  116.     Tcl_FSUnloadFileProc *unLoadProcPtr = NULL;
  117.     Tcl_UniChar ch;
  118.     int offset;
  119.     if ((objc < 2) || (objc > 4)) {
  120.         Tcl_WrongNumArgs(interp, 1, objv, "fileName ?packageName? ?interp?");
  121. return TCL_ERROR;
  122.     }
  123.     if (Tcl_FSConvertToPathType(interp, objv[1]) != TCL_OK) {
  124. return TCL_ERROR;
  125.     }
  126.     fullFileName = Tcl_GetString(objv[1]);
  127.     
  128.     Tcl_DStringInit(&pkgName);
  129.     Tcl_DStringInit(&initName);
  130.     Tcl_DStringInit(&safeInitName);
  131.     Tcl_DStringInit(&tmp);
  132.     packageName = NULL;
  133.     if (objc >= 3) {
  134. packageName = Tcl_GetString(objv[2]);
  135. if (packageName[0] == '') {
  136.     packageName = NULL;
  137. }
  138.     }
  139.     if ((fullFileName[0] == 0) && (packageName == NULL)) {
  140. Tcl_SetResult(interp,
  141. "must specify either file name or package name",
  142. TCL_STATIC);
  143. code = TCL_ERROR;
  144. goto done;
  145.     }
  146.     /*
  147.      * Figure out which interpreter we're going to load the package into.
  148.      */
  149.     target = interp;
  150.     if (objc == 4) {
  151. char *slaveIntName;
  152. slaveIntName = Tcl_GetString(objv[3]);
  153. target = Tcl_GetSlave(interp, slaveIntName);
  154. if (target == NULL) {
  155.     return TCL_ERROR;
  156. }
  157.     }
  158.     /*
  159.      * Scan through the packages that are currently loaded to see if the
  160.      * package we want is already loaded.  We'll use a loaded package if
  161.      * it meets any of the following conditions:
  162.      *  - Its name and file match the once we're looking for.
  163.      *  - Its file matches, and we weren't given a name.
  164.      *  - Its name matches, the file name was specified as empty, and there
  165.      *    is only no statically loaded package with the same name.
  166.      */
  167.     Tcl_MutexLock(&packageMutex);
  168.     defaultPtr = NULL;
  169.     for (pkgPtr = firstPackagePtr; pkgPtr != NULL; pkgPtr = pkgPtr->nextPtr) {
  170. if (packageName == NULL) {
  171.     namesMatch = 0;
  172. } else {
  173.     Tcl_DStringSetLength(&pkgName, 0);
  174.     Tcl_DStringAppend(&pkgName, packageName, -1);
  175.     Tcl_DStringSetLength(&tmp, 0);
  176.     Tcl_DStringAppend(&tmp, pkgPtr->packageName, -1);
  177.     Tcl_UtfToLower(Tcl_DStringValue(&pkgName));
  178.     Tcl_UtfToLower(Tcl_DStringValue(&tmp));
  179.     if (strcmp(Tcl_DStringValue(&tmp),
  180.     Tcl_DStringValue(&pkgName)) == 0) {
  181. namesMatch = 1;
  182.     } else {
  183. namesMatch = 0;
  184.     }
  185. }
  186. Tcl_DStringSetLength(&pkgName, 0);
  187. filesMatch = (strcmp(pkgPtr->fileName, fullFileName) == 0);
  188. if (filesMatch && (namesMatch || (packageName == NULL))) {
  189.     break;
  190. }
  191. if (namesMatch && (fullFileName[0] == 0)) {
  192.     defaultPtr = pkgPtr;
  193. }
  194. if (filesMatch && !namesMatch && (fullFileName[0] != 0)) {
  195.     /*
  196.      * Can't have two different packages loaded from the same
  197.      * file.
  198.      */
  199.     Tcl_AppendResult(interp, "file "", fullFileName,
  200.     "" is already loaded for package "",
  201.     pkgPtr->packageName, """, (char *) NULL);
  202.     code = TCL_ERROR;
  203.     Tcl_MutexUnlock(&packageMutex);
  204.     goto done;
  205. }
  206.     }
  207.     Tcl_MutexUnlock(&packageMutex);
  208.     if (pkgPtr == NULL) {
  209. pkgPtr = defaultPtr;
  210.     }
  211.     /*
  212.      * Scan through the list of packages already loaded in the target
  213.      * interpreter.  If the package we want is already loaded there,
  214.      * then there's nothing for us to to.
  215.      */
  216.     if (pkgPtr != NULL) {
  217. ipFirstPtr = (InterpPackage *) Tcl_GetAssocData(target, "tclLoad",
  218. (Tcl_InterpDeleteProc **) NULL);
  219. for (ipPtr = ipFirstPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
  220.     if (ipPtr->pkgPtr == pkgPtr) {
  221. code = TCL_OK;
  222. goto done;
  223.     }
  224. }
  225.     }
  226.     if (pkgPtr == NULL) {
  227. /*
  228.  * The desired file isn't currently loaded, so load it.  It's an
  229.  * error if the desired package is a static one.
  230.  */
  231. if (fullFileName[0] == 0) {
  232.     Tcl_AppendResult(interp, "package "", packageName,
  233.     "" isn't loaded statically", (char *) NULL);
  234.     code = TCL_ERROR;
  235.     goto done;
  236. }
  237. /*
  238.  * Figure out the module name if it wasn't provided explicitly.
  239.  */
  240. if (packageName != NULL) {
  241.     Tcl_DStringAppend(&pkgName, packageName, -1);
  242. } else {
  243.     int retc;
  244.     /*
  245.      * Threading note - this call used to be protected by a mutex.
  246.      */
  247.     retc = TclGuessPackageName(fullFileName, &pkgName);
  248.     if (!retc) {
  249. Tcl_Obj *splitPtr;
  250. Tcl_Obj *pkgGuessPtr;
  251. int pElements;
  252. char *pkgGuess;
  253. /*
  254.  * The platform-specific code couldn't figure out the
  255.  * module name.  Make a guess by taking the last element
  256.  * of the file name, stripping off any leading "lib",
  257.  * and then using all of the alphabetic and underline
  258.  * characters that follow that.
  259.  */
  260. splitPtr = Tcl_FSSplitPath(objv[1], &pElements);
  261. Tcl_ListObjIndex(NULL, splitPtr, pElements -1, &pkgGuessPtr);
  262. pkgGuess = Tcl_GetString(pkgGuessPtr);
  263. if ((pkgGuess[0] == 'l') && (pkgGuess[1] == 'i')
  264. && (pkgGuess[2] == 'b')) {
  265.     pkgGuess += 3;
  266. }
  267. for (p = pkgGuess; *p != 0; p += offset) {
  268.     offset = Tcl_UtfToUniChar(p, &ch);
  269.     if ((ch > 0x100)
  270.     || !(isalpha(UCHAR(ch)) /* INTL: ISO only */
  271.     || (UCHAR(ch) == '_'))) {
  272. break;
  273.     }
  274. }
  275. if (p == pkgGuess) {
  276.     Tcl_DecrRefCount(splitPtr);
  277.     Tcl_AppendResult(interp,
  278.     "couldn't figure out package name for ",
  279.     fullFileName, (char *) NULL);
  280.     code = TCL_ERROR;
  281.     goto done;
  282. }
  283. Tcl_DStringAppend(&pkgName, pkgGuess, (p - pkgGuess));
  284. Tcl_DecrRefCount(splitPtr);
  285.     }
  286. }
  287. /*
  288.  * Fix the capitalization in the package name so that the first
  289.  * character is in caps (or title case) but the others are all
  290.  * lower-case.
  291.  */
  292.     
  293. Tcl_DStringSetLength(&pkgName,
  294. Tcl_UtfToTitle(Tcl_DStringValue(&pkgName)));
  295. /*
  296.  * Compute the names of the two initialization procedures,
  297.  * based on the package name.
  298.  */
  299.     
  300. Tcl_DStringAppend(&initName, Tcl_DStringValue(&pkgName), -1);
  301. Tcl_DStringAppend(&initName, "_Init", 5);
  302. Tcl_DStringAppend(&safeInitName, Tcl_DStringValue(&pkgName), -1);
  303. Tcl_DStringAppend(&safeInitName, "_SafeInit", 9);
  304. /*
  305.  * Call platform-specific code to load the package and find the
  306.  * two initialization procedures.
  307.  */
  308. Tcl_MutexLock(&packageMutex);
  309. code = Tcl_FSLoadFile(interp, objv[1], Tcl_DStringValue(&initName),
  310. Tcl_DStringValue(&safeInitName), &initProc, &safeInitProc,
  311. &loadHandle,&unLoadProcPtr);
  312. Tcl_MutexUnlock(&packageMutex);
  313. if (code != TCL_OK) {
  314.     goto done;
  315. }
  316. if (initProc == NULL) {
  317.     Tcl_AppendResult(interp, "couldn't find procedure ",
  318.     Tcl_DStringValue(&initName), (char *) NULL);
  319.     if (unLoadProcPtr != NULL) {
  320. (*unLoadProcPtr)(loadHandle);
  321.     }
  322.     code = TCL_ERROR;
  323.     goto done;
  324. }
  325. /*
  326.  * Create a new record to describe this package.
  327.  */
  328. pkgPtr = (LoadedPackage *) ckalloc(sizeof(LoadedPackage));
  329. pkgPtr->fileName = (char *) ckalloc((unsigned)
  330. (strlen(fullFileName) + 1));
  331. strcpy(pkgPtr->fileName, fullFileName);
  332. pkgPtr->packageName = (char *) ckalloc((unsigned)
  333. (Tcl_DStringLength(&pkgName) + 1));
  334. strcpy(pkgPtr->packageName, Tcl_DStringValue(&pkgName));
  335. pkgPtr->loadHandle = loadHandle;
  336. pkgPtr->unLoadProcPtr = unLoadProcPtr;
  337. pkgPtr->initProc = initProc;
  338. pkgPtr->safeInitProc = safeInitProc;
  339. Tcl_MutexLock(&packageMutex);
  340. pkgPtr->nextPtr = firstPackagePtr;
  341. firstPackagePtr = pkgPtr;
  342. Tcl_MutexUnlock(&packageMutex);
  343.     }
  344.     /*
  345.      * Invoke the package's initialization procedure (either the
  346.      * normal one or the safe one, depending on whether or not the
  347.      * interpreter is safe).
  348.      */
  349.     if (Tcl_IsSafe(target)) {
  350. if (pkgPtr->safeInitProc != NULL) {
  351.     code = (*pkgPtr->safeInitProc)(target);
  352. } else {
  353.     Tcl_AppendResult(interp,
  354.     "can't use package in a safe interpreter: ",
  355.     "no ", pkgPtr->packageName, "_SafeInit procedure",
  356.     (char *) NULL);
  357.     code = TCL_ERROR;
  358.     goto done;
  359. }
  360.     } else {
  361. code = (*pkgPtr->initProc)(target);
  362.     }
  363.     /*
  364.      * Record the fact that the package has been loaded in the
  365.      * target interpreter.
  366.      */
  367.     if (code == TCL_OK) {
  368. /*
  369.  * Refetch ipFirstPtr: loading the package may have introduced
  370.  * additional static packages at the head of the linked list!
  371.  */
  372. ipFirstPtr = (InterpPackage *) Tcl_GetAssocData(target, "tclLoad",
  373. (Tcl_InterpDeleteProc **) NULL);
  374. ipPtr = (InterpPackage *) ckalloc(sizeof(InterpPackage));
  375. ipPtr->pkgPtr = pkgPtr;
  376. ipPtr->nextPtr = ipFirstPtr;
  377. Tcl_SetAssocData(target, "tclLoad", LoadCleanupProc,
  378. (ClientData) ipPtr);
  379.     } else {
  380. TclTransferResult(target, code, interp);
  381.     }
  382.     done:
  383.     Tcl_DStringFree(&pkgName);
  384.     Tcl_DStringFree(&initName);
  385.     Tcl_DStringFree(&safeInitName);
  386.     Tcl_DStringFree(&tmp);
  387.     return code;
  388. }
  389. /*
  390.  *----------------------------------------------------------------------
  391.  *
  392.  * Tcl_StaticPackage --
  393.  *
  394.  * This procedure is invoked to indicate that a particular
  395.  * package has been linked statically with an application.
  396.  *
  397.  * Results:
  398.  * None.
  399.  *
  400.  * Side effects:
  401.  * Once this procedure completes, the package becomes loadable
  402.  * via the "load" command with an empty file name.
  403.  *
  404.  *----------------------------------------------------------------------
  405.  */
  406. void
  407. Tcl_StaticPackage(interp, pkgName, initProc, safeInitProc)
  408.     Tcl_Interp *interp; /* If not NULL, it means that the
  409.  * package has already been loaded
  410.  * into the given interpreter by
  411.  * calling the appropriate init proc. */
  412.     CONST char *pkgName; /* Name of package (must be properly
  413.  * capitalized: first letter upper
  414.  * case, others lower case). */
  415.     Tcl_PackageInitProc *initProc; /* Procedure to call to incorporate
  416.  * this package into a trusted
  417.  * interpreter. */
  418.     Tcl_PackageInitProc *safeInitProc; /* Procedure to call to incorporate
  419.  * this package into a safe interpreter
  420.  * (one that will execute untrusted
  421.  * scripts).   NULL means the package
  422.  * can't be used in safe
  423.  * interpreters. */
  424. {
  425.     LoadedPackage *pkgPtr;
  426.     InterpPackage *ipPtr, *ipFirstPtr;
  427.     /*
  428.      * Check to see if someone else has already reported this package as
  429.      * statically loaded in the process.
  430.      */
  431.     Tcl_MutexLock(&packageMutex);
  432.     for (pkgPtr = firstPackagePtr; pkgPtr != NULL; pkgPtr = pkgPtr->nextPtr) {
  433. if ((pkgPtr->initProc == initProc)
  434. && (pkgPtr->safeInitProc == safeInitProc)
  435. && (strcmp(pkgPtr->packageName, pkgName) == 0)) {
  436.     break;
  437. }
  438.     }
  439.     Tcl_MutexUnlock(&packageMutex);
  440.     /*
  441.      * If the package is not yet recorded as being loaded statically,
  442.      * add it to the list now.
  443.      */
  444.     if ( pkgPtr == NULL ) {
  445. pkgPtr = (LoadedPackage *) ckalloc(sizeof(LoadedPackage));
  446. pkgPtr->fileName = (char *) ckalloc((unsigned) 1);
  447. pkgPtr->fileName[0] = 0;
  448. pkgPtr->packageName = (char *) ckalloc((unsigned)
  449.    (strlen(pkgName) + 1));
  450. strcpy(pkgPtr->packageName, pkgName);
  451. pkgPtr->loadHandle = NULL;
  452. pkgPtr->initProc = initProc;
  453. pkgPtr->safeInitProc = safeInitProc;
  454. Tcl_MutexLock(&packageMutex);
  455. pkgPtr->nextPtr = firstPackagePtr;
  456. firstPackagePtr = pkgPtr;
  457. Tcl_MutexUnlock(&packageMutex);
  458.     }
  459.     if (interp != NULL) {
  460. /*
  461.  * If we're loading the package into an interpreter,
  462.  * determine whether it's already loaded. 
  463.  */
  464. ipFirstPtr = (InterpPackage *) Tcl_GetAssocData(interp, "tclLoad",
  465. (Tcl_InterpDeleteProc **) NULL);
  466. for ( ipPtr = ipFirstPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr ) {
  467.     if ( ipPtr->pkgPtr == pkgPtr ) {
  468. return;
  469.     }
  470. }
  471. /*
  472.  * Package isn't loade in the current interp yet. Mark it as
  473.  * now being loaded.
  474.  */
  475. ipPtr = (InterpPackage *) ckalloc(sizeof(InterpPackage));
  476. ipPtr->pkgPtr = pkgPtr;
  477. ipPtr->nextPtr = ipFirstPtr;
  478. Tcl_SetAssocData(interp, "tclLoad", LoadCleanupProc,
  479. (ClientData) ipPtr);
  480.     }
  481. }
  482. /*
  483.  *----------------------------------------------------------------------
  484.  *
  485.  * TclGetLoadedPackages --
  486.  *
  487.  * This procedure returns information about all of the files
  488.  * that are loaded (either in a particular intepreter, or
  489.  * for all interpreters).
  490.  *
  491.  * Results:
  492.  * The return value is a standard Tcl completion code.  If
  493.  * successful, a list of lists is placed in the interp's result.
  494.  * Each sublist corresponds to one loaded file;  its first
  495.  * element is the name of the file (or an empty string for
  496.  * something that's statically loaded) and the second element
  497.  * is the name of the package in that file.
  498.  *
  499.  * Side effects:
  500.  * None.
  501.  *
  502.  *----------------------------------------------------------------------
  503.  */
  504. int
  505. TclGetLoadedPackages(interp, targetName)
  506.     Tcl_Interp *interp; /* Interpreter in which to return
  507.  * information or error message. */
  508.     char *targetName; /* Name of target interpreter or NULL.
  509.  * If NULL, return info about all interps;
  510.  * otherwise, just return info about this
  511.  * interpreter. */
  512. {
  513.     Tcl_Interp *target;
  514.     LoadedPackage *pkgPtr;
  515.     InterpPackage *ipPtr;
  516.     char *prefix;
  517.     if (targetName == NULL) {
  518. /* 
  519.  * Return information about all of the available packages.
  520.  */
  521. prefix = "{";
  522. Tcl_MutexLock(&packageMutex);
  523. for (pkgPtr = firstPackagePtr; pkgPtr != NULL;
  524. pkgPtr = pkgPtr->nextPtr) {
  525.     Tcl_AppendResult(interp, prefix, (char *) NULL);
  526.     Tcl_AppendElement(interp, pkgPtr->fileName);
  527.     Tcl_AppendElement(interp, pkgPtr->packageName);
  528.     Tcl_AppendResult(interp, "}", (char *) NULL);
  529.     prefix = " {";
  530. }
  531. Tcl_MutexUnlock(&packageMutex);
  532. return TCL_OK;
  533.     }
  534.     /*
  535.      * Return information about only the packages that are loaded in
  536.      * a given interpreter.
  537.      */
  538.     target = Tcl_GetSlave(interp, targetName);
  539.     if (target == NULL) {
  540. return TCL_ERROR;
  541.     }
  542.     ipPtr = (InterpPackage *) Tcl_GetAssocData(target, "tclLoad",
  543.     (Tcl_InterpDeleteProc **) NULL);
  544.     prefix = "{";
  545.     for ( ; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
  546. pkgPtr = ipPtr->pkgPtr;
  547. Tcl_AppendResult(interp, prefix, (char *) NULL);
  548. Tcl_AppendElement(interp, pkgPtr->fileName);
  549. Tcl_AppendElement(interp, pkgPtr->packageName);
  550. Tcl_AppendResult(interp, "}", (char *) NULL);
  551. prefix = " {";
  552.     }
  553.     return TCL_OK;
  554. }
  555. /*
  556.  *----------------------------------------------------------------------
  557.  *
  558.  * LoadCleanupProc --
  559.  *
  560.  * This procedure is called to delete all of the InterpPackage
  561.  * structures for an interpreter when the interpreter is deleted.
  562.  * It gets invoked via the Tcl AssocData mechanism.
  563.  *
  564.  * Results:
  565.  * None.
  566.  *
  567.  * Side effects:
  568.  * Storage for all of the InterpPackage procedures for interp
  569.  * get deleted.
  570.  *
  571.  *----------------------------------------------------------------------
  572.  */
  573. static void
  574. LoadCleanupProc(clientData, interp)
  575.     ClientData clientData; /* Pointer to first InterpPackage structure
  576.  * for interp. */
  577.     Tcl_Interp *interp; /* Interpreter that is being deleted. */
  578. {
  579.     InterpPackage *ipPtr, *nextPtr;
  580.     ipPtr = (InterpPackage *) clientData;
  581.     while (ipPtr != NULL) {
  582. nextPtr = ipPtr->nextPtr;
  583. ckfree((char *) ipPtr);
  584. ipPtr = nextPtr;
  585.     }
  586. }
  587. /*
  588.  *----------------------------------------------------------------------
  589.  *
  590.  * TclFinalizeLoad --
  591.  *
  592.  * This procedure is invoked just before the application exits.
  593.  * It frees all of the LoadedPackage structures.
  594.  *
  595.  * Results:
  596.  * None.
  597.  *
  598.  * Side effects:
  599.  * Memory is freed.
  600.  *
  601.  *----------------------------------------------------------------------
  602.  */
  603. void
  604. TclFinalizeLoad()
  605. {
  606.     LoadedPackage *pkgPtr;
  607.     /*
  608.      * No synchronization here because there should just be
  609.      * one thread alive at this point.  Logically, 
  610.      * packageMutex should be grabbed at this point, but
  611.      * the Mutexes get finalized before the call to this routine.
  612.      * The only subsystem left alive at this point is the
  613.      * memory allocator.
  614.      */
  615.     while (firstPackagePtr != NULL) {
  616. pkgPtr = firstPackagePtr;
  617. firstPackagePtr = pkgPtr->nextPtr;
  618. #if defined(TCL_UNLOAD_DLLS) || defined(__WIN32__)
  619. /*
  620.  * Some Unix dlls are poorly behaved - registering things like
  621.  * atexit calls that can't be unregistered.  If you unload
  622.  * such dlls, you get a core on exit because it wants to
  623.  * call a function in the dll after it's been unloaded.
  624.  */
  625. if (pkgPtr->fileName[0] != '') {
  626.     Tcl_FSUnloadFileProc *unLoadProcPtr = pkgPtr->unLoadProcPtr;
  627.     if (unLoadProcPtr != NULL) {
  628.         (*unLoadProcPtr)(pkgPtr->loadHandle);
  629.     }
  630. }
  631. #endif
  632. ckfree(pkgPtr->fileName);
  633. ckfree(pkgPtr->packageName);
  634. ckfree((char *) pkgPtr);
  635.     }
  636. }