pkgua.c

Go 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  doxygen 1.5.1