tclNamesp.cGo to the documentation of this file.00001 /* 00002 * tclNamesp.c -- 00003 * 00004 * Contains support for namespaces, which provide a separate context of 00005 * commands and global variables. The global :: namespace is the 00006 * traditional Tcl "global" scope. Other namespaces are created as 00007 * children of the global namespace. These other namespaces contain 00008 * special-purpose commands and variables for packages. Also includes the 00009 * TIP#112 ensemble machinery. 00010 * 00011 * Copyright (c) 1993-1997 Lucent Technologies. 00012 * Copyright (c) 1997 Sun Microsystems, Inc. 00013 * Copyright (c) 1998-1999 by Scriptics Corporation. 00014 * Copyright (c) 2002-2005 Donal K. Fellows. 00015 * Copyright (c) 2006 Neil Madden. 00016 * Contributions from Don Porter, NIST, 2007. (not subject to US copyright) 00017 * 00018 * Originally implemented by 00019 * Michael J. McLennan 00020 * Bell Labs Innovations for Lucent Technologies 00021 * mmclennan@lucent.com 00022 * 00023 * See the file "license.terms" for information on usage and redistribution of 00024 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 00025 * 00026 * RCS: @(#) $Id: tclNamesp.c,v 1.161 2007/12/13 15:23:19 dgp Exp $ 00027 */ 00028 00029 #include "tclInt.h" 00030 00031 /* 00032 * Thread-local storage used to avoid having a global lock on data that is not 00033 * limited to a single interpreter. 00034 */ 00035 00036 typedef struct ThreadSpecificData { 00037 long numNsCreated; /* Count of the number of namespaces created 00038 * within the thread. This value is used as a 00039 * unique id for each namespace. Cannot be 00040 * per-interp because the nsId is used to 00041 * distinguish objects which can be passed 00042 * around between interps in the same thread, 00043 * but does not need to be global because 00044 * object internal reps are always per-thread 00045 * anyway. */ 00046 } ThreadSpecificData; 00047 00048 static Tcl_ThreadDataKey dataKey; 00049 00050 /* 00051 * This structure contains a cached pointer to a namespace that is the result 00052 * of resolving the namespace's name in some other namespace. It is the 00053 * internal representation for a nsName object. It contains the pointer along 00054 * with some information that is used to check the cached pointer's validity. 00055 */ 00056 00057 typedef struct ResolvedNsName { 00058 Namespace *nsPtr; /* A cached pointer to the Namespace that the 00059 * name resolved to. */ 00060 Namespace *refNsPtr; /* Points to the namespace context in which the 00061 * name was resolved. NULL if the name is fully 00062 * qualified and thus the resolution does not 00063 * depend on the context. */ 00064 int refCount; /* Reference count: 1 for each nsName object 00065 * that has a pointer to this ResolvedNsName 00066 * structure as its internal rep. This 00067 * structure can be freed when refCount 00068 * becomes zero. */ 00069 } ResolvedNsName; 00070 00071 /* 00072 * The client data for an ensemble command. This consists of the table of 00073 * commands that are actually exported by the namespace, and an epoch counter 00074 * that, combined with the exportLookupEpoch field of the namespace structure, 00075 * defines whether the table contains valid data or will need to be recomputed 00076 * next time the ensemble command is called. 00077 */ 00078 00079 typedef struct EnsembleConfig { 00080 Namespace *nsPtr; /* The namspace backing this ensemble up. */ 00081 Tcl_Command token; /* The token for the command that provides 00082 * ensemble support for the namespace, or NULL 00083 * if the command has been deleted (or never 00084 * existed; the global namespace never has an 00085 * ensemble command.) */ 00086 int epoch; /* The epoch at which this ensemble's table of 00087 * exported commands is valid. */ 00088 char **subcommandArrayPtr; /* Array of ensemble subcommand names. At all 00089 * consistent points, this will have the same 00090 * number of entries as there are entries in 00091 * the subcommandTable hash. */ 00092 Tcl_HashTable subcommandTable; 00093 /* Hash table of ensemble subcommand names, 00094 * which are its keys so this also provides 00095 * the storage management for those subcommand 00096 * names. The contents of the entry values are 00097 * object version the prefix lists to use when 00098 * substituting for the command/subcommand to 00099 * build the ensemble implementation command. 00100 * Has to be stored here as well as in 00101 * subcommandDict because that field is NULL 00102 * when we are deriving the ensemble from the 00103 * namespace exports list. FUTURE WORK: use 00104 * object hash table here. */ 00105 struct EnsembleConfig *next;/* The next ensemble in the linked list of 00106 * ensembles associated with a namespace. If 00107 * this field points to this ensemble, the 00108 * structure has already been unlinked from 00109 * all lists, and cannot be found by scanning 00110 * the list from the namespace's ensemble 00111 * field. */ 00112 int flags; /* ORed combo of TCL_ENSEMBLE_PREFIX, ENS_DEAD 00113 * and ENSEMBLE_COMPILE. */ 00114 00115 /* OBJECT FIELDS FOR ENSEMBLE CONFIGURATION */ 00116 00117 Tcl_Obj *subcommandDict; /* Dictionary providing mapping from 00118 * subcommands to their implementing command 00119 * prefixes, or NULL if we are to build the 00120 * map automatically from the namespace 00121 * exports. */ 00122 Tcl_Obj *subcmdList; /* List of commands that this ensemble 00123 * actually provides, and whose implementation 00124 * will be built using the subcommandDict (if 00125 * present and defined) and by simple mapping 00126 * to the namespace otherwise. If NULL, 00127 * indicates that we are using the (dynamic) 00128 * list of currently exported commands. */ 00129 Tcl_Obj *unknownHandler; /* Script prefix used to handle the case when 00130 * no match is found (according to the rule 00131 * defined by flag bit TCL_ENSEMBLE_PREFIX) or 00132 * NULL to use the default error-generating 00133 * behaviour. The script execution gets all 00134 * the arguments to the ensemble command 00135 * (including objv[0]) and will have the 00136 * results passed directly back to the caller 00137 * (including the error code) unless the code 00138 * is TCL_CONTINUE in which case the 00139 * subcommand will be reparsed by the ensemble 00140 * core, presumably because the ensemble 00141 * itself has been updated. */ 00142 } EnsembleConfig; 00143 00144 #define ENS_DEAD 0x1 /* Flag value to say that the ensemble is dead 00145 * and on its way out. */ 00146 00147 /* 00148 * Declarations for functions local to this file: 00149 */ 00150 00151 static void DeleteImportedCmd(ClientData clientData); 00152 static int DoImport(Tcl_Interp *interp, 00153 Namespace *nsPtr, Tcl_HashEntry *hPtr, 00154 const char *cmdName, const char *pattern, 00155 Namespace *importNsPtr, int allowOverwrite); 00156 static void DupNsNameInternalRep(Tcl_Obj *objPtr,Tcl_Obj *copyPtr); 00157 static char * ErrorCodeRead(ClientData clientData,Tcl_Interp *interp, 00158 const char *name1, const char *name2, int flags); 00159 static char * ErrorInfoRead(ClientData clientData,Tcl_Interp *interp, 00160 const char *name1, const char *name2, int flags); 00161 static char * EstablishErrorCodeTraces(ClientData clientData, 00162 Tcl_Interp *interp, const char *name1, 00163 const char *name2, int flags); 00164 static char * EstablishErrorInfoTraces(ClientData clientData, 00165 Tcl_Interp *interp, const char *name1, 00166 const char *name2, int flags); 00167 static void FreeNsNameInternalRep(Tcl_Obj *objPtr); 00168 static int GetNamespaceFromObj(Tcl_Interp *interp, 00169 Tcl_Obj *objPtr, Tcl_Namespace **nsPtrPtr); 00170 static int InvokeImportedCmd(ClientData clientData, 00171 Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]); 00172 static int NamespaceChildrenCmd(ClientData dummy, 00173 Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]); 00174 static int NamespaceCodeCmd(ClientData dummy, Tcl_Interp *interp, 00175 int objc, Tcl_Obj *const objv[]); 00176 static int NamespaceCurrentCmd(ClientData dummy, 00177 Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]); 00178 static int NamespaceDeleteCmd(ClientData dummy,Tcl_Interp *interp, 00179 int objc, Tcl_Obj *const objv[]); 00180 static int NamespaceEnsembleCmd(ClientData dummy, 00181 Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]); 00182 static int NamespaceEvalCmd(ClientData dummy, Tcl_Interp *interp, 00183 int objc, Tcl_Obj *const objv[]); 00184 static int NamespaceExistsCmd(ClientData dummy,Tcl_Interp *interp, 00185 int objc, Tcl_Obj *const objv[]); 00186 static int NamespaceExportCmd(ClientData dummy,Tcl_Interp *interp, 00187 int objc, Tcl_Obj *const objv[]); 00188 static int NamespaceForgetCmd(ClientData dummy,Tcl_Interp *interp, 00189 int objc, Tcl_Obj *const objv[]); 00190 static void NamespaceFree(Namespace *nsPtr); 00191 static int NamespaceImportCmd(ClientData dummy,Tcl_Interp *interp, 00192 int objc, Tcl_Obj *const objv[]); 00193 static int NamespaceInscopeCmd(ClientData dummy, 00194 Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]); 00195 static int NamespaceOriginCmd(ClientData dummy,Tcl_Interp *interp, 00196 int objc, Tcl_Obj *const objv[]); 00197 static int NamespaceParentCmd(ClientData dummy,Tcl_Interp *interp, 00198 int objc, Tcl_Obj *const objv[]); 00199 static int NamespacePathCmd(ClientData dummy, Tcl_Interp *interp, 00200 int objc, Tcl_Obj *const objv[]); 00201 static int NamespaceQualifiersCmd(ClientData dummy, 00202 Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]); 00203 static int NamespaceTailCmd(ClientData dummy, Tcl_Interp *interp, 00204 int objc, Tcl_Obj *const objv[]); 00205 static int NamespaceUpvarCmd(ClientData dummy, Tcl_Interp *interp, 00206 int objc, Tcl_Obj *const objv[]); 00207 static int NamespaceUnknownCmd(ClientData dummy, 00208 Tcl_Interp *interp, int objc, 00209 Tcl_Obj *const objv[]); 00210 static int NamespaceWhichCmd(ClientData dummy, Tcl_Interp *interp, 00211 int objc, Tcl_Obj *const objv[]); 00212 static int SetNsNameFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr); 00213 static int NsEnsembleImplementationCmd(ClientData clientData, 00214 Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]); 00215 static void BuildEnsembleConfig(EnsembleConfig *ensemblePtr); 00216 static int NsEnsembleStringOrder(const void *strPtr1, 00217 const void *strPtr2); 00218 static void DeleteEnsembleConfig(ClientData clientData); 00219 static void MakeCachedEnsembleCommand(Tcl_Obj *objPtr, 00220 EnsembleConfig *ensemblePtr, 00221 const char *subcmdName, Tcl_Obj *prefixObjPtr); 00222 static void FreeEnsembleCmdRep(Tcl_Obj *objPtr); 00223 static void DupEnsembleCmdRep(Tcl_Obj *objPtr, Tcl_Obj *copyPtr); 00224 static void StringOfEnsembleCmdRep(Tcl_Obj *objPtr); 00225 static void UnlinkNsPath(Namespace *nsPtr); 00226 00227 /* 00228 * This structure defines a Tcl object type that contains a namespace 00229 * reference. It is used in commands that take the name of a namespace as an 00230 * argument. The namespace reference is resolved, and the result in cached in 00231 * the object. 00232 */ 00233 00234 static Tcl_ObjType nsNameType = { 00235 "nsName", /* the type's name */ 00236 FreeNsNameInternalRep, /* freeIntRepProc */ 00237 DupNsNameInternalRep, /* dupIntRepProc */ 00238 NULL, /* updateStringProc */ 00239 SetNsNameFromAny /* setFromAnyProc */ 00240 }; 00241 00242 /* 00243 * This structure defines a Tcl object type that contains a reference to an 00244 * ensemble subcommand (e.g. the "length" in [string length ab]). It is used 00245 * to cache the mapping between the subcommand itself and the real command 00246 * that implements it. 00247 */ 00248 00249 Tcl_ObjType tclEnsembleCmdType = { 00250 "ensembleCommand", /* the type's name */ 00251 FreeEnsembleCmdRep, /* freeIntRepProc */ 00252 DupEnsembleCmdRep, /* dupIntRepProc */ 00253 StringOfEnsembleCmdRep, /* updateStringProc */ 00254 NULL /* setFromAnyProc */ 00255 }; 00256 00257 /* 00258 *---------------------------------------------------------------------- 00259 * 00260 * TclInitNamespaceSubsystem -- 00261 * 00262 * This function is called to initialize all the structures that are used 00263 * by namespaces on a per-process basis. 00264 * 00265 * Results: 00266 * None. 00267 * 00268 * Side effects: 00269 * None. 00270 * 00271 *---------------------------------------------------------------------- 00272 */ 00273 00274 void 00275 TclInitNamespaceSubsystem(void) 00276 { 00277 /* 00278 * Does nothing for now. 00279 */ 00280 } 00281 00282 /* 00283 *---------------------------------------------------------------------- 00284 * 00285 * Tcl_GetCurrentNamespace -- 00286 * 00287 * Returns a pointer to an interpreter's currently active namespace. 00288 * 00289 * Results: 00290 * Returns a pointer to the interpreter's current namespace. 00291 * 00292 * Side effects: 00293 * None. 00294 * 00295 *---------------------------------------------------------------------- 00296 */ 00297 00298 Tcl_Namespace * 00299 Tcl_GetCurrentNamespace( 00300 register Tcl_Interp *interp)/* Interpreter whose current namespace is 00301 * being queried. */ 00302 { 00303 return TclGetCurrentNamespace(interp); 00304 } 00305 00306 /* 00307 *---------------------------------------------------------------------- 00308 * 00309 * Tcl_GetGlobalNamespace -- 00310 * 00311 * Returns a pointer to an interpreter's global :: namespace. 00312 * 00313 * Results: 00314 * Returns a pointer to the specified interpreter's global namespace. 00315 * 00316 * Side effects: 00317 * None. 00318 * 00319 *---------------------------------------------------------------------- 00320 */ 00321 00322 Tcl_Namespace * 00323 Tcl_GetGlobalNamespace( 00324 register Tcl_Interp *interp)/* Interpreter whose global namespace should 00325 * be returned. */ 00326 { 00327 return TclGetGlobalNamespace(interp); 00328 } 00329 00330 /* 00331 *---------------------------------------------------------------------- 00332 * 00333 * Tcl_PushCallFrame -- 00334 * 00335 * Pushes a new call frame onto the interpreter's Tcl call stack. Called 00336 * when executing a Tcl procedure or a "namespace eval" or "namespace 00337 * inscope" command. 00338 * 00339 * Results: 00340 * Returns TCL_OK if successful, or TCL_ERROR (along with an error 00341 * message in the interpreter's result object) if something goes wrong. 00342 * 00343 * Side effects: 00344 * Modifies the interpreter's Tcl call stack. 00345 * 00346 *---------------------------------------------------------------------- 00347 */ 00348 00349 int 00350 Tcl_PushCallFrame( 00351 Tcl_Interp *interp, /* Interpreter in which the new call frame is 00352 * to be pushed. */ 00353 Tcl_CallFrame *callFramePtr,/* Points to a call frame structure to push. 00354 * Storage for this has already been allocated 00355 * by the caller; typically this is the 00356 * address of a CallFrame structure allocated 00357 * on the caller's C stack. The call frame 00358 * will be initialized by this function. The 00359 * caller can pop the frame later with 00360 * Tcl_PopCallFrame, and it is responsible for 00361 * freeing the frame's storage. */ 00362 Tcl_Namespace *namespacePtr,/* Points to the namespace in which the frame 00363 * will execute. If NULL, the interpreter's 00364 * current namespace will be used. */ 00365 int isProcCallFrame) /* If nonzero, the frame represents a called 00366 * Tcl procedure and may have local vars. Vars 00367 * will ordinarily be looked up in the frame. 00368 * If new variables are created, they will be 00369 * created in the frame. If 0, the frame is 00370 * for a "namespace eval" or "namespace 00371 * inscope" command and var references are 00372 * treated as references to namespace 00373 * variables. */ 00374 { 00375 Interp *iPtr = (Interp *) interp; 00376 register CallFrame *framePtr = (CallFrame *) callFramePtr; 00377 register Namespace *nsPtr; 00378 00379 if (namespacePtr == NULL) { 00380 nsPtr = (Namespace *) TclGetCurrentNamespace(interp); 00381 } else { 00382 nsPtr = (Namespace *) namespacePtr; 00383 00384 /* 00385 * TODO: Examine whether it would be better to guard based on NS_DYING 00386 * or NS_KILLED. It appears that these are not tested because they can 00387 * be set in a global interp that has been [namespace delete]d, but 00388 * which never really completely goes away because of lingering global 00389 * things like ::errorInfo and [::unknown] and hidden commands. 00390 * Review of those designs might permit stricter checking here. 00391 */ 00392 00393 if (nsPtr->flags & NS_DEAD) { 00394 Tcl_Panic("Trying to push call frame for dead namespace"); 00395 /*NOTREACHED*/ 00396 } 00397 } 00398 00399 nsPtr->activationCount++; 00400 framePtr->nsPtr = nsPtr; 00401 framePtr->isProcCallFrame = isProcCallFrame; 00402 framePtr->objc = 0; 00403 framePtr->objv = NULL; 00404 framePtr->callerPtr = iPtr->framePtr; 00405 framePtr->callerVarPtr = iPtr->varFramePtr; 00406 if (iPtr->varFramePtr != NULL) { 00407 framePtr->level = (iPtr->varFramePtr->level + 1); 00408 } else { 00409 framePtr->level = 0; 00410 } 00411 framePtr->procPtr = NULL; /* no called procedure */ 00412 framePtr->varTablePtr = NULL; /* and no local variables */ 00413 framePtr->numCompiledLocals = 0; 00414 framePtr->compiledLocals = NULL; 00415 framePtr->clientData = NULL; 00416 framePtr->localCachePtr = NULL; 00417 00418 /* 00419 * Push the new call frame onto the interpreter's stack of procedure call 00420 * frames making it the current frame. 00421 */ 00422 00423 iPtr->framePtr = framePtr; 00424 iPtr->varFramePtr = framePtr; 00425 return TCL_OK; 00426 } 00427 00428 /* 00429 *---------------------------------------------------------------------- 00430 * 00431 * Tcl_PopCallFrame -- 00432 * 00433 * Removes a call frame from the Tcl call stack for the interpreter. 00434 * Called to remove a frame previously pushed by Tcl_PushCallFrame. 00435 * 00436 * Results: 00437 * None. 00438 * 00439 * Side effects: 00440 * Modifies the call stack of the interpreter. Resets various fields of 00441 * the popped call frame. If a namespace has been deleted and has no more 00442 * activations on the call stack, the namespace is destroyed. 00443 * 00444 *---------------------------------------------------------------------- 00445 */ 00446 00447 void 00448 Tcl_PopCallFrame( 00449 Tcl_Interp *interp) /* Interpreter with call frame to pop. */ 00450 { 00451 register Interp *iPtr = (Interp *) interp; 00452 register CallFrame *framePtr = iPtr->framePtr; 00453 Namespace *nsPtr; 00454 00455 /* 00456 * It's important to remove the call frame from the interpreter's stack of 00457 * call frames before deleting local variables, so that traces invoked by 00458 * the variable deletion don't see the partially-deleted frame. 00459 */ 00460 00461 if (framePtr->callerPtr) { 00462 iPtr->framePtr = framePtr->callerPtr; 00463 iPtr->varFramePtr = framePtr->callerVarPtr; 00464 } else { 00465 /* Tcl_PopCallFrame: trying to pop rootCallFrame! */ 00466 } 00467 00468 if (framePtr->varTablePtr != NULL) { 00469 TclDeleteVars(iPtr, framePtr->varTablePtr); 00470 ckfree((char *) framePtr->varTablePtr); 00471 framePtr->varTablePtr = NULL; 00472 } 00473 if (framePtr->numCompiledLocals > 0) { 00474 TclDeleteCompiledLocalVars(iPtr, framePtr); 00475 if (--framePtr->localCachePtr->refCount == 0) { 00476 TclFreeLocalCache(interp, framePtr->localCachePtr); 00477 } 00478 framePtr->localCachePtr = NULL; 00479 } 00480 00481 /* 00482 * Decrement the namespace's count of active call frames. If the namespace 00483 * is "dying" and there are no more active call frames, call 00484 * Tcl_DeleteNamespace to destroy it. 00485 */ 00486 00487 nsPtr = framePtr->nsPtr; 00488 nsPtr->activationCount--; 00489 if ((nsPtr->flags & NS_DYING) 00490 && (nsPtr->activationCount - (nsPtr == iPtr->globalNsPtr) == 0)) { 00491 Tcl_DeleteNamespace((Tcl_Namespace *) nsPtr); 00492 } 00493 framePtr->nsPtr = NULL; 00494 } 00495 00496 /* 00497 *---------------------------------------------------------------------- 00498 * 00499 * TclPushStackFrame -- 00500 * 00501 * Allocates a new call frame in the interpreter's execution stack, then 00502 * pushes it onto the interpreter's Tcl call stack. Called when executing 00503 * a Tcl procedure or a "namespace eval" or "namespace inscope" command. 00504 * 00505 * Results: 00506 * Returns TCL_OK if successful, or TCL_ERROR (along with an error 00507 * message in the interpreter's result object) if something goes wrong. 00508 * 00509 * Side effects: 00510 * Modifies the interpreter's Tcl call stack. 00511 * 00512 *---------------------------------------------------------------------- 00513 */ 00514 00515 int 00516 TclPushStackFrame( 00517 Tcl_Interp *interp, /* Interpreter in which the new call frame is 00518 * to be pushed. */ 00519 Tcl_CallFrame **framePtrPtr,/* Place to store a pointer to the stack 00520 * allocated call frame. */ 00521 Tcl_Namespace *namespacePtr,/* Points to the namespace in which the frame 00522 * will execute. If NULL, the interpreter's 00523 * current namespace will be used. */ 00524 int isProcCallFrame) /* If nonzero, the frame represents a called 00525 * Tcl procedure and may have local vars. Vars 00526 * will ordinarily be looked up in the frame. 00527 * If new variables are created, they will be 00528 * created in the frame. If 0, the frame is 00529 * for a "namespace eval" or "namespace 00530 * inscope" command and var references are 00531 * treated as references to namespace 00532 * variables. */ 00533 { 00534 *framePtrPtr = (Tcl_CallFrame *) TclStackAlloc(interp, sizeof(CallFrame)); 00535 return Tcl_PushCallFrame(interp, *framePtrPtr, namespacePtr, 00536 isProcCallFrame); 00537 } 00538 00539 void 00540 TclPopStackFrame( 00541 Tcl_Interp *interp) /* Interpreter with call frame to pop. */ 00542 { 00543 CallFrame *freePtr = ((Interp *)interp)->framePtr; 00544 00545 Tcl_PopCallFrame(interp); 00546 TclStackFree(interp, freePtr); 00547 } 00548 00549 /* 00550 *---------------------------------------------------------------------- 00551 * 00552 * EstablishErrorCodeTraces -- 00553 * 00554 * Creates traces on the ::errorCode variable to keep its value 00555 * consistent with the expectations of legacy code. 00556 * 00557 * Results: 00558 * None. 00559 * 00560 * Side effects: 00561 * Read and unset traces are established on ::errorCode. 00562 * 00563 *---------------------------------------------------------------------- 00564 */ 00565 00566 static char * 00567 EstablishErrorCodeTraces( 00568 ClientData clientData, 00569 Tcl_Interp *interp, 00570 const char *name1, 00571 const char *name2, 00572 int flags) 00573 { 00574 Tcl_TraceVar(interp, "errorCode", TCL_GLOBAL_ONLY | TCL_TRACE_READS, 00575 ErrorCodeRead, NULL); 00576 Tcl_TraceVar(interp, "errorCode", TCL_GLOBAL_ONLY | TCL_TRACE_UNSETS, 00577 EstablishErrorCodeTraces, NULL); 00578 return NULL; 00579 } 00580 00581 /* 00582 *---------------------------------------------------------------------- 00583 * 00584 * ErrorCodeRead -- 00585 * 00586 * Called when the ::errorCode variable is read. Copies the current value 00587 * of the interp's errorCode field into ::errorCode. 00588 * 00589 * Results: 00590 * None. 00591 * 00592 * Side effects: 00593 * None. 00594 * 00595 *---------------------------------------------------------------------- 00596 */ 00597 00598 static char * 00599 ErrorCodeRead( 00600 ClientData clientData, 00601 Tcl_Interp *interp, 00602 const char *name1, 00603 const char *name2, 00604 int flags) 00605 { 00606 Interp *iPtr = (Interp *)interp; 00607 00608 if (Tcl_InterpDeleted(interp) || !(iPtr->flags & ERR_LEGACY_COPY)) { 00609 return NULL; 00610 } 00611 if (iPtr->errorCode) { 00612 Tcl_ObjSetVar2(interp, iPtr->ecVar, NULL, 00613 iPtr->errorCode, TCL_GLOBAL_ONLY); 00614 return NULL; 00615 } 00616 if (NULL == Tcl_ObjGetVar2(interp, iPtr->ecVar, NULL, TCL_GLOBAL_ONLY)) { 00617 Tcl_ObjSetVar2(interp, iPtr->ecVar, NULL, 00618 Tcl_NewObj(), TCL_GLOBAL_ONLY); 00619 } 00620 return NULL; 00621 } 00622 00623 /* 00624 *---------------------------------------------------------------------- 00625 * 00626 * EstablishErrorInfoTraces -- 00627 * 00628 * Creates traces on the ::errorInfo variable to keep its value 00629 * consistent with the expectations of legacy code. 00630 * 00631 * Results: 00632 * None. 00633 * 00634 * Side effects: 00635 * Read and unset traces are established on ::errorInfo. 00636 * 00637 *---------------------------------------------------------------------- 00638 */ 00639 00640 static char * 00641 EstablishErrorInfoTraces( 00642 ClientData clientData, 00643 Tcl_Interp *interp, 00644 const char *name1, 00645 const char *name2, 00646 int flags) 00647 { 00648 Tcl_TraceVar(interp, "errorInfo", TCL_GLOBAL_ONLY | TCL_TRACE_READS, 00649 ErrorInfoRead, NULL); 00650 Tcl_TraceVar(interp, "errorInfo", TCL_GLOBAL_ONLY | TCL_TRACE_UNSETS, 00651 EstablishErrorInfoTraces, NULL); 00652 return NULL; 00653 } 00654 00655 /* 00656 *---------------------------------------------------------------------- 00657 * 00658 * ErrorInfoRead -- 00659 * 00660 * Called when the ::errorInfo variable is read. Copies the current value 00661 * of the interp's errorInfo field into ::errorInfo. 00662 * 00663 * Results: 00664 * None. 00665 * 00666 * Side effects: 00667 * None. 00668 * 00669 *---------------------------------------------------------------------- 00670 */ 00671 00672 static char * 00673 ErrorInfoRead( 00674 ClientData clientData, 00675 Tcl_Interp *interp, 00676 const char *name1, 00677 const char *name2, 00678 int flags) 00679 { 00680 Interp *iPtr = (Interp *) interp; 00681 00682 if (Tcl_InterpDeleted(interp) || !(iPtr->flags & ERR_LEGACY_COPY)) { 00683 return NULL; 00684 } 00685 if (iPtr->errorInfo) { 00686 Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL, 00687 iPtr->errorInfo, TCL_GLOBAL_ONLY); 00688 return NULL; 00689 } 00690 if (NULL == Tcl_ObjGetVar2(interp, iPtr->eiVar, NULL, TCL_GLOBAL_ONLY)) { 00691 Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL, 00692 Tcl_NewObj(), TCL_GLOBAL_ONLY); 00693 } 00694 return NULL; 00695 } 00696 00697 /* 00698 *---------------------------------------------------------------------- 00699 * 00700 * Tcl_CreateNamespace -- 00701 * 00702 * Creates a new namespace with the given name. If there is no active 00703 * namespace (i.e., the interpreter is being initialized), the global :: 00704 * namespace is created and returned. 00705 * 00706 * Results: 00707 * Returns a pointer to the new namespace if successful. If the namespace 00708 * already exists or if another error occurs, this routine returns NULL, 00709 * along with an error message in the interpreter's result object. 00710 * 00711 * Side effects: 00712 * If the name contains "::" qualifiers and a parent namespace does not 00713 * already exist, it is automatically created. 00714 * 00715 *---------------------------------------------------------------------- 00716 */ 00717 00718 Tcl_Namespace * 00719 Tcl_CreateNamespace( 00720 Tcl_Interp *interp, /* Interpreter in which a new namespace is 00721 * being created. Also used for error 00722 * reporting. */ 00723 const char *name, /* Name for the new namespace. May be a 00724 * qualified name with names of ancestor 00725 * namespaces separated by "::"s. */ 00726 ClientData clientData, /* One-word value to store with namespace. */ 00727 Tcl_NamespaceDeleteProc *deleteProc) 00728 /* Function called to delete client data when 00729 * the namespace is deleted. NULL if no 00730 * function should be called. */ 00731 { 00732 Interp *iPtr = (Interp *) interp; 00733 register Namespace *nsPtr, *ancestorPtr; 00734 Namespace *parentPtr, *dummy1Ptr, *dummy2Ptr; 00735 Namespace *globalNsPtr = iPtr->globalNsPtr; 00736 const char *simpleName; 00737 Tcl_HashEntry *entryPtr; 00738 Tcl_DString buffer1, buffer2; 00739 Tcl_DString *namePtr, *buffPtr; 00740 int newEntry, nameLen; 00741 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); 00742 00743 /* 00744 * If there is no active namespace, the interpreter is being initialized. 00745 */ 00746 00747 if ((globalNsPtr == NULL) && (iPtr->varFramePtr == NULL)) { 00748 /* 00749 * Treat this namespace as the global namespace, and avoid looking for 00750 * a parent. 00751 */ 00752 00753 parentPtr = NULL; 00754 simpleName = ""; 00755 } else if (*name == '\0') { 00756 Tcl_ResetResult(interp); 00757 Tcl_AppendResult(interp, "can't create namespace \"\": " 00758 "only global namespace can have empty name", NULL); 00759 return NULL; 00760 } else { 00761 /* 00762 * Find the parent for the new namespace. 00763 */ 00764 00765 TclGetNamespaceForQualName(interp, name, NULL, 00766 /*flags*/ (TCL_CREATE_NS_IF_UNKNOWN | TCL_LEAVE_ERR_MSG), 00767 &parentPtr, &dummy1Ptr, &dummy2Ptr, &simpleName); 00768 00769 /* 00770 * If the unqualified name at the end is empty, there were trailing 00771 * "::"s after the namespace's name which we ignore. The new namespace 00772 * was already (recursively) created and is pointed to by parentPtr. 00773 */ 00774 00775 if (*simpleName == '\0') { 00776 return (Tcl_Namespace *) parentPtr; 00777 } 00778 00779 /* 00780 * Check for a bad namespace name and make sure that the name does not 00781 * already exist in the parent namespace. 00782 */ 00783 00784 if (Tcl_FindHashEntry(&parentPtr->childTable, simpleName) != NULL) { 00785 Tcl_AppendResult(interp, "can't create namespace \"", name, 00786 "\": already exists", NULL); 00787 return NULL; 00788 } 00789 } 00790 00791 /* 00792 * Create the new namespace and root it in its parent. Increment the count 00793 * of namespaces created. 00794 */ 00795 00796 nsPtr = (Namespace *) ckalloc(sizeof(Namespace)); 00797 nsPtr->name = ckalloc((unsigned) (strlen(simpleName)+1)); 00798 strcpy(nsPtr->name, simpleName); 00799 nsPtr->fullName = NULL; /* Set below. */ 00800 nsPtr->clientData = clientData; 00801 nsPtr->deleteProc = deleteProc; 00802 nsPtr->parentPtr = parentPtr; 00803 Tcl_InitHashTable(&nsPtr->childTable, TCL_STRING_KEYS); 00804 nsPtr->nsId = ++(tsdPtr->numNsCreated); 00805 nsPtr->interp = interp; 00806 nsPtr->flags = 0; 00807 nsPtr->activationCount = 0; 00808 nsPtr->refCount = 0; 00809 Tcl_InitHashTable(&nsPtr->cmdTable, TCL_STRING_KEYS); 00810 TclInitVarHashTable(&nsPtr->varTable, nsPtr); 00811 nsPtr->exportArrayPtr = NULL; 00812 nsPtr->numExportPatterns = 0; 00813 nsPtr->maxExportPatterns = 0; 00814 nsPtr->cmdRefEpoch = 0; 00815 nsPtr->resolverEpoch = 0; 00816 nsPtr->cmdResProc = NULL; 00817 nsPtr->varResProc = NULL; 00818 nsPtr->compiledVarResProc = NULL; 00819 nsPtr->exportLookupEpoch = 0; 00820 nsPtr->ensembles = NULL; 00821 nsPtr->unknownHandlerPtr = NULL; 00822 nsPtr->commandPathLength = 0; 00823 nsPtr->commandPathArray = NULL; 00824 nsPtr->commandPathSourceList = NULL; 00825 00826 if (parentPtr != NULL) { 00827 entryPtr = Tcl_CreateHashEntry(&parentPtr->childTable, simpleName, 00828 &newEntry); 00829 Tcl_SetHashValue(entryPtr, nsPtr); 00830 } else { 00831 /* 00832 * In the global namespace create traces to maintain the ::errorInfo 00833 * and ::errorCode variables. 00834 */ 00835 00836 iPtr->globalNsPtr = nsPtr; 00837 EstablishErrorInfoTraces(NULL, interp, NULL, NULL, 0); 00838 EstablishErrorCodeTraces(NULL, interp, NULL, NULL, 0); 00839 } 00840 00841 /* 00842 * Build the fully qualified name for this namespace. 00843 */ 00844 00845 Tcl_DStringInit(&buffer1); 00846 Tcl_DStringInit(&buffer2); 00847 namePtr = &buffer1; 00848 buffPtr = &buffer2; 00849 for (ancestorPtr = nsPtr; ancestorPtr != NULL; 00850 ancestorPtr = ancestorPtr->parentPtr) { 00851 if (ancestorPtr != globalNsPtr) { 00852 register Tcl_DString *tempPtr = namePtr; 00853 00854 Tcl_DStringAppend(buffPtr, "::", 2); 00855 Tcl_DStringAppend(buffPtr, ancestorPtr->name, -1); 00856 Tcl_DStringAppend(buffPtr, Tcl_DStringValue(namePtr), 00857 Tcl_DStringLength(namePtr)); 00858 00859 /* 00860 * Clear the unwanted buffer or we end up appending to previous 00861 * results, making the namespace fullNames of nested namespaces 00862 * very wrong (and strange). 00863 */ 00864 00865 Tcl_DStringSetLength(namePtr, 0); 00866 00867 /* 00868 * Now swap the buffer pointers so that we build in the other 00869 * buffer. This is faster than repeated copying back and forth 00870 * between buffers. 00871 */ 00872 00873 namePtr = buffPtr; 00874 buffPtr = tempPtr; 00875 } 00876 } 00877 00878 name = Tcl_DStringValue(namePtr); 00879 nameLen = Tcl_DStringLength(namePtr); 00880 nsPtr->fullName = ckalloc((unsigned) (nameLen+1)); 00881 memcpy(nsPtr->fullName, name, (unsigned) nameLen + 1); 00882 00883 Tcl_DStringFree(&buffer1); 00884 Tcl_DStringFree(&buffer2); 00885 00886 /* 00887 * Return a pointer to the new namespace. 00888 */ 00889 00890 return (Tcl_Namespace *) nsPtr; 00891 } 00892 00893 /* 00894 *---------------------------------------------------------------------- 00895 * 00896 * Tcl_DeleteNamespace -- 00897 * 00898 * Deletes a namespace and all of the commands, variables, and other 00899 * namespaces within it. 00900 * 00901 * Results: 00902 * None. 00903 * 00904 * Side effects: 00905 * When a namespace is deleted, it is automatically removed as a child of 00906 * its parent namespace. Also, all its commands, variables and child 00907 * namespaces are deleted. 00908 * 00909 *---------------------------------------------------------------------- 00910 */ 00911 00912 void 00913 Tcl_DeleteNamespace( 00914 Tcl_Namespace *namespacePtr)/* Points to the namespace to delete. */ 00915 { 00916 register Namespace *nsPtr = (Namespace *) namespacePtr; 00917 Interp *iPtr = (Interp *) nsPtr->interp; 00918 Namespace *globalNsPtr = (Namespace *) 00919 TclGetGlobalNamespace((Tcl_Interp *) iPtr); 00920 Tcl_HashEntry *entryPtr; 00921 00922 /* 00923 * If the namespace has associated ensemble commands, delete them first. 00924 * This leaves the actual contents of the namespace alone (unless they are 00925 * linked ensemble commands, of course). Note that this code is actually 00926 * reentrant so command delete traces won't purturb things badly. 00927 */ 00928 00929 while (nsPtr->ensembles != NULL) { 00930 EnsembleConfig *ensemblePtr = (EnsembleConfig *) nsPtr->ensembles; 00931 00932 /* 00933 * Splice out and link to indicate that we've already been killed. 00934 */ 00935 00936 nsPtr->ensembles = (Tcl_Ensemble *) ensemblePtr->next; 00937 ensemblePtr->next = ensemblePtr; 00938 Tcl_DeleteCommandFromToken(nsPtr->interp, ensemblePtr->token); 00939 } 00940 00941 /* 00942 * If the namespace has a registered unknown handler (TIP 181), then free 00943 * it here. 00944 */ 00945 00946 if (nsPtr->unknownHandlerPtr != NULL) { 00947 Tcl_DecrRefCount(nsPtr->unknownHandlerPtr); 00948 nsPtr->unknownHandlerPtr = NULL; 00949 } 00950 00951 /* 00952 * If the namespace is on the call frame stack, it is marked as "dying" 00953 * (NS_DYING is OR'd into its flags): the namespace can't be looked up by 00954 * name but its commands and variables are still usable by those active 00955 * call frames. When all active call frames referring to the namespace 00956 * have been popped from the Tcl stack, Tcl_PopCallFrame will call this 00957 * function again to delete everything in the namespace. If no nsName 00958 * objects refer to the namespace (i.e., if its refCount is zero), its 00959 * commands and variables are deleted and the storage for its namespace 00960 * structure is freed. Otherwise, if its refCount is nonzero, the 00961 * namespace's commands and variables are deleted but the structure isn't 00962 * freed. Instead, NS_DEAD is OR'd into the structure's flags to allow the 00963 * namespace resolution code to recognize that the namespace is "deleted". 00964 * The structure's storage is freed by FreeNsNameInternalRep when its 00965 * refCount reaches 0. 00966 */ 00967 00968 if (nsPtr->activationCount - (nsPtr == globalNsPtr) > 0) { 00969 nsPtr->flags |= NS_DYING; 00970 if (nsPtr->parentPtr != NULL) { 00971 entryPtr = Tcl_FindHashEntry(&nsPtr->parentPtr->childTable, 00972 nsPtr->name); 00973 if (entryPtr != NULL) { 00974 Tcl_DeleteHashEntry(entryPtr); 00975 } 00976 } 00977 nsPtr->parentPtr = NULL; 00978 } else if (!(nsPtr->flags & NS_KILLED)) { 00979 /* 00980 * Delete the namespace and everything in it. If this is the global 00981 * namespace, then clear it but don't free its storage unless the 00982 * interpreter is being torn down. Set the NS_KILLED flag to avoid 00983 * recursive calls here - if the namespace is really in the process of 00984 * being deleted, ignore any second call. 00985 */ 00986 00987 nsPtr->flags |= (NS_DYING|NS_KILLED); 00988 00989 TclTeardownNamespace(nsPtr); 00990 00991 if ((nsPtr != globalNsPtr) || (iPtr->flags & DELETED)) { 00992 /* 00993 * If this is the global namespace, then it may have residual 00994 * "errorInfo" and "errorCode" variables for errors that occurred 00995 * while it was being torn down. Try to clear the variable list 00996 * one last time. 00997 */ 00998 00999 TclDeleteNamespaceVars(nsPtr); 01000 01001 Tcl_DeleteHashTable(&nsPtr->childTable); 01002 Tcl_DeleteHashTable(&nsPtr->cmdTable); 01003 01004 /* 01005 * If the reference count is 0, then discard the namespace. 01006 * Otherwise, mark it as "dead" so that it can't be used. 01007 */ 01008 01009 if (nsPtr->refCount == 0) { 01010 NamespaceFree(nsPtr); 01011 } else { 01012 nsPtr->flags |= NS_DEAD; 01013 } 01014 } else { 01015 /* 01016 * Restore the ::errorInfo and ::errorCode traces. 01017 */ 01018 01019 EstablishErrorInfoTraces(NULL, nsPtr->interp, NULL, NULL, 0); 01020 EstablishErrorCodeTraces(NULL, nsPtr->interp, NULL, NULL, 0); 01021 01022 /* 01023 * We didn't really kill it, so remove the KILLED marks, so it can 01024 * get killed later, avoiding mem leaks. 01025 */ 01026 01027 nsPtr->flags &= ~(NS_DYING|NS_KILLED); 01028 } 01029 } 01030 } 01031 01032 /* 01033 *---------------------------------------------------------------------- 01034 * 01035 * TclTeardownNamespace -- 01036 * 01037 * Used internally to dismantle and unlink a namespace when it is 01038 * deleted. Divorces the namespace from its parent, and deletes all 01039 * commands, variables, and child namespaces. 01040 * 01041 * This is kept separate from Tcl_DeleteNamespace so that the global 01042 * namespace can be handled specially. 01043 * 01044 * Results: 01045 * None. 01046 * 01047 * Side effects: 01048 * Removes this namespace from its parent's child namespace hashtable. 01049 * Deletes all commands, variables and namespaces in this namespace. 01050 * 01051 *---------------------------------------------------------------------- 01052 */ 01053 01054 void 01055 TclTeardownNamespace( 01056 register Namespace *nsPtr) /* Points to the namespace to be dismantled 01057 * and unlinked from its parent. */ 01058 { 01059 Interp *iPtr = (Interp *) nsPtr->interp; 01060 register Tcl_HashEntry *entryPtr; 01061 Tcl_HashSearch search; 01062 Tcl_Namespace *childNsPtr; 01063 Tcl_Command cmd; 01064 int i; 01065 01066 /* 01067 * Start by destroying the namespace's variable table, since variables 01068 * might trigger traces. Variable table should be cleared but not freed! 01069 * TclDeleteNamespaceVars frees it, so we reinitialize it afterwards. 01070 */ 01071 01072 TclDeleteNamespaceVars(nsPtr); 01073 TclInitVarHashTable(&nsPtr->varTable, nsPtr); 01074 01075 /* 01076 * Delete all commands in this namespace. Be careful when traversing the 01077 * hash table: when each command is deleted, it removes itself from the 01078 * command table. 01079 * 01080 * Don't optimize to Tcl_NextHashEntry() because of traces. 01081 */ 01082 01083 for (entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); 01084 entryPtr != NULL; 01085 entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search)) { 01086 cmd = Tcl_GetHashValue(entryPtr); 01087 Tcl_DeleteCommandFromToken((Tcl_Interp *) iPtr, cmd); 01088 } 01089 Tcl_DeleteHashTable(&nsPtr->cmdTable); 01090 Tcl_InitHashTable(&nsPtr->cmdTable, TCL_STRING_KEYS); 01091 01092 /* 01093 * Remove the namespace from its parent's child hashtable. 01094 */ 01095 01096 if (nsPtr->parentPtr != NULL) { 01097 entryPtr = Tcl_FindHashEntry(&nsPtr->parentPtr->childTable, 01098 nsPtr->name); 01099 if (entryPtr != NULL) { 01100 Tcl_DeleteHashEntry(entryPtr); 01101 } 01102 } 01103 nsPtr->parentPtr = NULL; 01104 01105 /* 01106 * Delete the namespace path if one is installed. 01107 */ 01108 01109 if (nsPtr->commandPathLength != 0) { 01110 UnlinkNsPath(nsPtr); 01111 nsPtr->commandPathLength = 0; 01112 } 01113 if (nsPtr->commandPathSourceList != NULL) { 01114 NamespacePathEntry *nsPathPtr = nsPtr->commandPathSourceList; 01115 do { 01116 if (nsPathPtr->nsPtr != NULL && nsPathPtr->creatorNsPtr != NULL) { 01117 nsPathPtr->creatorNsPtr->cmdRefEpoch++; 01118 } 01119 nsPathPtr->nsPtr = NULL; 01120 nsPathPtr = nsPathPtr->nextPtr; 01121 } while (nsPathPtr != NULL); 01122 nsPtr->commandPathSourceList = NULL; 01123 } 01124 01125 /* 01126 * Delete all the child namespaces. 01127 * 01128 * BE CAREFUL: When each child is deleted, it will divorce itself from its 01129 * parent. You can't traverse a hash table properly if its elements are 01130 * being deleted. We use only the Tcl_FirstHashEntry function to be safe. 01131 * 01132 * Don't optimize to Tcl_NextHashEntry() because of traces. 01133 */ 01134 01135 for (entryPtr = Tcl_FirstHashEntry(&nsPtr->childTable, &search); 01136 entryPtr != NULL; 01137 entryPtr = Tcl_FirstHashEntry(&nsPtr->childTable, &search)) { 01138 childNsPtr = Tcl_GetHashValue(entryPtr); 01139 Tcl_DeleteNamespace(childNsPtr); 01140 } 01141 01142 /* 01143 * Free the namespace's export pattern array. 01144 */ 01145 01146 if (nsPtr->exportArrayPtr != NULL) { 01147 for (i = 0; i < nsPtr->numExportPatterns; i++) { 01148 ckfree(nsPtr->exportArrayPtr[i]); 01149 } 01150 ckfree((char *) nsPtr->exportArrayPtr); 01151 nsPtr->exportArrayPtr = NULL; 01152 nsPtr->numExportPatterns = 0; 01153 nsPtr->maxExportPatterns = 0; 01154 } 01155 01156 /* 01157 * Free any client data associated with the namespace. 01158 */ 01159 01160 if (nsPtr->deleteProc != NULL) { 01161 (*nsPtr->deleteProc)(nsPtr->clientData); 01162 } 01163 nsPtr->deleteProc = NULL; 01164 nsPtr->clientData = NULL; 01165 01166 /* 01167 * Reset the namespace's id field to ensure that this namespace won't be 01168 * interpreted as valid by, e.g., the cache validation code for cached 01169 * command references in Tcl_GetCommandFromObj. 01170 */ 01171 01172 nsPtr->nsId = 0; 01173 } 01174 01175 /* 01176 *---------------------------------------------------------------------- 01177 * 01178 * NamespaceFree -- 01179 * 01180 * Called after a namespace has been deleted, when its reference count 01181 * reaches 0. Frees the data structure representing the namespace. 01182 * 01183 * Results: 01184 * None. 01185 * 01186 * Side effects: 01187 * None. 01188 * 01189 *---------------------------------------------------------------------- 01190 */ 01191 01192 static void 01193 NamespaceFree( 01194 register Namespace *nsPtr) /* Points to the namespace to free. */ 01195 { 01196 /* 01197 * Most of the namespace's contents are freed when the namespace is 01198 * deleted by Tcl_DeleteNamespace. All that remains is to free its names 01199 * (for error messages), and the structure itself. 01200 */ 01201 01202 ckfree(nsPtr->name); 01203 ckfree(nsPtr->fullName); 01204 01205 ckfree((char *) nsPtr); 01206 } 01207 01208 /* 01209 *---------------------------------------------------------------------- 01210 * 01211 * Tcl_Export -- 01212 * 01213 * Makes all the commands matching a pattern available to later be 01214 * imported from the namespace specified by namespacePtr (or the current 01215 * namespace if namespacePtr is NULL). The specified pattern is appended 01216 * onto the namespace's export pattern list, which is optionally cleared 01217 * beforehand. 01218 * 01219 * Results: 01220 * Returns TCL_OK if successful, or TCL_ERROR (along with an error 01221 * message in the interpreter's result) if something goes wrong. 01222 * 01223 * Side effects: 01224 * Appends the export pattern onto the namespace's export list. 01225 * Optionally reset the namespace's export pattern list. 01226 * 01227 *---------------------------------------------------------------------- 01228 */ 01229 01230 int 01231 Tcl_Export( 01232 Tcl_Interp *interp, /* Current interpreter. */ 01233 Tcl_Namespace *namespacePtr,/* Points to the namespace from which commands 01234 * are to be exported. NULL for the current 01235 * namespace. */ 01236 const char *pattern, /* String pattern indicating which commands to 01237 * export. This pattern may not include any 01238 * namespace qualifiers; only commands in the 01239 * specified namespace may be exported. */ 01240 int resetListFirst) /* If nonzero, resets the namespace's export 01241 * list before appending. */ 01242 { 01243 #define INIT_EXPORT_PATTERNS 5 01244 Namespace *nsPtr, *exportNsPtr, *dummyPtr; 01245 Namespace *currNsPtr = (Namespace *) TclGetCurrentNamespace(interp); 01246 const char *simplePattern; 01247 char *patternCpy; 01248 int neededElems, len, i; 01249 01250 /* 01251 * If the specified namespace is NULL, use the current namespace. 01252 */ 01253 01254 if (namespacePtr == NULL) { 01255 nsPtr = (Namespace *) currNsPtr; 01256 } else { 01257 nsPtr = (Namespace *) namespacePtr; 01258 } 01259 01260 /* 01261 * If resetListFirst is true (nonzero), clear the namespace's export 01262 * pattern list. 01263 */ 01264 01265 if (resetListFirst) { 01266 if (nsPtr->exportArrayPtr != NULL) { 01267 for (i = 0; i < nsPtr->numExportPatterns; i++) { 01268 ckfree(nsPtr->exportArrayPtr[i]); 01269 } 01270 ckfree((char *) nsPtr->exportArrayPtr); 01271 nsPtr->exportArrayPtr = NULL; 01272 TclInvalidateNsCmdLookup(nsPtr); 01273 nsPtr->numExportPatterns = 0; 01274 nsPtr->maxExportPatterns = 0; 01275 } 01276 } 01277 01278 /* 01279 * Check that the pattern doesn't have namespace qualifiers. 01280 */ 01281 01282 TclGetNamespaceForQualName(interp, pattern, nsPtr, 01283 /*flags*/ (TCL_LEAVE_ERR_MSG | TCL_NAMESPACE_ONLY), 01284 &exportNsPtr, &dummyPtr, &dummyPtr, &simplePattern); 01285 01286 if ((exportNsPtr != nsPtr) || (strcmp(pattern, simplePattern) != 0)) { 01287 Tcl_AppendResult(interp, "invalid export pattern \"", pattern, 01288 "\": pattern can't specify a namespace", NULL); 01289 return TCL_ERROR; 01290 } 01291 01292 /* 01293 * Make sure that we don't already have the pattern in the array 01294 */ 01295 01296 if (nsPtr->exportArrayPtr != NULL) { 01297 for (i = 0; i < nsPtr->numExportPatterns; i++) { 01298 if (strcmp(pattern, nsPtr->exportArrayPtr[i]) == 0) { 01299 /* 01300 * The pattern already exists in the list. 01301 */ 01302 01303 return TCL_OK; 01304 } 01305 } 01306 } 01307 01308 /* 01309 * Make sure there is room in the namespace's pattern array for the new 01310 * pattern. 01311 */ 01312 01313 neededElems = nsPtr->numExportPatterns + 1; 01314 if (neededElems > nsPtr->maxExportPatterns) { 01315 nsPtr->maxExportPatterns = nsPtr->maxExportPatterns ? 01316 2 * nsPtr->maxExportPatterns : INIT_EXPORT_PATTERNS; 01317 nsPtr->exportArrayPtr = (char **) 01318 ckrealloc((char *) nsPtr->exportArrayPtr, 01319 sizeof(char *) * nsPtr->maxExportPatterns); 01320 } 01321 01322 /* 01323 * Add the pattern to the namespace's array of export patterns. 01324 */ 01325 01326 len = strlen(pattern); 01327 patternCpy = ckalloc((unsigned) (len + 1)); 01328 memcpy(patternCpy, pattern, (unsigned) len + 1); 01329 01330 nsPtr->exportArrayPtr[nsPtr->numExportPatterns] = patternCpy; 01331 nsPtr->numExportPatterns++; 01332 01333 /* 01334 * The list of commands actually exported from the namespace might have 01335 * changed (probably will have!) However, we do not need to recompute this 01336 * just yet; next time we need the info will be soon enough. 01337 */ 01338 01339 TclInvalidateNsCmdLookup(nsPtr); 01340 01341 return TCL_OK; 01342 #undef INIT_EXPORT_PATTERNS 01343 } 01344 01345 /* 01346 *---------------------------------------------------------------------- 01347 * 01348 * Tcl_AppendExportList -- 01349 * 01350 * Appends onto the argument object the list of export patterns for the 01351 * specified namespace. 01352 * 01353 * Results: 01354 * The return value is normally TCL_OK; in this case the object 01355 * referenced by objPtr has each export pattern appended to it. If an 01356 * error occurs, TCL_ERROR is returned and the interpreter's result holds 01357 * an error message. 01358 * 01359 * Side effects: 01360 * If necessary, the object referenced by objPtr is converted into a list 01361 * object. 01362 * 01363 *---------------------------------------------------------------------- 01364 */ 01365 01366 int 01367 Tcl_AppendExportList( 01368 Tcl_Interp *interp, /* Interpreter used for error reporting. */ 01369 Tcl_Namespace *namespacePtr,/* Points to the namespace whose export 01370 * pattern list is appended onto objPtr. NULL 01371 * for the current namespace. */ 01372 Tcl_Obj *objPtr) /* Points to the Tcl object onto which the 01373 * export pattern list is appended. */ 01374 { 01375 Namespace *nsPtr; 01376 int i, result; 01377 01378 /* 01379 * If the specified namespace is NULL, use the current namespace. 01380 */ 01381 01382 if (namespacePtr == NULL) { 01383 nsPtr = (Namespace *) TclGetCurrentNamespace(interp); 01384 } else { 01385 nsPtr = (Namespace *) namespacePtr; 01386 } 01387 01388 /* 01389 * Append the export pattern list onto objPtr. 01390 */ 01391 01392 for (i = 0; i < nsPtr->numExportPatterns; i++) { 01393 result = Tcl_ListObjAppendElement(interp, objPtr, 01394 Tcl_NewStringObj(nsPtr->exportArrayPtr[i], -1)); 01395 if (result != TCL_OK) { 01396 return result; 01397 } 01398 } 01399 return TCL_OK; 01400 } 01401 01402 /* 01403 *---------------------------------------------------------------------- 01404 * 01405 * Tcl_Import -- 01406 * 01407 * Imports all of the commands matching a pattern into the namespace 01408 * specified by namespacePtr (or the current namespace if contextNsPtr is 01409 * NULL). This is done by creating a new command (the "imported command") 01410 * that points to the real command in its original namespace. 01411 * 01412 * If matching commands are on the autoload path but haven't been loaded 01413 * yet, this command forces them to be loaded, then creates the links to 01414 * them. 01415 * 01416 * Results: 01417 * Returns TCL_OK if successful, or TCL_ERROR (along with an error 01418 * message in the interpreter's result) if something goes wrong. 01419 * 01420 * Side effects: 01421 * Creates new commands in the importing namespace. These indirect calls 01422 * back to the real command and are deleted if the real commands are 01423 * deleted. 01424 * 01425 *---------------------------------------------------------------------- 01426 */ 01427 01428 int 01429 Tcl_Import( 01430 Tcl_Interp *interp, /* Current interpreter. */ 01431 Tcl_Namespace *namespacePtr,/* Points to the namespace into which the 01432 * commands are to be imported. NULL for the 01433 * current namespace. */ 01434 const char *pattern, /* String pattern indicating which commands to 01435 * import. This pattern should be qualified by 01436 * the name of the namespace from which to 01437 * import the command(s). */ 01438 int allowOverwrite) /* If nonzero, allow existing commands to be 01439 * overwritten by imported commands. If 0, 01440 * return an error if an imported cmd 01441 * conflicts with an existing one. */ 01442 { 01443 Namespace *nsPtr, *importNsPtr, *dummyPtr; 01444 const char *simplePattern; 01445 register Tcl_HashEntry *hPtr; 01446 Tcl_HashSearch search; 01447 01448 /* 01449 * If the specified namespace is NULL, use the current namespace. 01450 */ 01451 01452 if (namespacePtr == NULL) { 01453 nsPtr = (Namespace *) TclGetCurrentNamespace(interp); 01454 } else { 01455 nsPtr = (Namespace *) namespacePtr; 01456 } 01457 01458 /* 01459 * First, invoke the "auto_import" command with the pattern being 01460 * imported. This command is part of the Tcl library. It looks for 01461 * imported commands in autoloaded libraries and loads them in. That way, 01462 * they will be found when we try to create links below. 01463 * 01464 * Note that we don't just call Tcl_EvalObjv() directly because we do not 01465 * want absence of the command to be a failure case. 01466 */ 01467 01468 if (Tcl_FindCommand(interp,"auto_import",NULL,TCL_GLOBAL_ONLY) != NULL) { 01469 Tcl_Obj *objv[2]; 01470 int result; 01471 01472 TclNewLiteralStringObj(objv[0], "auto_import"); 01473 objv[1] = Tcl_NewStringObj(pattern, -1); 01474 01475 Tcl_IncrRefCount(objv[0]); 01476 Tcl_IncrRefCount(objv[1]); 01477 result = Tcl_EvalObjv(interp, 2, objv, TCL_GLOBAL_ONLY); 01478 Tcl_DecrRefCount(objv[0]); 01479 Tcl_DecrRefCount(objv[1]); 01480 01481 if (result != TCL_OK) { 01482 return TCL_ERROR; 01483 } 01484 Tcl_ResetResult(interp); 01485 } 01486 01487 /* 01488 * From the pattern, find the namespace from which we are importing and 01489 * get the simple pattern (no namespace qualifiers or ::'s) at the end. 01490 */ 01491 01492 if (strlen(pattern) == 0) { 01493 Tcl_SetObjResult(interp, Tcl_NewStringObj("empty import pattern", -1)); 01494 return TCL_ERROR; 01495 } 01496 TclGetNamespaceForQualName(interp, pattern, nsPtr, 01497 /*flags*/ (TCL_LEAVE_ERR_MSG | TCL_NAMESPACE_ONLY), 01498 &importNsPtr, &dummyPtr, &dummyPtr, &simplePattern); 01499 01500 if (importNsPtr == NULL) { 01501 Tcl_AppendResult(interp, "unknown namespace in import pattern \"", 01502 pattern, "\"", NULL); 01503 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", pattern, NULL); 01504 return TCL_ERROR; 01505 } 01506 if (importNsPtr == nsPtr) { 01507 if (pattern == simplePattern) { 01508 Tcl_AppendResult(interp, 01509 "no namespace specified in import pattern \"", pattern, 01510 "\"", NULL); 01511 } else { 01512 Tcl_AppendResult(interp, "import pattern \"", pattern, 01513 "\" tries to import from namespace \"", 01514 importNsPtr->name, "\" into itself", NULL); 01515 } 01516 return TCL_ERROR; 01517 } 01518 01519 /* 01520 * Scan through the command table in the source namespace and look for 01521 * exported commands that match the string pattern. Create an "imported 01522 * command" in the current namespace for each imported command; these 01523 * commands redirect their invocations to the "real" command. 01524 */ 01525 01526 if ((simplePattern != NULL) && TclMatchIsTrivial(simplePattern)) { 01527 hPtr = Tcl_FindHashEntry(&importNsPtr->cmdTable, simplePattern); 01528 if (hPtr == NULL) { 01529 return TCL_OK; 01530 } 01531 return DoImport(interp, nsPtr, hPtr, simplePattern, pattern, 01532 importNsPtr, allowOverwrite); 01533 } 01534 for (hPtr = Tcl_FirstHashEntry(&importNsPtr->cmdTable, &search); 01535 (hPtr != NULL); hPtr = Tcl_NextHashEntry(&search)) { 01536 char *cmdName = Tcl_GetHashKey(&importNsPtr->cmdTable, hPtr); 01537 if (Tcl_StringMatch(cmdName, simplePattern) && 01538 DoImport(interp, nsPtr, hPtr, cmdName, pattern, importNsPtr, 01539 allowOverwrite) == TCL_ERROR) { 01540 return TCL_ERROR; 01541 } 01542 } 01543 return TCL_OK; 01544 } 01545 01546 /* 01547 *---------------------------------------------------------------------- 01548 * 01549 * DoImport -- 01550 * 01551 * Import a particular command from one namespace into another. Helper 01552 * for Tcl_Import(). 01553 * 01554 * Results: 01555 * Standard Tcl result code. If TCL_ERROR, appends an error message to 01556 * the interpreter result. 01557 * 01558 * Side effects: 01559 * A new command is created in the target namespace unless this is a 01560 * reimport of exactly the same command as before. 01561 * 01562 *---------------------------------------------------------------------- 01563 */ 01564 01565 static int 01566 DoImport( 01567 Tcl_Interp *interp, 01568 Namespace *nsPtr, 01569 Tcl_HashEntry *hPtr, 01570 const char *cmdName, 01571 const char *pattern, 01572 Namespace *importNsPtr, 01573 int allowOverwrite) 01574 { 01575 int i = 0, exported = 0; 01576 Tcl_HashEntry *found; 01577 01578 /* 01579 * The command cmdName in the source namespace matches the pattern. Check 01580 * whether it was exported. If it wasn't, we ignore it. 01581 */ 01582 01583 while (!exported && (i < importNsPtr->numExportPatterns)) { 01584 exported |= Tcl_StringMatch(cmdName, importNsPtr->exportArrayPtr[i++]); 01585 } 01586 if (!exported) { 01587 return TCL_OK; 01588 } 01589 01590 /* 01591 * Unless there is a name clash, create an imported command in the current 01592 * namespace that refers to cmdPtr. 01593 */ 01594 01595 found = Tcl_FindHashEntry(&nsPtr->cmdTable, cmdName); 01596 if ((found == NULL) || allowOverwrite) { 01597 /* 01598 * Create the imported command and its client data. To create the new 01599 * command in the current namespace, generate a fully qualified name 01600 * for it. 01601 */ 01602 01603 Tcl_DString ds; 01604 Tcl_Command importedCmd; 01605 ImportedCmdData *dataPtr; 01606 Command *cmdPtr; 01607 ImportRef *refPtr; 01608 01609 Tcl_DStringInit(&ds); 01610 Tcl_DStringAppend(&ds, nsPtr->fullName, -1); 01611 if (nsPtr != ((Interp *) interp)->globalNsPtr) { 01612 Tcl_DStringAppend(&ds, "::", 2); 01613 } 01614 Tcl_DStringAppend(&ds, cmdName, -1); 01615 01616 /* 01617 * Check whether creating the new imported command in the current 01618 * namespace would create a cycle of imported command references. 01619 */ 01620 01621 cmdPtr = Tcl_GetHashValue(hPtr); 01622 if (found != NULL && cmdPtr->deleteProc == DeleteImportedCmd) { 01623 Command *overwrite = Tcl_GetHashValue(found); 01624 Command *link = cmdPtr; 01625 01626 while (link->deleteProc == DeleteImportedCmd) { 01627 ImportedCmdData *dataPtr = link->objClientData; 01628 01629 link = dataPtr->realCmdPtr; 01630 if (overwrite == link) { 01631 Tcl_AppendResult(interp, "import pattern \"", pattern, 01632 "\" would create a loop containing command \"", 01633 Tcl_DStringValue(&ds), "\"", NULL); 01634 Tcl_DStringFree(&ds); 01635 return TCL_ERROR; 01636 } 01637 } 01638 } 01639 01640 dataPtr = (ImportedCmdData *) ckalloc(sizeof(ImportedCmdData)); 01641 importedCmd = Tcl_CreateObjCommand(interp, Tcl_DStringValue(&ds), 01642 InvokeImportedCmd, dataPtr, DeleteImportedCmd); 01643 dataPtr->realCmdPtr = cmdPtr; 01644 dataPtr->selfPtr = (Command *) importedCmd; 01645 dataPtr->selfPtr->compileProc = cmdPtr->compileProc; 01646 Tcl_DStringFree(&ds); 01647 01648 /* 01649 * Create an ImportRef structure describing this new import command 01650 * and add it to the import ref list in the "real" command. 01651 */ 01652 01653 refPtr = (ImportRef *) ckalloc(sizeof(ImportRef)); 01654 refPtr->importedCmdPtr = (Command *) importedCmd; 01655 refPtr->nextPtr = cmdPtr->importRefPtr; 01656 cmdPtr->importRefPtr = refPtr; 01657 } else { 01658 Command *overwrite = Tcl_GetHashValue(found); 01659 01660 if (overwrite->deleteProc == DeleteImportedCmd) { 01661 ImportedCmdData *dataPtr = overwrite->objClientData; 01662 01663 if (dataPtr->realCmdPtr == Tcl_GetHashValue(hPtr)) { 01664 /* 01665 * Repeated import of same command is acceptable. 01666 */ 01667 01668 return TCL_OK; 01669 } 01670 } 01671 Tcl_AppendResult(interp, "can't import command \"", cmdName, 01672 "\": already exists", NULL); 01673 return TCL_ERROR; 01674 } 01675 return TCL_OK; 01676 } 01677 01678 /* 01679 *---------------------------------------------------------------------- 01680 * 01681 * Tcl_ForgetImport -- 01682 * 01683 * Deletes commands previously imported into the namespace indicated. 01684 * The by namespacePtr, or the current namespace of interp, when 01685 * namespacePtr is NULL. The pattern controls which imported commands are 01686 * deleted. A simple pattern, one without namespace separators, matches 01687 * the current command names of imported commands in the namespace. 01688 * Matching imported commands are deleted. A qualified pattern is 01689 * interpreted as deletion selection on the basis of where the command is 01690 * imported from. The original command and "first link" command for each 01691 * imported command are determined, and they are matched against the 01692 * pattern. A match leads to deletion of the imported command. 01693 * 01694 * Results: 01695 * Returns TCL_ERROR and records an error message in the interp result if 01696 * a namespace qualified pattern refers to a namespace that does not 01697 * exist. Otherwise, returns TCL_OK. 01698 * 01699 * Side effects: 01700 * May delete commands. 01701 * 01702 *---------------------------------------------------------------------- 01703 */ 01704 01705 int 01706 Tcl_ForgetImport( 01707 Tcl_Interp *interp, /* Current interpreter. */ 01708 Tcl_Namespace *namespacePtr,/* Points to the namespace from which 01709 * previously imported commands should be 01710 * removed. NULL for current namespace. */ 01711 const char *pattern) /* String pattern indicating which imported 01712 * commands to remove. */ 01713 { 01714 Namespace *nsPtr, *sourceNsPtr, *dummyPtr; 01715 const char *simplePattern; 01716 char *cmdName; 01717 register Tcl_HashEntry *hPtr; 01718 Tcl_HashSearch search; 01719 01720 /* 01721 * If the specified namespace is NULL, use the current namespace. 01722 */ 01723 01724 if (namespacePtr == NULL) { 01725 nsPtr = (Namespace *) TclGetCurrentNamespace(interp); 01726 } else { 01727 nsPtr = (Namespace *) namespacePtr; 01728 } 01729 01730 /* 01731 * Parse the pattern into its namespace-qualification (if any) and the 01732 * simple pattern. 01733 */ 01734 01735 TclGetNamespaceForQualName(interp, pattern, nsPtr, 01736 /*flags*/ (TCL_LEAVE_ERR_MSG | TCL_NAMESPACE_ONLY), 01737 &sourceNsPtr, &dummyPtr, &dummyPtr, &simplePattern); 01738 01739 if (sourceNsPtr == NULL) { 01740 Tcl_AppendResult(interp, 01741 "unknown namespace in namespace forget pattern \"", 01742 pattern, "\"", NULL); 01743 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", pattern, NULL); 01744 return TCL_ERROR; 01745 } 01746 01747 if (strcmp(pattern, simplePattern) == 0) { 01748 /* 01749 * The pattern is simple. Delete any imported commands that match it. 01750 */ 01751 01752 if (TclMatchIsTrivial(simplePattern)) { 01753 Command *cmdPtr; 01754 01755 hPtr = Tcl_FindHashEntry(&nsPtr->cmdTable, simplePattern); 01756 if ((hPtr != NULL) 01757 && (cmdPtr = Tcl_GetHashValue(hPtr)) 01758 && (cmdPtr->deleteProc == DeleteImportedCmd)) { 01759 Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr); 01760 } 01761 return TCL_OK; 01762 } 01763 for (hPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); 01764 (hPtr != NULL); hPtr = Tcl_NextHashEntry(&search)) { 01765 Command *cmdPtr = Tcl_GetHashValue(hPtr); 01766 01767 if (cmdPtr->deleteProc != DeleteImportedCmd) { 01768 continue; 01769 } 01770 cmdName = Tcl_GetHashKey(&nsPtr->cmdTable, hPtr); 01771 if (Tcl_StringMatch(cmdName, simplePattern)) { 01772 Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr); 01773 } 01774 } 01775 return TCL_OK; 01776 } 01777 01778 /* 01779 * The pattern was namespace-qualified. 01780 */ 01781 01782 for (hPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); (hPtr != NULL); 01783 hPtr = Tcl_NextHashEntry(&search)) { 01784 Tcl_CmdInfo info; 01785 Tcl_Command token = Tcl_GetHashValue(hPtr); 01786 Tcl_Command origin = TclGetOriginalCommand(token); 01787 01788 if (Tcl_GetCommandInfoFromToken(origin, &info) == 0) { 01789 continue; /* Not an imported command. */ 01790 } 01791 if (info.namespacePtr != (Tcl_Namespace *) sourceNsPtr) { 01792 /* 01793 * Original not in namespace we're matching. Check the first link 01794 * in the import chain. 01795 */ 01796 01797 Command *cmdPtr = (Command *) token; 01798 ImportedCmdData *dataPtr = cmdPtr->objClientData; 01799 Tcl_Command firstToken = (Tcl_Command) dataPtr->realCmdPtr; 01800 01801 if (firstToken == origin) { 01802 continue; 01803 } 01804 Tcl_GetCommandInfoFromToken(firstToken, &info); 01805 if (info.namespacePtr != (Tcl_Namespace *) sourceNsPtr) { 01806 continue; 01807 } 01808 origin = firstToken; 01809 } 01810 if (Tcl_StringMatch(Tcl_GetCommandName(NULL, origin), simplePattern)) { 01811 Tcl_DeleteCommandFromToken(interp, token); 01812 } 01813 } 01814 return TCL_OK; 01815 } 01816 01817 /* 01818 *---------------------------------------------------------------------- 01819 * 01820 * TclGetOriginalCommand -- 01821 * 01822 * An imported command is created in an namespace when a "real" command 01823 * is imported from another namespace. If the specified command is an 01824 * imported command, this function returns the original command it refers 01825 * to. 01826 * 01827 * Results: 01828 * If the command was imported into a sequence of namespaces a, b,...,n 01829 * where each successive namespace just imports the command from the 01830 * previous namespace, this function returns the Tcl_Command token in the 01831 * first namespace, a. Otherwise, if the specified command is not an 01832 * imported command, the function returns NULL. 01833 * 01834 * Side effects: 01835 * None. 01836 * 01837 *---------------------------------------------------------------------- 01838 */ 01839 01840 Tcl_Command 01841 TclGetOriginalCommand( 01842 Tcl_Command command) /* The imported command for which the original 01843 * command should be returned. */ 01844 { 01845 register Command *cmdPtr = (Command *) command; 01846 ImportedCmdData *dataPtr; 01847 01848 if (cmdPtr->deleteProc != DeleteImportedCmd) { 01849 return NULL; 01850 } 01851 01852 while (cmdPtr->deleteProc == DeleteImportedCmd) { 01853 dataPtr = cmdPtr->objClientData; 01854 cmdPtr = dataPtr->realCmdPtr; 01855 } 01856 return (Tcl_Command) cmdPtr; 01857 } 01858 01859 /* 01860 *---------------------------------------------------------------------- 01861 * 01862 * InvokeImportedCmd -- 01863 * 01864 * Invoked by Tcl whenever the user calls an imported command that was 01865 * created by Tcl_Import. Finds the "real" command (in another 01866 * namespace), and passes control to it. 01867 * 01868 * Results: 01869 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 01870 * 01871 * Side effects: 01872 * Returns a result in the interpreter's result object. If anything goes 01873 * wrong, the result object is set to an error message. 01874 * 01875 *---------------------------------------------------------------------- 01876 */ 01877 01878 static int 01879 InvokeImportedCmd( 01880 ClientData clientData, /* Points to the imported command's 01881 * ImportedCmdData structure. */ 01882 Tcl_Interp *interp, /* Current interpreter. */ 01883 int objc, /* Number of arguments. */ 01884 Tcl_Obj *const objv[]) /* The argument objects. */ 01885 { 01886 register ImportedCmdData *dataPtr = clientData; 01887 register Command *realCmdPtr = dataPtr->realCmdPtr; 01888 01889 return (*realCmdPtr->objProc)(realCmdPtr->objClientData, interp, 01890 objc, objv); 01891 } 01892 01893 /* 01894 *---------------------------------------------------------------------- 01895 * 01896 * DeleteImportedCmd -- 01897 * 01898 * Invoked by Tcl whenever an imported command is deleted. The "real" 01899 * command keeps a list of all the imported commands that refer to it, so 01900 * those imported commands can be deleted when the real command is 01901 * deleted. This function removes the imported command reference from the 01902 * real command's list, and frees up the memory associated with the 01903 * imported command. 01904 * 01905 * Results: 01906 * None. 01907 * 01908 * Side effects: 01909 * Removes the imported command from the real command's import list. 01910 * 01911 *---------------------------------------------------------------------- 01912 */ 01913 01914 static void 01915 DeleteImportedCmd( 01916 ClientData clientData) /* Points to the imported command's 01917 * ImportedCmdData structure. */ 01918 { 01919 ImportedCmdData *dataPtr = clientData; 01920 Command *realCmdPtr = dataPtr->realCmdPtr; 01921 Command *selfPtr = dataPtr->selfPtr; 01922 register ImportRef *refPtr, *prevPtr; 01923 01924 prevPtr = NULL; 01925 for (refPtr = realCmdPtr->importRefPtr; refPtr != NULL; 01926 refPtr = refPtr->nextPtr) { 01927 if (refPtr->importedCmdPtr == selfPtr) { 01928 /* 01929 * Remove *refPtr from real command's list of imported commands 01930 * that refer to it. 01931 */ 01932 01933 if (prevPtr == NULL) { /* refPtr is first in list. */ 01934 realCmdPtr->importRefPtr = refPtr->nextPtr; 01935 } else { 01936 prevPtr->nextPtr = refPtr->nextPtr; 01937 } 01938 ckfree((char *) refPtr); 01939 ckfree((char *) dataPtr); 01940 return; 01941 } 01942 prevPtr = refPtr; 01943 } 01944 01945 Tcl_Panic("DeleteImportedCmd: did not find cmd in real cmd's list of import references"); 01946 } 01947 01948 /* 01949 *---------------------------------------------------------------------- 01950 * 01951 * TclGetNamespaceForQualName -- 01952 * 01953 * Given a qualified name specifying a command, variable, or namespace, 01954 * and a namespace in which to resolve the name, this function returns a 01955 * pointer to the namespace that contains the item. A qualified name 01956 * consists of the "simple" name of an item qualified by the names of an 01957 * arbitrary number of containing namespace separated by "::"s. If the 01958 * qualified name starts with "::", it is interpreted absolutely from the 01959 * global namespace. Otherwise, it is interpreted relative to the 01960 * namespace specified by cxtNsPtr if it is non-NULL. If cxtNsPtr is 01961 * NULL, the name is interpreted relative to the current namespace. 01962 * 01963 * A relative name like "foo::bar::x" can be found starting in either the 01964 * current namespace or in the global namespace. So each search usually 01965 * follows two tracks, and two possible namespaces are returned. If the 01966 * function sets either *nsPtrPtr or *altNsPtrPtr to NULL, then that path 01967 * failed. 01968 * 01969 * If "flags" contains TCL_GLOBAL_ONLY, the relative qualified name is 01970 * sought only in the global :: namespace. The alternate search (also) 01971 * starting from the global namespace is ignored and *altNsPtrPtr is set 01972 * NULL. 01973 * 01974 * If "flags" contains TCL_NAMESPACE_ONLY, the relative qualified name is 01975 * sought only in the namespace specified by cxtNsPtr. The alternate 01976 * search starting from the global namespace is ignored and *altNsPtrPtr 01977 * is set NULL. If both TCL_GLOBAL_ONLY and TCL_NAMESPACE_ONLY are 01978 * specified, TCL_GLOBAL_ONLY is ignored and the search starts from the 01979 * namespace specified by cxtNsPtr. 01980 * 01981 * If "flags" contains TCL_CREATE_NS_IF_UNKNOWN, all namespace components 01982 * of the qualified name that cannot be found are automatically created 01983 * within their specified parent. This makes sure that functions like 01984 * Tcl_CreateCommand always succeed. There is no alternate search path, 01985 * so *altNsPtrPtr is set NULL. 01986 * 01987 * If "flags" contains TCL_FIND_ONLY_NS, the qualified name is treated as 01988 * a reference to a namespace, and the entire qualified name is followed. 01989 * If the name is relative, the namespace is looked up only in the 01990 * current namespace. A pointer to the namespace is stored in *nsPtrPtr 01991 * and NULL is stored in *simpleNamePtr. Otherwise, if TCL_FIND_ONLY_NS 01992 * is not specified, only the leading components are treated as namespace 01993 * names, and a pointer to the simple name of the final component is 01994 * stored in *simpleNamePtr. 01995 * 01996 * Results: 01997 * It sets *nsPtrPtr and *altNsPtrPtr to point to the two possible 01998 * namespaces which represent the last (containing) namespace in the 01999 * qualified name. If the function sets either *nsPtrPtr or *altNsPtrPtr 02000 * to NULL, then the search along that path failed. The function also 02001 * stores a pointer to the simple name of the final component in 02002 * *simpleNamePtr. If the qualified name is "::" or was treated as a 02003 * namespace reference (TCL_FIND_ONLY_NS), the function stores a pointer 02004 * to the namespace in *nsPtrPtr, NULL in *altNsPtrPtr, and sets 02005 * *simpleNamePtr to point to an empty string. 02006 * 02007 * If there is an error, this function returns TCL_ERROR. If "flags" 02008 * contains TCL_LEAVE_ERR_MSG, an error message is returned in the 02009 * interpreter's result object. Otherwise, the interpreter's result 02010 * object is left unchanged. 02011 * 02012 * *actualCxtPtrPtr is set to the actual context namespace. It is set to 02013 * the input context namespace pointer in cxtNsPtr. If cxtNsPtr is NULL, 02014 * it is set to the current namespace context. 02015 * 02016 * For backwards compatibility with the TclPro byte code loader, this 02017 * function always returns TCL_OK. 02018 * 02019 * Side effects: 02020 * If "flags" contains TCL_CREATE_NS_IF_UNKNOWN, new namespaces may be 02021 * created. 02022 * 02023 *---------------------------------------------------------------------- 02024 */ 02025 02026 int 02027 TclGetNamespaceForQualName( 02028 Tcl_Interp *interp, /* Interpreter in which to find the namespace 02029 * containing qualName. */ 02030 const char *qualName, /* A namespace-qualified name of an command, 02031 * variable, or namespace. */ 02032 Namespace *cxtNsPtr, /* The namespace in which to start the search 02033 * for qualName's namespace. If NULL start 02034 * from the current namespace. Ignored if 02035 * TCL_GLOBAL_ONLY is set. */ 02036 int flags, /* Flags controlling the search: an OR'd 02037 * combination of TCL_GLOBAL_ONLY, 02038 * TCL_NAMESPACE_ONLY, TCL_FIND_ONLY_NS, and 02039 * TCL_CREATE_NS_IF_UNKNOWN. */ 02040 Namespace **nsPtrPtr, /* Address where function stores a pointer to 02041 * containing namespace if qualName is found 02042 * starting from *cxtNsPtr or, if 02043 * TCL_GLOBAL_ONLY is set, if qualName is 02044 * found in the global :: namespace. NULL is 02045 * stored otherwise. */ 02046 Namespace **altNsPtrPtr, /* Address where function stores a pointer to 02047 * containing namespace if qualName is found 02048 * starting from the global :: namespace. 02049 * NULL is stored if qualName isn't found 02050 * starting from :: or if the TCL_GLOBAL_ONLY, 02051 * TCL_NAMESPACE_ONLY, TCL_FIND_ONLY_NS, 02052 * TCL_CREATE_NS_IF_UNKNOWN flag is set. */ 02053 Namespace **actualCxtPtrPtr,/* Address where function stores a pointer to 02054 * the actual namespace from which the search 02055 * started. This is either cxtNsPtr, the :: 02056 * namespace if TCL_GLOBAL_ONLY was specified, 02057 * or the current namespace if cxtNsPtr was 02058 * NULL. */ 02059 const char **simpleNamePtr) /* Address where function stores the simple 02060 * name at end of the qualName, or NULL if 02061 * qualName is "::" or the flag 02062 * TCL_FIND_ONLY_NS was specified. */ 02063 { 02064 Interp *iPtr = (Interp *) interp; 02065 Namespace *nsPtr = cxtNsPtr; 02066 Namespace *altNsPtr; 02067 Namespace *globalNsPtr = iPtr->globalNsPtr; 02068 const char *start, *end; 02069 const char *nsName; 02070 Tcl_HashEntry *entryPtr; 02071 Tcl_DString buffer; 02072 int len; 02073 02074 /* 02075 * Determine the context namespace nsPtr in which to start the primary 02076 * search. If the qualName name starts with a "::" or TCL_GLOBAL_ONLY was 02077 * specified, search from the global namespace. Otherwise, use the 02078 * namespace given in cxtNsPtr, or if that is NULL, use the current 02079 * namespace context. Note that we always treat two or more adjacent ":"s 02080 * as a namespace separator. 02081 */ 02082 02083 if (flags & TCL_GLOBAL_ONLY) { 02084 nsPtr = globalNsPtr; 02085 } else if (nsPtr == NULL) { 02086 nsPtr = iPtr->varFramePtr->nsPtr; 02087 } 02088 02089 start = qualName; /* Points to start of qualifying 02090 * namespace. */ 02091 if ((*qualName == ':') && (*(qualName+1) == ':')) { 02092 start = qualName+2; /* Skip over the initial :: */ 02093 while (*start == ':') { 02094 start++; /* Skip over a subsequent : */ 02095 } 02096 nsPtr = globalNsPtr; 02097 if (*start == '\0') { /* qualName is just two or more 02098 * ":"s. */ 02099 *nsPtrPtr = globalNsPtr; 02100 *altNsPtrPtr = NULL; 02101 *actualCxtPtrPtr = globalNsPtr; 02102 *simpleNamePtr = start; /* Points to empty string. */ 02103 return TCL_OK; 02104 } 02105 } 02106 *actualCxtPtrPtr = nsPtr; 02107 02108 /* 02109 * Start an alternate search path starting with the global namespace. 02110 * However, if the starting context is the global namespace, or if the 02111 * flag is set to search only the namespace *cxtNsPtr, ignore the 02112 * alternate search path. 02113 */ 02114 02115 altNsPtr = globalNsPtr; 02116 if ((nsPtr == globalNsPtr) 02117 || (flags & (TCL_NAMESPACE_ONLY | TCL_FIND_ONLY_NS))) { 02118 altNsPtr = NULL; 02119 } 02120 02121 /* 02122 * Loop to resolve each namespace qualifier in qualName. 02123 */ 02124 02125 Tcl_DStringInit(&buffer); 02126 end = start; 02127 while (*start != '\0') { 02128 /* 02129 * Find the next namespace qualifier (i.e., a name ending in "::") or 02130 * the end of the qualified name (i.e., a name ending in "\0"). Set 02131 * len to the number of characters, starting from start, in the name; 02132 * set end to point after the "::"s or at the "\0". 02133 */ 02134 02135 len = 0; 02136 for (end = start; *end != '\0'; end++) { 02137 if ((*end == ':') && (*(end+1) == ':')) { 02138 end += 2; /* Skip over the initial :: */ 02139 while (*end == ':') { 02140 end++; /* Skip over the subsequent : */ 02141 } 02142 break; /* Exit for loop; end is after ::'s */ 02143 } 02144 len++; 02145 } 02146 02147 if (*end=='\0' && !(end-start>=2 && *(end-1)==':' && *(end-2)==':')) { 02148 /* 02149 * qualName ended with a simple name at start. If TCL_FIND_ONLY_NS 02150 * was specified, look this up as a namespace. Otherwise, start is 02151 * the name of a cmd or var and we are done. 02152 */ 02153 02154 if (flags & TCL_FIND_ONLY_NS) { 02155 nsName = start; 02156 } else { 02157 *nsPtrPtr = nsPtr; 02158 *altNsPtrPtr = altNsPtr; 02159 *simpleNamePtr = start; 02160 Tcl_DStringFree(&buffer); 02161 return TCL_OK; 02162 } 02163 } else { 02164 /* 02165 * start points to the beginning of a namespace qualifier ending 02166 * in "::". end points to the start of a name in that namespace 02167 * that might be empty. Copy the namespace qualifier to a buffer 02168 * so it can be null terminated. We can't modify the incoming 02169 * qualName since it may be a string constant. 02170 */ 02171 02172 Tcl_DStringSetLength(&buffer, 0); 02173 Tcl_DStringAppend(&buffer, start, len); 02174 nsName = Tcl_DStringValue(&buffer); 02175 } 02176 02177 /* 02178 * Look up the namespace qualifier nsName in the current namespace 02179 * context. If it isn't found but TCL_CREATE_NS_IF_UNKNOWN is set, 02180 * create that qualifying namespace. This is needed for functions like 02181 * Tcl_CreateCommand that cannot fail. 02182 */ 02183 02184 if (nsPtr != NULL) { 02185 entryPtr = Tcl_FindHashEntry(&nsPtr->childTable, nsName); 02186 if (entryPtr != NULL) { 02187 nsPtr = Tcl_GetHashValue(entryPtr); 02188 } else if (flags & TCL_CREATE_NS_IF_UNKNOWN) { 02189 Tcl_CallFrame *framePtr; 02190 02191 (void) TclPushStackFrame(interp, &framePtr, 02192 (Tcl_Namespace *) nsPtr, /*isProcCallFrame*/ 0); 02193 02194 nsPtr = (Namespace *) Tcl_CreateNamespace(interp, nsName, 02195 NULL, NULL); 02196 TclPopStackFrame(interp); 02197 02198 if (nsPtr == NULL) { 02199 Tcl_Panic("Could not create namespace '%s'", nsName); 02200 } 02201 } else { /* Namespace not found and was not 02202 * created. */ 02203 nsPtr = NULL; 02204 } 02205 } 02206 02207 /* 02208 * Look up the namespace qualifier in the alternate search path too. 02209 */ 02210 02211 if (altNsPtr != NULL) { 02212 entryPtr = Tcl_FindHashEntry(&altNsPtr->childTable, nsName); 02213 if (entryPtr != NULL) { 02214 altNsPtr = Tcl_GetHashValue(entryPtr); 02215 } else { 02216 altNsPtr = NULL; 02217 } 02218 } 02219 02220 /* 02221 * If both search paths have failed, return NULL results. 02222 */ 02223 02224 if ((nsPtr == NULL) && (altNsPtr == NULL)) { 02225 *nsPtrPtr = NULL; 02226 *altNsPtrPtr = NULL; 02227 *simpleNamePtr = NULL; 02228 Tcl_DStringFree(&buffer); 02229 return TCL_OK; 02230 } 02231 02232 start = end; 02233 } 02234 02235 /* 02236 * We ignore trailing "::"s in a namespace name, but in a command or 02237 * variable name, trailing "::"s refer to the cmd or var named {}. 02238 */ 02239 02240 if ((flags & TCL_FIND_ONLY_NS) || (end>start && *(end-1)!=':')) { 02241 *simpleNamePtr = NULL; /* Found namespace name. */ 02242 } else { 02243 *simpleNamePtr = end; /* Found cmd/var: points to empty 02244 * string. */ 02245 } 02246 02247 /* 02248 * As a special case, if we are looking for a namespace and qualName is "" 02249 * and the current active namespace (nsPtr) is not the global namespace, 02250 * return NULL (no namespace was found). This is because namespaces can 02251 * not have empty names except for the global namespace. 02252 */ 02253 02254 if ((flags & TCL_FIND_ONLY_NS) && (*qualName == '\0') 02255 && (nsPtr != globalNsPtr)) { 02256 nsPtr = NULL; 02257 } 02258 02259 *nsPtrPtr = nsPtr; 02260 *altNsPtrPtr = altNsPtr; 02261 Tcl_DStringFree(&buffer); 02262 return TCL_OK; 02263 } 02264 02265 /* 02266 *---------------------------------------------------------------------- 02267 * 02268 * Tcl_FindNamespace -- 02269 * 02270 * Searches for a namespace. 02271 * 02272 * Results: 02273 * Returns a pointer to the namespace if it is found. Otherwise, returns 02274 * NULL and leaves an error message in the interpreter's result object if 02275 * "flags" contains TCL_LEAVE_ERR_MSG. 02276 * 02277 * Side effects: 02278 * None. 02279 * 02280 *---------------------------------------------------------------------- 02281 */ 02282 02283 Tcl_Namespace * 02284 Tcl_FindNamespace( 02285 Tcl_Interp *interp, /* The interpreter in which to find the 02286 * namespace. */ 02287 const char *name, /* Namespace name. If it starts with "::", 02288 * will be looked up in global namespace. 02289 * Else, looked up first in contextNsPtr 02290 * (current namespace if contextNsPtr is 02291 * NULL), then in global namespace. */ 02292 Tcl_Namespace *contextNsPtr,/* Ignored if TCL_GLOBAL_ONLY flag is set or 02293 * if the name starts with "::". Otherwise, 02294 * points to namespace in which to resolve 02295 * name; if NULL, look up name in the current 02296 * namespace. */ 02297 register int flags) /* Flags controlling namespace lookup: an OR'd 02298 * combination of TCL_GLOBAL_ONLY and 02299 * TCL_LEAVE_ERR_MSG flags. */ 02300 { 02301 Namespace *nsPtr, *dummy1Ptr, *dummy2Ptr; 02302 const char *dummy; 02303 02304 /* 02305 * Find the namespace(s) that contain the specified namespace name. Add 02306 * the TCL_FIND_ONLY_NS flag to resolve the name all the way down to its 02307 * last component, a namespace. 02308 */ 02309 02310 TclGetNamespaceForQualName(interp, name, (Namespace *) contextNsPtr, 02311 flags|TCL_FIND_ONLY_NS, &nsPtr, &dummy1Ptr, &dummy2Ptr, &dummy); 02312 02313 if (nsPtr != NULL) { 02314 return (Tcl_Namespace *) nsPtr; 02315 } else if (flags & TCL_LEAVE_ERR_MSG) { 02316 Tcl_ResetResult(interp); 02317 Tcl_AppendResult(interp, "unknown namespace \"", name, "\"", NULL); 02318 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", name, NULL); 02319 } 02320 return NULL; 02321 } 02322 02323 /* 02324 *---------------------------------------------------------------------- 02325 * 02326 * Tcl_FindCommand -- 02327 * 02328 * Searches for a command. 02329 * 02330 * Results: 02331 * Returns a token for the command if it is found. Otherwise, if it can't 02332 * be found or there is an error, returns NULL and leaves an error 02333 * message in the interpreter's result object if "flags" contains 02334 * TCL_LEAVE_ERR_MSG. 02335 * 02336 * Side effects: 02337 * None. 02338 * 02339 *---------------------------------------------------------------------- 02340 */ 02341 02342 Tcl_Command 02343 Tcl_FindCommand( 02344 Tcl_Interp *interp, /* The interpreter in which to find the 02345 * command and to report errors. */ 02346 const char *name, /* Command's name. If it starts with "::", 02347 * will be looked up in global namespace. 02348 * Else, looked up first in contextNsPtr 02349 * (current namespace if contextNsPtr is 02350 * NULL), then in global namespace. */ 02351 Tcl_Namespace *contextNsPtr,/* Ignored if TCL_GLOBAL_ONLY flag set. 02352 * Otherwise, points to namespace in which to 02353 * resolve name. If NULL, look up name in the 02354 * current namespace. */ 02355 int flags) /* An OR'd combination of flags: 02356 * TCL_GLOBAL_ONLY (look up name only in 02357 * global namespace), TCL_NAMESPACE_ONLY (look 02358 * up only in contextNsPtr, or the current 02359 * namespace if contextNsPtr is NULL), and 02360 * TCL_LEAVE_ERR_MSG. If both TCL_GLOBAL_ONLY 02361 * and TCL_NAMESPACE_ONLY are given, 02362 * TCL_GLOBAL_ONLY is ignored. */ 02363 { 02364 Interp *iPtr = (Interp *) interp; 02365 Namespace *cxtNsPtr; 02366 register Tcl_HashEntry *entryPtr; 02367 register Command *cmdPtr; 02368 const char *simpleName; 02369 int result; 02370 02371 /* 02372 * If this namespace has a command resolver, then give it first crack at 02373 * the command resolution. If the interpreter has any command resolvers, 02374 * consult them next. The command resolver functions may return a 02375 * Tcl_Command value, they may signal to continue onward, or they may 02376 * signal an error. 02377 */ 02378 02379 if ((flags & TCL_GLOBAL_ONLY) || !strncmp(name, "::", 2)) { 02380 cxtNsPtr = (Namespace *) TclGetGlobalNamespace(interp); 02381 } else if (contextNsPtr != NULL) { 02382 cxtNsPtr = (Namespace *) contextNsPtr; 02383 } else { 02384 cxtNsPtr = (Namespace *) TclGetCurrentNamespace(interp); 02385 } 02386 02387 if (cxtNsPtr->cmdResProc != NULL || iPtr->resolverPtr != NULL) { 02388 ResolverScheme *resPtr = iPtr->resolverPtr; 02389 Tcl_Command cmd; 02390 02391 if (cxtNsPtr->cmdResProc) { 02392 result = (*cxtNsPtr->cmdResProc)(interp, name, 02393 (Tcl_Namespace *) cxtNsPtr, flags, &cmd); 02394 } else { 02395 result = TCL_CONTINUE; 02396 } 02397 02398 while (result == TCL_CONTINUE && resPtr) { 02399 if (resPtr->cmdResProc) { 02400 result = (*resPtr->cmdResProc)(interp, name, 02401 (Tcl_Namespace *) cxtNsPtr, flags, &cmd); 02402 } 02403 resPtr = resPtr->nextPtr; 02404 } 02405 02406 if (result == TCL_OK) { 02407 return cmd; 02408 } else if (result != TCL_CONTINUE) { 02409 return NULL; 02410 } 02411 } 02412 02413 /* 02414 * Find the namespace(s) that contain the command. 02415 */ 02416 02417 cmdPtr = NULL; 02418 if (cxtNsPtr->commandPathLength!=0 && strncmp(name, "::", 2)) { 02419 int i; 02420 Namespace *pathNsPtr, *realNsPtr, *dummyNsPtr; 02421 02422 (void) TclGetNamespaceForQualName(interp, name, cxtNsPtr, 02423 TCL_NAMESPACE_ONLY, &realNsPtr, &dummyNsPtr, &dummyNsPtr, 02424 &simpleName); 02425 if ((realNsPtr != NULL) && (simpleName != NULL)) { 02426 if ((cxtNsPtr == realNsPtr) 02427 || !(realNsPtr->flags & NS_DYING)) { 02428 entryPtr = Tcl_FindHashEntry(&realNsPtr->cmdTable, simpleName); 02429 if (entryPtr != NULL) { 02430 cmdPtr = Tcl_GetHashValue(entryPtr); 02431 } 02432 } 02433 } 02434 02435 /* 02436 * Next, check along the path. 02437 */ 02438 02439 for (i=0 ; i<cxtNsPtr->commandPathLength && cmdPtr==NULL ; i++) { 02440 pathNsPtr = cxtNsPtr->commandPathArray[i].nsPtr; 02441 if (pathNsPtr == NULL) { 02442 continue; 02443 } 02444 (void) TclGetNamespaceForQualName(interp, name, pathNsPtr, 02445 TCL_NAMESPACE_ONLY, &realNsPtr, &dummyNsPtr, &dummyNsPtr, 02446 &simpleName); 02447 if ((realNsPtr != NULL) && (simpleName != NULL) 02448 && !(realNsPtr->flags & NS_DYING)) { 02449 entryPtr = Tcl_FindHashEntry(&realNsPtr->cmdTable, simpleName); 02450 if (entryPtr != NULL) { 02451 cmdPtr = Tcl_GetHashValue(entryPtr); 02452 } 02453 } 02454 } 02455 02456 /* 02457 * If we've still not found the command, look in the global namespace 02458 * as a last resort. 02459 */ 02460 02461 if (cmdPtr == NULL) { 02462 (void) TclGetNamespaceForQualName(interp, name, NULL, 02463 TCL_GLOBAL_ONLY, &realNsPtr, &dummyNsPtr, &dummyNsPtr, 02464 &simpleName); 02465 if ((realNsPtr != NULL) && (simpleName != NULL) 02466 && !(realNsPtr->flags & NS_DYING)) { 02467 entryPtr = Tcl_FindHashEntry(&realNsPtr->cmdTable, simpleName); 02468 if (entryPtr != NULL) { 02469 cmdPtr = Tcl_GetHashValue(entryPtr); 02470 } 02471 } 02472 } 02473 } else { 02474 Namespace *nsPtr[2]; 02475 register int search; 02476 02477 TclGetNamespaceForQualName(interp, name, (Namespace *) contextNsPtr, 02478 flags, &nsPtr[0], &nsPtr[1], &cxtNsPtr, &simpleName); 02479 02480 /* 02481 * Look for the command in the command table of its namespace. Be sure 02482 * to check both possible search paths: from the specified namespace 02483 * context and from the global namespace. 02484 */ 02485 02486 for (search = 0; (search < 2) && (cmdPtr == NULL); search++) { 02487 if ((nsPtr[search] != NULL) && (simpleName != NULL)) { 02488 entryPtr = Tcl_FindHashEntry(&nsPtr[search]->cmdTable, 02489 simpleName); 02490 if (entryPtr != NULL) { 02491 cmdPtr = Tcl_GetHashValue(entryPtr); 02492 } 02493 } 02494 } 02495 } 02496 02497 if (cmdPtr != NULL) { 02498 return (Tcl_Command) cmdPtr; 02499 } 02500 02501 if (flags & TCL_LEAVE_ERR_MSG) { 02502 Tcl_ResetResult(interp); 02503 Tcl_AppendResult(interp, "unknown command \"", name, "\"", NULL); 02504 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND", name, NULL); 02505 } 02506 return NULL; 02507 } 02508 02509 /* 02510 *---------------------------------------------------------------------- 02511 * 02512 * TclResetShadowedCmdRefs -- 02513 * 02514 * Called when a command is added to a namespace to check for existing 02515 * command references that the new command may invalidate. Consider the 02516 * following cases that could happen when you add a command "foo" to a 02517 * namespace "b": 02518 * 1. It could shadow a command named "foo" at the global scope. If 02519 * it does, all command references in the namespace "b" are 02520 * suspect. 02521 * 2. Suppose the namespace "b" resides in a namespace "a". Then to 02522 * "a" the new command "b::foo" could shadow another command 02523 * "b::foo" in the global namespace. If so, then all command 02524 * references in "a" * are suspect. 02525 * The same checks are applied to all parent namespaces, until we reach 02526 * the global :: namespace. 02527 * 02528 * Results: 02529 * None. 02530 * 02531 * Side effects: 02532 * If the new command shadows an existing command, the cmdRefEpoch 02533 * counter is incremented in each namespace that sees the shadow. This 02534 * invalidates all command references that were previously cached in that 02535 * namespace. The next time the commands are used, they are resolved from 02536 * scratch. 02537 * 02538 *---------------------------------------------------------------------- 02539 */ 02540 02541 void 02542 TclResetShadowedCmdRefs( 02543 Tcl_Interp *interp, /* Interpreter containing the new command. */ 02544 Command *newCmdPtr) /* Points to the new command. */ 02545 { 02546 char *cmdName; 02547 Tcl_HashEntry *hPtr; 02548 register Namespace *nsPtr; 02549 Namespace *trailNsPtr, *shadowNsPtr; 02550 Namespace *globalNsPtr = (Namespace *) TclGetGlobalNamespace(interp); 02551 int found, i; 02552 int trailFront = -1; 02553 int trailSize = 5; /* Formerly NUM_TRAIL_ELEMS. */ 02554 Namespace **trailPtr = (Namespace **) 02555 TclStackAlloc(interp, trailSize * sizeof(Namespace *)); 02556 02557 /* 02558 * Start at the namespace containing the new command, and work up through 02559 * the list of parents. Stop just before the global namespace, since the 02560 * global namespace can't "shadow" its own entries. 02561 * 02562 * The namespace "trail" list we build consists of the names of each 02563 * namespace that encloses the new command, in order from outermost to 02564 * innermost: for example, "a" then "b". Each iteration of this loop 02565 * eventually extends the trail upwards by one namespace, nsPtr. We use 02566 * this trail list to see if nsPtr (e.g. "a" in 2. above) could have 02567 * now-invalid cached command references. This will happen if nsPtr 02568 * (e.g. "a") contains a sequence of child namespaces (e.g. "b") such that 02569 * there is a identically-named sequence of child namespaces starting from 02570 * :: (e.g. "::b") whose tail namespace contains a command also named 02571 * cmdName. 02572 */ 02573 02574 cmdName = Tcl_GetHashKey(newCmdPtr->hPtr->tablePtr, newCmdPtr->hPtr); 02575 for (nsPtr=newCmdPtr->nsPtr ; (nsPtr!=NULL) && (nsPtr!=globalNsPtr) ; 02576 nsPtr=nsPtr->parentPtr) { 02577 /* 02578 * Find the maximal sequence of child namespaces contained in nsPtr 02579 * such that there is a identically-named sequence of child namespaces 02580 * starting from ::. shadowNsPtr will be the tail of this sequence, or 02581 * the deepest namespace under :: that might contain a command now 02582 * shadowed by cmdName. We check below if shadowNsPtr actually 02583 * contains a command cmdName. 02584 */ 02585 02586 found = 1; 02587 shadowNsPtr = globalNsPtr; 02588 02589 for (i = trailFront; i >= 0; i--) { 02590 trailNsPtr = trailPtr[i]; 02591 hPtr = Tcl_FindHashEntry(&shadowNsPtr->childTable, 02592 trailNsPtr->name); 02593 if (hPtr != NULL) { 02594 shadowNsPtr = Tcl_GetHashValue(hPtr); 02595 } else { 02596 found = 0; 02597 break; 02598 } 02599 } 02600 02601 /* 02602 * If shadowNsPtr contains a command named cmdName, we invalidate all 02603 * of the command refs cached in nsPtr. As a boundary case, 02604 * shadowNsPtr is initially :: and we check for case 1. above. 02605 */ 02606 02607 if (found) { 02608 hPtr = Tcl_FindHashEntry(&shadowNsPtr->cmdTable, cmdName); 02609 if (hPtr != NULL) { 02610 nsPtr->cmdRefEpoch++; 02611 TclInvalidateNsPath(nsPtr); 02612 02613 /* 02614 * If the shadowed command was compiled to bytecodes, we 02615 * invalidate all the bytecodes in nsPtr, to force a new 02616 * compilation. We use the resolverEpoch to signal the need 02617 * for a fresh compilation of every bytecode. 02618 */ 02619 02620 if (((Command *)Tcl_GetHashValue(hPtr))->compileProc != NULL) { 02621 nsPtr->resolverEpoch++; 02622 } 02623 } 02624 } 02625 02626 /* 02627 * Insert nsPtr at the front of the trail list: i.e., at the end of 02628 * the trailPtr array. 02629 */ 02630 02631 trailFront++; 02632 if (trailFront == trailSize) { 02633 int newSize = 2 * trailSize; 02634 trailPtr = (Namespace **) TclStackRealloc(interp, 02635 trailPtr, newSize * sizeof(Namespace *)); 02636 trailSize = newSize; 02637 } 02638 trailPtr[trailFront] = nsPtr; 02639 } 02640 TclStackFree(interp, trailPtr); 02641 } 02642 02643 /* 02644 *---------------------------------------------------------------------- 02645 * 02646 * TclGetNamespaceFromObj, GetNamespaceFromObj -- 02647 * 02648 * Gets the namespace specified by the name in a Tcl_Obj. 02649 * 02650 * Results: 02651 * Returns TCL_OK if the namespace was resolved successfully, and stores 02652 * a pointer to the namespace in the location specified by nsPtrPtr. If 02653 * the namespace can't be found, or anything else goes wrong, this 02654 * function returns TCL_ERROR and writes an error message to interp, 02655 * if non-NULL. 02656 * 02657 * Side effects: 02658 * May update the internal representation for the object, caching the 02659 * namespace reference. The next time this function is called, the 02660 * namespace value can be found quickly. 02661 * 02662 *---------------------------------------------------------------------- 02663 */ 02664 02665 int 02666 TclGetNamespaceFromObj( 02667 Tcl_Interp *interp, /* The current interpreter. */ 02668 Tcl_Obj *objPtr, /* The object to be resolved as the name of a 02669 * namespace. */ 02670 Tcl_Namespace **nsPtrPtr) /* Result namespace pointer goes here. */ 02671 { 02672 if (GetNamespaceFromObj(interp, objPtr, nsPtrPtr) == TCL_ERROR) { 02673 const char *name = TclGetString(objPtr); 02674 02675 if ((name[0] == ':') && (name[1] == ':')) { 02676 Tcl_SetObjResult(interp, Tcl_ObjPrintf( 02677 "namespace \"%s\" not found", name)); 02678 } else { 02679 /* 02680 * Get the current namespace name. 02681 */ 02682 02683 NamespaceCurrentCmd(NULL, interp, 2, NULL); 02684 Tcl_SetObjResult(interp, Tcl_ObjPrintf( 02685 "namespace \"%s\" not found in \"%s\"", name, 02686 Tcl_GetStringResult(interp))); 02687 } 02688 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", name, NULL); 02689 return TCL_ERROR; 02690 } 02691 return TCL_OK; 02692 } 02693 02694 static int 02695 GetNamespaceFromObj( 02696 Tcl_Interp *interp, /* The current interpreter. */ 02697 Tcl_Obj *objPtr, /* The object to be resolved as the name of a 02698 * namespace. */ 02699 Tcl_Namespace **nsPtrPtr) /* Result namespace pointer goes here. */ 02700 { 02701 ResolvedNsName *resNamePtr; 02702 Namespace *nsPtr; 02703 02704 if (objPtr->typePtr == &nsNameType) { 02705 /* 02706 * Check that the ResolvedNsName is still valid. 02707 */ 02708 02709 resNamePtr = (ResolvedNsName *) objPtr->internalRep.twoPtrValue.ptr1; 02710 nsPtr = resNamePtr->nsPtr; 02711 if (!(nsPtr->flags & NS_DYING) 02712 && ((resNamePtr->refNsPtr == NULL) || (resNamePtr->refNsPtr 02713 == (Namespace *) Tcl_GetCurrentNamespace(interp)))) { 02714 *nsPtrPtr = (Tcl_Namespace *) nsPtr; 02715 return TCL_OK; 02716 } 02717 } 02718 if (SetNsNameFromAny(interp, objPtr) == TCL_OK) { 02719 resNamePtr = (ResolvedNsName *) objPtr->internalRep.twoPtrValue.ptr1; 02720 *nsPtrPtr = (Tcl_Namespace *) resNamePtr->nsPtr; 02721 return TCL_OK; 02722 } 02723 return TCL_ERROR; 02724 } 02725 02726 /* 02727 *---------------------------------------------------------------------- 02728 * 02729 * Tcl_NamespaceObjCmd -- 02730 * 02731 * Invoked to implement the "namespace" command that creates, deletes, or 02732 * manipulates Tcl namespaces. Handles the following syntax: 02733 * 02734 * namespace children ?name? ?pattern? 02735 * namespace code arg 02736 * namespace current 02737 * namespace delete ?name name...? 02738 * namespace ensemble subcommand ?arg...? 02739 * namespace eval name arg ?arg...? 02740 * namespace exists name 02741 * namespace export ?-clear? ?pattern pattern...? 02742 * namespace forget ?pattern pattern...? 02743 * namespace import ?-force? ?pattern pattern...? 02744 * namespace inscope name arg ?arg...? 02745 * namespace origin name 02746 * namespace parent ?name? 02747 * namespace qualifiers string 02748 * namespace tail string 02749 * namespace which ?-command? ?-variable? name 02750 * 02751 * Results: 02752 * Returns TCL_OK if the command is successful. Returns TCL_ERROR if 02753 * anything goes wrong. 02754 * 02755 * Side effects: 02756 * Based on the subcommand name (e.g., "import"), this function 02757 * dispatches to a corresponding function NamespaceXXXCmd defined 02758 * statically in this file. This function's side effects depend on 02759 * whatever that subcommand function does. If there is an error, this 02760 * function returns an error message in the interpreter's result object. 02761 * Otherwise it may return a result in the interpreter's result object. 02762 * 02763 *---------------------------------------------------------------------- 02764 */ 02765 02766 int 02767 Tcl_NamespaceObjCmd( 02768 ClientData clientData, /* Arbitrary value passed to cmd. */ 02769 Tcl_Interp *interp, /* Current interpreter. */ 02770 int objc, /* Number of arguments. */ 02771 Tcl_Obj *const objv[]) /* Argument objects. */ 02772 { 02773 static const char *subCmds[] = { 02774 "children", "code", "current", "delete", "ensemble", 02775 "eval", "exists", "export", "forget", "import", 02776 "inscope", "origin", "parent", "path", "qualifiers", 02777 "tail", "unknown", "upvar", "which", NULL 02778 }; 02779 enum NSSubCmdIdx { 02780 NSChildrenIdx, NSCodeIdx, NSCurrentIdx, NSDeleteIdx, NSEnsembleIdx, 02781 NSEvalIdx, NSExistsIdx, NSExportIdx, NSForgetIdx, NSImportIdx, 02782 NSInscopeIdx, NSOriginIdx, NSParentIdx, NSPathIdx, NSQualifiersIdx, 02783 NSTailIdx, NSUnknownIdx, NSUpvarIdx, NSWhichIdx 02784 }; 02785 int index, result; 02786 02787 if (objc < 2) { 02788 Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?arg ...?"); 02789 return TCL_ERROR; 02790 } 02791 02792 /* 02793 * Return an index reflecting the particular subcommand. 02794 */ 02795 02796 result = Tcl_GetIndexFromObj((Tcl_Interp *) interp, objv[1], subCmds, 02797 "option", /*flags*/ 0, (int *) &index); 02798 if (result != TCL_OK) { 02799 return result; 02800 } 02801 02802 switch (index) { 02803 case NSChildrenIdx: 02804 result = NamespaceChildrenCmd(clientData, interp, objc, objv); 02805 break; 02806 case NSCodeIdx: 02807 result = NamespaceCodeCmd(clientData, interp, objc, objv); 02808 break; 02809 case NSCurrentIdx: 02810 result = NamespaceCurrentCmd(clientData, interp, objc, objv); 02811 break; 02812 case NSDeleteIdx: 02813 result = NamespaceDeleteCmd(clientData, interp, objc, objv); 02814 break; 02815 case NSEnsembleIdx: 02816 result = NamespaceEnsembleCmd(clientData, interp, objc, objv); 02817 break; 02818 case NSEvalIdx: 02819 result = NamespaceEvalCmd(clientData, interp, objc, objv); 02820 break; 02821 case NSExistsIdx: 02822 result = NamespaceExistsCmd(clientData, interp, objc, objv); 02823 break; 02824 case NSExportIdx: 02825 result = NamespaceExportCmd(clientData, interp, objc, objv); 02826 break; 02827 case NSForgetIdx: 02828 result = NamespaceForgetCmd(clientData, interp, objc, objv); 02829 break; 02830 case NSImportIdx: 02831 result = NamespaceImportCmd(clientData, interp, objc, objv); 02832 break; 02833 case NSInscopeIdx: 02834 result = NamespaceInscopeCmd(clientData, interp, objc, objv); 02835 break; 02836 case NSOriginIdx: 02837 result = NamespaceOriginCmd(clientData, interp, objc, objv); 02838 break; 02839 case NSParentIdx: 02840 result = NamespaceParentCmd(clientData, interp, objc, objv); 02841 break; 02842 case NSPathIdx: 02843 result = NamespacePathCmd(clientData, interp, objc, objv); 02844 break; 02845 case NSQualifiersIdx: 02846 result = NamespaceQualifiersCmd(clientData, interp, objc, objv); 02847 break; 02848 case NSTailIdx: 02849 result = NamespaceTailCmd(clientData, interp, objc, objv); 02850 break; 02851 case NSUpvarIdx: 02852 result = NamespaceUpvarCmd(clientData, interp, objc, objv); 02853 break; 02854 case NSUnknownIdx: 02855 result = NamespaceUnknownCmd(clientData, interp, objc, objv); 02856 break; 02857 case NSWhichIdx: 02858 result = NamespaceWhichCmd(clientData, interp, objc, objv); 02859 break; 02860 } 02861 return result; 02862 } 02863 02864 /* 02865 *---------------------------------------------------------------------- 02866 * 02867 * NamespaceChildrenCmd -- 02868 * 02869 * Invoked to implement the "namespace children" command that returns a 02870 * list containing the fully-qualified names of the child namespaces of a 02871 * given namespace. Handles the following syntax: 02872 * 02873 * namespace children ?name? ?pattern? 02874 * 02875 * Results: 02876 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 02877 * 02878 * Side effects: 02879 * Returns a result in the interpreter's result object. If anything goes 02880 * wrong, the result is an error message. 02881 * 02882 *---------------------------------------------------------------------- 02883 */ 02884 02885 static int 02886 NamespaceChildrenCmd( 02887 ClientData dummy, /* Not used. */ 02888 Tcl_Interp *interp, /* Current interpreter. */ 02889 int objc, /* Number of arguments. */ 02890 Tcl_Obj *const objv[]) /* Argument objects. */ 02891 { 02892 Tcl_Namespace *namespacePtr; 02893 Namespace *nsPtr, *childNsPtr; 02894 Namespace *globalNsPtr = (Namespace *) TclGetGlobalNamespace(interp); 02895 char *pattern = NULL; 02896 Tcl_DString buffer; 02897 register Tcl_HashEntry *entryPtr; 02898 Tcl_HashSearch search; 02899 Tcl_Obj *listPtr, *elemPtr; 02900 02901 /* 02902 * Get a pointer to the specified namespace, or the current namespace. 02903 */ 02904 02905 if (objc == 2) { 02906 nsPtr = (Namespace *) TclGetCurrentNamespace(interp); 02907 } else if ((objc == 3) || (objc == 4)) { 02908 if (TclGetNamespaceFromObj(interp, objv[2], &namespacePtr) != TCL_OK) { 02909 return TCL_ERROR; 02910 } 02911 nsPtr = (Namespace *) namespacePtr; 02912 } else { 02913 Tcl_WrongNumArgs(interp, 2, objv, "?name? ?pattern?"); 02914 return TCL_ERROR; 02915 } 02916 02917 /* 02918 * Get the glob-style pattern, if any, used to narrow the search. 02919 */ 02920 02921 Tcl_DStringInit(&buffer); 02922 if (objc == 4) { 02923 char *name = TclGetString(objv[3]); 02924 02925 if ((*name == ':') && (*(name+1) == ':')) { 02926 pattern = name; 02927 } else { 02928 Tcl_DStringAppend(&buffer, nsPtr->fullName, -1); 02929 if (nsPtr != globalNsPtr) { 02930 Tcl_DStringAppend(&buffer, "::", 2); 02931 } 02932 Tcl_DStringAppend(&buffer, name, -1); 02933 pattern = Tcl_DStringValue(&buffer); 02934 } 02935 } 02936 02937 /* 02938 * Create a list containing the full names of all child namespaces whose 02939 * names match the specified pattern, if any. 02940 */ 02941 02942 listPtr = Tcl_NewListObj(0, NULL); 02943 if ((pattern != NULL) && TclMatchIsTrivial(pattern)) { 02944 unsigned int length = strlen(nsPtr->fullName); 02945 02946 if (strncmp(pattern, nsPtr->fullName, length) != 0) { 02947 goto searchDone; 02948 } 02949 if (Tcl_FindHashEntry(&nsPtr->childTable, pattern+length) != NULL) { 02950 Tcl_ListObjAppendElement(interp, listPtr, 02951 Tcl_NewStringObj(pattern, -1)); 02952 } 02953 goto searchDone; 02954 } 02955 entryPtr = Tcl_FirstHashEntry(&nsPtr->childTable, &search); 02956 while (entryPtr != NULL) { 02957 childNsPtr = Tcl_GetHashValue(entryPtr); 02958 if ((pattern == NULL) 02959 || Tcl_StringMatch(childNsPtr->fullName, pattern)) { 02960 elemPtr = Tcl_NewStringObj(childNsPtr->fullName, -1); 02961 Tcl_ListObjAppendElement(interp, listPtr, elemPtr); 02962 } 02963 entryPtr = Tcl_NextHashEntry(&search); 02964 } 02965 02966 searchDone: 02967 Tcl_SetObjResult(interp, listPtr); 02968 Tcl_DStringFree(&buffer); 02969 return TCL_OK; 02970 } 02971 02972 /* 02973 *---------------------------------------------------------------------- 02974 * 02975 * NamespaceCodeCmd -- 02976 * 02977 * Invoked to implement the "namespace code" command to capture the 02978 * namespace context of a command. Handles the following syntax: 02979 * 02980 * namespace code arg 02981 * 02982 * Here "arg" can be a list. "namespace code arg" produces a result 02983 * equivalent to that produced by the command 02984 * 02985 * list ::namespace inscope [namespace current] $arg 02986 * 02987 * However, if "arg" is itself a scoped value starting with "::namespace 02988 * inscope", then the result is just "arg". 02989 * 02990 * Results: 02991 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 02992 * 02993 * Side effects: 02994 * If anything goes wrong, this function returns an error message as the 02995 * result in the interpreter's result object. 02996 * 02997 *---------------------------------------------------------------------- 02998 */ 02999 03000 static int 03001 NamespaceCodeCmd( 03002 ClientData dummy, /* Not used. */ 03003 Tcl_Interp *interp, /* Current interpreter. */ 03004 int objc, /* Number of arguments. */ 03005 Tcl_Obj *const objv[]) /* Argument objects. */ 03006 { 03007 Namespace *currNsPtr; 03008 Tcl_Obj *listPtr, *objPtr; 03009 register char *arg, *p; 03010 int length; 03011 03012 if (objc != 3) { 03013 Tcl_WrongNumArgs(interp, 2, objv, "arg"); 03014 return TCL_ERROR; 03015 } 03016 03017 /* 03018 * If "arg" is already a scoped value, then return it directly. 03019 */ 03020 03021 arg = TclGetStringFromObj(objv[2], &length); 03022 while (*arg == ':') { 03023 arg++; 03024 length--; 03025 } 03026 if (*arg=='n' && length>17 && strncmp(arg, "namespace", 9)==0) { 03027 for (p=arg+9 ; isspace(UCHAR(*p)) ; p++) { 03028 /* empty body: skip over whitespace */ 03029 } 03030 if (*p=='i' && (p+7 <= arg+length) && strncmp(p, "inscope", 7)==0) { 03031 Tcl_SetObjResult(interp, objv[2]); 03032 return TCL_OK; 03033 } 03034 } 03035 03036 /* 03037 * Otherwise, construct a scoped command by building a list with 03038 * "namespace inscope", the full name of the current namespace, and the 03039 * argument "arg". By constructing a list, we ensure that scoped commands 03040 * are interpreted properly when they are executed later, by the 03041 * "namespace inscope" command. 03042 */ 03043 03044 TclNewObj(listPtr); 03045 TclNewLiteralStringObj(objPtr, "::namespace"); 03046 Tcl_ListObjAppendElement(interp, listPtr, objPtr); 03047 TclNewLiteralStringObj(objPtr, "inscope"); 03048 Tcl_ListObjAppendElement(interp, listPtr, objPtr); 03049 03050 currNsPtr = (Namespace *) TclGetCurrentNamespace(interp); 03051 if (currNsPtr == (Namespace *) TclGetGlobalNamespace(interp)) { 03052 TclNewLiteralStringObj(objPtr, "::"); 03053 } else { 03054 objPtr = Tcl_NewStringObj(currNsPtr->fullName, -1); 03055 } 03056 Tcl_ListObjAppendElement(interp, listPtr, objPtr); 03057 03058 Tcl_ListObjAppendElement(interp, listPtr, objv[2]); 03059 03060 Tcl_SetObjResult(interp, listPtr); 03061 return TCL_OK; 03062 } 03063 03064 /* 03065 *---------------------------------------------------------------------- 03066 * 03067 * NamespaceCurrentCmd -- 03068 * 03069 * Invoked to implement the "namespace current" command which returns the 03070 * fully-qualified name of the current namespace. Handles the following 03071 * syntax: 03072 * 03073 * namespace current 03074 * 03075 * Results: 03076 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 03077 * 03078 * Side effects: 03079 * Returns a result in the interpreter's result object. If anything goes 03080 * wrong, the result is an error message. 03081 * 03082 *---------------------------------------------------------------------- 03083 */ 03084 03085 static int 03086 NamespaceCurrentCmd( 03087 ClientData dummy, /* Not used. */ 03088 Tcl_Interp *interp, /* Current interpreter. */ 03089 int objc, /* Number of arguments. */ 03090 Tcl_Obj *const objv[]) /* Argument objects. */ 03091 { 03092 register Namespace *currNsPtr; 03093 03094 if (objc != 2) { 03095 Tcl_WrongNumArgs(interp, 2, objv, NULL); 03096 return TCL_ERROR; 03097 } 03098 03099 /* 03100 * The "real" name of the global namespace ("::") is the null string, but 03101 * we return "::" for it as a convenience to programmers. Note that "" and 03102 * "::" are treated as synonyms by the namespace code so that it is still 03103 * easy to do things like: 03104 * 03105 * namespace [namespace current]::bar { ... } 03106 */ 03107 03108 currNsPtr = (Namespace *) TclGetCurrentNamespace(interp); 03109 if (currNsPtr == (Namespace *) TclGetGlobalNamespace(interp)) { 03110 Tcl_SetObjResult(interp, Tcl_NewStringObj("::", 2)); 03111 } else { 03112 Tcl_SetObjResult(interp, Tcl_NewStringObj(currNsPtr->fullName, -1)); 03113 } 03114 return TCL_OK; 03115 } 03116 03117 /* 03118 *---------------------------------------------------------------------- 03119 * 03120 * NamespaceDeleteCmd -- 03121 * 03122 * Invoked to implement the "namespace delete" command to delete 03123 * namespace(s). Handles the following syntax: 03124 * 03125 * namespace delete ?name name...? 03126 * 03127 * Each name identifies a namespace. It may include a sequence of 03128 * namespace qualifiers separated by "::"s. If a namespace is found, it 03129 * is deleted: all variables and procedures contained in that namespace 03130 * are deleted. If that namespace is being used on the call stack, it is 03131 * kept alive (but logically deleted) until it is removed from the call 03132 * stack: that is, it can no longer be referenced by name but any 03133 * currently executing procedure that refers to it is allowed to do so 03134 * until the procedure returns. If the namespace can't be found, this 03135 * function returns an error. If no namespaces are specified, this 03136 * command does nothing. 03137 * 03138 * Results: 03139 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 03140 * 03141 * Side effects: 03142 * Deletes the specified namespaces. If anything goes wrong, this 03143 * function returns an error message in the interpreter's result object. 03144 * 03145 *---------------------------------------------------------------------- 03146 */ 03147 03148 static int 03149 NamespaceDeleteCmd( 03150 ClientData dummy, /* Not used. */ 03151 Tcl_Interp *interp, /* Current interpreter. */ 03152 int objc, /* Number of arguments. */ 03153 Tcl_Obj *const objv[]) /* Argument objects. */ 03154 { 03155 Tcl_Namespace *namespacePtr; 03156 char *name; 03157 register int i; 03158 03159 if (objc < 2) { 03160 Tcl_WrongNumArgs(interp, 2, objv, "?name name...?"); 03161 return TCL_ERROR; 03162 } 03163 03164 /* 03165 * Destroying one namespace may cause another to be destroyed. Break this 03166 * into two passes: first check to make sure that all namespaces on the 03167 * command line are valid, and report any errors. 03168 */ 03169 03170 for (i = 2; i < objc; i++) { 03171 name = TclGetString(objv[i]); 03172 namespacePtr = Tcl_FindNamespace(interp, name, NULL, /*flags*/ 0); 03173 if ((namespacePtr == NULL) 03174 || (((Namespace *)namespacePtr)->flags & NS_KILLED)) { 03175 Tcl_AppendResult(interp, "unknown namespace \"", 03176 TclGetString(objv[i]), 03177 "\" in namespace delete command", NULL); 03178 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", 03179 TclGetString(objv[i]), NULL); 03180 return TCL_ERROR; 03181 } 03182 } 03183 03184 /* 03185 * Okay, now delete each namespace. 03186 */ 03187 03188 for (i = 2; i < objc; i++) { 03189 name = TclGetString(objv[i]); 03190 namespacePtr = Tcl_FindNamespace(interp, name, NULL, /* flags */ 0); 03191 if (namespacePtr) { 03192 Tcl_DeleteNamespace(namespacePtr); 03193 } 03194 } 03195 return TCL_OK; 03196 } 03197 03198 /* 03199 *---------------------------------------------------------------------- 03200 * 03201 * NamespaceEvalCmd -- 03202 * 03203 * Invoked to implement the "namespace eval" command. Executes commands 03204 * in a namespace. If the namespace does not already exist, it is 03205 * created. Handles the following syntax: 03206 * 03207 * namespace eval name arg ?arg...? 03208 * 03209 * If more than one arg argument is specified, the command that is 03210 * executed is the result of concatenating the arguments together with a 03211 * space between each argument. 03212 * 03213 * Results: 03214 * Returns TCL_OK if the namespace is found and the commands are executed 03215 * successfully. Returns TCL_ERROR if anything goes wrong. 03216 * 03217 * Side effects: 03218 * Returns the result of the command in the interpreter's result object. 03219 * If anything goes wrong, this function returns an error message as the 03220 * result. 03221 * 03222 *---------------------------------------------------------------------- 03223 */ 03224 03225 static int 03226 NamespaceEvalCmd( 03227 ClientData dummy, /* Not used. */ 03228 Tcl_Interp *interp, /* Current interpreter. */ 03229 int objc, /* Number of arguments. */ 03230 Tcl_Obj *const objv[]) /* Argument objects. */ 03231 { 03232 Tcl_Namespace *namespacePtr; 03233 CallFrame *framePtr, **framePtrPtr; 03234 Tcl_Obj *objPtr; 03235 int result; 03236 03237 if (objc < 4) { 03238 Tcl_WrongNumArgs(interp, 2, objv, "name arg ?arg...?"); 03239 return TCL_ERROR; 03240 } 03241 03242 /* 03243 * Try to resolve the namespace reference, caching the result in the 03244 * namespace object along the way. 03245 */ 03246 03247 result = GetNamespaceFromObj(interp, objv[2], &namespacePtr); 03248 03249 /* 03250 * If the namespace wasn't found, try to create it. 03251 */ 03252 03253 if (result == TCL_ERROR) { 03254 char *name = TclGetString(objv[2]); 03255 03256 namespacePtr = Tcl_CreateNamespace(interp, name, NULL, NULL); 03257 if (namespacePtr == NULL) { 03258 return TCL_ERROR; 03259 } 03260 } 03261 03262 /* 03263 * Make the specified namespace the current namespace and evaluate the 03264 * command(s). 03265 */ 03266 03267 /* This is needed to satisfy GCC 3.3's strict aliasing rules */ 03268 framePtrPtr = &framePtr; 03269 result = TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr, 03270 namespacePtr, /*isProcCallFrame*/ 0); 03271 if (result != TCL_OK) { 03272 return TCL_ERROR; 03273 } 03274 03275 framePtr->objc = objc; 03276 framePtr->objv = objv; 03277 03278 if (objc == 4) { 03279 /* 03280 * TIP #280: Make invoker available to eval'd script. 03281 */ 03282 03283 Interp *iPtr = (Interp *) interp; 03284 03285 result = TclEvalObjEx(interp, objv[3], 0, iPtr->cmdFramePtr, 3); 03286 } else { 03287 /* 03288 * More than one argument: concatenate them together with spaces 03289 * between, then evaluate the result. Tcl_EvalObjEx will delete the 03290 * object when it decrements its refcount after eval'ing it. 03291 */ 03292 03293 objPtr = Tcl_ConcatObj(objc-3, objv+3); 03294 03295 /* 03296 * TIP #280: Make invoking context available to eval'd script. 03297 */ 03298 03299 result = TclEvalObjEx(interp, objPtr, TCL_EVAL_DIRECT, NULL, 0); 03300 } 03301 03302 if (result == TCL_ERROR) { 03303 int length = strlen(namespacePtr->fullName); 03304 int limit = 200; 03305 int overflow = (length > limit); 03306 03307 Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( 03308 "\n (in namespace eval \"%.*s%s\" script line %d)", 03309 (overflow ? limit : length), namespacePtr->fullName, 03310 (overflow ? "..." : ""), interp->errorLine)); 03311 } 03312 03313 /* 03314 * Restore the previous "current" namespace. 03315 */ 03316 03317 TclPopStackFrame(interp); 03318 return result; 03319 } 03320 03321 /* 03322 *---------------------------------------------------------------------- 03323 * 03324 * NamespaceExistsCmd -- 03325 * 03326 * Invoked to implement the "namespace exists" command that returns true 03327 * if the given namespace currently exists, and false otherwise. Handles 03328 * the following syntax: 03329 * 03330 * namespace exists name 03331 * 03332 * Results: 03333 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 03334 * 03335 * Side effects: 03336 * Returns a result in the interpreter's result object. If anything goes 03337 * wrong, the result is an error message. 03338 * 03339 *---------------------------------------------------------------------- 03340 */ 03341 03342 static int 03343 NamespaceExistsCmd( 03344 ClientData dummy, /* Not used. */ 03345 Tcl_Interp *interp, /* Current interpreter. */ 03346 int objc, /* Number of arguments. */ 03347 Tcl_Obj *const objv[]) /* Argument objects. */ 03348 { 03349 Tcl_Namespace *namespacePtr; 03350 03351 if (objc != 3) { 03352 Tcl_WrongNumArgs(interp, 2, objv, "name"); 03353 return TCL_ERROR; 03354 } 03355 03356 Tcl_SetObjResult(interp, Tcl_NewBooleanObj( 03357 GetNamespaceFromObj(interp, objv[2], &namespacePtr) == TCL_OK)); 03358 return TCL_OK; 03359 } 03360 03361 /* 03362 *---------------------------------------------------------------------- 03363 * 03364 * NamespaceExportCmd -- 03365 * 03366 * Invoked to implement the "namespace export" command that specifies 03367 * which commands are exported from a namespace. The exported commands 03368 * are those that can be imported into another namespace using "namespace 03369 * import". Both commands defined in a namespace and commands the 03370 * namespace has imported can be exported by a namespace. This command 03371 * has the following syntax: 03372 * 03373 * namespace export ?-clear? ?pattern pattern...? 03374 * 03375 * Each pattern may contain "string match"-style pattern matching special 03376 * characters, but the pattern may not include any namespace qualifiers: 03377 * that is, the pattern must specify commands in the current (exporting) 03378 * namespace. The specified patterns are appended onto the namespace's 03379 * list of export patterns. 03380 * 03381 * To reset the namespace's export pattern list, specify the "-clear" 03382 * flag. 03383 * 03384 * If there are no export patterns and the "-clear" flag isn't given, 03385 * this command returns the namespace's current export list. 03386 * 03387 * Results: 03388 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 03389 * 03390 * Side effects: 03391 * Returns a result in the interpreter's result object. If anything goes 03392 * wrong, the result is an error message. 03393 * 03394 *---------------------------------------------------------------------- 03395 */ 03396 03397 static int 03398 NamespaceExportCmd( 03399 ClientData dummy, /* Not used. */ 03400 Tcl_Interp *interp, /* Current interpreter. */ 03401 int objc, /* Number of arguments. */ 03402 Tcl_Obj *const objv[]) /* Argument objects. */ 03403 { 03404 Namespace *currNsPtr = (Namespace *) TclGetCurrentNamespace(interp); 03405 char *pattern, *string; 03406 int resetListFirst = 0; 03407 int firstArg, patternCt, i, result; 03408 03409 if (objc < 2) { 03410 Tcl_WrongNumArgs(interp, 2, objv, "?-clear? ?pattern pattern...?"); 03411 return TCL_ERROR; 03412 } 03413 03414 /* 03415 * Process the optional "-clear" argument. 03416 */ 03417 03418 firstArg = 2; 03419 if (firstArg < objc) { 03420 string = TclGetString(objv[firstArg]); 03421 if (strcmp(string, "-clear") == 0) { 03422 resetListFirst = 1; 03423 firstArg++; 03424 } 03425 } 03426 03427 /* 03428 * If no pattern arguments are given, and "-clear" isn't specified, return 03429 * the namespace's current export pattern list. 03430 */ 03431 03432 patternCt = (objc - firstArg); 03433 if (patternCt == 0) { 03434 if (firstArg > 2) { 03435 return TCL_OK; 03436 } else { 03437 /* 03438 * Create list with export patterns. 03439 */ 03440 03441 Tcl_Obj *listPtr = Tcl_NewListObj(0, NULL); 03442 result = Tcl_AppendExportList(interp, (Tcl_Namespace *) currNsPtr, 03443 listPtr); 03444 if (result != TCL_OK) { 03445 return result; 03446 } 03447 Tcl_SetObjResult(interp, listPtr); 03448 return TCL_OK; 03449 } 03450 } 03451 03452 /* 03453 * Add each pattern to the namespace's export pattern list. 03454 */ 03455 03456 for (i = firstArg; i < objc; i++) { 03457 pattern = TclGetString(objv[i]); 03458 result = Tcl_Export(interp, (Tcl_Namespace *) currNsPtr, pattern, 03459 ((i == firstArg)? resetListFirst : 0)); 03460 if (result != TCL_OK) { 03461 return result; 03462 } 03463 } 03464 return TCL_OK; 03465 } 03466 03467 /* 03468 *---------------------------------------------------------------------- 03469 * 03470 * NamespaceForgetCmd -- 03471 * 03472 * Invoked to implement the "namespace forget" command to remove imported 03473 * commands from a namespace. Handles the following syntax: 03474 * 03475 * namespace forget ?pattern pattern...? 03476 * 03477 * Each pattern is a name like "foo::*" or "a::b::x*". That is, the 03478 * pattern may include the special pattern matching characters recognized 03479 * by the "string match" command, but only in the command name at the end 03480 * of the qualified name; the special pattern characters may not appear 03481 * in a namespace name. All of the commands that match that pattern are 03482 * checked to see if they have an imported command in the current 03483 * namespace that refers to the matched command. If there is an alias, it 03484 * is removed. 03485 * 03486 * Results: 03487 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 03488 * 03489 * Side effects: 03490 * Imported commands are removed from the current namespace. If anything 03491 * goes wrong, this function returns an error message in the 03492 * interpreter's result object. 03493 * 03494 *---------------------------------------------------------------------- 03495 */ 03496 03497 static int 03498 NamespaceForgetCmd( 03499 ClientData dummy, /* Not used. */ 03500 Tcl_Interp *interp, /* Current interpreter. */ 03501 int objc, /* Number of arguments. */ 03502 Tcl_Obj *const objv[]) /* Argument objects. */ 03503 { 03504 char *pattern; 03505 register int i, result; 03506 03507 if (objc < 2) { 03508 Tcl_WrongNumArgs(interp, 2, objv, "?pattern pattern...?"); 03509 return TCL_ERROR; 03510 } 03511 03512 for (i = 2; i < objc; i++) { 03513 pattern = TclGetString(objv[i]); 03514 result = Tcl_ForgetImport(interp, NULL, pattern); 03515 if (result != TCL_OK) { 03516 return result; 03517 } 03518 } 03519 return TCL_OK; 03520 } 03521 03522 /* 03523 *---------------------------------------------------------------------- 03524 * 03525 * NamespaceImportCmd -- 03526 * 03527 * Invoked to implement the "namespace import" command that imports 03528 * commands into a namespace. Handles the following syntax: 03529 * 03530 * namespace import ?-force? ?pattern pattern...? 03531 * 03532 * Each pattern is a namespace-qualified name like "foo::*", "a::b::x*", 03533 * or "bar::p". That is, the pattern may include the special pattern 03534 * matching characters recognized by the "string match" command, but only 03535 * in the command name at the end of the qualified name; the special 03536 * pattern characters may not appear in a namespace name. All of the 03537 * commands that match the pattern and which are exported from their 03538 * namespace are made accessible from the current namespace context. This 03539 * is done by creating a new "imported command" in the current namespace 03540 * that points to the real command in its original namespace; when the 03541 * imported command is called, it invokes the real command. 03542 * 03543 * If an imported command conflicts with an existing command, it is 03544 * treated as an error. But if the "-force" option is included, then 03545 * existing commands are overwritten by the imported commands. 03546 * 03547 * If there are no pattern arguments and the "-force" flag isn't given, 03548 * this command returns the list of commands currently imported in 03549 * the current namespace. 03550 * 03551 * Results: 03552 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 03553 * 03554 * Side effects: 03555 * Adds imported commands to the current namespace. If anything goes 03556 * wrong, this function returns an error message in the interpreter's 03557 * result object. 03558 * 03559 *---------------------------------------------------------------------- 03560 */ 03561 03562 static int 03563 NamespaceImportCmd( 03564 ClientData dummy, /* Not used. */ 03565 Tcl_Interp *interp, /* Current interpreter. */ 03566 int objc, /* Number of arguments. */ 03567 Tcl_Obj *const objv[]) /* Argument objects. */ 03568 { 03569 int allowOverwrite = 0; 03570 char *string, *pattern; 03571 register int i, result; 03572 int firstArg; 03573 03574 if (objc < 2) { 03575 Tcl_WrongNumArgs(interp, 2, objv, "?-force? ?pattern pattern...?"); 03576 return TCL_ERROR; 03577 } 03578 03579 /* 03580 * Skip over the optional "-force" as the first argument. 03581 */ 03582 03583 firstArg = 2; 03584 if (firstArg < objc) { 03585 string = TclGetString(objv[firstArg]); 03586 if ((*string == '-') && (strcmp(string, "-force") == 0)) { 03587 allowOverwrite = 1; 03588 firstArg++; 03589 } 03590 } else { 03591 /* 03592 * When objc == 2, command is just [namespace import]. Introspection 03593 * form to return list of imported commands. 03594 */ 03595 03596 Tcl_HashEntry *hPtr; 03597 Tcl_HashSearch search; 03598 Namespace *nsPtr = (Namespace *) TclGetCurrentNamespace(interp); 03599 Tcl_Obj *listPtr; 03600 03601 TclNewObj(listPtr); 03602 for (hPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search); 03603 hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { 03604 Command *cmdPtr = Tcl_GetHashValue(hPtr); 03605 03606 if (cmdPtr->deleteProc == DeleteImportedCmd) { 03607 Tcl_ListObjAppendElement(NULL, listPtr, Tcl_NewStringObj( 03608 Tcl_GetHashKey(&nsPtr->cmdTable, hPtr) ,-1)); 03609 } 03610 } 03611 Tcl_SetObjResult(interp, listPtr); 03612 return TCL_OK; 03613 } 03614 03615 /* 03616 * Handle the imports for each of the patterns. 03617 */ 03618 03619 for (i = firstArg; i < objc; i++) { 03620 pattern = TclGetString(objv[i]); 03621 result = Tcl_Import(interp, NULL, pattern, allowOverwrite); 03622 if (result != TCL_OK) { 03623 return result; 03624 } 03625 } 03626 return TCL_OK; 03627 } 03628 03629 /* 03630 *---------------------------------------------------------------------- 03631 * 03632 * NamespaceInscopeCmd -- 03633 * 03634 * Invoked to implement the "namespace inscope" command that executes a 03635 * script in the context of a particular namespace. This command is not 03636 * expected to be used directly by programmers; calls to it are generated 03637 * implicitly when programs use "namespace code" commands to register 03638 * callback scripts. Handles the following syntax: 03639 * 03640 * namespace inscope name arg ?arg...? 03641 * 03642 * The "namespace inscope" command is much like the "namespace eval" 03643 * command except that it has lappend semantics and the namespace must 03644 * already exist. It treats the first argument as a list, and appends any 03645 * arguments after the first onto the end as proper list elements. For 03646 * example, 03647 * 03648 * namespace inscope ::foo {a b} c d e 03649 * 03650 * is equivalent to 03651 * 03652 * namespace eval ::foo [concat {a b} [list c d e]] 03653 * 03654 * This lappend semantics is important because many callback scripts are 03655 * actually prefixes. 03656 * 03657 * Results: 03658 * Returns TCL_OK to indicate success, or TCL_ERROR to indicate failure. 03659 * 03660 * Side effects: 03661 * Returns a result in the Tcl interpreter's result object. 03662 * 03663 *---------------------------------------------------------------------- 03664 */ 03665 03666 static int 03667 NamespaceInscopeCmd( 03668 ClientData dummy, /* Not used. */ 03669 Tcl_Interp *interp, /* Current interpreter. */ 03670 int objc, /* Number of arguments. */ 03671 Tcl_Obj *const objv[]) /* Argument objects. */ 03672 { 03673 Tcl_Namespace *namespacePtr; 03674 CallFrame *framePtr, **framePtrPtr; 03675 int i, result; 03676 03677 if (objc < 4) { 03678 Tcl_WrongNumArgs(interp, 2, objv, "name arg ?arg...?"); 03679 return TCL_ERROR; 03680 } 03681 03682 /* 03683 * Resolve the namespace reference. 03684 */ 03685 03686 if (TclGetNamespaceFromObj(interp, objv[2], &namespacePtr) != TCL_OK) { 03687 return TCL_ERROR; 03688 } 03689 03690 /* 03691 * Make the specified namespace the current namespace. 03692 */ 03693 03694 framePtrPtr = &framePtr; /* This is needed to satisfy GCC's 03695 * strict aliasing rules. */ 03696 result = TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr, 03697 namespacePtr, /*isProcCallFrame*/ 0); 03698 if (result != TCL_OK) { 03699 return result; 03700 } 03701 03702 framePtr->objc = objc; 03703 framePtr->objv = objv; 03704 03705 /* 03706 * Execute the command. If there is just one argument, just treat it as a 03707 * script and evaluate it. Otherwise, create a list from the arguments 03708 * after the first one, then concatenate the first argument and the list 03709 * of extra arguments to form the command to evaluate. 03710 */ 03711 03712 if (objc == 4) { 03713 result = Tcl_EvalObjEx(interp, objv[3], 0); 03714 } else { 03715 Tcl_Obj *concatObjv[2]; 03716 register Tcl_Obj *listPtr, *cmdObjPtr; 03717 03718 listPtr = Tcl_NewListObj(0, NULL); 03719 for (i = 4; i < objc; i++) { 03720 if (Tcl_ListObjAppendElement(interp, listPtr, objv[i]) != TCL_OK) { 03721 Tcl_DecrRefCount(listPtr); /* Free unneeded obj. */ 03722 return TCL_ERROR; 03723 } 03724 } 03725 03726 concatObjv[0] = objv[3]; 03727 concatObjv[1] = listPtr; 03728 cmdObjPtr = Tcl_ConcatObj(2, concatObjv); 03729 result = Tcl_EvalObjEx(interp, cmdObjPtr, TCL_EVAL_DIRECT); 03730 Tcl_DecrRefCount(listPtr); /* We're done with the list object. */ 03731 } 03732 03733 if (result == TCL_ERROR) { 03734 int length = strlen(namespacePtr->fullName); 03735 int limit = 200; 03736 int overflow = (length > limit); 03737 03738 Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( 03739 "\n (in namespace inscope \"%.*s%s\" script line %d)", 03740 (overflow ? limit : length), namespacePtr->fullName, 03741 (overflow ? "..." : ""), interp->errorLine)); 03742 } 03743 03744 /* 03745 * Restore the previous "current" namespace. 03746 */ 03747 03748 TclPopStackFrame(interp); 03749 return result; 03750 } 03751 03752 /* 03753 *---------------------------------------------------------------------- 03754 * 03755 * NamespaceOriginCmd -- 03756 * 03757 * Invoked to implement the "namespace origin" command to return the 03758 * fully-qualified name of the "real" command to which the specified 03759 * "imported command" refers. Handles the following syntax: 03760 * 03761 * namespace origin name 03762 * 03763 * Results: 03764 * An imported command is created in an namespace when that namespace 03765 * imports a command from another namespace. If a command is imported 03766 * into a sequence of namespaces a, b,...,n where each successive 03767 * namespace just imports the command from the previous namespace, this 03768 * command returns the fully-qualified name of the original command in 03769 * the first namespace, a. If "name" does not refer to an alias, its 03770 * fully-qualified name is returned. The returned name is stored in the 03771 * interpreter's result object. This function returns TCL_OK if 03772 * successful, and TCL_ERROR if anything goes wrong. 03773 * 03774 * Side effects: 03775 * If anything goes wrong, this function returns an error message in the 03776 * interpreter's result object. 03777 * 03778 *---------------------------------------------------------------------- 03779 */ 03780 03781 static int 03782 NamespaceOriginCmd( 03783 ClientData dummy, /* Not used. */ 03784 Tcl_Interp *interp, /* Current interpreter. */ 03785 int objc, /* Number of arguments. */ 03786 Tcl_Obj *const objv[]) /* Argument objects. */ 03787 { 03788 Tcl_Command command, origCommand; 03789 Tcl_Obj *resultPtr; 03790 03791 if (objc != 3) { 03792 Tcl_WrongNumArgs(interp, 2, objv, "name"); 03793 return TCL_ERROR; 03794 } 03795 03796 command = Tcl_GetCommandFromObj(interp, objv[2]); 03797 if (command == NULL) { 03798 Tcl_AppendResult(interp, "invalid command name \"", 03799 TclGetString(objv[2]), "\"", NULL); 03800 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND", 03801 TclGetString(objv[2]), NULL); 03802 return TCL_ERROR; 03803 } 03804 origCommand = TclGetOriginalCommand(command); 03805 TclNewObj(resultPtr); 03806 if (origCommand == NULL) { 03807 /* 03808 * The specified command isn't an imported command. Return the 03809 * command's name qualified by the full name of the namespace it was 03810 * defined in. 03811 */ 03812 03813 Tcl_GetCommandFullName(interp, command, resultPtr); 03814 } else { 03815 Tcl_GetCommandFullName(interp, origCommand, resultPtr); 03816 } 03817 Tcl_SetObjResult(interp, resultPtr); 03818 return TCL_OK; 03819 } 03820 03821 /* 03822 *---------------------------------------------------------------------- 03823 * 03824 * NamespaceParentCmd -- 03825 * 03826 * Invoked to implement the "namespace parent" command that returns the 03827 * fully-qualified name of the parent namespace for a specified 03828 * namespace. Handles the following syntax: 03829 * 03830 * namespace parent ?name? 03831 * 03832 * Results: 03833 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 03834 * 03835 * Side effects: 03836 * Returns a result in the interpreter's result object. If anything goes 03837 * wrong, the result is an error message. 03838 * 03839 *---------------------------------------------------------------------- 03840 */ 03841 03842 static int 03843 NamespaceParentCmd( 03844 ClientData dummy, /* Not used. */ 03845 Tcl_Interp *interp, /* Current interpreter. */ 03846 int objc, /* Number of arguments. */ 03847 Tcl_Obj *const objv[]) /* Argument objects. */ 03848 { 03849 Tcl_Namespace *nsPtr; 03850 03851 if (objc == 2) { 03852 nsPtr = TclGetCurrentNamespace(interp); 03853 } else if (objc == 3) { 03854 if (TclGetNamespaceFromObj(interp, objv[2], &nsPtr) != TCL_OK) { 03855 return TCL_ERROR; 03856 } 03857 } else { 03858 Tcl_WrongNumArgs(interp, 2, objv, "?name?"); 03859 return TCL_ERROR; 03860 } 03861 03862 /* 03863 * Report the parent of the specified namespace. 03864 */ 03865 03866 if (nsPtr->parentPtr != NULL) { 03867 Tcl_SetObjResult(interp, Tcl_NewStringObj( 03868 nsPtr->parentPtr->fullName, -1)); 03869 } 03870 return TCL_OK; 03871 } 03872 03873 /* 03874 *---------------------------------------------------------------------- 03875 * 03876 * NamespacePathCmd -- 03877 * 03878 * Invoked to implement the "namespace path" command that reads and 03879 * writes the current namespace's command resolution path. Has one 03880 * optional argument: if present, it is a list of named namespaces to set 03881 * the path to, and if absent, the current path should be returned. 03882 * Handles the following syntax: 03883 * 03884 * namespace path ?nsList? 03885 * 03886 * Results: 03887 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong 03888 * (most notably if the namespace list contains the name of something 03889 * other than a namespace). In the successful-exit case, may set the 03890 * interpreter result to the list of names of the namespaces on the 03891 * current namespace's path. 03892 * 03893 * Side effects: 03894 * May update the namespace path (triggering a recomputing of all command 03895 * names that depend on the namespace for resolution). 03896 * 03897 *---------------------------------------------------------------------- 03898 */ 03899 03900 static int 03901 NamespacePathCmd( 03902 ClientData dummy, /* Not used. */ 03903 Tcl_Interp *interp, /* Current interpreter. */ 03904 int objc, /* Number of arguments. */ 03905 Tcl_Obj *const objv[]) /* Argument objects. */ 03906 { 03907 Namespace *nsPtr = (Namespace *) TclGetCurrentNamespace(interp); 03908 int i, nsObjc, result = TCL_ERROR; 03909 Tcl_Obj **nsObjv; 03910 Tcl_Namespace **namespaceList = NULL; 03911 03912 if (objc > 3) { 03913 Tcl_WrongNumArgs(interp, 2, objv, "?pathList?"); 03914 return TCL_ERROR; 03915 } 03916 03917 /* 03918 * If no path is given, return the current path. 03919 */ 03920 03921 if (objc == 2) { 03922 /* 03923 * Not a very fast way to compute this, but easy to get right. 03924 */ 03925 03926 for (i=0 ; i<nsPtr->commandPathLength ; i++) { 03927 if (nsPtr->commandPathArray[i].nsPtr != NULL) { 03928 Tcl_AppendElement(interp, 03929 nsPtr->commandPathArray[i].nsPtr->fullName); 03930 } 03931 } 03932 return TCL_OK; 03933 } 03934 03935 /* 03936 * There is a path given, so parse it into an array of namespace pointers. 03937 */ 03938 03939 if (TclListObjGetElements(interp, objv[2], &nsObjc, &nsObjv) != TCL_OK) { 03940 goto badNamespace; 03941 } 03942 if (nsObjc != 0) { 03943 namespaceList = (Tcl_Namespace **) 03944 TclStackAlloc(interp, sizeof(Tcl_Namespace *) * nsObjc); 03945 03946 for (i=0 ; i<nsObjc ; i++) { 03947 if (TclGetNamespaceFromObj(interp, nsObjv[i], 03948 &namespaceList[i]) != TCL_OK) { 03949 goto badNamespace; 03950 } 03951 } 03952 } 03953 03954 /* 03955 * Now we have the list of valid namespaces, install it as the path. 03956 */ 03957 03958 TclSetNsPath(nsPtr, nsObjc, namespaceList); 03959 03960 result = TCL_OK; 03961 badNamespace: 03962 if (namespaceList != NULL) { 03963 TclStackFree(interp, namespaceList); 03964 } 03965 return result; 03966 } 03967 03968 /* 03969 *---------------------------------------------------------------------- 03970 * 03971 * TclSetNsPath -- 03972 * 03973 * Sets the namespace command name resolution path to the given list of 03974 * namespaces. If the list is empty (of zero length) the path is set to 03975 * empty and the default old-style behaviour of command name resolution 03976 * is used. 03977 * 03978 * Results: 03979 * nothing 03980 * 03981 * Side effects: 03982 * Invalidates the command name resolution caches for any command 03983 * resolved in the given namespace. 03984 * 03985 *---------------------------------------------------------------------- 03986 */ 03987 03988 void 03989 TclSetNsPath( 03990 Namespace *nsPtr, /* Namespace whose path is to be set. */ 03991 int pathLength, /* Length of pathAry. */ 03992 Tcl_Namespace *pathAry[]) /* Array of namespaces that are the path. */ 03993 { 03994 if (pathLength != 0) { 03995 NamespacePathEntry *tmpPathArray = (NamespacePathEntry *) 03996 ckalloc(sizeof(NamespacePathEntry) * pathLength); 03997 int i; 03998 03999 for (i=0 ; i<pathLength ; i++) { 04000 tmpPathArray[i].nsPtr = (Namespace *) pathAry[i]; 04001 tmpPathArray[i].creatorNsPtr = nsPtr; 04002 tmpPathArray[i].prevPtr = NULL; 04003 tmpPathArray[i].nextPtr = 04004 tmpPathArray[i].nsPtr->commandPathSourceList; 04005 if (tmpPathArray[i].nextPtr != NULL) { 04006 tmpPathArray[i].nextPtr->prevPtr = &tmpPathArray[i]; 04007 } 04008 tmpPathArray[i].nsPtr->commandPathSourceList = &tmpPathArray[i]; 04009 } 04010 if (nsPtr->commandPathLength != 0) { 04011 UnlinkNsPath(nsPtr); 04012 } 04013 nsPtr->commandPathArray = tmpPathArray; 04014 } else { 04015 if (nsPtr->commandPathLength != 0) { 04016 UnlinkNsPath(nsPtr); 04017 } 04018 } 04019 04020 nsPtr->commandPathLength = pathLength; 04021 nsPtr->cmdRefEpoch++; 04022 nsPtr->resolverEpoch++; 04023 } 04024 04025 /* 04026 *---------------------------------------------------------------------- 04027 * 04028 * UnlinkNsPath -- 04029 * 04030 * Delete the given namespace's command name resolution path. Only call 04031 * if the path is non-empty. Caller must reset the counter containing the 04032 * path size. 04033 * 04034 * Results: 04035 * nothing 04036 * 04037 * Side effects: 04038 * Deletes the array of path entries and unlinks those path entries from 04039 * the target namespace's list of interested namespaces. 04040 * 04041 *---------------------------------------------------------------------- 04042 */ 04043 04044 static void 04045 UnlinkNsPath( 04046 Namespace *nsPtr) 04047 { 04048 int i; 04049 for (i=0 ; i<nsPtr->commandPathLength ; i++) { 04050 NamespacePathEntry *nsPathPtr = &nsPtr->commandPathArray[i]; 04051 if (nsPathPtr->prevPtr != NULL) { 04052 nsPathPtr->prevPtr->nextPtr = nsPathPtr->nextPtr; 04053 } 04054 if (nsPathPtr->nextPtr != NULL) { 04055 nsPathPtr->nextPtr->prevPtr = nsPathPtr->prevPtr; 04056 } 04057 if (nsPathPtr->nsPtr != NULL) { 04058 if (nsPathPtr->nsPtr->commandPathSourceList == nsPathPtr) { 04059 nsPathPtr->nsPtr->commandPathSourceList = nsPathPtr->nextPtr; 04060 } 04061 } 04062 } 04063 ckfree((char *) nsPtr->commandPathArray); 04064 } 04065 04066 /* 04067 *---------------------------------------------------------------------- 04068 * 04069 * TclInvalidateNsPath -- 04070 * 04071 * Invalidate the name resolution caches for all names looked up in 04072 * namespaces whose name path includes the given namespace. 04073 * 04074 * Results: 04075 * nothing 04076 * 04077 * Side effects: 04078 * Increments the command reference epoch in each namespace whose path 04079 * includes the given namespace. This causes any cached resolved names 04080 * whose root cacheing context starts at that namespace to be recomputed 04081 * the next time they are used. 04082 * 04083 *---------------------------------------------------------------------- 04084 */ 04085 04086 void 04087 TclInvalidateNsPath( 04088 Namespace *nsPtr) 04089 { 04090 NamespacePathEntry *nsPathPtr = nsPtr->commandPathSourceList; 04091 while (nsPathPtr != NULL) { 04092 if (nsPathPtr->nsPtr != NULL) { 04093 nsPathPtr->creatorNsPtr->cmdRefEpoch++; 04094 } 04095 nsPathPtr = nsPathPtr->nextPtr; 04096 } 04097 } 04098 04099 /* 04100 *---------------------------------------------------------------------- 04101 * 04102 * NamespaceQualifiersCmd -- 04103 * 04104 * Invoked to implement the "namespace qualifiers" command that returns 04105 * any leading namespace qualifiers in a string. These qualifiers are 04106 * namespace names separated by "::"s. For example, for "::foo::p" this 04107 * command returns "::foo", and for "::" it returns "". This command is 04108 * the complement of the "namespace tail" command. Note that this command 04109 * does not check whether the "namespace" names are, in fact, the names 04110 * of currently defined namespaces. Handles the following syntax: 04111 * 04112 * namespace qualifiers string 04113 * 04114 * Results: 04115 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 04116 * 04117 * Side effects: 04118 * Returns a result in the interpreter's result object. If anything goes 04119 * wrong, the result is an error message. 04120 * 04121 *---------------------------------------------------------------------- 04122 */ 04123 04124 static int 04125 NamespaceQualifiersCmd( 04126 ClientData dummy, /* Not used. */ 04127 Tcl_Interp *interp, /* Current interpreter. */ 04128 int objc, /* Number of arguments. */ 04129 Tcl_Obj *const objv[]) /* Argument objects. */ 04130 { 04131 register char *name, *p; 04132 int length; 04133 04134 if (objc != 3) { 04135 Tcl_WrongNumArgs(interp, 2, objv, "string"); 04136 return TCL_ERROR; 04137 } 04138 04139 /* 04140 * Find the end of the string, then work backward and find the start of 04141 * the last "::" qualifier. 04142 */ 04143 04144 name = TclGetString(objv[2]); 04145 for (p = name; *p != '\0'; p++) { 04146 /* empty body */ 04147 } 04148 while (--p >= name) { 04149 if ((*p == ':') && (p > name) && (*(p-1) == ':')) { 04150 p -= 2; /* Back up over the :: */ 04151 while ((p >= name) && (*p == ':')) { 04152 p--; /* Back up over the preceeding : */ 04153 } 04154 break; 04155 } 04156 } 04157 04158 if (p >= name) { 04159 length = p-name+1; 04160 Tcl_SetObjResult(interp, Tcl_NewStringObj(name, length)); 04161 } 04162 return TCL_OK; 04163 } 04164 04165 /* 04166 *---------------------------------------------------------------------- 04167 * 04168 * NamespaceUnknownCmd -- 04169 * 04170 * Invoked to implement the "namespace unknown" command (TIP 181) that 04171 * sets or queries a per-namespace unknown command handler. This handler 04172 * is called when command lookup fails (current and global ns). The 04173 * default handler for the global namespace is ::unknown. The default 04174 * handler for other namespaces is to call the global namespace unknown 04175 * handler. Passing an empty list results in resetting the handler to its 04176 * default. 04177 * 04178 * namespace unknown ?handler? 04179 * 04180 * Results: 04181 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 04182 * 04183 * Side effects: 04184 * If no handler is specified, returns a result in the interpreter's 04185 * result object, otherwise it sets the unknown handler pointer in the 04186 * current namespace to the script fragment provided. If anything goes 04187 * wrong, the result is an error message. 04188 * 04189 *---------------------------------------------------------------------- 04190 */ 04191 04192 static int 04193 NamespaceUnknownCmd( 04194 ClientData dummy, /* Not used. */ 04195 Tcl_Interp *interp, /* Current interpreter. */ 04196 int objc, /* Number of arguments. */ 04197 Tcl_Obj *const objv[]) /* Argument objects. */ 04198 { 04199 Tcl_Namespace *currNsPtr; 04200 Tcl_Obj *resultPtr; 04201 int rc; 04202 04203 if (objc > 3) { 04204 Tcl_WrongNumArgs(interp, 2, objv, "?script?"); 04205 return TCL_ERROR; 04206 } 04207 04208 currNsPtr = TclGetCurrentNamespace(interp); 04209 04210 if (objc == 2) { 04211 /* 04212 * Introspection - return the current namespace handler. 04213 */ 04214 04215 resultPtr = Tcl_GetNamespaceUnknownHandler(interp, currNsPtr); 04216 if (resultPtr == NULL) { 04217 TclNewObj(resultPtr); 04218 } 04219 Tcl_SetObjResult(interp, resultPtr); 04220 } else { 04221 rc = Tcl_SetNamespaceUnknownHandler(interp, currNsPtr, objv[2]); 04222 if (rc == TCL_OK) { 04223 Tcl_SetObjResult(interp, objv[2]); 04224 } 04225 return rc; 04226 } 04227 return TCL_OK; 04228 } 04229 04230 /* 04231 *---------------------------------------------------------------------- 04232 * 04233 * Tcl_GetNamespaceUnknownHandler -- 04234 * 04235 * Returns the unknown command handler registered for the given 04236 * namespace. 04237 * 04238 * Results: 04239 * Returns the current unknown command handler, or NULL if none exists 04240 * for the namespace. 04241 * 04242 * Side effects: 04243 * None. 04244 * 04245 *---------------------------------------------------------------------- 04246 */ 04247 04248 Tcl_Obj * 04249 Tcl_GetNamespaceUnknownHandler( 04250 Tcl_Interp *interp, /* The interpreter in which the namespace 04251 * exists. */ 04252 Tcl_Namespace *nsPtr) /* The namespace. */ 04253 { 04254 Namespace *currNsPtr = (Namespace *)nsPtr; 04255 04256 if (currNsPtr->unknownHandlerPtr == NULL && 04257 currNsPtr == ((Interp *)interp)->globalNsPtr) { 04258 /* 04259 * Default handler for global namespace is "::unknown". For all other 04260 * namespaces, it is NULL (which falls back on the global unknown 04261 * handler). 04262 */ 04263 04264 TclNewLiteralStringObj(currNsPtr->unknownHandlerPtr, "::unknown"); 04265 Tcl_IncrRefCount(currNsPtr->unknownHandlerPtr); 04266 } 04267 return currNsPtr->unknownHandlerPtr; 04268 } 04269 04270 /* 04271 *---------------------------------------------------------------------- 04272 * 04273 * Tcl_SetNamespaceUnknownHandler -- 04274 * 04275 * Sets the unknown command handler for the given namespace to the 04276 * command prefix passed. 04277 * 04278 * Results: 04279 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 04280 * 04281 * Side effects: 04282 * Sets the namespace unknown command handler. If the passed in handler 04283 * is NULL or an empty list, then the handler is reset to its default. If 04284 * an error occurs, then an error message is left in the interpreter 04285 * result. 04286 * 04287 *---------------------------------------------------------------------- 04288 */ 04289 04290 int 04291 Tcl_SetNamespaceUnknownHandler( 04292 Tcl_Interp *interp, /* Interpreter in which the namespace 04293 * exists. */ 04294 Tcl_Namespace *nsPtr, /* Namespace which is being updated. */ 04295 Tcl_Obj *handlerPtr) /* The new handler, or NULL to reset. */ 04296 { 04297 int lstlen; 04298 Namespace *currNsPtr = (Namespace *)nsPtr; 04299 04300 if (currNsPtr->unknownHandlerPtr != NULL) { 04301 /* 04302 * Remove old handler first. 04303 */ 04304 04305 Tcl_DecrRefCount(currNsPtr->unknownHandlerPtr); 04306 currNsPtr->unknownHandlerPtr = NULL; 04307 } 04308 04309 /* 04310 * If NULL or an empty list is passed, then reset to the default 04311 * handler. 04312 */ 04313 04314 if (handlerPtr == NULL) { 04315 currNsPtr->unknownHandlerPtr = NULL; 04316 } else if (TclListObjLength(interp, handlerPtr, &lstlen) != TCL_OK) { 04317 /* 04318 * Not a list. 04319 */ 04320 04321 return TCL_ERROR; 04322 } else if (lstlen == 0) { 04323 /* 04324 * Empty list - reset to default. 04325 */ 04326 04327 currNsPtr->unknownHandlerPtr = NULL; 04328 } else { 04329 /* 04330 * Increment ref count and store. The reference count is decremented 04331 * either in the code above, or when the namespace is deleted. 04332 */ 04333 04334 Tcl_IncrRefCount(handlerPtr); 04335 currNsPtr->unknownHandlerPtr = handlerPtr; 04336 } 04337 return TCL_OK; 04338 } 04339 04340 /* 04341 *---------------------------------------------------------------------- 04342 * 04343 * NamespaceTailCmd -- 04344 * 04345 * Invoked to implement the "namespace tail" command that returns the 04346 * trailing name at the end of a string with "::" namespace qualifiers. 04347 * These qualifiers are namespace names separated by "::"s. For example, 04348 * for "::foo::p" this command returns "p", and for "::" it returns "". 04349 * This command is the complement of the "namespace qualifiers" command. 04350 * Note that this command does not check whether the "namespace" names 04351 * are, in fact, the names of currently defined namespaces. Handles the 04352 * following syntax: 04353 * 04354 * namespace tail string 04355 * 04356 * Results: 04357 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 04358 * 04359 * Side effects: 04360 * Returns a result in the interpreter's result object. If anything goes 04361 * wrong, the result is an error message. 04362 * 04363 *---------------------------------------------------------------------- 04364 */ 04365 04366 static int 04367 NamespaceTailCmd( 04368 ClientData dummy, /* Not used. */ 04369 Tcl_Interp *interp, /* Current interpreter. */ 04370 int objc, /* Number of arguments. */ 04371 Tcl_Obj *const objv[]) /* Argument objects. */ 04372 { 04373 register char *name, *p; 04374 04375 if (objc != 3) { 04376 Tcl_WrongNumArgs(interp, 2, objv, "string"); 04377 return TCL_ERROR; 04378 } 04379 04380 /* 04381 * Find the end of the string, then work backward and find the last "::" 04382 * qualifier. 04383 */ 04384 04385 name = TclGetString(objv[2]); 04386 for (p = name; *p != '\0'; p++) { 04387 /* empty body */ 04388 } 04389 while (--p > name) { 04390 if ((*p == ':') && (*(p-1) == ':')) { 04391 p++; /* Just after the last "::" */ 04392 break; 04393 } 04394 } 04395 04396 if (p >= name) { 04397 Tcl_SetObjResult(interp, Tcl_NewStringObj(p, -1)); 04398 } 04399 return TCL_OK; 04400 } 04401 04402 /* 04403 *---------------------------------------------------------------------- 04404 * 04405 * NamespaceUpvarCmd -- 04406 * 04407 * Invoked to implement the "namespace upvar" command, that creates 04408 * variables in the current scope linked to variables in another 04409 * namespace. Handles the following syntax: 04410 * 04411 * namespace upvar ns otherVar myVar ?otherVar myVar ...? 04412 * 04413 * Results: 04414 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 04415 * 04416 * Side effects: 04417 * Creates new variables in the current scope, linked to the 04418 * corresponding variables in the stipulated nmamespace. If anything goes 04419 * wrong, the result is an error message. 04420 * 04421 *---------------------------------------------------------------------- 04422 */ 04423 04424 static int 04425 NamespaceUpvarCmd( 04426 ClientData dummy, /* Not used. */ 04427 Tcl_Interp *interp, /* Current interpreter. */ 04428 int objc, /* Number of arguments. */ 04429 Tcl_Obj *const objv[]) /* Argument objects. */ 04430 { 04431 Interp *iPtr = (Interp *) interp; 04432 Tcl_Namespace *nsPtr, *savedNsPtr; 04433 Var *otherPtr, *arrayPtr; 04434 char *myName; 04435 04436 if (objc < 5 || !(objc & 1)) { 04437 Tcl_WrongNumArgs(interp, 2, objv, 04438 "ns otherVar myVar ?otherVar myVar ...?"); 04439 return TCL_ERROR; 04440 } 04441 04442 if (TclGetNamespaceFromObj(interp, objv[2], &nsPtr) != TCL_OK) { 04443 return TCL_ERROR; 04444 } 04445 04446 objc -= 3; 04447 objv += 3; 04448 04449 for (; objc>0 ; objc-=2, objv+=2) { 04450 /* 04451 * Locate the other variable 04452 */ 04453 04454 savedNsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr; 04455 iPtr->varFramePtr->nsPtr = (Namespace *) nsPtr; 04456 otherPtr = TclObjLookupVarEx(interp, objv[0], NULL, 04457 (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "access", 04458 /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); 04459 iPtr->varFramePtr->nsPtr = (Namespace *) savedNsPtr; 04460 if (otherPtr == NULL) { 04461 return TCL_ERROR; 04462 } 04463 04464 /* 04465 * Create the new variable and link it to otherPtr. 04466 */ 04467 04468 myName = TclGetString(objv[1]); 04469 if (TclPtrMakeUpvar(interp, otherPtr, myName, 0, -1) != TCL_OK) { 04470 return TCL_ERROR; 04471 } 04472 } 04473 04474 return TCL_OK; 04475 } 04476 04477 /* 04478 *---------------------------------------------------------------------- 04479 * 04480 * NamespaceWhichCmd -- 04481 * 04482 * Invoked to implement the "namespace which" command that returns the 04483 * fully-qualified name of a command or variable. If the specified 04484 * command or variable does not exist, it returns "". Handles the 04485 * following syntax: 04486 * 04487 * namespace which ?-command? ?-variable? name 04488 * 04489 * Results: 04490 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 04491 * 04492 * Side effects: 04493 * Returns a result in the interpreter's result object. If anything goes 04494 * wrong, the result is an error message. 04495 * 04496 *---------------------------------------------------------------------- 04497 */ 04498 04499 static int 04500 NamespaceWhichCmd( 04501 ClientData dummy, /* Not used. */ 04502 Tcl_Interp *interp, /* Current interpreter. */ 04503 int objc, /* Number of arguments. */ 04504 Tcl_Obj *const objv[]) /* Argument objects. */ 04505 { 04506 static const char *opts[] = { 04507 "-command", "-variable", NULL 04508 }; 04509 int lookupType = 0; 04510 Tcl_Obj *resultPtr; 04511 04512 if (objc < 3 || objc > 4) { 04513 badArgs: 04514 Tcl_WrongNumArgs(interp, 2, objv, "?-command? ?-variable? name"); 04515 return TCL_ERROR; 04516 } else if (objc == 4) { 04517 /* 04518 * Look for a flag controlling the lookup. 04519 */ 04520 04521 if (Tcl_GetIndexFromObj(interp, objv[2], opts, "option", 0, 04522 &lookupType) != TCL_OK) { 04523 /* 04524 * Preserve old style of error message! 04525 */ 04526 04527 Tcl_ResetResult(interp); 04528 goto badArgs; 04529 } 04530 } 04531 04532 TclNewObj(resultPtr); 04533 switch (lookupType) { 04534 case 0: { /* -command */ 04535 Tcl_Command cmd = Tcl_GetCommandFromObj(interp, objv[objc-1]); 04536 04537 if (cmd != NULL) { 04538 Tcl_GetCommandFullName(interp, cmd, resultPtr); 04539 } 04540 break; 04541 } 04542 case 1: { /* -variable */ 04543 Tcl_Var var = Tcl_FindNamespaceVar(interp, 04544 TclGetString(objv[objc-1]), NULL, /*flags*/ 0); 04545 04546 if (var != NULL) { 04547 Tcl_GetVariableFullName(interp, var, resultPtr); 04548 } 04549 break; 04550 } 04551 } 04552 Tcl_SetObjResult(interp, resultPtr); 04553 return TCL_OK; 04554 } 04555 04556 /* 04557 *---------------------------------------------------------------------- 04558 * 04559 * FreeNsNameInternalRep -- 04560 * 04561 * Frees the resources associated with a nsName object's internal 04562 * representation. 04563 * 04564 * Results: 04565 * None. 04566 * 04567 * Side effects: 04568 * Decrements the ref count of any Namespace structure pointed to by the 04569 * nsName's internal representation. If there are no more references to 04570 * the namespace, it's structure will be freed. 04571 * 04572 *---------------------------------------------------------------------- 04573 */ 04574 04575 static void 04576 FreeNsNameInternalRep( 04577 register Tcl_Obj *objPtr) /* nsName object with internal representation 04578 * to free. */ 04579 { 04580 register ResolvedNsName *resNamePtr = (ResolvedNsName *) 04581 objPtr->internalRep.twoPtrValue.ptr1; 04582 Namespace *nsPtr; 04583 04584 /* 04585 * Decrement the reference count of the namespace. If there are no more 04586 * references, free it up. 04587 */ 04588 04589 resNamePtr->refCount--; 04590 if (resNamePtr->refCount == 0) { 04591 04592 /* 04593 * Decrement the reference count for the cached namespace. If the 04594 * namespace is dead, and there are no more references to it, free 04595 * it. 04596 */ 04597 04598 nsPtr = resNamePtr->nsPtr; 04599 nsPtr->refCount--; 04600 if ((nsPtr->refCount == 0) && (nsPtr->flags & NS_DEAD)) { 04601 NamespaceFree(nsPtr); 04602 } 04603 ckfree((char *) resNamePtr); 04604 } 04605 } 04606 04607 /* 04608 *---------------------------------------------------------------------- 04609 * 04610 * DupNsNameInternalRep -- 04611 * 04612 * Initializes the internal representation of a nsName object to a copy 04613 * of the internal representation of another nsName object. 04614 * 04615 * Results: 04616 * None. 04617 * 04618 * Side effects: 04619 * copyPtr's internal rep is set to refer to the same namespace 04620 * referenced by srcPtr's internal rep. Increments the ref count of the 04621 * ResolvedNsName structure used to hold the namespace reference. 04622 * 04623 *---------------------------------------------------------------------- 04624 */ 04625 04626 static void 04627 DupNsNameInternalRep( 04628 Tcl_Obj *srcPtr, /* Object with internal rep to copy. */ 04629 register Tcl_Obj *copyPtr) /* Object with internal rep to set. */ 04630 { 04631 register ResolvedNsName *resNamePtr = (ResolvedNsName *) 04632 srcPtr->internalRep.twoPtrValue.ptr1; 04633 04634 copyPtr->internalRep.twoPtrValue.ptr1 = resNamePtr; 04635 resNamePtr->refCount++; 04636 copyPtr->typePtr = &nsNameType; 04637 } 04638 04639 /* 04640 *---------------------------------------------------------------------- 04641 * 04642 * SetNsNameFromAny -- 04643 * 04644 * Attempt to generate a nsName internal representation for a Tcl object. 04645 * 04646 * Results: 04647 * Returns TCL_OK if the value could be converted to a proper namespace 04648 * reference. Otherwise, it returns TCL_ERROR, along with an error 04649 * message in the interpreter's result object. 04650 * 04651 * Side effects: 04652 * If successful, the object is made a nsName object. Its internal rep is 04653 * set to point to a ResolvedNsName, which contains a cached pointer to 04654 * the Namespace. Reference counts are kept on both the ResolvedNsName 04655 * and the Namespace, so we can keep track of their usage and free them 04656 * when appropriate. 04657 * 04658 *---------------------------------------------------------------------- 04659 */ 04660 04661 static int 04662 SetNsNameFromAny( 04663 Tcl_Interp *interp, /* Points to the namespace in which to resolve 04664 * name. Also used for error reporting if not 04665 * NULL. */ 04666 register Tcl_Obj *objPtr) /* The object to convert. */ 04667 { 04668 const char *dummy; 04669 Namespace *nsPtr, *dummy1Ptr, *dummy2Ptr; 04670 register ResolvedNsName *resNamePtr; 04671 const char *name = TclGetString(objPtr); 04672 04673 TclGetNamespaceForQualName(interp, name, NULL, TCL_FIND_ONLY_NS, 04674 &nsPtr, &dummy1Ptr, &dummy2Ptr, &dummy); 04675 04676 /* 04677 * If we found a namespace, then create a new ResolvedNsName structure 04678 * that holds a reference to it. 04679 */ 04680 04681 if ((nsPtr == NULL) || (nsPtr->flags & NS_DYING)) { 04682 /* 04683 * Our failed lookup proves any previously cached nsName intrep is no 04684 * longer valid. Get rid of it so we no longer waste memory storing 04685 * it, nor time determining its invalidity again and again. 04686 */ 04687 04688 if (objPtr->typePtr == &nsNameType) { 04689 TclFreeIntRep(objPtr); 04690 objPtr->typePtr = NULL; 04691 } 04692 return TCL_ERROR; 04693 } 04694 04695 nsPtr->refCount++; 04696 resNamePtr = (ResolvedNsName *) ckalloc(sizeof(ResolvedNsName)); 04697 resNamePtr->nsPtr = nsPtr; 04698 if ((name[0] == ':') && (name[1] == ':')) { 04699 resNamePtr->refNsPtr = NULL; 04700 } else { 04701 resNamePtr->refNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp); 04702 } 04703 resNamePtr->refCount = 1; 04704 TclFreeIntRep(objPtr); 04705 objPtr->internalRep.twoPtrValue.ptr1 = resNamePtr; 04706 objPtr->typePtr = &nsNameType; 04707 return TCL_OK; 04708 } 04709 04710 /* 04711 *---------------------------------------------------------------------- 04712 * 04713 * NamespaceEnsembleCmd -- 04714 * 04715 * Invoked to implement the "namespace ensemble" command that creates and 04716 * manipulates ensembles built on top of namespaces. Handles the 04717 * following syntax: 04718 * 04719 * namespace ensemble name ?dictionary? 04720 * 04721 * Results: 04722 * Returns TCL_OK if successful, and TCL_ERROR if anything goes wrong. 04723 * 04724 * Side effects: 04725 * Creates the ensemble for the namespace if one did not previously 04726 * exist. Alternatively, alters the way that the ensemble's subcommand => 04727 * implementation prefix is configured. 04728 * 04729 *---------------------------------------------------------------------- 04730 */ 04731 04732 static int 04733 NamespaceEnsembleCmd( 04734 ClientData dummy, 04735 Tcl_Interp *interp, 04736 int objc, 04737 Tcl_Obj *const objv[]) 04738 { 04739 Namespace *nsPtr; 04740 Tcl_Command token; 04741 static const char *subcommands[] = { 04742 "configure", "create", "exists", NULL 04743 }; 04744 enum EnsSubcmds { 04745 ENS_CONFIG, ENS_CREATE, ENS_EXISTS 04746 }; 04747 static const char *createOptions[] = { 04748 "-command", "-map", "-prefixes", "-subcommands", "-unknown", NULL 04749 }; 04750 enum EnsCreateOpts { 04751 CRT_CMD, CRT_MAP, CRT_PREFIX, CRT_SUBCMDS, CRT_UNKNOWN 04752 }; 04753 static const char *configOptions[] = { 04754 "-map", "-namespace", "-prefixes", "-subcommands", "-unknown", NULL 04755 }; 04756 enum EnsConfigOpts { 04757 CONF_MAP, CONF_NAMESPACE, CONF_PREFIX, CONF_SUBCMDS, CONF_UNKNOWN 04758 }; 04759 int index; 04760 04761 nsPtr = (Namespace *) TclGetCurrentNamespace(interp); 04762 if (nsPtr == NULL || nsPtr->flags & NS_DYING) { 04763 if (!Tcl_InterpDeleted(interp)) { 04764 Tcl_AppendResult(interp, 04765 "tried to manipulate ensemble of deleted namespace", NULL); 04766 } 04767 return TCL_ERROR; 04768 } 04769 04770 if (objc < 3) { 04771 Tcl_WrongNumArgs(interp, 2, objv, "subcommand ?arg ...?"); 04772 return TCL_ERROR; 04773 } 04774 if (Tcl_GetIndexFromObj(interp, objv[2], subcommands, "subcommand", 0, 04775 &index) != TCL_OK) { 04776 return TCL_ERROR; 04777 } 04778 04779 switch ((enum EnsSubcmds) index) { 04780 case ENS_CREATE: { 04781 char *name; 04782 Tcl_DictSearch search; 04783 Tcl_Obj *listObj; 04784 int done, len, allocatedMapFlag = 0; 04785 /* 04786 * Defaults 04787 */ 04788 Tcl_Obj *subcmdObj = NULL; 04789 Tcl_Obj *mapObj = NULL; 04790 int permitPrefix = 1; 04791 Tcl_Obj *unknownObj = NULL; 04792 04793 objv += 3; 04794 objc -= 3; 04795 04796 /* 04797 * Work out what name to use for the command to create. If supplied, 04798 * it is either fully specified or relative to the current namespace. 04799 * If not supplied, it is exactly the name of the current namespace. 04800 */ 04801 04802 name = nsPtr->fullName; 04803 04804 /* 04805 * Parse the option list, applying type checks as we go. Note that we 04806 * are not incrementing any reference counts in the objects at this 04807 * stage, so the presence of an option multiple times won't cause any 04808 * memory leaks. 04809 */ 04810 04811 for (; objc>1 ; objc-=2,objv+=2 ) { 04812 if (Tcl_GetIndexFromObj(interp, objv[0], createOptions, "option", 04813 0, &index) != TCL_OK) { 04814 if (allocatedMapFlag) { 04815 Tcl_DecrRefCount(mapObj); 04816 } 04817 return TCL_ERROR; 04818 } 04819 switch ((enum EnsCreateOpts) index) { 04820 case CRT_CMD: 04821 name = TclGetString(objv[1]); 04822 continue; 04823 case CRT_SUBCMDS: 04824 if (TclListObjLength(interp, objv[1], &len) != TCL_OK) { 04825 if (allocatedMapFlag) { 04826 Tcl_DecrRefCount(mapObj); 04827 } 04828 return TCL_ERROR; 04829 } 04830 subcmdObj = (len > 0 ? objv[1] : NULL); 04831 continue; 04832 case CRT_MAP: { 04833 Tcl_Obj *patchedDict = NULL, *subcmdObj; 04834 04835 /* 04836 * Verify that the map is sensible. 04837 */ 04838 04839 if (Tcl_DictObjFirst(interp, objv[1], &search, 04840 &subcmdObj, &listObj, &done) != TCL_OK) { 04841 if (allocatedMapFlag) { 04842 Tcl_DecrRefCount(mapObj); 04843 } 04844 return TCL_ERROR; 04845 } 04846 if (done) { 04847 mapObj = NULL; 04848 continue; 04849 } 04850 do { 04851 Tcl_Obj **listv; 04852 char *cmd; 04853 04854 if (TclListObjGetElements(interp, listObj, &len, 04855 &listv) != TCL_OK) { 04856 Tcl_DictObjDone(&search); 04857 if (patchedDict) { 04858 Tcl_DecrRefCount(patchedDict); 04859 } 04860 if (allocatedMapFlag) { 04861 Tcl_DecrRefCount(mapObj); 04862 } 04863 return TCL_ERROR; 04864 } 04865 if (len < 1) { 04866 Tcl_SetResult(interp, 04867 "ensemble subcommand implementations " 04868 "must be non-empty lists", TCL_STATIC); 04869 Tcl_DictObjDone(&search); 04870 if (patchedDict) { 04871 Tcl_DecrRefCount(patchedDict); 04872 } 04873 if (allocatedMapFlag) { 04874 Tcl_DecrRefCount(mapObj); 04875 } 04876 return TCL_ERROR; 04877 } 04878 cmd = TclGetString(listv[0]); 04879 if (!(cmd[0] == ':' && cmd[1] == ':')) { 04880 Tcl_Obj *newList = Tcl_NewListObj(len, listv); 04881 Tcl_Obj *newCmd = Tcl_NewStringObj(nsPtr->fullName,-1); 04882 04883 if (nsPtr->parentPtr) { 04884 Tcl_AppendStringsToObj(newCmd, "::", NULL); 04885 } 04886 Tcl_AppendObjToObj(newCmd, listv[0]); 04887 Tcl_ListObjReplace(NULL, newList, 0, 1, 1, &newCmd); 04888 if (patchedDict == NULL) { 04889 patchedDict = Tcl_DuplicateObj(objv[1]); 04890 } 04891 Tcl_DictObjPut(NULL, patchedDict, subcmdObj, newList); 04892 } 04893 Tcl_DictObjNext(&search, &subcmdObj, &listObj, &done); 04894 } while (!done); 04895 04896 if (allocatedMapFlag) { 04897 Tcl_DecrRefCount(mapObj); 04898 } 04899 mapObj = (patchedDict ? patchedDict : objv[1]); 04900 if (patchedDict) { 04901 allocatedMapFlag = 1; 04902 } 04903 continue; 04904 } 04905 case CRT_PREFIX: 04906 if (Tcl_GetBooleanFromObj(interp, objv[1], 04907 &permitPrefix) != TCL_OK) { 04908 if (allocatedMapFlag) { 04909 Tcl_DecrRefCount(mapObj); 04910 } 04911 return TCL_ERROR; 04912 } 04913 continue; 04914 case CRT_UNKNOWN: 04915 if (TclListObjLength(interp, objv[1], &len) != TCL_OK) { 04916 if (allocatedMapFlag) { 04917 Tcl_DecrRefCount(mapObj); 04918 } 04919 return TCL_ERROR; 04920 } 04921 unknownObj = (len > 0 ? objv[1] : NULL); 04922 continue; 04923 } 04924 } 04925 04926 /* 04927 * Create the ensemble. Note that this might delete another ensemble 04928 * linked to the same namespace, so we must be careful. However, we 04929 * should be OK because we only link the namespace into the list once 04930 * we've created it (and after any deletions have occurred.) 04931 */ 04932 04933 token = Tcl_CreateEnsemble(interp, name, NULL, 04934 (permitPrefix ? TCL_ENSEMBLE_PREFIX : 0)); 04935 Tcl_SetEnsembleSubcommandList(interp, token, subcmdObj); 04936 Tcl_SetEnsembleMappingDict(interp, token, mapObj); 04937 Tcl_SetEnsembleUnknownHandler(interp, token, unknownObj); 04938 04939 /* 04940 * Tricky! Must ensure that the result is not shared (command delete 04941 * traces could have corrupted the pristine object that we started 04942 * with). [Snit test rename-1.5] 04943 */ 04944 04945 Tcl_ResetResult(interp); 04946 Tcl_GetCommandFullName(interp, token, Tcl_GetObjResult(interp)); 04947 return TCL_OK; 04948 } 04949 04950 case ENS_EXISTS: 04951 if (objc != 4) { 04952 Tcl_WrongNumArgs(interp, 3, objv, "cmdname"); 04953 return TCL_ERROR; 04954 } 04955 Tcl_SetObjResult(interp, Tcl_NewBooleanObj( 04956 Tcl_FindEnsemble(interp, objv[3], 0) != NULL)); 04957 return TCL_OK; 04958 04959 case ENS_CONFIG: 04960 if (objc < 4 || (objc != 5 && objc & 1)) { 04961 Tcl_WrongNumArgs(interp, 3, objv, "cmdname ?opt? ?value? ..."); 04962 return TCL_ERROR; 04963 } 04964 token = Tcl_FindEnsemble(interp, objv[3], TCL_LEAVE_ERR_MSG); 04965 if (token == NULL) { 04966 return TCL_ERROR; 04967 } 04968 04969 if (objc == 5) { 04970 Tcl_Obj *resultObj = NULL; /* silence gcc 4 warning */ 04971 04972 if (Tcl_GetIndexFromObj(interp, objv[4], configOptions, "option", 04973 0, &index) != TCL_OK) { 04974 return TCL_ERROR; 04975 } 04976 switch ((enum EnsConfigOpts) index) { 04977 case CONF_SUBCMDS: 04978 Tcl_GetEnsembleSubcommandList(NULL, token, &resultObj); 04979 if (resultObj != NULL) { 04980 Tcl_SetObjResult(interp, resultObj); 04981 } 04982 break; 04983 case CONF_MAP: 04984 Tcl_GetEnsembleMappingDict(NULL, token, &resultObj); 04985 if (resultObj != NULL) { 04986 Tcl_SetObjResult(interp, resultObj); 04987 } 04988 break; 04989 case CONF_NAMESPACE: { 04990 Tcl_Namespace *namespacePtr = NULL; /* silence gcc 4 warning */ 04991 04992 Tcl_GetEnsembleNamespace(NULL, token, &namespacePtr); 04993 Tcl_SetResult(interp, ((Namespace *)namespacePtr)->fullName, 04994 TCL_VOLATILE); 04995 break; 04996 } 04997 case CONF_PREFIX: { 04998 int flags = 0; /* silence gcc 4 warning */ 04999 05000 Tcl_GetEnsembleFlags(NULL, token, &flags); 05001 Tcl_SetObjResult(interp, 05002 Tcl_NewBooleanObj(flags & TCL_ENSEMBLE_PREFIX)); 05003 break; 05004 } 05005 case CONF_UNKNOWN: 05006 Tcl_GetEnsembleUnknownHandler(NULL, token, &resultObj); 05007 if (resultObj != NULL) { 05008 Tcl_SetObjResult(interp, resultObj); 05009 } 05010 break; 05011 } 05012 return TCL_OK; 05013 05014 } else if (objc == 4) { 05015 /* 05016 * Produce list of all information. 05017 */ 05018 05019 Tcl_Obj *resultObj, *tmpObj = NULL; /* silence gcc 4 warning */ 05020 Tcl_Namespace *namespacePtr = NULL; /* silence gcc 4 warning */ 05021 int flags = 0; /* silence gcc 4 warning */ 05022 05023 TclNewObj(resultObj); 05024 05025 /* -map option */ 05026 Tcl_ListObjAppendElement(NULL, resultObj, 05027 Tcl_NewStringObj(configOptions[CONF_MAP], -1)); 05028 Tcl_GetEnsembleMappingDict(NULL, token, &tmpObj); 05029 Tcl_ListObjAppendElement(NULL, resultObj, 05030 (tmpObj != NULL) ? tmpObj : Tcl_NewObj()); 05031 05032 /* -namespace option */ 05033 Tcl_ListObjAppendElement(NULL, resultObj, 05034 Tcl_NewStringObj(configOptions[CONF_NAMESPACE], -1)); 05035 Tcl_GetEnsembleNamespace(NULL, token, &namespacePtr); 05036 Tcl_ListObjAppendElement(NULL, resultObj, 05037 Tcl_NewStringObj(((Namespace *)namespacePtr)->fullName, 05038 -1)); 05039 05040 /* -prefix option */ 05041 Tcl_ListObjAppendElement(NULL, resultObj, 05042 Tcl_NewStringObj(configOptions[CONF_PREFIX], -1)); 05043 Tcl_GetEnsembleFlags(NULL, token, &flags); 05044 Tcl_ListObjAppendElement(NULL, resultObj, 05045 Tcl_NewBooleanObj(flags & TCL_ENSEMBLE_PREFIX)); 05046 05047 /* -subcommands option */ 05048 Tcl_ListObjAppendElement(NULL, resultObj, 05049 Tcl_NewStringObj(configOptions[CONF_SUBCMDS], -1)); 05050 Tcl_GetEnsembleSubcommandList(NULL, token, &tmpObj); 05051 Tcl_ListObjAppendElement(NULL, resultObj, 05052 (tmpObj != NULL) ? tmpObj : Tcl_NewObj()); 05053 05054 /* -unknown option */ 05055 Tcl_ListObjAppendElement(NULL, resultObj, 05056 Tcl_NewStringObj(configOptions[CONF_UNKNOWN], -1)); 05057 Tcl_GetEnsembleUnknownHandler(NULL, token, &tmpObj); 05058 Tcl_ListObjAppendElement(NULL, resultObj, 05059 (tmpObj != NULL) ? tmpObj : Tcl_NewObj()); 05060 05061 Tcl_SetObjResult(interp, resultObj); 05062 return TCL_OK; 05063 } else { 05064 Tcl_DictSearch search; 05065 Tcl_Obj *listObj; 05066 int done, len, allocatedMapFlag = 0; 05067 Tcl_Obj *subcmdObj = NULL, *mapObj = NULL, 05068 *unknownObj = NULL; /* Defaults, silence gcc 4 warnings */ 05069 int permitPrefix, flags = 0; /* silence gcc 4 warning */ 05070 05071 Tcl_GetEnsembleSubcommandList(NULL, token, &subcmdObj); 05072 Tcl_GetEnsembleMappingDict(NULL, token, &mapObj); 05073 Tcl_GetEnsembleUnknownHandler(NULL, token, &unknownObj); 05074 Tcl_GetEnsembleFlags(NULL, token, &flags); 05075 permitPrefix = (flags & TCL_ENSEMBLE_PREFIX) != 0; 05076 05077 objv += 4; 05078 objc -= 4; 05079 05080 /* 05081 * Parse the option list, applying type checks as we go. Note that 05082 * we are not incrementing any reference counts in the objects at 05083 * this stage, so the presence of an option multiple times won't 05084 * cause any memory leaks. 05085 */ 05086 05087 for (; objc>0 ; objc-=2,objv+=2 ) { 05088 if (Tcl_GetIndexFromObj(interp, objv[0], configOptions, 05089 "option", 0, &index) != TCL_OK) { 05090 if (allocatedMapFlag) { 05091 Tcl_DecrRefCount(mapObj); 05092 } 05093 return TCL_ERROR; 05094 } 05095 switch ((enum EnsConfigOpts) index) { 05096 case CONF_SUBCMDS: 05097 if (TclListObjLength(interp, objv[1], &len) != TCL_OK) { 05098 if (allocatedMapFlag) { 05099 Tcl_DecrRefCount(mapObj); 05100 } 05101 return TCL_ERROR; 05102 } 05103 subcmdObj = (len > 0 ? objv[1] : NULL); 05104 continue; 05105 case CONF_MAP: { 05106 Tcl_Obj *patchedDict = NULL, *subcmdObj; 05107 05108 /* 05109 * Verify that the map is sensible. 05110 */ 05111 05112 if (Tcl_DictObjFirst(interp, objv[1], &search, 05113 &subcmdObj, &listObj, &done) != TCL_OK) { 05114 if (allocatedMapFlag) { 05115 Tcl_DecrRefCount(mapObj); 05116 } 05117 return TCL_ERROR; 05118 } 05119 if (done) { 05120 mapObj = NULL; 05121 continue; 05122 } 05123 do { 05124 Tcl_Obj **listv; 05125 char *cmd; 05126 05127 if (TclListObjGetElements(interp, listObj, &len, 05128 &listv) != TCL_OK) { 05129 Tcl_DictObjDone(&search); 05130 if (patchedDict) { 05131 Tcl_DecrRefCount(patchedDict); 05132 } 05133 if (allocatedMapFlag) { 05134 Tcl_DecrRefCount(mapObj); 05135 } 05136 return TCL_ERROR; 05137 } 05138 if (len < 1) { 05139 Tcl_SetResult(interp, 05140 "ensemble subcommand implementations " 05141 "must be non-empty lists", TCL_STATIC); 05142 Tcl_DictObjDone(&search); 05143 if (patchedDict) { 05144 Tcl_DecrRefCount(patchedDict); 05145 } 05146 if (allocatedMapFlag) { 05147 Tcl_DecrRefCount(mapObj); 05148 } 05149 return TCL_ERROR; 05150 } 05151 cmd = TclGetString(listv[0]); 05152 if (!(cmd[0] == ':' && cmd[1] == ':')) { 05153 Tcl_Obj *newList = Tcl_NewListObj(len, listv); 05154 Tcl_Obj *newCmd = 05155 Tcl_NewStringObj(nsPtr->fullName, -1); 05156 if (nsPtr->parentPtr) { 05157 Tcl_AppendStringsToObj(newCmd, "::", NULL); 05158 } 05159 Tcl_AppendObjToObj(newCmd, listv[0]); 05160 Tcl_ListObjReplace(NULL, newList, 0,1, 1,&newCmd); 05161 if (patchedDict == NULL) { 05162 patchedDict = Tcl_DuplicateObj(objv[1]); 05163 } 05164 Tcl_DictObjPut(NULL, patchedDict, subcmdObj, 05165 newList); 05166 } 05167 Tcl_DictObjNext(&search, &subcmdObj, &listObj, &done); 05168 } while (!done); 05169 if (allocatedMapFlag) { 05170 Tcl_DecrRefCount(mapObj); 05171 } 05172 mapObj = (patchedDict ? patchedDict : objv[1]); 05173 if (patchedDict) { 05174 allocatedMapFlag = 1; 05175 } 05176 continue; 05177 } 05178 case CONF_NAMESPACE: 05179 if (allocatedMapFlag) { 05180 Tcl_DecrRefCount(mapObj); 05181 } 05182 Tcl_AppendResult(interp, "option -namespace is read-only", 05183 NULL); 05184 return TCL_ERROR; 05185 case CONF_PREFIX: 05186 if (Tcl_GetBooleanFromObj(interp, objv[1], 05187 &permitPrefix) != TCL_OK) { 05188 if (allocatedMapFlag) { 05189 Tcl_DecrRefCount(mapObj); 05190 } 05191 return TCL_ERROR; 05192 } 05193 continue; 05194 case CONF_UNKNOWN: 05195 if (TclListObjLength(interp, objv[1], &len) != TCL_OK) { 05196 if (allocatedMapFlag) { 05197 Tcl_DecrRefCount(mapObj); 05198 } 05199 return TCL_ERROR; 05200 } 05201 unknownObj = (len > 0 ? objv[1] : NULL); 05202 continue; 05203 } 05204 } 05205 05206 /* 05207 * Update the namespace now that we've finished the parsing stage. 05208 */ 05209 05210 flags = (permitPrefix ? flags|TCL_ENSEMBLE_PREFIX 05211 : flags&~TCL_ENSEMBLE_PREFIX); 05212 Tcl_SetEnsembleSubcommandList(interp, token, subcmdObj); 05213 Tcl_SetEnsembleMappingDict(interp, token, mapObj); 05214 Tcl_SetEnsembleUnknownHandler(interp, token, unknownObj); 05215 Tcl_SetEnsembleFlags(interp, token, flags); 05216 return TCL_OK; 05217 } 05218 05219 default: 05220 Tcl_Panic("unexpected ensemble command"); 05221 } 05222 return TCL_OK; 05223 } 05224 05225 /* 05226 *---------------------------------------------------------------------- 05227 * 05228 * Tcl_CreateEnsemble -- 05229 * 05230 * Create a simple ensemble attached to the given namespace. 05231 * 05232 * Results: 05233 * The token for the command created. 05234 * 05235 * Side effects: 05236 * The ensemble is created and marked for compilation. 05237 * 05238 *---------------------------------------------------------------------- 05239 */ 05240 05241 Tcl_Command 05242 Tcl_CreateEnsemble( 05243 Tcl_Interp *interp, 05244 const char *name, 05245 Tcl_Namespace *namespacePtr, 05246 int flags) 05247 { 05248 Namespace *nsPtr = (Namespace *) namespacePtr; 05249 EnsembleConfig *ensemblePtr = (EnsembleConfig *) 05250 ckalloc(sizeof(EnsembleConfig)); 05251 Tcl_Obj *nameObj = NULL; 05252 05253 if (nsPtr == NULL) { 05254 nsPtr = (Namespace *) TclGetCurrentNamespace(interp); 05255 } 05256 05257 /* 05258 * Make the name of the ensemble into a fully qualified name. This might 05259 * allocate a temporary object. 05260 */ 05261 05262 if (!(name[0] == ':' && name[1] == ':')) { 05263 nameObj = Tcl_NewStringObj(nsPtr->fullName, -1); 05264 if (nsPtr->parentPtr == NULL) { 05265 Tcl_AppendStringsToObj(nameObj, name, NULL); 05266 } else { 05267 Tcl_AppendStringsToObj(nameObj, "::", name, NULL); 05268 } 05269 Tcl_IncrRefCount(nameObj); 05270 name = TclGetString(nameObj); 05271 } 05272 05273 ensemblePtr->nsPtr = nsPtr; 05274 ensemblePtr->epoch = 0; 05275 Tcl_InitHashTable(&ensemblePtr->subcommandTable, TCL_STRING_KEYS); 05276 ensemblePtr->subcommandArrayPtr = NULL; 05277 ensemblePtr->subcmdList = NULL; 05278 ensemblePtr->subcommandDict = NULL; 05279 ensemblePtr->flags = flags; 05280 ensemblePtr->unknownHandler = NULL; 05281 ensemblePtr->token = Tcl_CreateObjCommand(interp, name, 05282 NsEnsembleImplementationCmd, ensemblePtr, DeleteEnsembleConfig); 05283 ensemblePtr->next = (EnsembleConfig *) nsPtr->ensembles; 05284 nsPtr->ensembles = (Tcl_Ensemble *) ensemblePtr; 05285 05286 /* 05287 * Trigger an eventual recomputation of the ensemble command set. Note 05288 * that this is slightly tricky, as it means that we are not actually 05289 * counting the number of namespace export actions, but it is the simplest 05290 * way to go! 05291 */ 05292 05293 nsPtr->exportLookupEpoch++; 05294 05295 if (flags & ENSEMBLE_COMPILE) { 05296 ((Command *) ensemblePtr->token)->compileProc = TclCompileEnsemble; 05297 } 05298 05299 if (nameObj != NULL) { 05300 TclDecrRefCount(nameObj); 05301 } 05302 return ensemblePtr->token; 05303 } 05304 05305 /* 05306 *---------------------------------------------------------------------- 05307 * 05308 * Tcl_SetEnsembleSubcommandList -- 05309 * 05310 * Set the subcommand list for a particular ensemble. 05311 * 05312 * Results: 05313 * Tcl result code (error if command token does not indicate an ensemble 05314 * or the subcommand list - if non-NULL - is not a list). 05315 * 05316 * Side effects: 05317 * The ensemble is updated and marked for recompilation. 05318 * 05319 *---------------------------------------------------------------------- 05320 */ 05321 05322 int 05323 Tcl_SetEnsembleSubcommandList( 05324 Tcl_Interp *interp, 05325 Tcl_Command token, 05326 Tcl_Obj *subcmdList) 05327 { 05328 Command *cmdPtr = (Command *) token; 05329 EnsembleConfig *ensemblePtr; 05330 Tcl_Obj *oldList; 05331 05332 if (cmdPtr->objProc != NsEnsembleImplementationCmd) { 05333 Tcl_AppendResult(interp, "command is not an ensemble", NULL); 05334 return TCL_ERROR; 05335 } 05336 if (subcmdList != NULL) { 05337 int length; 05338 05339 if (TclListObjLength(interp, subcmdList, &length) != TCL_OK) { 05340 return TCL_ERROR; 05341 } 05342 if (length < 1) { 05343 subcmdList = NULL; 05344 } 05345 } 05346 05347 ensemblePtr = cmdPtr->objClientData; 05348 oldList = ensemblePtr->subcmdList; 05349 ensemblePtr->subcmdList = subcmdList; 05350 if (subcmdList != NULL) { 05351 Tcl_IncrRefCount(subcmdList); 05352 } 05353 if (oldList != NULL) { 05354 TclDecrRefCount(oldList); 05355 } 05356 05357 /* 05358 * Trigger an eventual recomputation of the ensemble command set. Note 05359 * that this is slightly tricky, as it means that we are not actually 05360 * counting the number of namespace export actions, but it is the simplest 05361 * way to go! 05362 */ 05363 05364 ensemblePtr->nsPtr->exportLookupEpoch++; 05365 05366 /* 05367 * Special hack to make compiling of [info exists] work when the 05368 * dictionary is modified. 05369 */ 05370 05371 if (cmdPtr->compileProc != NULL) { 05372 ((Interp *)interp)->compileEpoch++; 05373 } 05374 05375 return TCL_OK; 05376 } 05377 05378 /* 05379 *---------------------------------------------------------------------- 05380 * 05381 * Tcl_SetEnsembleMappingDict -- 05382 * 05383 * Set the mapping dictionary for a particular ensemble. 05384 * 05385 * Results: 05386 * Tcl result code (error if command token does not indicate an ensemble 05387 * or the mapping - if non-NULL - is not a dict). 05388 * 05389 * Side effects: 05390 * The ensemble is updated and marked for recompilation. 05391 * 05392 *---------------------------------------------------------------------- 05393 */ 05394 05395 int 05396 Tcl_SetEnsembleMappingDict( 05397 Tcl_Interp *interp, 05398 Tcl_Command token, 05399 Tcl_Obj *mapDict) 05400 { 05401 Command *cmdPtr = (Command *) token; 05402 EnsembleConfig *ensemblePtr; 05403 Tcl_Obj *oldDict; 05404 05405 if (cmdPtr->objProc != NsEnsembleImplementationCmd) { 05406 Tcl_AppendResult(interp, "command is not an ensemble", NULL); 05407 return TCL_ERROR; 05408 } 05409 if (mapDict != NULL) { 05410 int size, done; 05411 Tcl_DictSearch search; 05412 Tcl_Obj *valuePtr; 05413 05414 if (Tcl_DictObjSize(interp, mapDict, &size) != TCL_OK) { 05415 return TCL_ERROR; 05416 } 05417 05418 for (Tcl_DictObjFirst(NULL, mapDict, &search, NULL, &valuePtr, &done); 05419 !done; Tcl_DictObjNext(&search, NULL, &valuePtr, &done)) { 05420 Tcl_Obj *cmdPtr; 05421 const char *bytes; 05422 05423 if (Tcl_ListObjIndex(interp, valuePtr, 0, &cmdPtr) != TCL_OK) { 05424 Tcl_DictObjDone(&search); 05425 return TCL_ERROR; 05426 } 05427 bytes = TclGetString(cmdPtr); 05428 if (bytes[0] != ':' || bytes[1] != ':') { 05429 Tcl_AppendResult(interp, 05430 "ensemble target is not a fully-qualified command", 05431 NULL); 05432 Tcl_DictObjDone(&search); 05433 return TCL_ERROR; 05434 } 05435 } 05436 05437 if (size < 1) { 05438 mapDict = NULL; 05439 } 05440 } 05441 05442 ensemblePtr = cmdPtr->objClientData; 05443 oldDict = ensemblePtr->subcommandDict; 05444 ensemblePtr->subcommandDict = mapDict; 05445 if (mapDict != NULL) { 05446 Tcl_IncrRefCount(mapDict); 05447 } 05448 if (oldDict != NULL) { 05449 TclDecrRefCount(oldDict); 05450 } 05451 05452 /* 05453 * Trigger an eventual recomputation of the ensemble command set. Note 05454 * that this is slightly tricky, as it means that we are not actually 05455 * counting the number of namespace export actions, but it is the simplest 05456 * way to go! 05457 */ 05458 05459 ensemblePtr->nsPtr->exportLookupEpoch++; 05460 05461 /* 05462 * Special hack to make compiling of [info exists] work when the 05463 * dictionary is modified. 05464 */ 05465 05466 if (cmdPtr->compileProc != NULL) { 05467 ((Interp *)interp)->compileEpoch++; 05468 } 05469 05470 return TCL_OK; 05471 } 05472 05473 /* 05474 *---------------------------------------------------------------------- 05475 * 05476 * Tcl_SetEnsembleUnknownHandler -- 05477 * 05478 * Set the unknown handler for a particular ensemble. 05479 * 05480 * Results: 05481 * Tcl result code (error if command token does not indicate an ensemble 05482 * or the unknown handler - if non-NULL - is not a list). 05483 * 05484 * Side effects: 05485 * The ensemble is updated and marked for recompilation. 05486 * 05487 *---------------------------------------------------------------------- 05488 */ 05489 05490 int 05491 Tcl_SetEnsembleUnknownHandler( 05492 Tcl_Interp *interp, 05493 Tcl_Command token, 05494 Tcl_Obj *unknownList) 05495 { 05496 Command *cmdPtr = (Command *) token; 05497 EnsembleConfig *ensemblePtr; 05498 Tcl_Obj *oldList; 05499 05500 if (cmdPtr->objProc != NsEnsembleImplementationCmd) { 05501 Tcl_AppendResult(interp, "command is not an ensemble", NULL); 05502 return TCL_ERROR; 05503 } 05504 if (unknownList != NULL) { 05505 int length; 05506 05507 if (TclListObjLength(interp, unknownList, &length) != TCL_OK) { 05508 return TCL_ERROR; 05509 } 05510 if (length < 1) { 05511 unknownList = NULL; 05512 } 05513 } 05514 05515 ensemblePtr = cmdPtr->objClientData; 05516 oldList = ensemblePtr->unknownHandler; 05517 ensemblePtr->unknownHandler = unknownList; 05518 if (unknownList != NULL) { 05519 Tcl_IncrRefCount(unknownList); 05520 } 05521 if (oldList != NULL) { 05522 TclDecrRefCount(oldList); 05523 } 05524 05525 /* 05526 * Trigger an eventual recomputation of the ensemble command set. Note 05527 * that this is slightly tricky, as it means that we are not actually 05528 * counting the number of namespace export actions, but it is the simplest 05529 * way to go! 05530 */ 05531 05532 ensemblePtr->nsPtr->exportLookupEpoch++; 05533 05534 return TCL_OK; 05535 } 05536 05537 /* 05538 *---------------------------------------------------------------------- 05539 * 05540 * Tcl_SetEnsembleFlags -- 05541 * 05542 * Set the flags for a particular ensemble. 05543 * 05544 * Results: 05545 * Tcl result code (error if command token does not indicate an 05546 * ensemble). 05547 * 05548 * Side effects: 05549 * The ensemble is updated and marked for recompilation. 05550 * 05551 *---------------------------------------------------------------------- 05552 */ 05553 05554 int 05555 Tcl_SetEnsembleFlags( 05556 Tcl_Interp *interp, 05557 Tcl_Command token, 05558 int flags) 05559 { 05560 Command *cmdPtr = (Command *) token; 05561 EnsembleConfig *ensemblePtr; 05562 int wasCompiled; 05563 05564 if (cmdPtr->objProc != NsEnsembleImplementationCmd) { 05565 Tcl_AppendResult(interp, "command is not an ensemble", NULL); 05566 return TCL_ERROR; 05567 } 05568 05569 ensemblePtr = cmdPtr->objClientData; 05570 wasCompiled = ensemblePtr->flags & ENSEMBLE_COMPILE; 05571 05572 /* 05573 * This API refuses to set the ENS_DEAD flag... 05574 */ 05575 05576 ensemblePtr->flags &= ENS_DEAD; 05577 ensemblePtr->flags |= flags & ~ENS_DEAD; 05578 05579 /* 05580 * Trigger an eventual recomputation of the ensemble command set. Note 05581 * that this is slightly tricky, as it means that we are not actually 05582 * counting the number of namespace export actions, but it is the simplest 05583 * way to go! 05584 */ 05585 05586 ensemblePtr->nsPtr->exportLookupEpoch++; 05587 05588 /* 05589 * If the ENSEMBLE_COMPILE flag status was changed, install or remove the 05590 * compiler function and bump the interpreter's compilation epoch so that 05591 * bytecode gets regenerated. 05592 */ 05593 05594 if (flags & ENSEMBLE_COMPILE) { 05595 if (!wasCompiled) { 05596 ((Command*) ensemblePtr->token)->compileProc = TclCompileEnsemble; 05597 ((Interp *) interp)->compileEpoch++; 05598 } 05599 } else { 05600 if (wasCompiled) { 05601 ((Command*) ensemblePtr->token)->compileProc = NULL; 05602 ((Interp *) interp)->compileEpoch++; 05603 } 05604 } 05605 05606 return TCL_OK; 05607 } 05608 05609 /* 05610 *---------------------------------------------------------------------- 05611 * 05612 * Tcl_GetEnsembleSubcommandList -- 05613 * 05614 * Get the list of subcommands associated with a particular ensemble. 05615 * 05616 * Results: 05617 * Tcl result code (error if command token does not indicate an 05618 * ensemble). The list of subcommands is returned by updating the 05619 * variable pointed to by the last parameter (NULL if this is to be 05620 * derived from the mapping dictionary or the associated namespace's 05621 * exported commands). 05622 * 05623 * Side effects: 05624 * None 05625 * 05626 *---------------------------------------------------------------------- 05627 */ 05628 05629 int 05630 Tcl_GetEnsembleSubcommandList( 05631 Tcl_Interp *interp, 05632 Tcl_Command token, 05633 Tcl_Obj **subcmdListPtr) 05634 { 05635 Command *cmdPtr = (Command *) token; 05636 EnsembleConfig *ensemblePtr; 05637 05638 if (cmdPtr->objProc != NsEnsembleImplementationCmd) { 05639 if (interp != NULL) { 05640 Tcl_AppendResult(interp, "command is not an ensemble", NULL); 05641 } 05642 return TCL_ERROR; 05643 } 05644 05645 ensemblePtr = cmdPtr->objClientData; 05646 *subcmdListPtr = ensemblePtr->subcmdList; 05647 return TCL_OK; 05648 } 05649 05650 /* 05651 *---------------------------------------------------------------------- 05652 * 05653 * Tcl_GetEnsembleMappingDict -- 05654 * 05655 * Get the command mapping dictionary associated with a particular 05656 * ensemble. 05657 * 05658 * Results: 05659 * Tcl result code (error if command token does not indicate an 05660 * ensemble). The mapping dict is returned by updating the variable 05661 * pointed to by the last parameter (NULL if none is installed). 05662 * 05663 * Side effects: 05664 * None 05665 * 05666 *---------------------------------------------------------------------- 05667 */ 05668 05669 int 05670 Tcl_GetEnsembleMappingDict( 05671 Tcl_Interp *interp, 05672 Tcl_Command token, 05673 Tcl_Obj **mapDictPtr) 05674 { 05675 Command *cmdPtr = (Command *) token; 05676 EnsembleConfig *ensemblePtr; 05677 05678 if (cmdPtr->objProc != NsEnsembleImplementationCmd) { 05679 if (interp != NULL) { 05680 Tcl_AppendResult(interp, "command is not an ensemble", NULL); 05681 } 05682 return TCL_ERROR; 05683 } 05684 05685 ensemblePtr = cmdPtr->objClientData; 05686 *mapDictPtr = ensemblePtr->subcommandDict; 05687 return TCL_OK; 05688 } 05689 05690 /* 05691 *---------------------------------------------------------------------- 05692 * 05693 * Tcl_GetEnsembleUnknownHandler -- 05694 * 05695 * Get the unknown handler associated with a particular ensemble. 05696 * 05697 * Results: 05698 * Tcl result code (error if command token does not indicate an 05699 * ensemble). The unknown handler is returned by updating the variable 05700 * pointed to by the last parameter (NULL if no handler is installed). 05701 * 05702 * Side effects: 05703 * None 05704 * 05705 *---------------------------------------------------------------------- 05706 */ 05707 05708 int 05709 Tcl_GetEnsembleUnknownHandler( 05710 Tcl_Interp *interp, 05711 Tcl_Command token, 05712 Tcl_Obj **unknownListPtr) 05713 { 05714 Command *cmdPtr = (Command *) token; 05715 EnsembleConfig *ensemblePtr; 05716 05717 if (cmdPtr->objProc != NsEnsembleImplementationCmd) { 05718 if (interp != NULL) { 05719 Tcl_AppendResult(interp, "command is not an ensemble", NULL); 05720 } 05721 return TCL_ERROR; 05722 } 05723 05724 ensemblePtr = cmdPtr->objClientData; 05725 *unknownListPtr = ensemblePtr->unknownHandler; 05726 return TCL_OK; 05727 } 05728 05729 /* 05730 *---------------------------------------------------------------------- 05731 * 05732 * Tcl_GetEnsembleFlags -- 05733 * 05734 * Get the flags for a particular ensemble. 05735 * 05736 * Results: 05737 * Tcl result code (error if command token does not indicate an 05738 * ensemble). The flags are returned by updating the variable pointed to 05739 * by the last parameter. 05740 * 05741 * Side effects: 05742 * None 05743 * 05744 *---------------------------------------------------------------------- 05745 */ 05746 05747 int 05748 Tcl_GetEnsembleFlags( 05749 Tcl_Interp *interp, 05750 Tcl_Command token, 05751 int *flagsPtr) 05752 { 05753 Command *cmdPtr = (Command *) token; 05754 EnsembleConfig *ensemblePtr; 05755 05756 if (cmdPtr->objProc != NsEnsembleImplementationCmd) { 05757 if (interp != NULL) { 05758 Tcl_AppendResult(interp, "command is not an ensemble", NULL); 05759 } 05760 return TCL_ERROR; 05761 } 05762 05763 ensemblePtr = cmdPtr->objClientData; 05764 *flagsPtr = ensemblePtr->flags; 05765 return TCL_OK; 05766 } 05767 05768 /* 05769 *---------------------------------------------------------------------- 05770 * 05771 * Tcl_GetEnsembleNamespace -- 05772 * 05773 * Get the namespace associated with a particular ensemble. 05774 * 05775 * Results: 05776 * Tcl result code (error if command token does not indicate an 05777 * ensemble). Namespace is returned by updating the variable pointed to 05778 * by the last parameter. 05779 * 05780 * Side effects: 05781 * None 05782 * 05783 *---------------------------------------------------------------------- 05784 */ 05785 05786 int 05787 Tcl_GetEnsembleNamespace( 05788 Tcl_Interp *interp, 05789 Tcl_Command token, 05790 Tcl_Namespace **namespacePtrPtr) 05791 { 05792 Command *cmdPtr = (Command *) token; 05793 EnsembleConfig *ensemblePtr; 05794 05795 if (cmdPtr->objProc != NsEnsembleImplementationCmd) { 05796 if (interp != NULL) { 05797 Tcl_AppendResult(interp, "command is not an ensemble", NULL); 05798 } 05799 return TCL_ERROR; 05800 } 05801 05802 ensemblePtr = cmdPtr->objClientData; 05803 *namespacePtrPtr = (Tcl_Namespace *) ensemblePtr->nsPtr; 05804 return TCL_OK; 05805 } 05806 05807 /* 05808 *---------------------------------------------------------------------- 05809 * 05810 * Tcl_FindEnsemble -- 05811 * 05812 * Given a command name, get the ensemble token for it, allowing for 05813 * [namespace import]s. [Bug 1017022] 05814 * 05815 * Results: 05816 * The token for the ensemble command with the given name, or NULL if the 05817 * command either does not exist or is not an ensemble (when an error 05818 * message will be written into the interp if thats non-NULL). 05819 * 05820 * Side effects: 05821 * None 05822 * 05823 *---------------------------------------------------------------------- 05824 */ 05825 05826 Tcl_Command 05827 Tcl_FindEnsemble( 05828 Tcl_Interp *interp, /* Where to do the lookup, and where to write 05829 * the errors if TCL_LEAVE_ERR_MSG is set in 05830 * the flags. */ 05831 Tcl_Obj *cmdNameObj, /* Name of command to look up. */ 05832 int flags) /* Either 0 or TCL_LEAVE_ERR_MSG; other flags 05833 * are probably not useful. */ 05834 { 05835 Command *cmdPtr; 05836 05837 cmdPtr = (Command *) 05838 Tcl_FindCommand(interp, TclGetString(cmdNameObj), NULL, flags); 05839 if (cmdPtr == NULL) { 05840 return NULL; 05841 } 05842 05843 if (cmdPtr->objProc != NsEnsembleImplementationCmd) { 05844 /* 05845 * Reuse existing infrastructure for following import link chains 05846 * rather than duplicating it. 05847 */ 05848 05849 cmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr); 05850 05851 if (cmdPtr == NULL || cmdPtr->objProc != NsEnsembleImplementationCmd) { 05852 if (flags & TCL_LEAVE_ERR_MSG) { 05853 Tcl_AppendResult(interp, "\"", TclGetString(cmdNameObj), 05854 "\" is not an ensemble command", NULL); 05855 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ENSEMBLE", 05856 TclGetString(cmdNameObj), NULL); 05857 } 05858 return NULL; 05859 } 05860 } 05861 05862 return (Tcl_Command) cmdPtr; 05863 } 05864 05865 /* 05866 *---------------------------------------------------------------------- 05867 * 05868 * Tcl_IsEnsemble -- 05869 * 05870 * Simple test for ensemble-hood that takes into account imported 05871 * ensemble commands as well. 05872 * 05873 * Results: 05874 * Boolean value 05875 * 05876 * Side effects: 05877 * None 05878 * 05879 *---------------------------------------------------------------------- 05880 */ 05881 05882 int 05883 Tcl_IsEnsemble( 05884 Tcl_Command token) 05885 { 05886 Command *cmdPtr = (Command *) token; 05887 if (cmdPtr->objProc == NsEnsembleImplementationCmd) { 05888 return 1; 05889 } 05890 cmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr); 05891 if (cmdPtr == NULL || cmdPtr->objProc != NsEnsembleImplementationCmd) { 05892 return 0; 05893 } 05894 return 1; 05895 } 05896 05897 /* 05898 *---------------------------------------------------------------------- 05899 * 05900 * TclMakeEnsemble -- 05901 * 05902 * Create an ensemble from a table of implementation commands. The 05903 * ensemble will be subject to (limited) compilation if any of the 05904 * implementation commands are compilable. 05905 * 05906 * Results: 05907 * Handle for the ensemble, or NULL if creation of it fails. 05908 * 05909 * Side effects: 05910 * May advance bytecode compilation epoch. 05911 * 05912 *---------------------------------------------------------------------- 05913 */ 05914 05915 Tcl_Command 05916 TclMakeEnsemble( 05917 Tcl_Interp *interp, 05918 const char *name, 05919 const EnsembleImplMap map[]) 05920 { 05921 Tcl_Command ensemble; /* The overall ensemble. */ 05922 Tcl_Namespace *tclNsPtr; /* Reference to the "::tcl" namespace. */ 05923 Tcl_DString buf; 05924 05925 tclNsPtr = Tcl_FindNamespace(interp, "::tcl", NULL, 05926 TCL_CREATE_NS_IF_UNKNOWN); 05927 if (tclNsPtr == NULL) { 05928 Tcl_Panic("unable to find or create ::tcl namespace!"); 05929 } 05930 Tcl_DStringInit(&buf); 05931 Tcl_DStringAppend(&buf, "::tcl::", -1); 05932 Tcl_DStringAppend(&buf, name, -1); 05933 tclNsPtr = Tcl_FindNamespace(interp, Tcl_DStringValue(&buf), NULL, 05934 TCL_CREATE_NS_IF_UNKNOWN); 05935 if (tclNsPtr == NULL) { 05936 Tcl_Panic("unable to find or create %s namespace!", 05937 Tcl_DStringValue(&buf)); 05938 } 05939 ensemble = Tcl_CreateEnsemble(interp, Tcl_DStringValue(&buf)+5, tclNsPtr, 05940 TCL_ENSEMBLE_PREFIX); 05941 Tcl_DStringAppend(&buf, "::", -1); 05942 if (ensemble != NULL) { 05943 Tcl_Obj *mapDict; 05944 int i, compile = 0; 05945 05946 TclNewObj(mapDict); 05947 for (i=0 ; map[i].name != NULL ; i++) { 05948 Tcl_Obj *fromObj, *toObj; 05949 Command *cmdPtr; 05950 05951 fromObj = Tcl_NewStringObj(map[i].name, -1); 05952 TclNewStringObj(toObj, Tcl_DStringValue(&buf), 05953 Tcl_DStringLength(&buf)); 05954 Tcl_AppendToObj(toObj, map[i].name, -1); 05955 Tcl_DictObjPut(NULL, mapDict, fromObj, toObj); 05956 cmdPtr = (Command *) Tcl_CreateObjCommand(interp, 05957 TclGetString(toObj), map[i].proc, NULL, NULL); 05958 cmdPtr->compileProc = map[i].compileProc; 05959 compile |= (map[i].compileProc != NULL); 05960 } 05961 Tcl_SetEnsembleMappingDict(interp, ensemble, mapDict); 05962 if (compile) { 05963 Tcl_SetEnsembleFlags(interp, ensemble, 05964 TCL_ENSEMBLE_PREFIX | ENSEMBLE_COMPILE); 05965 } 05966 } 05967 Tcl_DStringFree(&buf); 05968 05969 return ensemble; 05970 } 05971 05972 /* 05973 *---------------------------------------------------------------------- 05974 * 05975 * NsEnsembleImplementationCmd -- 05976 * 05977 * Implements an ensemble of commands (being those exported by a 05978 * namespace other than the global namespace) as a command with the same 05979 * (short) name as the namespace in the parent namespace. 05980 * 05981 * Results: 05982 * A standard Tcl result code. Will be TCL_ERROR if the command is not an 05983 * unambiguous prefix of any command exported by the ensemble's 05984 * namespace. 05985 * 05986 * Side effects: 05987 * Depends on the command within the namespace that gets executed. If the 05988 * ensemble itself returns TCL_ERROR, a descriptive error message will be 05989 * placed in the interpreter's result. 05990 * 05991 *---------------------------------------------------------------------- 05992 */ 05993 05994 static int 05995 NsEnsembleImplementationCmd( 05996 ClientData clientData, 05997 Tcl_Interp *interp, 05998 int objc, 05999 Tcl_Obj *const objv[]) 06000 { 06001 EnsembleConfig *ensemblePtr = clientData; 06002 /* The ensemble itself. */ 06003 Tcl_Obj **tempObjv; /* Space used to construct the list of 06004 * arguments to pass to the command that 06005 * implements the ensemble subcommand. */ 06006 int result; /* The result of the subcommand execution. */ 06007 Tcl_Obj *prefixObj; /* An object containing the prefix words of 06008 * the command that implements the 06009 * subcommand. */ 06010 Tcl_HashEntry *hPtr; /* Used for efficient lookup of fully 06011 * specified but not yet cached command 06012 * names. */ 06013 Tcl_Obj **prefixObjv; /* The list of objects to substitute in as the 06014 * target command prefix. */ 06015 int prefixObjc; /* Size of prefixObjv of course! */ 06016 int reparseCount = 0; /* Number of reparses. */ 06017 06018 if (objc < 2) { 06019 Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?argument ...?"); 06020 return TCL_ERROR; 06021 } 06022 06023 restartEnsembleParse: 06024 if (ensemblePtr->nsPtr->flags & NS_DYING) { 06025 /* 06026 * Don't know how we got here, but make things give up quickly. 06027 */ 06028 06029 if (!Tcl_InterpDeleted(interp)) { 06030 Tcl_AppendResult(interp, 06031 "ensemble activated for deleted namespace", NULL); 06032 } 06033 return TCL_ERROR; 06034 } 06035 06036 /* 06037 * Determine if the table of subcommands is right. If so, we can just look 06038 * up in there and go straight to dispatch. 06039 */ 06040 06041 if (ensemblePtr->epoch == ensemblePtr->nsPtr->exportLookupEpoch) { 06042 /* 06043 * Table of subcommands is still valid; therefore there might be a 06044 * valid cache of discovered information which we can reuse. Do the 06045 * check here, and if we're still valid, we can jump straight to the 06046 * part where we do the invocation of the subcommand. 06047 */ 06048 06049 if (objv[1]->typePtr == &tclEnsembleCmdType) { 06050 EnsembleCmdRep *ensembleCmd = objv[1]->internalRep.otherValuePtr; 06051 06052 if (ensembleCmd->nsPtr == ensemblePtr->nsPtr && 06053 ensembleCmd->epoch == ensemblePtr->epoch && 06054 ensembleCmd->token == ensemblePtr->token) { 06055 prefixObj = ensembleCmd->realPrefixObj; 06056 Tcl_IncrRefCount(prefixObj); 06057 goto runResultingSubcommand; 06058 } 06059 } 06060 } else { 06061 BuildEnsembleConfig(ensemblePtr); 06062 ensemblePtr->epoch = ensemblePtr->nsPtr->exportLookupEpoch; 06063 } 06064 06065 /* 06066 * Look in the hashtable for the subcommand name; this is the fastest way 06067 * of all. 06068 */ 06069 06070 hPtr = Tcl_FindHashEntry(&ensemblePtr->subcommandTable, 06071 TclGetString(objv[1])); 06072 if (hPtr != NULL) { 06073 char *fullName = Tcl_GetHashKey(&ensemblePtr->subcommandTable, hPtr); 06074 06075 prefixObj = Tcl_GetHashValue(hPtr); 06076 06077 /* 06078 * Cache for later in the subcommand object. 06079 */ 06080 06081 MakeCachedEnsembleCommand(objv[1], ensemblePtr, fullName, prefixObj); 06082 } else if (!(ensemblePtr->flags & TCL_ENSEMBLE_PREFIX)) { 06083 /* 06084 * Could not map, no prefixing, go to unknown/error handling. 06085 */ 06086 06087 goto unknownOrAmbiguousSubcommand; 06088 } else { 06089 /* 06090 * If we've not already confirmed the command with the hash as part of 06091 * building our export table, we need to scan the sorted array for 06092 * matches. 06093 */ 06094 06095 char *subcmdName; /* Name of the subcommand, or unique prefix of 06096 * it (will be an error for a non-unique 06097 * prefix). */ 06098 char *fullName = NULL; /* Full name of the subcommand. */ 06099 int stringLength, i; 06100 int tableLength = ensemblePtr->subcommandTable.numEntries; 06101 06102 subcmdName = TclGetString(objv[1]); 06103 stringLength = objv[1]->length; 06104 for (i=0 ; i<tableLength ; i++) { 06105 register int cmp = strncmp(subcmdName, 06106 ensemblePtr->subcommandArrayPtr[i], 06107 (unsigned) stringLength); 06108 06109 if (cmp == 0) { 06110 if (fullName != NULL) { 06111 /* 06112 * Since there's never the exact-match case to worry about 06113 * (hash search filters this), getting here indicates that 06114 * our subcommand is an ambiguous prefix of (at least) two 06115 * exported subcommands, which is an error case. 06116 */ 06117 06118 goto unknownOrAmbiguousSubcommand; 06119 } 06120 fullName = ensemblePtr->subcommandArrayPtr[i]; 06121 } else if (cmp < 0) { 06122 /* 06123 * Because we are searching a sorted table, we can now stop 06124 * searching because we have gone past anything that could 06125 * possibly match. 06126 */ 06127 06128 break; 06129 } 06130 } 06131 if (fullName == NULL) { 06132 /* 06133 * The subcommand is not a prefix of anything, so bail out! 06134 */ 06135 06136 goto unknownOrAmbiguousSubcommand; 06137 } 06138 hPtr = Tcl_FindHashEntry(&ensemblePtr->subcommandTable, fullName); 06139 if (hPtr == NULL) { 06140 Tcl_Panic("full name %s not found in supposedly synchronized hash", 06141 fullName); 06142 } 06143 prefixObj = Tcl_GetHashValue(hPtr); 06144 06145 /* 06146 * Cache for later in the subcommand object. 06147 */ 06148 06149 MakeCachedEnsembleCommand(objv[1], ensemblePtr, fullName, prefixObj); 06150 } 06151 06152 Tcl_IncrRefCount(prefixObj); 06153 runResultingSubcommand: 06154 06155 /* 06156 * Do the real work of execution of the subcommand by building an array of 06157 * objects (note that this is potentially not the same length as the 06158 * number of arguments to this ensemble command), populating it and then 06159 * feeding it back through the main command-lookup engine. In theory, we 06160 * could look up the command in the namespace ourselves, as we already 06161 * have the namespace in which it is guaranteed to exist, but we don't do 06162 * that (the cacheing of the command object used should help with that.) 06163 */ 06164 06165 { 06166 Interp *iPtr = (Interp *) interp; 06167 int isRootEnsemble; 06168 Tcl_Obj *copyObj; 06169 06170 /* 06171 * Get the prefix that we're rewriting to. To do this we need to 06172 * ensure that the internal representation of the list does not change 06173 * so that we can safely keep the internal representations of the 06174 * elements in the list. 06175 */ 06176 06177 copyObj = TclListObjCopy(NULL, prefixObj); 06178 TclListObjGetElements(NULL, copyObj, &prefixObjc, &prefixObjv); 06179 06180 /* 06181 * Record what arguments the script sent in so that things like 06182 * Tcl_WrongNumArgs can give the correct error message. 06183 */ 06184 06185 isRootEnsemble = (iPtr->ensembleRewrite.sourceObjs == NULL); 06186 if (isRootEnsemble) { 06187 iPtr->ensembleRewrite.sourceObjs = objv; 06188 iPtr->ensembleRewrite.numRemovedObjs = 2; 06189 iPtr->ensembleRewrite.numInsertedObjs = prefixObjc; 06190 } else { 06191 int ni = iPtr->ensembleRewrite.numInsertedObjs; 06192 06193 if (ni < 2) { 06194 iPtr->ensembleRewrite.numRemovedObjs += 2 - ni; 06195 iPtr->ensembleRewrite.numInsertedObjs += prefixObjc-1; 06196 } else { 06197 iPtr->ensembleRewrite.numInsertedObjs += prefixObjc-2; 06198 } 06199 } 06200 06201 /* 06202 * Allocate a workspace and build the list of arguments to pass to the 06203 * target command in it. 06204 */ 06205 06206 tempObjv = (Tcl_Obj **) TclStackAlloc(interp, 06207 (int) sizeof(Tcl_Obj *) * (objc - 2 + prefixObjc)); 06208 memcpy(tempObjv, prefixObjv, sizeof(Tcl_Obj *) * prefixObjc); 06209 memcpy(tempObjv+prefixObjc, objv+2, sizeof(Tcl_Obj *) * (objc-2)); 06210 06211 /* 06212 * Hand off to the target command. 06213 */ 06214 06215 result = Tcl_EvalObjv(interp, objc-2+prefixObjc, tempObjv, 06216 TCL_EVAL_INVOKE); 06217 06218 /* 06219 * Clean up. 06220 */ 06221 06222 TclStackFree(interp, tempObjv); 06223 Tcl_DecrRefCount(copyObj); 06224 if (isRootEnsemble) { 06225 iPtr->ensembleRewrite.sourceObjs = NULL; 06226 iPtr->ensembleRewrite.numRemovedObjs = 0; 06227 iPtr->ensembleRewrite.numInsertedObjs = 0; 06228 } 06229 } 06230 Tcl_DecrRefCount(prefixObj); 06231 return result; 06232 06233 unknownOrAmbiguousSubcommand: 06234 /* 06235 * Have not been able to match the subcommand asked for with a real 06236 * subcommand that we export. See whether a handler has been registered 06237 * for dealing with this situation. Will only call (at most) once for any 06238 * particular ensemble invocation. 06239 */ 06240 06241 if (ensemblePtr->unknownHandler != NULL && reparseCount++ < 1) { 06242 int paramc, i; 06243 Tcl_Obj **paramv, *unknownCmd, *ensObj; 06244 06245 unknownCmd = Tcl_DuplicateObj(ensemblePtr->unknownHandler); 06246 TclNewObj(ensObj); 06247 Tcl_GetCommandFullName(interp, ensemblePtr->token, ensObj); 06248 Tcl_ListObjAppendElement(NULL, unknownCmd, ensObj); 06249 for (i=1 ; i<objc ; i++) { 06250 Tcl_ListObjAppendElement(NULL, unknownCmd, objv[i]); 06251 } 06252 TclListObjGetElements(NULL, unknownCmd, ¶mc, ¶mv); 06253 Tcl_Preserve(ensemblePtr); 06254 Tcl_IncrRefCount(unknownCmd); 06255 result = Tcl_EvalObjv(interp, paramc, paramv, 0); 06256 if (result == TCL_OK) { 06257 prefixObj = Tcl_GetObjResult(interp); 06258 Tcl_IncrRefCount(prefixObj); 06259 Tcl_DecrRefCount(unknownCmd); 06260 Tcl_Release(ensemblePtr); 06261 Tcl_ResetResult(interp); 06262 if (ensemblePtr->flags & ENS_DEAD) { 06263 Tcl_DecrRefCount(prefixObj); 06264 Tcl_SetResult(interp, 06265 "unknown subcommand handler deleted its ensemble", 06266 TCL_STATIC); 06267 return TCL_ERROR; 06268 } 06269 06270 /* 06271 * Namespace is still there. Check if the result is a valid list. 06272 * If it is, and it is non-empty, that list is what we are using 06273 * as our replacement. 06274 */ 06275 06276 if (TclListObjLength(interp, prefixObj, &prefixObjc) != TCL_OK) { 06277 Tcl_DecrRefCount(prefixObj); 06278 Tcl_AddErrorInfo(interp, "\n while parsing result of " 06279 "ensemble unknown subcommand handler"); 06280 return TCL_ERROR; 06281 } 06282 if (prefixObjc > 0) { 06283 goto runResultingSubcommand; 06284 } 06285 06286 /* 06287 * Namespace alive & empty result => reparse. 06288 */ 06289 06290 Tcl_DecrRefCount(prefixObj); 06291 goto restartEnsembleParse; 06292 } 06293 if (!Tcl_InterpDeleted(interp)) { 06294 if (result != TCL_ERROR) { 06295 char buf[TCL_INTEGER_SPACE]; 06296 06297 Tcl_ResetResult(interp); 06298 Tcl_SetResult(interp, 06299 "unknown subcommand handler returned bad code: ", 06300 TCL_STATIC); 06301 switch (result) { 06302 case TCL_RETURN: 06303 Tcl_AppendResult(interp, "return", NULL); 06304 break; 06305 case TCL_BREAK: 06306 Tcl_AppendResult(interp, "break", NULL); 06307 break; 06308 case TCL_CONTINUE: 06309 Tcl_AppendResult(interp, "continue", NULL); 06310 break; 06311 default: 06312 sprintf(buf, "%d", result); 06313 Tcl_AppendResult(interp, buf, NULL); 06314 } 06315 Tcl_AddErrorInfo(interp, "\n result of " 06316 "ensemble unknown subcommand handler: "); 06317 Tcl_AddErrorInfo(interp, TclGetString(unknownCmd)); 06318 } else { 06319 Tcl_AddErrorInfo(interp, 06320 "\n (ensemble unknown subcommand handler)"); 06321 } 06322 } 06323 Tcl_DecrRefCount(unknownCmd); 06324 Tcl_Release(ensemblePtr); 06325 return TCL_ERROR; 06326 } 06327 06328 /* 06329 * We cannot determine what subcommand to hand off to, so generate a 06330 * (standard) failure message. Note the one odd case compared with 06331 * standard ensemble-like command, which is where a namespace has no 06332 * exported commands at all... 06333 */ 06334 06335 Tcl_ResetResult(interp); 06336 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ENSEMBLE", 06337 TclGetString(objv[1]), NULL); 06338 if (ensemblePtr->subcommandTable.numEntries == 0) { 06339 Tcl_AppendResult(interp, "unknown subcommand \"",TclGetString(objv[1]), 06340 "\": namespace ", ensemblePtr->nsPtr->fullName, 06341 " does not export any commands", NULL); 06342 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "SUBCOMMAND", 06343 TclGetString(objv[1]), NULL); 06344 return TCL_ERROR; 06345 } 06346 Tcl_AppendResult(interp, "unknown ", 06347 (ensemblePtr->flags & TCL_ENSEMBLE_PREFIX ? "or ambiguous " : ""), 06348 "subcommand \"", TclGetString(objv[1]), "\": must be ", NULL); 06349 if (ensemblePtr->subcommandTable.numEntries == 1) { 06350 Tcl_AppendResult(interp, ensemblePtr->subcommandArrayPtr[0], NULL); 06351 } else { 06352 int i; 06353 06354 for (i=0 ; i<ensemblePtr->subcommandTable.numEntries-1 ; i++) { 06355 Tcl_AppendResult(interp, 06356 ensemblePtr->subcommandArrayPtr[i], ", ", NULL); 06357 } 06358 Tcl_AppendResult(interp, "or ", 06359 ensemblePtr->subcommandArrayPtr[i], NULL); 06360 } 06361 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "SUBCOMMAND", 06362 TclGetString(objv[1]), NULL); 06363 return TCL_ERROR; 06364 } 06365 06366 /* 06367 *---------------------------------------------------------------------- 06368 * 06369 * MakeCachedEnsembleCommand -- 06370 * 06371 * Cache what we've computed so far; it's not nice to repeatedly copy 06372 * strings about. Note that to do this, we start by deleting any old 06373 * representation that there was (though if it was an out of date 06374 * ensemble rep, we can skip some of the deallocation process.) 06375 * 06376 * Results: 06377 * None 06378 * 06379 * Side effects: 06380 * Alters the internal representation of the first object parameter. 06381 * 06382 *---------------------------------------------------------------------- 06383 */ 06384 06385 static void 06386 MakeCachedEnsembleCommand( 06387 Tcl_Obj *objPtr, 06388 EnsembleConfig *ensemblePtr, 06389 const char *subcommandName, 06390 Tcl_Obj *prefixObjPtr) 06391 { 06392 register EnsembleCmdRep *ensembleCmd; 06393 int length; 06394 06395 if (objPtr->typePtr == &tclEnsembleCmdType) { 06396 ensembleCmd = objPtr->internalRep.otherValuePtr; 06397 Tcl_DecrRefCount(ensembleCmd->realPrefixObj); 06398 ensembleCmd->nsPtr->refCount--; 06399 if ((ensembleCmd->nsPtr->refCount == 0) 06400 && (ensembleCmd->nsPtr->flags & NS_DEAD)) { 06401 NamespaceFree(ensembleCmd->nsPtr); 06402 } 06403 ckfree(ensembleCmd->fullSubcmdName); 06404 } else { 06405 /* 06406 * Kill the old internal rep, and replace it with a brand new one of 06407 * our own. 06408 */ 06409 06410 TclFreeIntRep(objPtr); 06411 ensembleCmd = (EnsembleCmdRep *) ckalloc(sizeof(EnsembleCmdRep)); 06412 objPtr->internalRep.otherValuePtr = ensembleCmd; 06413 objPtr->typePtr = &tclEnsembleCmdType; 06414 } 06415 06416 /* 06417 * Populate the internal rep. 06418 */ 06419 06420 ensembleCmd->nsPtr = ensemblePtr->nsPtr; 06421 ensembleCmd->epoch = ensemblePtr->epoch; 06422 ensembleCmd->token = ensemblePtr->token; 06423 ensemblePtr->nsPtr->refCount++; 06424 ensembleCmd->realPrefixObj = prefixObjPtr; 06425 length = strlen(subcommandName)+1; 06426 ensembleCmd->fullSubcmdName = ckalloc((unsigned) length); 06427 memcpy(ensembleCmd->fullSubcmdName, subcommandName, (unsigned) length); 06428 Tcl_IncrRefCount(ensembleCmd->realPrefixObj); 06429 } 06430 06431 /* 06432 *---------------------------------------------------------------------- 06433 * 06434 * DeleteEnsembleConfig -- 06435 * 06436 * Destroys the data structure used to represent an ensemble. This is 06437 * called when the ensemble's command is deleted (which happens 06438 * automatically if the ensemble's namespace is deleted.) Maintainers 06439 * should note that ensembles should be deleted by deleting their 06440 * commands. 06441 * 06442 * Results: 06443 * None. 06444 * 06445 * Side effects: 06446 * Memory is (eventually) deallocated. 06447 * 06448 *---------------------------------------------------------------------- 06449 */ 06450 06451 static void 06452 DeleteEnsembleConfig( 06453 ClientData clientData) 06454 { 06455 EnsembleConfig *ensemblePtr = clientData; 06456 Namespace *nsPtr = ensemblePtr->nsPtr; 06457 Tcl_HashSearch search; 06458 Tcl_HashEntry *hEnt; 06459 06460 /* 06461 * Unlink from the ensemble chain if it has not been marked as having been 06462 * done already. 06463 */ 06464 06465 if (ensemblePtr->next != ensemblePtr) { 06466 EnsembleConfig *ensPtr = (EnsembleConfig *) nsPtr->ensembles; 06467 if (ensPtr == ensemblePtr) { 06468 nsPtr->ensembles = (Tcl_Ensemble *) ensemblePtr->next; 06469 } else { 06470 while (ensPtr != NULL) { 06471 if (ensPtr->next == ensemblePtr) { 06472 ensPtr->next = ensemblePtr->next; 06473 break; 06474 } 06475 ensPtr = ensPtr->next; 06476 } 06477 } 06478 } 06479 06480 /* 06481 * Mark the namespace as dead so code that uses Tcl_Preserve() can tell 06482 * whether disaster happened anyway. 06483 */ 06484 06485 ensemblePtr->flags |= ENS_DEAD; 06486 06487 /* 06488 * Kill the pointer-containing fields. 06489 */ 06490 06491 if (ensemblePtr->subcommandTable.numEntries != 0) { 06492 ckfree((char *) ensemblePtr->subcommandArrayPtr); 06493 } 06494 hEnt = Tcl_FirstHashEntry(&ensemblePtr->subcommandTable, &search); 06495 while (hEnt != NULL) { 06496 Tcl_Obj *prefixObj = Tcl_GetHashValue(hEnt); 06497 06498 Tcl_DecrRefCount(prefixObj); 06499 hEnt = Tcl_NextHashEntry(&search); 06500 } 06501 Tcl_DeleteHashTable(&ensemblePtr->subcommandTable); 06502 if (ensemblePtr->subcmdList != NULL) { 06503 Tcl_DecrRefCount(ensemblePtr->subcmdList); 06504 } 06505 if (ensemblePtr->subcommandDict != NULL) { 06506 Tcl_DecrRefCount(ensemblePtr->subcommandDict); 06507 } 06508 if (ensemblePtr->unknownHandler != NULL) { 06509 Tcl_DecrRefCount(ensemblePtr->unknownHandler); 06510 } 06511 06512 /* 06513 * Arrange for the structure to be reclaimed. Note that this is complex 06514 * because we have to make sure that we can react sensibly when an 06515 * ensemble is deleted during the process of initialising the ensemble 06516 * (especially the unknown callback.) 06517 */ 06518 06519 Tcl_EventuallyFree(ensemblePtr, TCL_DYNAMIC); 06520 } 06521 06522 /* 06523 *---------------------------------------------------------------------- 06524 * 06525 * BuildEnsembleConfig -- 06526 * 06527 * Create the internal data structures that describe how an ensemble 06528 * looks, being a hash mapping from the full command name to the Tcl list 06529 * that describes the implementation prefix words, and a sorted array of 06530 * all the full command names to allow for reasonably efficient 06531 * unambiguous prefix handling. 06532 * 06533 * Results: 06534 * None. 06535 * 06536 * Side effects: 06537 * Reallocates and rebuilds the hash table and array stored at the 06538 * ensemblePtr argument. For large ensembles or large namespaces, this is 06539 * a potentially expensive operation. 06540 * 06541 *---------------------------------------------------------------------- 06542 */ 06543 06544 static void 06545 BuildEnsembleConfig( 06546 EnsembleConfig *ensemblePtr) 06547 { 06548 Tcl_HashSearch search; /* Used for scanning the set of commands in 06549 * the namespace that backs up this 06550 * ensemble. */ 06551 int i, j, isNew; 06552 Tcl_HashTable *hash = &ensemblePtr->subcommandTable; 06553 Tcl_HashEntry *hPtr; 06554 06555 if (hash->numEntries != 0) { 06556 /* 06557 * Remove pre-existing table. 06558 */ 06559 06560 Tcl_HashSearch search; 06561 06562 ckfree((char *) ensemblePtr->subcommandArrayPtr); 06563 hPtr = Tcl_FirstHashEntry(hash, &search); 06564 while (hPtr != NULL) { 06565 Tcl_Obj *prefixObj = Tcl_GetHashValue(hPtr); 06566 Tcl_DecrRefCount(prefixObj); 06567 hPtr = Tcl_NextHashEntry(&search); 06568 } 06569 Tcl_DeleteHashTable(hash); 06570 Tcl_InitHashTable(hash, TCL_STRING_KEYS); 06571 } 06572 06573 /* 06574 * See if we've got an export list. If so, we will only export exactly 06575 * those commands, which may be either implemented by the prefix in the 06576 * subcommandDict or mapped directly onto the namespace's commands. 06577 */ 06578 06579 if (ensemblePtr->subcmdList != NULL) { 06580 Tcl_Obj **subcmdv, *target, *cmdObj, *cmdPrefixObj; 06581 int subcmdc; 06582 06583 TclListObjGetElements(NULL, ensemblePtr->subcmdList, &subcmdc, 06584 &subcmdv); 06585 for (i=0 ; i<subcmdc ; i++) { 06586 char *name = TclGetString(subcmdv[i]); 06587 06588 hPtr = Tcl_CreateHashEntry(hash, name, &isNew); 06589 06590 /* 06591 * Skip non-unique cases. 06592 */ 06593 06594 if (!isNew) { 06595 continue; 06596 } 06597 06598 /* 06599 * Look in our dictionary (if present) for the command. 06600 */ 06601 06602 if (ensemblePtr->subcommandDict != NULL) { 06603 Tcl_DictObjGet(NULL, ensemblePtr->subcommandDict, subcmdv[i], 06604 &target); 06605 if (target != NULL) { 06606 Tcl_SetHashValue(hPtr, target); 06607 Tcl_IncrRefCount(target); 06608 continue; 06609 } 06610 } 06611 06612 /* 06613 * Not there, so map onto the namespace. Note in this case that we 06614 * do not guarantee that the command is actually there; that is 06615 * the programmer's responsibility (or [::unknown] of course). 06616 */ 06617 06618 cmdObj = Tcl_NewStringObj(ensemblePtr->nsPtr->fullName, -1); 06619 if (ensemblePtr->nsPtr->parentPtr != NULL) { 06620 Tcl_AppendStringsToObj(cmdObj, "::", name, NULL); 06621 } else { 06622 Tcl_AppendStringsToObj(cmdObj, name, NULL); 06623 } 06624 cmdPrefixObj = Tcl_NewListObj(1, &cmdObj); 06625 Tcl_SetHashValue(hPtr, cmdPrefixObj); 06626 Tcl_IncrRefCount(cmdPrefixObj); 06627 } 06628 } else if (ensemblePtr->subcommandDict != NULL) { 06629 /* 06630 * No subcmd list, but we do have a mapping dictionary so we should 06631 * use the keys of that. Convert the dictionary's contents into the 06632 * form required for the ensemble's internal hashtable. 06633 */ 06634 06635 Tcl_DictSearch dictSearch; 06636 Tcl_Obj *keyObj, *valueObj; 06637 int done; 06638 06639 Tcl_DictObjFirst(NULL, ensemblePtr->subcommandDict, &dictSearch, 06640 &keyObj, &valueObj, &done); 06641 while (!done) { 06642 char *name = TclGetString(keyObj); 06643 06644 hPtr = Tcl_CreateHashEntry(hash, name, &isNew); 06645 Tcl_SetHashValue(hPtr, valueObj); 06646 Tcl_IncrRefCount(valueObj); 06647 Tcl_DictObjNext(&dictSearch, &keyObj, &valueObj, &done); 06648 } 06649 } else { 06650 /* 06651 * Discover what commands are actually exported by the namespace. 06652 * What we have is an array of patterns and a hash table whose keys 06653 * are the command names exported by the namespace (the contents do 06654 * not matter here.) We must find out what commands are actually 06655 * exported by filtering each command in the namespace against each of 06656 * the patterns in the export list. Note that we use an intermediate 06657 * hash table to make memory management easier, and because that makes 06658 * exact matching far easier too. 06659 * 06660 * Suggestion for future enhancement: compute the unique prefixes and 06661 * place them in the hash too, which should make for even faster 06662 * matching. 06663 */ 06664 06665 hPtr = Tcl_FirstHashEntry(&ensemblePtr->nsPtr->cmdTable, &search); 06666 for (; hPtr!= NULL ; hPtr=Tcl_NextHashEntry(&search)) { 06667 char *nsCmdName = /* Name of command in namespace. */ 06668 Tcl_GetHashKey(&ensemblePtr->nsPtr->cmdTable, hPtr); 06669 06670 for (i=0 ; i<ensemblePtr->nsPtr->numExportPatterns ; i++) { 06671 if (Tcl_StringMatch(nsCmdName, 06672 ensemblePtr->nsPtr->exportArrayPtr[i])) { 06673 hPtr = Tcl_CreateHashEntry(hash, nsCmdName, &isNew); 06674 06675 /* 06676 * Remember, hash entries have a full reference to the 06677 * substituted part of the command (as a list) as their 06678 * content! 06679 */ 06680 06681 if (isNew) { 06682 Tcl_Obj *cmdObj, *cmdPrefixObj; 06683 06684 TclNewObj(cmdObj); 06685 Tcl_AppendStringsToObj(cmdObj, 06686 ensemblePtr->nsPtr->fullName, 06687 (ensemblePtr->nsPtr->parentPtr ? "::" : ""), 06688 nsCmdName, NULL); 06689 cmdPrefixObj = Tcl_NewListObj(1, &cmdObj); 06690 Tcl_SetHashValue(hPtr, cmdPrefixObj); 06691 Tcl_IncrRefCount(cmdPrefixObj); 06692 } 06693 break; 06694 } 06695 } 06696 } 06697 } 06698 06699 if (hash->numEntries == 0) { 06700 ensemblePtr->subcommandArrayPtr = NULL; 06701 return; 06702 } 06703 06704 /* 06705 * Create a sorted array of all subcommands in the ensemble; hash tables 06706 * are all very well for a quick look for an exact match, but they can't 06707 * determine things like whether a string is a prefix of another (not 06708 * without lots of preparation anyway) and they're no good for when we're 06709 * generating the error message either. 06710 * 06711 * We do this by filling an array with the names (we use the hash keys 06712 * directly to save a copy, since any time we change the array we change 06713 * the hash too, and vice versa) and running quicksort over the array. 06714 */ 06715 06716 ensemblePtr->subcommandArrayPtr = (char **) 06717 ckalloc(sizeof(char *) * hash->numEntries); 06718 06719 /* 06720 * Fill array from both ends as this makes us less likely to end up with 06721 * performance problems in qsort(), which is good. Note that doing this 06722 * makes this code much more opaque, but the naive alternatve: 06723 * 06724 * for (hPtr=Tcl_FirstHashEntry(hash,&search),i=0 ; 06725 * hPtr!=NULL ; hPtr=Tcl_NextHashEntry(&search),i++) { 06726 * ensemblePtr->subcommandArrayPtr[i] = Tcl_GetHashKey(hash, &hPtr); 06727 * } 06728 * 06729 * can produce long runs of precisely ordered table entries when the 06730 * commands in the namespace are declared in a sorted fashion (an ordering 06731 * some people like) and the hashing functions (or the command names 06732 * themselves) are fairly unfortunate. By filling from both ends, it 06733 * requires active malice (and probably a debugger) to get qsort() to have 06734 * awful runtime behaviour. 06735 */ 06736 06737 i = 0; 06738 j = hash->numEntries; 06739 hPtr = Tcl_FirstHashEntry(hash, &search); 06740 while (hPtr != NULL) { 06741 ensemblePtr->subcommandArrayPtr[i++] = Tcl_GetHashKey(hash, hPtr); 06742 hPtr = Tcl_NextHashEntry(&search); 06743 if (hPtr == NULL) { 06744 break; 06745 } 06746 ensemblePtr->subcommandArrayPtr[--j] = Tcl_GetHashKey(hash, hPtr); 06747 hPtr = Tcl_NextHashEntry(&search); 06748 } 06749 if (hash->numEntries > 1) { 06750 qsort(ensemblePtr->subcommandArrayPtr, (unsigned)hash->numEntries, 06751 sizeof(char *), NsEnsembleStringOrder); 06752 } 06753 } 06754 06755 /* 06756 *---------------------------------------------------------------------- 06757 * 06758 * NsEnsembleStringOrder -- 06759 * 06760 * Helper function to compare two pointers to two strings for use with 06761 * qsort(). 06762 * 06763 * Results: 06764 * -1 if the first string is smaller, 1 if the second string is smaller, 06765 * and 0 if they are equal. 06766 * 06767 * Side effects: 06768 * None. 06769 * 06770 *---------------------------------------------------------------------- 06771 */ 06772 06773 static int 06774 NsEnsembleStringOrder( 06775 const void *strPtr1, 06776 const void *strPtr2) 06777 { 06778 return strcmp(*(const char **)strPtr1, *(const char **)strPtr2); 06779 } 06780 06781 /* 06782 *---------------------------------------------------------------------- 06783 * 06784 * FreeEnsembleCmdRep -- 06785 * 06786 * Destroys the internal representation of a Tcl_Obj that has been 06787 * holding information about a command in an ensemble. 06788 * 06789 * Results: 06790 * None. 06791 * 06792 * Side effects: 06793 * Memory is deallocated. If this held the last reference to a 06794 * namespace's main structure, that main structure will also be 06795 * destroyed. 06796 * 06797 *---------------------------------------------------------------------- 06798 */ 06799 06800 static void 06801 FreeEnsembleCmdRep( 06802 Tcl_Obj *objPtr) 06803 { 06804 EnsembleCmdRep *ensembleCmd = objPtr->internalRep.otherValuePtr; 06805 06806 Tcl_DecrRefCount(ensembleCmd->realPrefixObj); 06807 ckfree(ensembleCmd->fullSubcmdName); 06808 ensembleCmd->nsPtr->refCount--; 06809 if ((ensembleCmd->nsPtr->refCount == 0) 06810 && (ensembleCmd->nsPtr->flags & NS_DEAD)) { 06811 NamespaceFree(ensembleCmd->nsPtr); 06812 } 06813 ckfree((char *) ensembleCmd); 06814 } 06815 06816 /* 06817 *---------------------------------------------------------------------- 06818 * 06819 * DupEnsembleCmdRep -- 06820 * 06821 * Makes one Tcl_Obj into a copy of another that is a subcommand of an 06822 * ensemble. 06823 * 06824 * Results: 06825 * None. 06826 * 06827 * Side effects: 06828 * Memory is allocated, and the namespace that the ensemble is built on 06829 * top of gains another reference. 06830 * 06831 *---------------------------------------------------------------------- 06832 */ 06833 06834 static void 06835 DupEnsembleCmdRep( 06836 Tcl_Obj *objPtr, 06837 Tcl_Obj *copyPtr) 06838 { 06839 EnsembleCmdRep *ensembleCmd = objPtr->internalRep.otherValuePtr; 06840 EnsembleCmdRep *ensembleCopy = (EnsembleCmdRep *) 06841 ckalloc(sizeof(EnsembleCmdRep)); 06842 int length = strlen(ensembleCmd->fullSubcmdName); 06843 06844 copyPtr->typePtr = &tclEnsembleCmdType; 06845 copyPtr->internalRep.otherValuePtr = ensembleCopy; 06846 ensembleCopy->nsPtr = ensembleCmd->nsPtr; 06847 ensembleCopy->epoch = ensembleCmd->epoch; 06848 ensembleCopy->token = ensembleCmd->token; 06849 ensembleCopy->nsPtr->refCount++; 06850 ensembleCopy->realPrefixObj = ensembleCmd->realPrefixObj; 06851 Tcl_IncrRefCount(ensembleCopy->realPrefixObj); 06852 ensembleCopy->fullSubcmdName = ckalloc((unsigned) length+1); 06853 memcpy(ensembleCopy->fullSubcmdName, ensembleCmd->fullSubcmdName, 06854 (unsigned) length+1); 06855 } 06856 06857 /* 06858 *---------------------------------------------------------------------- 06859 * 06860 * StringOfEnsembleCmdRep -- 06861 * 06862 * Creates a string representation of a Tcl_Obj that holds a subcommand 06863 * of an ensemble. 06864 * 06865 * Results: 06866 * None. 06867 * 06868 * Side effects: 06869 * The object gains a string (UTF-8) representation. 06870 * 06871 *---------------------------------------------------------------------- 06872 */ 06873 06874 static void 06875 StringOfEnsembleCmdRep( 06876 Tcl_Obj *objPtr) 06877 { 06878 EnsembleCmdRep *ensembleCmd = objPtr->internalRep.otherValuePtr; 06879 int length = strlen(ensembleCmd->fullSubcmdName); 06880 06881 objPtr->length = length; 06882 objPtr->bytes = ckalloc((unsigned) length+1); 06883 memcpy(objPtr->bytes, ensembleCmd->fullSubcmdName, (unsigned) length+1); 06884 } 06885 06886 /* 06887 *---------------------------------------------------------------------- 06888 * 06889 * Tcl_LogCommandInfo -- 06890 * 06891 * This function is invoked after an error occurs in an interpreter. It 06892 * adds information to iPtr->errorInfo field to describe the command that 06893 * was being executed when the error occurred. 06894 * 06895 * Results: 06896 * None. 06897 * 06898 * Side effects: 06899 * Information about the command is added to errorInfo and the line 06900 * number stored internally in the interpreter is set. 06901 * 06902 *---------------------------------------------------------------------- 06903 */ 06904 06905 void 06906 Tcl_LogCommandInfo( 06907 Tcl_Interp *interp, /* Interpreter in which to log information. */ 06908 const char *script, /* First character in script containing 06909 * command (must be <= command). */ 06910 const char *command, /* First character in command that generated 06911 * the error. */ 06912 int length) /* Number of bytes in command (-1 means use 06913 * all bytes up to first null byte). */ 06914 { 06915 register const char *p; 06916 Interp *iPtr = (Interp *) interp; 06917 int overflow, limit = 150; 06918 Var *varPtr, *arrayPtr; 06919 06920 if (iPtr->flags & ERR_ALREADY_LOGGED) { 06921 /* 06922 * Someone else has already logged error information for this command; 06923 * we shouldn't add anything more. 06924 */ 06925 06926 return; 06927 } 06928 06929 /* 06930 * Compute the line number where the error occurred. 06931 */ 06932 06933 iPtr->errorLine = 1; 06934 for (p = script; p != command; p++) { 06935 if (*p == '\n') { 06936 iPtr->errorLine++; 06937 } 06938 } 06939 06940 overflow = (length > limit); 06941 Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( 06942 "\n %s\n\"%.*s%s\"", ((iPtr->errorInfo == NULL) 06943 ? "while executing" : "invoked from within"), 06944 (overflow ? limit : length), command, (overflow ? "..." : ""))); 06945 06946 varPtr = TclObjLookupVarEx(interp, iPtr->eiVar, NULL, TCL_GLOBAL_ONLY, 06947 NULL, 0, 0, &arrayPtr); 06948 if ((varPtr == NULL) || !TclIsVarTraced(varPtr)) { 06949 /* 06950 * Should not happen. 06951 */ 06952 06953 return; 06954 } else { 06955 Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&iPtr->varTraces, 06956 (char *) varPtr); 06957 VarTrace *tracePtr = Tcl_GetHashValue(hPtr); 06958 06959 if (tracePtr->traceProc != EstablishErrorInfoTraces) { 06960 /* 06961 * The most recent trace set on ::errorInfo is not the one the 06962 * core itself puts on last. This means some other code is tracing 06963 * the variable, and the additional trace(s) might be write traces 06964 * that expect the timing of writes to ::errorInfo that existed 06965 * Tcl releases before 8.5. To satisfy that compatibility need, we 06966 * write the current -errorinfo value to the ::errorInfo variable. 06967 */ 06968 06969 Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL, iPtr->errorInfo, 06970 TCL_GLOBAL_ONLY); 06971 } 06972 } 06973 } 06974 06975 /* 06976 * Local Variables: 06977 * mode: c 06978 * c-basic-offset: 4 06979 * fill-column: 78 06980 * End: 06981 */
Generated on Wed Mar 12 12:18:19 2008 by 1.5.1 |