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