OSDN Git Service

Please enter the commit message for your changes. Lines starting
[eos/base.git] / util / src / TclTk / tcl8.6.12 / unix / dltest / pkgua.c
diff --git a/util/src/TclTk/tcl8.6.12/unix/dltest/pkgua.c b/util/src/TclTk/tcl8.6.12/unix/dltest/pkgua.c
new file mode 100644 (file)
index 0000000..ad2b2b3
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * pkgua.c --
+ *
+ *     This file contains a simple Tcl package "pkgua" that is intended for
+ *     testing the Tcl dynamic unloading facilities.
+ *
+ * Copyright (c) 1995 Sun Microsystems, Inc.
+ * Copyright (c) 2004 Georgios Petasis
+ *
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ */
+
+#undef STATIC_BUILD
+#include "tcl.h"
+
+/*
+ * Prototypes for procedures defined later in this file:
+ */
+
+static int    PkguaEqObjCmd(ClientData clientData,
+               Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);
+static int    PkguaQuoteObjCmd(ClientData clientData,
+               Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);
+static void   CommandDeleted(ClientData clientData);
+
+/*
+ * In the following hash table we are going to store a struct that holds all
+ * the command tokens created by Tcl_CreateObjCommand in an interpreter,
+ * indexed by the interpreter. In this way, we can find which command tokens
+ * we have registered in a specific interpreter, in order to unload them. We
+ * need to keep the various command tokens we have registered, as they are the
+ * only safe way to unregister our registered commands, even if they have been
+ * renamed.
+ */
+
+typedef struct ThreadSpecificData {
+    int interpTokenMapInitialised;
+    Tcl_HashTable interpTokenMap;
+} ThreadSpecificData;
+static Tcl_ThreadDataKey dataKey;
+#define MAX_REGISTERED_COMMANDS 2
+
+static void
+CommandDeleted(ClientData clientData)
+{
+    Tcl_Command *cmdToken = (Tcl_Command *)clientData;
+    *cmdToken = NULL;
+}
+\f
+static void
+PkguaInitTokensHashTable(void)
+{
+    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
+
+    if (tsdPtr->interpTokenMapInitialised) {
+       return;
+    }
+    Tcl_InitHashTable(&tsdPtr->interpTokenMap, TCL_ONE_WORD_KEYS);
+    tsdPtr->interpTokenMapInitialised = 1;
+}
+\f
+static void
+PkguaFreeTokensHashTable(void)
+{
+    Tcl_HashSearch search;
+    Tcl_HashEntry *entryPtr;
+    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
+
+    for (entryPtr = Tcl_FirstHashEntry(&tsdPtr->interpTokenMap, &search);
+           entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
+       Tcl_Free((char *) Tcl_GetHashValue(entryPtr));
+    }
+    tsdPtr->interpTokenMapInitialised = 0;
+}
+\f
+static Tcl_Command *
+PkguaInterpToTokens(
+    Tcl_Interp *interp)
+{
+    int newEntry;
+    Tcl_Command *cmdTokens;
+    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
+    Tcl_HashEntry *entryPtr =
+           Tcl_CreateHashEntry(&tsdPtr->interpTokenMap, (char *) interp, &newEntry);
+
+    if (newEntry) {
+       cmdTokens = (Tcl_Command *)
+               Tcl_Alloc(sizeof(Tcl_Command) * (MAX_REGISTERED_COMMANDS));
+       for (newEntry=0 ; newEntry<MAX_REGISTERED_COMMANDS ; ++newEntry) {
+           cmdTokens[newEntry] = NULL;
+       }
+       Tcl_SetHashValue(entryPtr, cmdTokens);
+    } else {
+       cmdTokens = (Tcl_Command *) Tcl_GetHashValue(entryPtr);
+    }
+    return cmdTokens;
+}
+\f
+static void
+PkguaDeleteTokens(
+    Tcl_Interp *interp)
+{
+    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
+    Tcl_HashEntry *entryPtr =
+           Tcl_FindHashEntry(&tsdPtr->interpTokenMap, (char *) interp);
+
+    if (entryPtr) {
+       Tcl_Free((char *) Tcl_GetHashValue(entryPtr));
+       Tcl_DeleteHashEntry(entryPtr);
+    }
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * PkguaEqObjCmd --
+ *
+ *     This procedure is invoked to process the "pkgua_eq" Tcl command. It
+ *     expects two arguments and returns 1 if they are the same, 0 if they
+ *     are different.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+PkguaEqObjCmd(
+    ClientData dummy,          /* Not used. */
+    Tcl_Interp *interp,                /* Current interpreter. */
+    int objc,                  /* Number of arguments. */
+    Tcl_Obj *const objv[])     /* Argument objects. */
+{
+    int result;
+    const char *str1, *str2;
+    int len1, len2;
+    (void)dummy;
+
+    if (objc != 3) {
+       Tcl_WrongNumArgs(interp, 1, objv,  "string1 string2");
+       return TCL_ERROR;
+    }
+
+    str1 = Tcl_GetStringFromObj(objv[1], &len1);
+    str2 = Tcl_GetStringFromObj(objv[2], &len2);
+    if (len1 == len2) {
+       result = (Tcl_UtfNcmp(str1, str2, len1) == 0);
+    } else {
+       result = 0;
+    }
+    Tcl_SetObjResult(interp, Tcl_NewIntObj(result));
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * PkguaQuoteObjCmd --
+ *
+ *     This procedure is invoked to process the "pkgua_quote" Tcl command. It
+ *     expects one argument, which it returns as result.
+ *
+ * Results:
+ *     A standard Tcl result.
+ *
+ * Side effects:
+ *     See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+PkguaQuoteObjCmd(
+    ClientData dummy,          /* Not used. */
+    Tcl_Interp *interp,                /* Current interpreter. */
+    int objc,                  /* Number of arguments. */
+    Tcl_Obj *const objv[])     /* Argument strings. */
+{
+    (void)dummy;
+
+    if (objc != 2) {
+       Tcl_WrongNumArgs(interp, 1, objv, "value");
+       return TCL_ERROR;
+    }
+    Tcl_SetObjResult(interp, objv[1]);
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * Pkgua_Init --
+ *
+ *     This is a package initialization procedure, which is called by Tcl
+ *     when this package is to be added to an interpreter.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+DLLEXPORT int
+Pkgua_Init(
+    Tcl_Interp *interp)                /* Interpreter in which the package is to be
+                                * made available. */
+{
+    int code;
+    Tcl_Command *cmdTokens;
+
+    if (Tcl_InitStubs(interp, "8.5", 0) == NULL) {
+       return TCL_ERROR;
+    }
+
+    /*
+     * Initialize our Hash table, where we store the registered command tokens
+     * for each interpreter.
+     */
+
+    PkguaInitTokensHashTable();
+
+    code = Tcl_PkgProvide(interp, "pkgua", "1.0");
+    if (code != TCL_OK) {
+       return code;
+    }
+
+    Tcl_SetVar2(interp, "::pkgua_loaded", NULL, ".", TCL_APPEND_VALUE);
+
+    cmdTokens = PkguaInterpToTokens(interp);
+    cmdTokens[0] =
+           Tcl_CreateObjCommand(interp, "pkgua_eq", PkguaEqObjCmd, &cmdTokens[0],
+                   CommandDeleted);
+    cmdTokens[1] =
+           Tcl_CreateObjCommand(interp, "pkgua_quote", PkguaQuoteObjCmd,
+                   &cmdTokens[1], CommandDeleted);
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * Pkgua_SafeInit --
+ *
+ *     This is a package initialization procedure, which is called by Tcl
+ *     when this package is to be added to a safe interpreter.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+DLLEXPORT int
+Pkgua_SafeInit(
+    Tcl_Interp *interp)                /* Interpreter in which the package is to be
+                                * made available. */
+{
+    return Pkgua_Init(interp);
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * Pkgua_Unload --
+ *
+ *     This is a package unloading initialization procedure, which is called
+ *     by Tcl when this package is to be unloaded from an interpreter.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+DLLEXPORT int
+Pkgua_Unload(
+    Tcl_Interp *interp,                /* Interpreter from which the package is to be
+                                * unloaded. */
+    int flags)                 /* Flags passed by the unloading mechanism */
+{
+    int code, cmdIndex;
+    Tcl_Command *cmdTokens = PkguaInterpToTokens(interp);
+
+    for (cmdIndex=0 ; cmdIndex<MAX_REGISTERED_COMMANDS ; cmdIndex++) {
+       if (cmdTokens[cmdIndex] == NULL) {
+           continue;
+       }
+       code = Tcl_DeleteCommandFromToken(interp, cmdTokens[cmdIndex]);
+       if (code != TCL_OK) {
+           return code;
+       }
+    }
+
+    PkguaDeleteTokens(interp);
+
+    Tcl_SetVar2(interp, "::pkgua_detached", NULL, ".", TCL_APPEND_VALUE);
+
+    if (flags == TCL_UNLOAD_DETACH_FROM_PROCESS) {
+       /*
+        * Tcl is ready to detach this library from the running application.
+        * We should free all the memory that is not related to any
+        * interpreter.
+        */
+
+       PkguaFreeTokensHashTable();
+       Tcl_SetVar2(interp, "::pkgua_unloaded", NULL, ".", TCL_APPEND_VALUE);
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * Pkgua_SafeUnload --
+ *
+ *     This is a package unloading initialization procedure, which is called
+ *     by Tcl when this package is to be unloaded from an interpreter.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+DLLEXPORT int
+Pkgua_SafeUnload(
+    Tcl_Interp *interp,                /* Interpreter from which the package is to be
+                                * unloaded. */
+    int flags)                 /* Flags passed by the unloading mechanism */
+{
+    return Pkgua_Unload(interp, flags);
+}