tclLoad.cGo to the documentation of this file.00001 /* 00002 * tclLoad.c -- 00003 * 00004 * This file provides the generic portion (those that are the same on all 00005 * platforms) of Tcl's dynamic loading facilities. 00006 * 00007 * Copyright (c) 1995-1997 Sun Microsystems, Inc. 00008 * 00009 * See the file "license.terms" for information on usage and redistribution of 00010 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 00011 * 00012 * RCS: @(#) $Id: tclLoad.c,v 1.16 2007/02/20 23:24:03 nijtmans Exp $ 00013 */ 00014 00015 #include "tclInt.h" 00016 00017 /* 00018 * The following structure describes a package that has been loaded either 00019 * dynamically (with the "load" command) or statically (as indicated by a call 00020 * to TclGetLoadedPackages). All such packages are linked together into a 00021 * single list for the process. Packages are never unloaded, until the 00022 * application exits, when TclFinalizeLoad is called, and these structures are 00023 * freed. 00024 */ 00025 00026 typedef struct LoadedPackage { 00027 char *fileName; /* Name of the file from which the package was 00028 * loaded. An empty string means the package 00029 * is loaded statically. Malloc-ed. */ 00030 char *packageName; /* Name of package prefix for the package, 00031 * properly capitalized (first letter UC, 00032 * others LC), no "_", as in "Net". 00033 * Malloc-ed. */ 00034 Tcl_LoadHandle loadHandle; /* Token for the loaded file which should be 00035 * passed to (*unLoadProcPtr)() when the file 00036 * is no longer needed. If fileName is NULL, 00037 * then this field is irrelevant. */ 00038 Tcl_PackageInitProc *initProc; 00039 /* Initialization function to call to 00040 * incorporate this package into a trusted 00041 * interpreter. */ 00042 Tcl_PackageInitProc *safeInitProc; 00043 /* Initialization function to call to 00044 * incorporate this package into a safe 00045 * interpreter (one that will execute 00046 * untrusted scripts). NULL means the package 00047 * can't be used in unsafe interpreters. */ 00048 Tcl_PackageUnloadProc *unloadProc; 00049 /* Finalisation function to unload a package 00050 * from a trusted interpreter. NULL means that 00051 * the package cannot be unloaded. */ 00052 Tcl_PackageUnloadProc *safeUnloadProc; 00053 /* Finalisation function to unload a package 00054 * from a safe interpreter. NULL means that 00055 * the package cannot be unloaded. */ 00056 int interpRefCount; /* How many times the package has been loaded 00057 * in trusted interpreters. */ 00058 int safeInterpRefCount; /* How many times the package has been loaded 00059 * in safe interpreters. */ 00060 Tcl_FSUnloadFileProc *unLoadProcPtr; 00061 /* Function to use to unload this package. If 00062 * NULL, then we do not attempt to unload the 00063 * package. If fileName is NULL, then this 00064 * field is irrelevant. */ 00065 struct LoadedPackage *nextPtr; 00066 /* Next in list of all packages loaded into 00067 * this application process. NULL means end of 00068 * list. */ 00069 } LoadedPackage; 00070 00071 /* 00072 * TCL_THREADS 00073 * There is a global list of packages that is anchored at firstPackagePtr. 00074 * Access to this list is governed by a mutex. 00075 */ 00076 00077 static LoadedPackage *firstPackagePtr = NULL; 00078 /* First in list of all packages loaded into 00079 * this process. */ 00080 00081 TCL_DECLARE_MUTEX(packageMutex) 00082 00083 /* 00084 * The following structure represents a particular package that has been 00085 * incorporated into a particular interpreter (by calling its initialization 00086 * function). There is a list of these structures for each interpreter, with 00087 * an AssocData value (key "load") for the interpreter that points to the 00088 * first package (if any). 00089 */ 00090 00091 typedef struct InterpPackage { 00092 LoadedPackage *pkgPtr; /* Points to detailed information about 00093 * package. */ 00094 struct InterpPackage *nextPtr; 00095 /* Next package in this interpreter, or NULL 00096 * for end of list. */ 00097 } InterpPackage; 00098 00099 /* 00100 * Prototypes for functions that are private to this file: 00101 */ 00102 00103 static void LoadCleanupProc(ClientData clientData, 00104 Tcl_Interp *interp); 00105 00106 /* 00107 *---------------------------------------------------------------------- 00108 * 00109 * Tcl_LoadObjCmd -- 00110 * 00111 * This function is invoked to process the "load" Tcl command. See the 00112 * user documentation for details on what it does. 00113 * 00114 * Results: 00115 * A standard Tcl result. 00116 * 00117 * Side effects: 00118 * See the user documentation. 00119 * 00120 *---------------------------------------------------------------------- 00121 */ 00122 00123 int 00124 Tcl_LoadObjCmd( 00125 ClientData dummy, /* Not used. */ 00126 Tcl_Interp *interp, /* Current interpreter. */ 00127 int objc, /* Number of arguments. */ 00128 Tcl_Obj *const objv[]) /* Argument objects. */ 00129 { 00130 Tcl_Interp *target; 00131 LoadedPackage *pkgPtr, *defaultPtr; 00132 Tcl_DString pkgName, tmp, initName, safeInitName; 00133 Tcl_DString unloadName, safeUnloadName; 00134 Tcl_PackageInitProc *initProc, *safeInitProc, *unloadProc, *safeUnloadProc; 00135 InterpPackage *ipFirstPtr, *ipPtr; 00136 int code, namesMatch, filesMatch, offset; 00137 const char *symbols[4]; 00138 Tcl_PackageInitProc **procPtrs[4]; 00139 ClientData clientData; 00140 char *p, *fullFileName, *packageName; 00141 Tcl_LoadHandle loadHandle; 00142 Tcl_FSUnloadFileProc *unLoadProcPtr = NULL; 00143 Tcl_UniChar ch; 00144 00145 if ((objc < 2) || (objc > 4)) { 00146 Tcl_WrongNumArgs(interp, 1, objv, "fileName ?packageName? ?interp?"); 00147 return TCL_ERROR; 00148 } 00149 if (Tcl_FSConvertToPathType(interp, objv[1]) != TCL_OK) { 00150 return TCL_ERROR; 00151 } 00152 fullFileName = Tcl_GetString(objv[1]); 00153 00154 Tcl_DStringInit(&pkgName); 00155 Tcl_DStringInit(&initName); 00156 Tcl_DStringInit(&safeInitName); 00157 Tcl_DStringInit(&unloadName); 00158 Tcl_DStringInit(&safeUnloadName); 00159 Tcl_DStringInit(&tmp); 00160 00161 packageName = NULL; 00162 if (objc >= 3) { 00163 packageName = Tcl_GetString(objv[2]); 00164 if (packageName[0] == '\0') { 00165 packageName = NULL; 00166 } 00167 } 00168 if ((fullFileName[0] == 0) && (packageName == NULL)) { 00169 Tcl_SetResult(interp, 00170 "must specify either file name or package name", 00171 TCL_STATIC); 00172 code = TCL_ERROR; 00173 goto done; 00174 } 00175 00176 /* 00177 * Figure out which interpreter we're going to load the package into. 00178 */ 00179 00180 target = interp; 00181 if (objc == 4) { 00182 char *slaveIntName = Tcl_GetString(objv[3]); 00183 00184 target = Tcl_GetSlave(interp, slaveIntName); 00185 if (target == NULL) { 00186 code = TCL_ERROR; 00187 goto done; 00188 } 00189 } 00190 00191 /* 00192 * Scan through the packages that are currently loaded to see if the 00193 * package we want is already loaded. We'll use a loaded package if it 00194 * meets any of the following conditions: 00195 * - Its name and file match the once we're looking for. 00196 * - Its file matches, and we weren't given a name. 00197 * - Its name matches, the file name was specified as empty, and there is 00198 * only no statically loaded package with the same name. 00199 */ 00200 00201 Tcl_MutexLock(&packageMutex); 00202 00203 defaultPtr = NULL; 00204 for (pkgPtr = firstPackagePtr; pkgPtr != NULL; pkgPtr = pkgPtr->nextPtr) { 00205 if (packageName == NULL) { 00206 namesMatch = 0; 00207 } else { 00208 Tcl_DStringSetLength(&pkgName, 0); 00209 Tcl_DStringAppend(&pkgName, packageName, -1); 00210 Tcl_DStringSetLength(&tmp, 0); 00211 Tcl_DStringAppend(&tmp, pkgPtr->packageName, -1); 00212 Tcl_UtfToLower(Tcl_DStringValue(&pkgName)); 00213 Tcl_UtfToLower(Tcl_DStringValue(&tmp)); 00214 if (strcmp(Tcl_DStringValue(&tmp), 00215 Tcl_DStringValue(&pkgName)) == 0) { 00216 namesMatch = 1; 00217 } else { 00218 namesMatch = 0; 00219 } 00220 } 00221 Tcl_DStringSetLength(&pkgName, 0); 00222 00223 filesMatch = (strcmp(pkgPtr->fileName, fullFileName) == 0); 00224 if (filesMatch && (namesMatch || (packageName == NULL))) { 00225 break; 00226 } 00227 if (namesMatch && (fullFileName[0] == 0)) { 00228 defaultPtr = pkgPtr; 00229 } 00230 if (filesMatch && !namesMatch && (fullFileName[0] != 0)) { 00231 /* 00232 * Can't have two different packages loaded from the same file. 00233 */ 00234 00235 Tcl_AppendResult(interp, "file \"", fullFileName, 00236 "\" is already loaded for package \"", 00237 pkgPtr->packageName, "\"", NULL); 00238 code = TCL_ERROR; 00239 Tcl_MutexUnlock(&packageMutex); 00240 goto done; 00241 } 00242 } 00243 Tcl_MutexUnlock(&packageMutex); 00244 if (pkgPtr == NULL) { 00245 pkgPtr = defaultPtr; 00246 } 00247 00248 /* 00249 * Scan through the list of packages already loaded in the target 00250 * interpreter. If the package we want is already loaded there, then 00251 * there's nothing for us to do. 00252 */ 00253 00254 if (pkgPtr != NULL) { 00255 ipFirstPtr = (InterpPackage *) Tcl_GetAssocData(target, 00256 "tclLoad", NULL); 00257 for (ipPtr = ipFirstPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { 00258 if (ipPtr->pkgPtr == pkgPtr) { 00259 code = TCL_OK; 00260 goto done; 00261 } 00262 } 00263 } 00264 00265 if (pkgPtr == NULL) { 00266 /* 00267 * The desired file isn't currently loaded, so load it. It's an error 00268 * if the desired package is a static one. 00269 */ 00270 00271 if (fullFileName[0] == 0) { 00272 Tcl_AppendResult(interp, "package \"", packageName, 00273 "\" isn't loaded statically", NULL); 00274 code = TCL_ERROR; 00275 goto done; 00276 } 00277 00278 /* 00279 * Figure out the module name if it wasn't provided explicitly. 00280 */ 00281 00282 if (packageName != NULL) { 00283 Tcl_DStringAppend(&pkgName, packageName, -1); 00284 } else { 00285 int retc; 00286 00287 /* 00288 * Threading note - this call used to be protected by a mutex. 00289 */ 00290 00291 retc = TclGuessPackageName(fullFileName, &pkgName); 00292 if (!retc) { 00293 Tcl_Obj *splitPtr; 00294 Tcl_Obj *pkgGuessPtr; 00295 int pElements; 00296 char *pkgGuess; 00297 00298 /* 00299 * The platform-specific code couldn't figure out the module 00300 * name. Make a guess by taking the last element of the file 00301 * name, stripping off any leading "lib", and then using all 00302 * of the alphabetic and underline characters that follow 00303 * that. 00304 */ 00305 00306 splitPtr = Tcl_FSSplitPath(objv[1], &pElements); 00307 Tcl_ListObjIndex(NULL, splitPtr, pElements -1, &pkgGuessPtr); 00308 pkgGuess = Tcl_GetString(pkgGuessPtr); 00309 if ((pkgGuess[0] == 'l') && (pkgGuess[1] == 'i') 00310 && (pkgGuess[2] == 'b')) { 00311 pkgGuess += 3; 00312 } 00313 for (p = pkgGuess; *p != 0; p += offset) { 00314 offset = Tcl_UtfToUniChar(p, &ch); 00315 if ((ch > 0x100) 00316 || !(isalpha(UCHAR(ch)) /* INTL: ISO only */ 00317 || (UCHAR(ch) == '_'))) { 00318 break; 00319 } 00320 } 00321 if (p == pkgGuess) { 00322 Tcl_DecrRefCount(splitPtr); 00323 Tcl_AppendResult(interp, 00324 "couldn't figure out package name for ", 00325 fullFileName, NULL); 00326 code = TCL_ERROR; 00327 goto done; 00328 } 00329 Tcl_DStringAppend(&pkgName, pkgGuess, (p - pkgGuess)); 00330 Tcl_DecrRefCount(splitPtr); 00331 } 00332 } 00333 00334 /* 00335 * Fix the capitalization in the package name so that the first 00336 * character is in caps (or title case) but the others are all 00337 * lower-case. 00338 */ 00339 00340 Tcl_DStringSetLength(&pkgName, 00341 Tcl_UtfToTitle(Tcl_DStringValue(&pkgName))); 00342 00343 /* 00344 * Compute the names of the two initialization functions, based on the 00345 * package name. 00346 */ 00347 00348 Tcl_DStringAppend(&initName, Tcl_DStringValue(&pkgName), -1); 00349 Tcl_DStringAppend(&initName, "_Init", 5); 00350 Tcl_DStringAppend(&safeInitName, Tcl_DStringValue(&pkgName), -1); 00351 Tcl_DStringAppend(&safeInitName, "_SafeInit", 9); 00352 Tcl_DStringAppend(&unloadName, Tcl_DStringValue(&pkgName), -1); 00353 Tcl_DStringAppend(&unloadName, "_Unload", 7); 00354 Tcl_DStringAppend(&safeUnloadName, Tcl_DStringValue(&pkgName), -1); 00355 Tcl_DStringAppend(&safeUnloadName, "_SafeUnload", 11); 00356 00357 /* 00358 * Call platform-specific code to load the package and find the two 00359 * initialization functions. 00360 */ 00361 00362 symbols[0] = Tcl_DStringValue(&initName); 00363 symbols[1] = Tcl_DStringValue(&safeInitName); 00364 symbols[2] = Tcl_DStringValue(&unloadName); 00365 symbols[3] = Tcl_DStringValue(&safeUnloadName); 00366 procPtrs[0] = &initProc; 00367 procPtrs[1] = &safeInitProc; 00368 procPtrs[2] = &unloadProc; 00369 procPtrs[3] = &safeUnloadProc; 00370 00371 Tcl_MutexLock(&packageMutex); 00372 code = TclLoadFile(interp, objv[1], 4, symbols, procPtrs, 00373 &loadHandle, &clientData, &unLoadProcPtr); 00374 Tcl_MutexUnlock(&packageMutex); 00375 loadHandle = (Tcl_LoadHandle) clientData; 00376 if (code != TCL_OK) { 00377 goto done; 00378 } 00379 00380 if (*procPtrs[0] /* initProc */ == NULL) { 00381 Tcl_AppendResult(interp, "couldn't find procedure ", 00382 Tcl_DStringValue(&initName), NULL); 00383 if (unLoadProcPtr != NULL) { 00384 (*unLoadProcPtr)(loadHandle); 00385 } 00386 code = TCL_ERROR; 00387 goto done; 00388 } 00389 00390 /* 00391 * Create a new record to describe this package. 00392 */ 00393 00394 pkgPtr = (LoadedPackage *) ckalloc(sizeof(LoadedPackage)); 00395 pkgPtr->fileName = (char *) ckalloc((unsigned) 00396 (strlen(fullFileName) + 1)); 00397 strcpy(pkgPtr->fileName, fullFileName); 00398 pkgPtr->packageName = (char *) ckalloc((unsigned) 00399 (Tcl_DStringLength(&pkgName) + 1)); 00400 strcpy(pkgPtr->packageName, Tcl_DStringValue(&pkgName)); 00401 pkgPtr->loadHandle = loadHandle; 00402 pkgPtr->unLoadProcPtr = unLoadProcPtr; 00403 pkgPtr->initProc = *procPtrs[0]; 00404 pkgPtr->safeInitProc = *procPtrs[1]; 00405 pkgPtr->unloadProc = (Tcl_PackageUnloadProc*) *procPtrs[2]; 00406 pkgPtr->safeUnloadProc = (Tcl_PackageUnloadProc*) *procPtrs[3]; 00407 pkgPtr->interpRefCount = 0; 00408 pkgPtr->safeInterpRefCount = 0; 00409 00410 Tcl_MutexLock(&packageMutex); 00411 pkgPtr->nextPtr = firstPackagePtr; 00412 firstPackagePtr = pkgPtr; 00413 Tcl_MutexUnlock(&packageMutex); 00414 } 00415 00416 /* 00417 * Invoke the package's initialization function (either the normal one or 00418 * the safe one, depending on whether or not the interpreter is safe). 00419 */ 00420 00421 if (Tcl_IsSafe(target)) { 00422 if (pkgPtr->safeInitProc != NULL) { 00423 code = (*pkgPtr->safeInitProc)(target); 00424 } else { 00425 Tcl_AppendResult(interp, 00426 "can't use package in a safe interpreter: no ", 00427 pkgPtr->packageName, "_SafeInit procedure", NULL); 00428 code = TCL_ERROR; 00429 goto done; 00430 } 00431 } else { 00432 code = (*pkgPtr->initProc)(target); 00433 } 00434 00435 /* 00436 * Record the fact that the package has been loaded in the target 00437 * interpreter. 00438 */ 00439 00440 if (code == TCL_OK) { 00441 /* 00442 * Update the proper reference count. 00443 */ 00444 00445 Tcl_MutexLock(&packageMutex); 00446 if (Tcl_IsSafe(target)) { 00447 ++pkgPtr->safeInterpRefCount; 00448 } else { 00449 ++pkgPtr->interpRefCount; 00450 } 00451 Tcl_MutexUnlock(&packageMutex); 00452 00453 /* 00454 * Refetch ipFirstPtr: loading the package may have introduced 00455 * additional static packages at the head of the linked list! 00456 */ 00457 00458 ipFirstPtr = (InterpPackage *) Tcl_GetAssocData(target, 00459 "tclLoad", NULL); 00460 ipPtr = (InterpPackage *) ckalloc(sizeof(InterpPackage)); 00461 ipPtr->pkgPtr = pkgPtr; 00462 ipPtr->nextPtr = ipFirstPtr; 00463 Tcl_SetAssocData(target, "tclLoad", LoadCleanupProc, 00464 (ClientData) ipPtr); 00465 } else { 00466 TclTransferResult(target, code, interp); 00467 } 00468 00469 done: 00470 Tcl_DStringFree(&pkgName); 00471 Tcl_DStringFree(&initName); 00472 Tcl_DStringFree(&safeInitName); 00473 Tcl_DStringFree(&unloadName); 00474 Tcl_DStringFree(&safeUnloadName); 00475 Tcl_DStringFree(&tmp); 00476 return code; 00477 } 00478 00479 /* 00480 *---------------------------------------------------------------------- 00481 * 00482 * Tcl_UnloadObjCmd -- 00483 * 00484 * This function is invoked to process the "unload" Tcl command. See the 00485 * user documentation for details on what it does. 00486 * 00487 * Results: 00488 * A standard Tcl result. 00489 * 00490 * Side effects: 00491 * See the user documentation. 00492 * 00493 *---------------------------------------------------------------------- 00494 */ 00495 00496 int 00497 Tcl_UnloadObjCmd( 00498 ClientData dummy, /* Not used. */ 00499 Tcl_Interp *interp, /* Current interpreter. */ 00500 int objc, /* Number of arguments. */ 00501 Tcl_Obj *const objv[]) /* Argument objects. */ 00502 { 00503 Tcl_Interp *target; /* Which interpreter to unload from. */ 00504 LoadedPackage *pkgPtr, *defaultPtr; 00505 Tcl_DString pkgName, tmp; 00506 Tcl_PackageUnloadProc *unloadProc; 00507 InterpPackage *ipFirstPtr, *ipPtr; 00508 int i, index, code, complain = 1, keepLibrary = 0; 00509 int trustedRefCount = -1, safeRefCount = -1; 00510 const char *fullFileName = ""; 00511 char *packageName; 00512 static const char *options[] = { 00513 "-nocomplain", "-keeplibrary", "--", NULL 00514 }; 00515 enum options { 00516 UNLOAD_NOCOMPLAIN, UNLOAD_KEEPLIB, UNLOAD_LAST 00517 }; 00518 00519 for (i = 1; i < objc; i++) { 00520 if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0, 00521 &index) != TCL_OK) { 00522 fullFileName = Tcl_GetString(objv[i]); 00523 if (fullFileName[0] == '-') { 00524 /* 00525 * It looks like the command contains an option so signal an 00526 * error 00527 */ 00528 00529 return TCL_ERROR; 00530 } else { 00531 /* 00532 * This clearly isn't an option; assume it's the filename. We 00533 * must clear the error. 00534 */ 00535 00536 Tcl_ResetResult(interp); 00537 break; 00538 } 00539 } 00540 switch (index) { 00541 case UNLOAD_NOCOMPLAIN: /* -nocomplain */ 00542 complain = 0; 00543 break; 00544 case UNLOAD_KEEPLIB: /* -keeplibrary */ 00545 keepLibrary = 1; 00546 break; 00547 case UNLOAD_LAST: /* -- */ 00548 i++; 00549 goto endOfForLoop; 00550 } 00551 } 00552 endOfForLoop: 00553 if ((objc-i < 1) || (objc-i > 3)) { 00554 Tcl_WrongNumArgs(interp, 1, objv, 00555 "?switches? fileName ?packageName? ?interp?"); 00556 return TCL_ERROR; 00557 } 00558 if (Tcl_FSConvertToPathType(interp, objv[i]) != TCL_OK) { 00559 return TCL_ERROR; 00560 } 00561 00562 fullFileName = Tcl_GetString(objv[i]); 00563 Tcl_DStringInit(&pkgName); 00564 Tcl_DStringInit(&tmp); 00565 00566 packageName = NULL; 00567 if (objc - i >= 2) { 00568 packageName = Tcl_GetString(objv[i+1]); 00569 if (packageName[0] == '\0') { 00570 packageName = NULL; 00571 } 00572 } 00573 if ((fullFileName[0] == 0) && (packageName == NULL)) { 00574 Tcl_SetResult(interp, 00575 "must specify either file name or package name", 00576 TCL_STATIC); 00577 code = TCL_ERROR; 00578 goto done; 00579 } 00580 00581 /* 00582 * Figure out which interpreter we're going to load the package into. 00583 */ 00584 00585 target = interp; 00586 if (objc - i == 3) { 00587 char *slaveIntName; 00588 slaveIntName = Tcl_GetString(objv[i+2]); 00589 target = Tcl_GetSlave(interp, slaveIntName); 00590 if (target == NULL) { 00591 return TCL_ERROR; 00592 } 00593 } 00594 00595 /* 00596 * Scan through the packages that are currently loaded to see if the 00597 * package we want is already loaded. We'll use a loaded package if it 00598 * meets any of the following conditions: 00599 * - Its name and file match the once we're looking for. 00600 * - Its file matches, and we weren't given a name. 00601 * - Its name matches, the file name was specified as empty, and there is 00602 * only no statically loaded package with the same name. 00603 */ 00604 00605 Tcl_MutexLock(&packageMutex); 00606 00607 defaultPtr = NULL; 00608 for (pkgPtr = firstPackagePtr; pkgPtr != NULL; pkgPtr = pkgPtr->nextPtr) { 00609 int namesMatch, filesMatch; 00610 00611 if (packageName == NULL) { 00612 namesMatch = 0; 00613 } else { 00614 Tcl_DStringSetLength(&pkgName, 0); 00615 Tcl_DStringAppend(&pkgName, packageName, -1); 00616 Tcl_DStringSetLength(&tmp, 0); 00617 Tcl_DStringAppend(&tmp, pkgPtr->packageName, -1); 00618 Tcl_UtfToLower(Tcl_DStringValue(&pkgName)); 00619 Tcl_UtfToLower(Tcl_DStringValue(&tmp)); 00620 if (strcmp(Tcl_DStringValue(&tmp), 00621 Tcl_DStringValue(&pkgName)) == 0) { 00622 namesMatch = 1; 00623 } else { 00624 namesMatch = 0; 00625 } 00626 } 00627 Tcl_DStringSetLength(&pkgName, 0); 00628 00629 filesMatch = (strcmp(pkgPtr->fileName, fullFileName) == 0); 00630 if (filesMatch && (namesMatch || (packageName == NULL))) { 00631 break; 00632 } 00633 if (namesMatch && (fullFileName[0] == 0)) { 00634 defaultPtr = pkgPtr; 00635 } 00636 if (filesMatch && !namesMatch && (fullFileName[0] != 0)) { 00637 break; 00638 } 00639 } 00640 Tcl_MutexUnlock(&packageMutex); 00641 if (fullFileName[0] == 0) { 00642 /* 00643 * It's an error to try unload a static package. 00644 */ 00645 00646 Tcl_AppendResult(interp, "package \"", packageName, 00647 "\" is loaded statically and cannot be unloaded", NULL); 00648 code = TCL_ERROR; 00649 goto done; 00650 } 00651 if (pkgPtr == NULL) { 00652 /* 00653 * The DLL pointed by the provided filename has never been loaded. 00654 */ 00655 00656 Tcl_AppendResult(interp, "file \"", fullFileName, 00657 "\" has never been loaded", NULL); 00658 code = TCL_ERROR; 00659 goto done; 00660 } 00661 00662 /* 00663 * Scan through the list of packages already loaded in the target 00664 * interpreter. If the package we want is already loaded there, then we 00665 * should proceed with unloading. 00666 */ 00667 00668 code = TCL_ERROR; 00669 if (pkgPtr != NULL) { 00670 ipFirstPtr = (InterpPackage *) Tcl_GetAssocData(target, 00671 "tclLoad", NULL); 00672 for (ipPtr = ipFirstPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { 00673 if (ipPtr->pkgPtr == pkgPtr) { 00674 code = TCL_OK; 00675 break; 00676 } 00677 } 00678 } 00679 if (code != TCL_OK) { 00680 /* 00681 * The package has not been loaded in this interpreter. 00682 */ 00683 00684 Tcl_AppendResult(interp, "file \"", fullFileName, 00685 "\" has never been loaded in this interpreter", NULL); 00686 code = TCL_ERROR; 00687 goto done; 00688 } 00689 00690 /* 00691 * Ensure that the DLL can be unloaded. If it is a trusted interpreter, 00692 * pkgPtr->unloadProc must not be NULL for the DLL to be unloadable. If 00693 * the interpreter is a safe one, pkgPtr->safeUnloadProc must be non-NULL. 00694 */ 00695 00696 if (Tcl_IsSafe(target)) { 00697 if (pkgPtr->safeUnloadProc == NULL) { 00698 Tcl_AppendResult(interp, "file \"", fullFileName, 00699 "\" cannot be unloaded under a safe interpreter", NULL); 00700 code = TCL_ERROR; 00701 goto done; 00702 } 00703 unloadProc = pkgPtr->safeUnloadProc; 00704 } else { 00705 if (pkgPtr->unloadProc == NULL) { 00706 Tcl_AppendResult(interp, "file \"", fullFileName, 00707 "\" cannot be unloaded under a trusted interpreter", NULL); 00708 code = TCL_ERROR; 00709 goto done; 00710 } 00711 unloadProc = pkgPtr->unloadProc; 00712 } 00713 00714 /* 00715 * We are ready to unload the package. First, evaluate the unload 00716 * function. If this fails, we cannot proceed with unload. Also, we must 00717 * specify the proper flag to pass to the unload callback. 00718 * TCL_UNLOAD_DETACH_FROM_INTERPRETER is defined when the callback should 00719 * only remove itself from the interpreter; the library will be unloaded 00720 * in a future call of unload. In case the library will be unloaded just 00721 * after the callback returns, TCL_UNLOAD_DETACH_FROM_PROCESS is passed. 00722 */ 00723 00724 code = TCL_UNLOAD_DETACH_FROM_INTERPRETER; 00725 if (!keepLibrary) { 00726 Tcl_MutexLock(&packageMutex); 00727 trustedRefCount = pkgPtr->interpRefCount; 00728 safeRefCount = pkgPtr->safeInterpRefCount; 00729 Tcl_MutexUnlock(&packageMutex); 00730 00731 if (Tcl_IsSafe(target)) { 00732 --safeRefCount; 00733 } else { 00734 --trustedRefCount; 00735 } 00736 00737 if (safeRefCount <= 0 && trustedRefCount <= 0) { 00738 code = TCL_UNLOAD_DETACH_FROM_PROCESS; 00739 } 00740 } 00741 code = (*unloadProc)(target, code); 00742 if (code != TCL_OK) { 00743 TclTransferResult(target, code, interp); 00744 goto done; 00745 } 00746 00747 /* 00748 * The unload function executed fine. Examine the reference count to see 00749 * if we unload the DLL. 00750 */ 00751 00752 Tcl_MutexLock(&packageMutex); 00753 if (Tcl_IsSafe(target)) { 00754 --pkgPtr->safeInterpRefCount; 00755 00756 /* 00757 * Do not let counter get negative. 00758 */ 00759 00760 if (pkgPtr->safeInterpRefCount < 0) { 00761 pkgPtr->safeInterpRefCount = 0; 00762 } 00763 } else { 00764 --pkgPtr->interpRefCount; 00765 00766 /* 00767 * Do not let counter get negative. 00768 */ 00769 00770 if (pkgPtr->interpRefCount < 0) { 00771 pkgPtr->interpRefCount = 0; 00772 } 00773 } 00774 trustedRefCount = pkgPtr->interpRefCount; 00775 safeRefCount = pkgPtr->safeInterpRefCount; 00776 Tcl_MutexUnlock(&packageMutex); 00777 00778 code = TCL_OK; 00779 if (pkgPtr->safeInterpRefCount <= 0 && pkgPtr->interpRefCount <= 0 00780 && !keepLibrary) { 00781 /* 00782 * Unload the shared library from the application memory... 00783 */ 00784 00785 #if defined(TCL_UNLOAD_DLLS) || defined(__WIN32__) 00786 /* 00787 * Some Unix dlls are poorly behaved - registering things like atexit 00788 * calls that can't be unregistered. If you unload such dlls, you get 00789 * a core on exit because it wants to call a function in the dll after 00790 * it's been unloaded. 00791 */ 00792 00793 if (pkgPtr->fileName[0] != '\0') { 00794 Tcl_FSUnloadFileProc *unLoadProcPtr = pkgPtr->unLoadProcPtr; 00795 00796 if (unLoadProcPtr != NULL) { 00797 Tcl_MutexLock(&packageMutex); 00798 (*unLoadProcPtr)(pkgPtr->loadHandle); 00799 00800 /* 00801 * Remove this library from the loaded library cache. 00802 */ 00803 00804 defaultPtr = pkgPtr; 00805 if (defaultPtr == firstPackagePtr) { 00806 firstPackagePtr = pkgPtr->nextPtr; 00807 } else { 00808 for (pkgPtr = firstPackagePtr; pkgPtr != NULL; 00809 pkgPtr = pkgPtr->nextPtr) { 00810 if (pkgPtr->nextPtr == defaultPtr) { 00811 pkgPtr->nextPtr = defaultPtr->nextPtr; 00812 break; 00813 } 00814 } 00815 } 00816 00817 /* 00818 * Remove this library from the interpreter's library cache. 00819 */ 00820 00821 ipFirstPtr = (InterpPackage *) Tcl_GetAssocData(target, 00822 "tclLoad", NULL); 00823 ipPtr = ipFirstPtr; 00824 if (ipPtr->pkgPtr == defaultPtr) { 00825 ipFirstPtr = ipFirstPtr->nextPtr; 00826 } else { 00827 InterpPackage *ipPrevPtr; 00828 00829 for (ipPrevPtr = ipPtr; ipPtr != NULL; 00830 ipPrevPtr = ipPtr, ipPtr = ipPtr->nextPtr) { 00831 if (ipPtr->pkgPtr == pkgPtr) { 00832 ipPrevPtr->nextPtr = ipPtr->nextPtr; 00833 break; 00834 } 00835 } 00836 } 00837 Tcl_SetAssocData(target, "tclLoad", LoadCleanupProc, 00838 (ClientData) ipFirstPtr); 00839 ckfree(defaultPtr->fileName); 00840 ckfree(defaultPtr->packageName); 00841 ckfree((char *) defaultPtr); 00842 ckfree((char *) ipPtr); 00843 Tcl_MutexUnlock(&packageMutex); 00844 } else { 00845 Tcl_AppendResult(interp, "file \"", fullFileName, 00846 "\" cannot be unloaded: filesystem does not support unloading", 00847 NULL); 00848 code = TCL_ERROR; 00849 } 00850 } 00851 #else 00852 Tcl_AppendResult(interp, "file \"", fullFileName, 00853 "\" cannot be unloaded: unloading disabled", NULL); 00854 code = TCL_ERROR; 00855 #endif 00856 } 00857 00858 done: 00859 Tcl_DStringFree(&pkgName); 00860 Tcl_DStringFree(&tmp); 00861 if (!complain && code!=TCL_OK) { 00862 code = TCL_OK; 00863 Tcl_ResetResult(interp); 00864 } 00865 if (code == TCL_OK) { 00866 #if 0 00867 /* 00868 * Result of [unload] was not documented in TIP#100, so force to be 00869 * the empty string by commenting this out. DKF. 00870 */ 00871 00872 Tcl_Obj *resultObjPtr, *objPtr[2]; 00873 00874 /* 00875 * Our result is the two reference counts. 00876 */ 00877 00878 objPtr[0] = Tcl_NewIntObj(trustedRefCount); 00879 objPtr[1] = Tcl_NewIntObj(safeRefCount); 00880 if (objPtr[0] == NULL || objPtr[1] == NULL) { 00881 if (objPtr[0]) { 00882 Tcl_DecrRefCount(objPtr[0]); 00883 } 00884 if (objPtr[1]) { 00885 Tcl_DecrRefCount(objPtr[1]); 00886 } 00887 } else { 00888 resultObjPtr = Tcl_NewListObj(2, objPtr); 00889 if (resultObjPtr != NULL) { 00890 Tcl_SetObjResult(interp, resultObjPtr); 00891 } 00892 } 00893 #endif 00894 } 00895 return code; 00896 } 00897 00898 /* 00899 *---------------------------------------------------------------------- 00900 * 00901 * Tcl_StaticPackage -- 00902 * 00903 * This function is invoked to indicate that a particular package has 00904 * been linked statically with an application. 00905 * 00906 * Results: 00907 * None. 00908 * 00909 * Side effects: 00910 * Once this function completes, the package becomes loadable via the 00911 * "load" command with an empty file name. 00912 * 00913 *---------------------------------------------------------------------- 00914 */ 00915 00916 void 00917 Tcl_StaticPackage( 00918 Tcl_Interp *interp, /* If not NULL, it means that the package has 00919 * already been loaded into the given 00920 * interpreter by calling the appropriate init 00921 * proc. */ 00922 const char *pkgName, /* Name of package (must be properly 00923 * capitalized: first letter upper case, 00924 * others lower case). */ 00925 Tcl_PackageInitProc *initProc, 00926 /* Function to call to incorporate this 00927 * package into a trusted interpreter. */ 00928 Tcl_PackageInitProc *safeInitProc) 00929 /* Function to call to incorporate this 00930 * package into a safe interpreter (one that 00931 * will execute untrusted scripts). NULL means 00932 * the package can't be used in safe 00933 * interpreters. */ 00934 { 00935 LoadedPackage *pkgPtr; 00936 InterpPackage *ipPtr, *ipFirstPtr; 00937 00938 /* 00939 * Check to see if someone else has already reported this package as 00940 * statically loaded in the process. 00941 */ 00942 00943 Tcl_MutexLock(&packageMutex); 00944 for (pkgPtr = firstPackagePtr; pkgPtr != NULL; pkgPtr = pkgPtr->nextPtr) { 00945 if ((pkgPtr->initProc == initProc) 00946 && (pkgPtr->safeInitProc == safeInitProc) 00947 && (strcmp(pkgPtr->packageName, pkgName) == 0)) { 00948 break; 00949 } 00950 } 00951 Tcl_MutexUnlock(&packageMutex); 00952 00953 /* 00954 * If the package is not yet recorded as being loaded statically, add it 00955 * to the list now. 00956 */ 00957 00958 if ( pkgPtr == NULL ) { 00959 pkgPtr = (LoadedPackage *) ckalloc(sizeof(LoadedPackage)); 00960 pkgPtr->fileName = (char *) ckalloc((unsigned) 1); 00961 pkgPtr->fileName[0] = 0; 00962 pkgPtr->packageName = (char *) 00963 ckalloc((unsigned) (strlen(pkgName) + 1)); 00964 strcpy(pkgPtr->packageName, pkgName); 00965 pkgPtr->loadHandle = NULL; 00966 pkgPtr->initProc = initProc; 00967 pkgPtr->safeInitProc = safeInitProc; 00968 Tcl_MutexLock(&packageMutex); 00969 pkgPtr->nextPtr = firstPackagePtr; 00970 firstPackagePtr = pkgPtr; 00971 Tcl_MutexUnlock(&packageMutex); 00972 } 00973 00974 if (interp != NULL) { 00975 00976 /* 00977 * If we're loading the package into an interpreter, determine whether 00978 * it's already loaded. 00979 */ 00980 00981 ipFirstPtr = (InterpPackage *) Tcl_GetAssocData(interp, 00982 "tclLoad", NULL); 00983 for ( ipPtr = ipFirstPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr ) { 00984 if ( ipPtr->pkgPtr == pkgPtr ) { 00985 return; 00986 } 00987 } 00988 00989 /* 00990 * Package isn't loade in the current interp yet. Mark it as now being 00991 * loaded. 00992 */ 00993 00994 ipPtr = (InterpPackage *) ckalloc(sizeof(InterpPackage)); 00995 ipPtr->pkgPtr = pkgPtr; 00996 ipPtr->nextPtr = ipFirstPtr; 00997 Tcl_SetAssocData(interp, "tclLoad", LoadCleanupProc, 00998 (ClientData) ipPtr); 00999 } 01000 } 01001 01002 /* 01003 *---------------------------------------------------------------------- 01004 * 01005 * TclGetLoadedPackages -- 01006 * 01007 * This function returns information about all of the files that are 01008 * loaded (either in a particular intepreter, or for all interpreters). 01009 * 01010 * Results: 01011 * The return value is a standard Tcl completion code. If successful, a 01012 * list of lists is placed in the interp's result. Each sublist 01013 * corresponds to one loaded file; its first element is the name of the 01014 * file (or an empty string for something that's statically loaded) and 01015 * the second element is the name of the package in that file. 01016 * 01017 * Side effects: 01018 * None. 01019 * 01020 *---------------------------------------------------------------------- 01021 */ 01022 01023 int 01024 TclGetLoadedPackages( 01025 Tcl_Interp *interp, /* Interpreter in which to return information 01026 * or error message. */ 01027 char *targetName) /* Name of target interpreter or NULL. If 01028 * NULL, return info about all interps; 01029 * otherwise, just return info about this 01030 * interpreter. */ 01031 { 01032 Tcl_Interp *target; 01033 LoadedPackage *pkgPtr; 01034 InterpPackage *ipPtr; 01035 const char *prefix; 01036 01037 if (targetName == NULL) { 01038 /* 01039 * Return information about all of the available packages. 01040 */ 01041 01042 prefix = "{"; 01043 Tcl_MutexLock(&packageMutex); 01044 for (pkgPtr = firstPackagePtr; pkgPtr != NULL; 01045 pkgPtr = pkgPtr->nextPtr) { 01046 Tcl_AppendResult(interp, prefix, NULL); 01047 Tcl_AppendElement(interp, pkgPtr->fileName); 01048 Tcl_AppendElement(interp, pkgPtr->packageName); 01049 Tcl_AppendResult(interp, "}", NULL); 01050 prefix = " {"; 01051 } 01052 Tcl_MutexUnlock(&packageMutex); 01053 return TCL_OK; 01054 } 01055 01056 /* 01057 * Return information about only the packages that are loaded in a given 01058 * interpreter. 01059 */ 01060 01061 target = Tcl_GetSlave(interp, targetName); 01062 if (target == NULL) { 01063 return TCL_ERROR; 01064 } 01065 ipPtr = (InterpPackage *) Tcl_GetAssocData(target, "tclLoad", NULL); 01066 prefix = "{"; 01067 for ( ; ipPtr != NULL; ipPtr = ipPtr->nextPtr) { 01068 pkgPtr = ipPtr->pkgPtr; 01069 Tcl_AppendResult(interp, prefix, NULL); 01070 Tcl_AppendElement(interp, pkgPtr->fileName); 01071 Tcl_AppendElement(interp, pkgPtr->packageName); 01072 Tcl_AppendResult(interp, "}", NULL); 01073 prefix = " {"; 01074 } 01075 return TCL_OK; 01076 } 01077 01078 /* 01079 *---------------------------------------------------------------------- 01080 * 01081 * LoadCleanupProc -- 01082 * 01083 * This function is called to delete all of the InterpPackage structures 01084 * for an interpreter when the interpreter is deleted. It gets invoked 01085 * via the Tcl AssocData mechanism. 01086 * 01087 * Results: 01088 * None. 01089 * 01090 * Side effects: 01091 * Storage for all of the InterpPackage functions for interp get deleted. 01092 * 01093 *---------------------------------------------------------------------- 01094 */ 01095 01096 static void 01097 LoadCleanupProc( 01098 ClientData clientData, /* Pointer to first InterpPackage structure 01099 * for interp. */ 01100 Tcl_Interp *interp) /* Interpreter that is being deleted. */ 01101 { 01102 InterpPackage *ipPtr, *nextPtr; 01103 01104 ipPtr = (InterpPackage *) clientData; 01105 while (ipPtr != NULL) { 01106 nextPtr = ipPtr->nextPtr; 01107 ckfree((char *) ipPtr); 01108 ipPtr = nextPtr; 01109 } 01110 } 01111 01112 /* 01113 *---------------------------------------------------------------------- 01114 * 01115 * TclFinalizeLoad -- 01116 * 01117 * This function is invoked just before the application exits. It frees 01118 * all of the LoadedPackage structures. 01119 * 01120 * Results: 01121 * None. 01122 * 01123 * Side effects: 01124 * Memory is freed. 01125 * 01126 *---------------------------------------------------------------------- 01127 */ 01128 01129 void 01130 TclFinalizeLoad(void) 01131 { 01132 LoadedPackage *pkgPtr; 01133 01134 /* 01135 * No synchronization here because there should just be one thread alive 01136 * at this point. Logically, packageMutex should be grabbed at this point, 01137 * but the Mutexes get finalized before the call to this routine. The 01138 * only subsystem left alive at this point is the memory allocator. 01139 */ 01140 01141 while (firstPackagePtr != NULL) { 01142 pkgPtr = firstPackagePtr; 01143 firstPackagePtr = pkgPtr->nextPtr; 01144 01145 #if defined(TCL_UNLOAD_DLLS) || defined(__WIN32__) 01146 /* 01147 * Some Unix dlls are poorly behaved - registering things like atexit 01148 * calls that can't be unregistered. If you unload such dlls, you get 01149 * a core on exit because it wants to call a function in the dll after 01150 * it has been unloaded. 01151 */ 01152 01153 if (pkgPtr->fileName[0] != '\0') { 01154 Tcl_FSUnloadFileProc *unLoadProcPtr = pkgPtr->unLoadProcPtr; 01155 if (unLoadProcPtr != NULL) { 01156 (*unLoadProcPtr)(pkgPtr->loadHandle); 01157 } 01158 } 01159 #endif 01160 01161 ckfree(pkgPtr->fileName); 01162 ckfree(pkgPtr->packageName); 01163 ckfree((char *) pkgPtr); 01164 } 01165 } 01166 01167 /* 01168 * Local Variables: 01169 * mode: c 01170 * c-basic-offset: 4 01171 * fill-column: 78 01172 * End: 01173 */
Generated on Wed Mar 12 12:18:19 2008 by 1.5.1 |