4 * This file contains a simple Tcl package "pkgua" that is intended for
5 * testing the Tcl dynamic unloading facilities.
7 * Copyright (c) 1995 Sun Microsystems, Inc.
8 * Copyright (c) 2004 Georgios Petasis
10 * See the file "license.terms" for information on usage and redistribution of
11 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
18 * Prototypes for procedures defined later in this file:
21 static int PkguaEqObjCmd(ClientData clientData,
22 Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);
23 static int PkguaQuoteObjCmd(ClientData clientData,
24 Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);
25 static void CommandDeleted(ClientData clientData);
28 * In the following hash table we are going to store a struct that holds all
29 * the command tokens created by Tcl_CreateObjCommand in an interpreter,
30 * indexed by the interpreter. In this way, we can find which command tokens
31 * we have registered in a specific interpreter, in order to unload them. We
32 * need to keep the various command tokens we have registered, as they are the
33 * only safe way to unregister our registered commands, even if they have been
37 typedef struct ThreadSpecificData {
38 int interpTokenMapInitialised;
39 Tcl_HashTable interpTokenMap;
41 static Tcl_ThreadDataKey dataKey;
42 #define MAX_REGISTERED_COMMANDS 2
45 CommandDeleted(ClientData clientData)
47 Tcl_Command *cmdToken = (Tcl_Command *)clientData;
52 PkguaInitTokensHashTable(void)
54 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
56 if (tsdPtr->interpTokenMapInitialised) {
59 Tcl_InitHashTable(&tsdPtr->interpTokenMap, TCL_ONE_WORD_KEYS);
60 tsdPtr->interpTokenMapInitialised = 1;
64 PkguaFreeTokensHashTable(void)
66 Tcl_HashSearch search;
67 Tcl_HashEntry *entryPtr;
68 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
70 for (entryPtr = Tcl_FirstHashEntry(&tsdPtr->interpTokenMap, &search);
71 entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
72 Tcl_Free((char *) Tcl_GetHashValue(entryPtr));
74 tsdPtr->interpTokenMapInitialised = 0;
82 Tcl_Command *cmdTokens;
83 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
84 Tcl_HashEntry *entryPtr =
85 Tcl_CreateHashEntry(&tsdPtr->interpTokenMap, (char *) interp, &newEntry);
88 cmdTokens = (Tcl_Command *)
89 Tcl_Alloc(sizeof(Tcl_Command) * (MAX_REGISTERED_COMMANDS));
90 for (newEntry=0 ; newEntry<MAX_REGISTERED_COMMANDS ; ++newEntry) {
91 cmdTokens[newEntry] = NULL;
93 Tcl_SetHashValue(entryPtr, cmdTokens);
95 cmdTokens = (Tcl_Command *) Tcl_GetHashValue(entryPtr);
104 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
105 Tcl_HashEntry *entryPtr =
106 Tcl_FindHashEntry(&tsdPtr->interpTokenMap, (char *) interp);
109 Tcl_Free((char *) Tcl_GetHashValue(entryPtr));
110 Tcl_DeleteHashEntry(entryPtr);
115 *----------------------------------------------------------------------
119 * This procedure is invoked to process the "pkgua_eq" Tcl command. It
120 * expects two arguments and returns 1 if they are the same, 0 if they
124 * A standard Tcl result.
127 * See the user documentation.
129 *----------------------------------------------------------------------
134 ClientData dummy, /* Not used. */
135 Tcl_Interp *interp, /* Current interpreter. */
136 int objc, /* Number of arguments. */
137 Tcl_Obj *const objv[]) /* Argument objects. */
140 const char *str1, *str2;
145 Tcl_WrongNumArgs(interp, 1, objv, "string1 string2");
149 str1 = Tcl_GetStringFromObj(objv[1], &len1);
150 str2 = Tcl_GetStringFromObj(objv[2], &len2);
152 result = (Tcl_UtfNcmp(str1, str2, len1) == 0);
156 Tcl_SetObjResult(interp, Tcl_NewIntObj(result));
161 *----------------------------------------------------------------------
163 * PkguaQuoteObjCmd --
165 * This procedure is invoked to process the "pkgua_quote" Tcl command. It
166 * expects one argument, which it returns as result.
169 * A standard Tcl result.
172 * See the user documentation.
174 *----------------------------------------------------------------------
179 ClientData dummy, /* Not used. */
180 Tcl_Interp *interp, /* Current interpreter. */
181 int objc, /* Number of arguments. */
182 Tcl_Obj *const objv[]) /* Argument strings. */
187 Tcl_WrongNumArgs(interp, 1, objv, "value");
190 Tcl_SetObjResult(interp, objv[1]);
195 *----------------------------------------------------------------------
199 * This is a package initialization procedure, which is called by Tcl
200 * when this package is to be added to an interpreter.
208 *----------------------------------------------------------------------
213 Tcl_Interp *interp) /* Interpreter in which the package is to be
217 Tcl_Command *cmdTokens;
219 if (Tcl_InitStubs(interp, "8.5", 0) == NULL) {
224 * Initialize our Hash table, where we store the registered command tokens
225 * for each interpreter.
228 PkguaInitTokensHashTable();
230 code = Tcl_PkgProvide(interp, "pkgua", "1.0");
231 if (code != TCL_OK) {
235 Tcl_SetVar2(interp, "::pkgua_loaded", NULL, ".", TCL_APPEND_VALUE);
237 cmdTokens = PkguaInterpToTokens(interp);
239 Tcl_CreateObjCommand(interp, "pkgua_eq", PkguaEqObjCmd, &cmdTokens[0],
242 Tcl_CreateObjCommand(interp, "pkgua_quote", PkguaQuoteObjCmd,
243 &cmdTokens[1], CommandDeleted);
248 *----------------------------------------------------------------------
252 * This is a package initialization procedure, which is called by Tcl
253 * when this package is to be added to a safe interpreter.
261 *----------------------------------------------------------------------
266 Tcl_Interp *interp) /* Interpreter in which the package is to be
269 return Pkgua_Init(interp);
273 *----------------------------------------------------------------------
277 * This is a package unloading initialization procedure, which is called
278 * by Tcl when this package is to be unloaded from an interpreter.
286 *----------------------------------------------------------------------
291 Tcl_Interp *interp, /* Interpreter from which the package is to be
293 int flags) /* Flags passed by the unloading mechanism */
296 Tcl_Command *cmdTokens = PkguaInterpToTokens(interp);
298 for (cmdIndex=0 ; cmdIndex<MAX_REGISTERED_COMMANDS ; cmdIndex++) {
299 if (cmdTokens[cmdIndex] == NULL) {
302 code = Tcl_DeleteCommandFromToken(interp, cmdTokens[cmdIndex]);
303 if (code != TCL_OK) {
308 PkguaDeleteTokens(interp);
310 Tcl_SetVar2(interp, "::pkgua_detached", NULL, ".", TCL_APPEND_VALUE);
312 if (flags == TCL_UNLOAD_DETACH_FROM_PROCESS) {
314 * Tcl is ready to detach this library from the running application.
315 * We should free all the memory that is not related to any
319 PkguaFreeTokensHashTable();
320 Tcl_SetVar2(interp, "::pkgua_unloaded", NULL, ".", TCL_APPEND_VALUE);
326 *----------------------------------------------------------------------
328 * Pkgua_SafeUnload --
330 * This is a package unloading initialization procedure, which is called
331 * by Tcl when this package is to be unloaded from an interpreter.
339 *----------------------------------------------------------------------
344 Tcl_Interp *interp, /* Interpreter from which the package is to be
346 int flags) /* Flags passed by the unloading mechanism */
348 return Pkgua_Unload(interp, flags);