pkgua.cGo to the documentation of this file.00001 /* 00002 * pkgua.c -- 00003 * 00004 * This file contains a simple Tcl package "pkgua" that is intended for 00005 * testing the Tcl dynamic unloading facilities. 00006 * 00007 * Copyright (c) 1995 Sun Microsystems, Inc. 00008 * Copyright (c) 2004 Georgios Petasis 00009 * 00010 * See the file "license.terms" for information on usage and redistribution of 00011 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 00012 * 00013 * RCS: @(#) $Id: pkgua.c,v 1.7 2007/12/13 15:28:43 dgp Exp $ 00014 */ 00015 00016 #include "tcl.h" 00017 00018 /* 00019 * Prototypes for procedures defined later in this file: 00020 */ 00021 00022 static int PkguaEqObjCmd(ClientData clientData, 00023 Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); 00024 static int PkguaQuoteObjCmd(ClientData clientData, 00025 Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); 00026 00027 /* 00028 * In the following hash table we are going to store a struct that holds all 00029 * the command tokens created by Tcl_CreateObjCommand in an interpreter, 00030 * indexed by the interpreter. In this way, we can find which command tokens 00031 * we have registered in a specific interpreter, in order to unload them. We 00032 * need to keep the various command tokens we have registered, as they are the 00033 * only safe way to unregister our registered commands, even if they have been 00034 * renamed. 00035 * 00036 * Note that this code is utterly single-threaded. 00037 */ 00038 00039 static Tcl_HashTable interpTokenMap; 00040 static int interpTokenMapInitialised = 0; 00041 #define MAX_REGISTERED_COMMANDS 2 00042 00043 00044 static void 00045 PkguaInitTokensHashTable(void) 00046 { 00047 if (interpTokenMapInitialised) { 00048 return; 00049 } 00050 Tcl_InitHashTable(&interpTokenMap, TCL_ONE_WORD_KEYS); 00051 interpTokenMapInitialised = 1; 00052 } 00053 00054 void 00055 PkguaFreeTokensHashTable(void) 00056 { 00057 Tcl_HashSearch search; 00058 Tcl_HashEntry *entryPtr; 00059 00060 for (entryPtr = Tcl_FirstHashEntry(&interpTokenMap, &search); 00061 entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { 00062 Tcl_Free((char *) Tcl_GetHashValue(entryPtr)); 00063 } 00064 interpTokenMapInitialised = 0; 00065 } 00066 00067 static Tcl_Command * 00068 PkguaInterpToTokens( 00069 Tcl_Interp *interp) 00070 { 00071 int newEntry; 00072 Tcl_Command *cmdTokens; 00073 Tcl_HashEntry *entryPtr = 00074 Tcl_CreateHashEntry(&interpTokenMap, (char *) interp, &newEntry); 00075 00076 if (newEntry) { 00077 cmdTokens = (Tcl_Command *) 00078 Tcl_Alloc(sizeof(Tcl_Command) * (MAX_REGISTERED_COMMANDS+1)); 00079 for (newEntry=0 ; newEntry<MAX_REGISTERED_COMMANDS+1 ; ++newEntry) { 00080 cmdTokens[newEntry] = NULL; 00081 } 00082 Tcl_SetHashValue(entryPtr, (ClientData) cmdTokens); 00083 } else { 00084 cmdTokens = (Tcl_Command *) Tcl_GetHashValue(entryPtr); 00085 } 00086 return cmdTokens; 00087 } 00088 00089 static void 00090 PkguaDeleteTokens( 00091 Tcl_Interp *interp) 00092 { 00093 Tcl_HashEntry *entryPtr = 00094 Tcl_FindHashEntry(&interpTokenMap, (char *) interp); 00095 00096 if (entryPtr) { 00097 Tcl_Free((char *) Tcl_GetHashValue(entryPtr)); 00098 Tcl_DeleteHashEntry(entryPtr); 00099 } 00100 } 00101 00102 /* 00103 *---------------------------------------------------------------------- 00104 * 00105 * PkguaEqObjCmd -- 00106 * 00107 * This procedure is invoked to process the "pkgua_eq" Tcl command. It 00108 * expects two arguments and returns 1 if they are the same, 0 if they 00109 * are different. 00110 * 00111 * Results: 00112 * A standard Tcl result. 00113 * 00114 * Side effects: 00115 * See the user documentation. 00116 * 00117 *---------------------------------------------------------------------- 00118 */ 00119 00120 static int 00121 PkguaEqObjCmd( 00122 ClientData dummy, /* Not used. */ 00123 Tcl_Interp *interp, /* Current interpreter. */ 00124 int objc, /* Number of arguments. */ 00125 Tcl_Obj *CONST objv[]) /* Argument objects. */ 00126 { 00127 int result; 00128 CONST char *str1, *str2; 00129 int len1, len2; 00130 00131 if (objc != 3) { 00132 Tcl_WrongNumArgs(interp, 1, objv, "string1 string2"); 00133 return TCL_ERROR; 00134 } 00135 00136 str1 = Tcl_GetStringFromObj(objv[1], &len1); 00137 str2 = Tcl_GetStringFromObj(objv[2], &len2); 00138 if (len1 == len2) { 00139 result = (Tcl_UtfNcmp(str1, str2, len1) == 0); 00140 } else { 00141 result = 0; 00142 } 00143 Tcl_SetObjResult(interp, Tcl_NewIntObj(result)); 00144 return TCL_OK; 00145 } 00146 00147 /* 00148 *---------------------------------------------------------------------- 00149 * 00150 * PkguaQuoteObjCmd -- 00151 * 00152 * This procedure is invoked to process the "pkgua_quote" Tcl command. It 00153 * expects one argument, which it returns as result. 00154 * 00155 * Results: 00156 * A standard Tcl result. 00157 * 00158 * Side effects: 00159 * See the user documentation. 00160 * 00161 *---------------------------------------------------------------------- 00162 */ 00163 00164 static int 00165 PkguaQuoteObjCmd( 00166 ClientData dummy, /* Not used. */ 00167 Tcl_Interp *interp, /* Current interpreter. */ 00168 int objc, /* Number of arguments. */ 00169 Tcl_Obj *CONST objv[]) /* Argument strings. */ 00170 { 00171 if (objc != 2) { 00172 Tcl_WrongNumArgs(interp, 1, objv, "value"); 00173 return TCL_ERROR; 00174 } 00175 Tcl_SetObjResult(interp, objv[1]); 00176 return TCL_OK; 00177 } 00178 00179 /* 00180 *---------------------------------------------------------------------- 00181 * 00182 * Pkgua_Init -- 00183 * 00184 * This is a package initialization procedure, which is called by Tcl 00185 * when this package is to be added to an interpreter. 00186 * 00187 * Results: 00188 * None. 00189 * 00190 * Side effects: 00191 * None. 00192 * 00193 *---------------------------------------------------------------------- 00194 */ 00195 00196 int 00197 Pkgua_Init( 00198 Tcl_Interp *interp) /* Interpreter in which the package is to be 00199 * made available. */ 00200 { 00201 int code, cmdIndex = 0; 00202 Tcl_Command *cmdTokens; 00203 00204 if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) { 00205 return TCL_ERROR; 00206 } 00207 00208 /* 00209 * Initialise our Hash table, where we store the registered command tokens 00210 * for each interpreter. 00211 */ 00212 00213 PkguaInitTokensHashTable(); 00214 00215 code = Tcl_PkgProvide(interp, "Pkgua", "1.0"); 00216 if (code != TCL_OK) { 00217 return code; 00218 } 00219 00220 Tcl_SetVar(interp, "::pkgua_loaded", ".", TCL_APPEND_VALUE); 00221 00222 cmdTokens = PkguaInterpToTokens(interp); 00223 cmdTokens[cmdIndex++] = 00224 Tcl_CreateObjCommand(interp, "pkgua_eq", PkguaEqObjCmd, 00225 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); 00226 cmdTokens[cmdIndex++] = 00227 Tcl_CreateObjCommand(interp, "pkgua_quote", PkguaQuoteObjCmd, 00228 (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); 00229 return TCL_OK; 00230 } 00231 00232 /* 00233 *---------------------------------------------------------------------- 00234 * 00235 * Pkgua_SafeInit -- 00236 * 00237 * This is a package initialization procedure, which is called by Tcl 00238 * when this package is to be added to a safe interpreter. 00239 * 00240 * Results: 00241 * None. 00242 * 00243 * Side effects: 00244 * None. 00245 * 00246 *---------------------------------------------------------------------- 00247 */ 00248 00249 int 00250 Pkgua_SafeInit( 00251 Tcl_Interp *interp) /* Interpreter in which the package is to be 00252 * made available. */ 00253 { 00254 return Pkgua_Init(interp); 00255 } 00256 00257 /* 00258 *---------------------------------------------------------------------- 00259 * 00260 * Pkgua_Unload -- 00261 * 00262 * This is a package unloading initialization procedure, which is called 00263 * by Tcl when this package is to be unloaded from an interpreter. 00264 * 00265 * Results: 00266 * None. 00267 * 00268 * Side effects: 00269 * None. 00270 * 00271 *---------------------------------------------------------------------- 00272 */ 00273 00274 int 00275 Pkgua_Unload( 00276 Tcl_Interp *interp, /* Interpreter from which the package is to be 00277 * unloaded. */ 00278 int flags) /* Flags passed by the unloading mechanism */ 00279 { 00280 int code, cmdIndex; 00281 Tcl_Command *cmdTokens = PkguaInterpToTokens(interp); 00282 00283 for (cmdIndex=0 ; cmdIndex<MAX_REGISTERED_COMMANDS ; cmdIndex++) { 00284 if (cmdTokens[cmdIndex] == NULL) { 00285 continue; 00286 } 00287 code = Tcl_DeleteCommandFromToken(interp, cmdTokens[cmdIndex]); 00288 if (code != TCL_OK) { 00289 return code; 00290 } 00291 } 00292 00293 PkguaDeleteTokens(interp); 00294 00295 Tcl_SetVar(interp, "::pkgua_detached", ".", TCL_APPEND_VALUE); 00296 00297 if (flags == TCL_UNLOAD_DETACH_FROM_PROCESS) { 00298 /* 00299 * Tcl is ready to detach this library from the running application. 00300 * We should free all the memory that is not related to any 00301 * interpreter. 00302 */ 00303 00304 PkguaFreeTokensHashTable(); 00305 Tcl_SetVar(interp, "::pkgua_unloaded", ".", TCL_APPEND_VALUE); 00306 } 00307 return TCL_OK; 00308 } 00309 00310 /* 00311 *---------------------------------------------------------------------- 00312 * 00313 * Pkgua_SafeUnload -- 00314 * 00315 * This is a package unloading initialization procedure, which is called 00316 * by Tcl when this package is to be unloaded from an interpreter. 00317 * 00318 * Results: 00319 * None. 00320 * 00321 * Side effects: 00322 * None. 00323 * 00324 *---------------------------------------------------------------------- 00325 */ 00326 00327 int 00328 Pkgua_SafeUnload( 00329 Tcl_Interp *interp, /* Interpreter from which the package is to be 00330 * unloaded. */ 00331 int flags) /* Flags passed by the unloading mechanism */ 00332 { 00333 return Pkgua_Unload(interp, flags); 00334 }
Generated on Wed Mar 12 12:18:25 2008 by 1.5.1 |