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