tclResolve.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:14k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tclResolve.c --
  3.  *
  4.  *      Contains hooks for customized command/variable name resolution
  5.  *      schemes.  These hooks allow extensions like [incr Tcl] to add
  6.  *      their own name resolution rules to the Tcl language.  Rules can
  7.  *      be applied to a particular namespace, to the interpreter as a
  8.  *      whole, or both.
  9.  *
  10.  * Copyright (c) 1998 Lucent Technologies, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * RCS: @(#) $Id: tclResolve.c,v 1.4 2002/01/25 22:01:32 dgp Exp $
  16.  */
  17. #include "tclInt.h"
  18. /*
  19.  * Declarations for procedures local to this file:
  20.  */
  21. static void BumpCmdRefEpochs _ANSI_ARGS_((Namespace *nsPtr));
  22. /*
  23.  *----------------------------------------------------------------------
  24.  *
  25.  * Tcl_AddInterpResolvers --
  26.  *
  27.  * Adds a set of command/variable resolution procedures to an
  28.  * interpreter.  These procedures are consulted when commands
  29.  * are resolved in Tcl_FindCommand, and when variables are
  30.  * resolved in TclLookupVar and LookupCompiledLocal.  Each
  31.  * namespace may also have its own set of resolution procedures
  32.  * which take precedence over those for the interpreter.
  33.  *
  34.  * When a name is resolved, it is handled as follows.  First,
  35.  * the name is passed to the resolution procedures for the
  36.  * namespace.  If not resolved, the name is passed to each of
  37.  * the resolution procedures added to the interpreter.  Finally,
  38.  * if still not resolved, the name is handled using the default
  39.  * Tcl rules for name resolution.
  40.  *
  41.  * Results:
  42.  * Returns pointers to the current name resolution procedures
  43.  * in the cmdProcPtr, varProcPtr and compiledVarProcPtr
  44.  * arguments.
  45.  *
  46.  * Side effects:
  47.  * If a compiledVarProc is specified, this procedure bumps the
  48.  * compileEpoch for the interpreter, forcing all code to be
  49.  * recompiled.  If a cmdProc is specified, this procedure bumps
  50.  * the cmdRefEpoch in all namespaces, forcing commands to be
  51.  * resolved again using the new rules.
  52.  *
  53.  *----------------------------------------------------------------------
  54.  */
  55. void
  56. Tcl_AddInterpResolvers(interp, name, cmdProc, varProc, compiledVarProc)
  57.     Tcl_Interp *interp; /* Interpreter whose name resolution
  58.  * rules are being modified. */
  59.     CONST char *name; /* Name of this resolution scheme. */
  60.     Tcl_ResolveCmdProc *cmdProc; /* New procedure for command
  61.  * resolution */
  62.     Tcl_ResolveVarProc *varProc; /* Procedure for variable resolution
  63.  * at runtime */
  64.     Tcl_ResolveCompiledVarProc *compiledVarProc;
  65. /* Procedure for variable resolution
  66.  * at compile time. */
  67. {
  68.     Interp *iPtr = (Interp*)interp;
  69.     ResolverScheme *resPtr;
  70.     /*
  71.      *  Since we're adding a new name resolution scheme, we must force
  72.      *  all code to be recompiled to use the new scheme.  If there
  73.      *  are new compiled variable resolution rules, bump the compiler
  74.      *  epoch to invalidate compiled code.  If there are new command
  75.      *  resolution rules, bump the cmdRefEpoch in all namespaces.
  76.      */
  77.     if (compiledVarProc) {
  78.         iPtr->compileEpoch++;
  79.     }
  80.     if (cmdProc) {
  81.         BumpCmdRefEpochs(iPtr->globalNsPtr);
  82.     }
  83.     /*
  84.      *  Look for an existing scheme with the given name.  If found,
  85.      *  then replace its rules.
  86.      */
  87.     for (resPtr = iPtr->resolverPtr; resPtr != NULL; resPtr = resPtr->nextPtr) {
  88.         if (*name == *resPtr->name && strcmp(name, resPtr->name) == 0) {
  89.             resPtr->cmdResProc = cmdProc;
  90.             resPtr->varResProc = varProc;
  91.             resPtr->compiledVarResProc = compiledVarProc;
  92.             return;
  93.         }
  94.     }
  95.     /*
  96.      *  Otherwise, this is a new scheme.  Add it to the FRONT
  97.      *  of the linked list, so that it overrides existing schemes.
  98.      */
  99.     resPtr = (ResolverScheme *) ckalloc(sizeof(ResolverScheme));
  100.     resPtr->name = (char*)ckalloc((unsigned)(strlen(name)+1));
  101.     strcpy(resPtr->name, name);
  102.     resPtr->cmdResProc = cmdProc;
  103.     resPtr->varResProc = varProc;
  104.     resPtr->compiledVarResProc = compiledVarProc;
  105.     resPtr->nextPtr = iPtr->resolverPtr;
  106.     iPtr->resolverPtr = resPtr;
  107. }
  108. /*
  109.  *----------------------------------------------------------------------
  110.  *
  111.  * Tcl_GetInterpResolvers --
  112.  *
  113.  * Looks for a set of command/variable resolution procedures with
  114.  * the given name in an interpreter.  These procedures are
  115.  * registered by calling Tcl_AddInterpResolvers.
  116.  *
  117.  * Results:
  118.  * If the name is recognized, this procedure returns non-zero,
  119.  * along with pointers to the name resolution procedures in
  120.  * the Tcl_ResolverInfo structure.  If the name is not recognized,
  121.  * this procedure returns zero.
  122.  *
  123.  * Side effects:
  124.  * None.
  125.  *
  126.  *----------------------------------------------------------------------
  127.  */
  128. int
  129. Tcl_GetInterpResolvers(interp, name, resInfoPtr)
  130.     Tcl_Interp *interp; /* Interpreter whose name resolution
  131.  * rules are being queried. */
  132.     CONST char *name;                   /* Look for a scheme with this name. */
  133.     Tcl_ResolverInfo *resInfoPtr; /* Returns pointers to the procedures,
  134.  * if found */
  135. {
  136.     Interp *iPtr = (Interp*)interp;
  137.     ResolverScheme *resPtr;
  138.     /*
  139.      *  Look for an existing scheme with the given name.  If found,
  140.      *  then return pointers to its procedures.
  141.      */
  142.     for (resPtr = iPtr->resolverPtr; resPtr != NULL; resPtr = resPtr->nextPtr) {
  143.         if (*name == *resPtr->name && strcmp(name, resPtr->name) == 0) {
  144.     resInfoPtr->cmdResProc = resPtr->cmdResProc;
  145.     resInfoPtr->varResProc = resPtr->varResProc;
  146.     resInfoPtr->compiledVarResProc = resPtr->compiledVarResProc;
  147.             return 1;
  148.         }
  149.     }
  150.     return 0;
  151. }
  152. /*
  153.  *----------------------------------------------------------------------
  154.  *
  155.  * Tcl_RemoveInterpResolvers --
  156.  *
  157.  * Removes a set of command/variable resolution procedures
  158.  * previously added by Tcl_AddInterpResolvers.  The next time
  159.  * a command/variable name is resolved, these procedures
  160.  * won't be consulted.
  161.  *
  162.  * Results:
  163.  * Returns non-zero if the name was recognized and the
  164.  * resolution scheme was deleted.  Returns zero otherwise.
  165.  *
  166.  * Side effects:
  167.  * If a scheme with a compiledVarProc was deleted, this procedure
  168.  * bumps the compileEpoch for the interpreter, forcing all code
  169.  * to be recompiled.  If a scheme with a cmdProc was deleted,
  170.  * this procedure bumps the cmdRefEpoch in all namespaces,
  171.  * forcing commands to be resolved again using the new rules.
  172.  *
  173.  *----------------------------------------------------------------------
  174.  */
  175. int
  176. Tcl_RemoveInterpResolvers(interp, name)
  177.     Tcl_Interp *interp; /* Interpreter whose name resolution
  178.  * rules are being modified. */
  179.     CONST char *name;                   /* Name of the scheme to be removed. */
  180. {
  181.     Interp *iPtr = (Interp*)interp;
  182.     ResolverScheme **prevPtrPtr, *resPtr;
  183.     /*
  184.      *  Look for an existing scheme with the given name.
  185.      */
  186.     prevPtrPtr = &iPtr->resolverPtr;
  187.     for (resPtr = iPtr->resolverPtr; resPtr != NULL; resPtr = resPtr->nextPtr) {
  188.         if (*name == *resPtr->name && strcmp(name, resPtr->name) == 0) {
  189.             break;
  190.         }
  191.         prevPtrPtr = &resPtr->nextPtr;
  192.     }
  193.     /*
  194.      *  If we found the scheme, delete it.
  195.      */
  196.     if (resPtr) {
  197.         /*
  198.          *  If we're deleting a scheme with compiled variable resolution
  199.          *  rules, bump the compiler epoch to invalidate compiled code.
  200.          *  If we're deleting a scheme with command resolution rules,
  201.          *  bump the cmdRefEpoch in all namespaces.
  202.          */
  203.         if (resPtr->compiledVarResProc) {
  204.             iPtr->compileEpoch++;
  205.         }
  206.         if (resPtr->cmdResProc) {
  207.             BumpCmdRefEpochs(iPtr->globalNsPtr);
  208.         }
  209.         *prevPtrPtr = resPtr->nextPtr;
  210.         ckfree(resPtr->name);
  211.         ckfree((char *) resPtr);
  212.         return 1;
  213.     }
  214.     return 0;
  215. }
  216. /*
  217.  *----------------------------------------------------------------------
  218.  *
  219.  * BumpCmdRefEpochs --
  220.  *
  221.  * This procedure is used to bump the cmdRefEpoch counters in
  222.  * the specified namespace and all of its child namespaces.
  223.  * It is used whenever name resolution schemes are added/removed
  224.  * from an interpreter, to invalidate all command references.
  225.  *
  226.  * Results:
  227.  * None.
  228.  *
  229.  * Side effects:
  230.  * Bumps the cmdRefEpoch in the specified namespace and its
  231.  * children, recursively.
  232.  *
  233.  *----------------------------------------------------------------------
  234.  */
  235. static void
  236. BumpCmdRefEpochs(nsPtr)
  237.     Namespace *nsPtr; /* Namespace being modified. */
  238. {
  239.     Tcl_HashEntry *entry;
  240.     Tcl_HashSearch search;
  241.     Namespace *childNsPtr;
  242.     nsPtr->cmdRefEpoch++;
  243.     for (entry = Tcl_FirstHashEntry(&nsPtr->childTable, &search);
  244.     entry != NULL;
  245.     entry = Tcl_NextHashEntry(&search)) {
  246.         childNsPtr = (Namespace *) Tcl_GetHashValue(entry);
  247.         BumpCmdRefEpochs(childNsPtr);
  248.     }
  249. }
  250. /*
  251.  *----------------------------------------------------------------------
  252.  *
  253.  * Tcl_SetNamespaceResolvers --
  254.  *
  255.  * Sets the command/variable resolution procedures for a namespace,
  256.  * thereby changing the way that command/variable names are
  257.  * interpreted.  This allows extension writers to support different
  258.  * name resolution schemes, such as those for object-oriented
  259.  * packages.
  260.  *
  261.  * Command resolution is handled by a procedure of the following
  262.  * type:
  263.  *
  264.  *   typedef int (Tcl_ResolveCmdProc) _ANSI_ARGS_((
  265.  * Tcl_Interp* interp, CONST char* name, Tcl_Namespace *context,
  266.  *              int flags, Tcl_Command *rPtr));
  267.  *          
  268.  * Whenever a command is executed or Tcl_FindCommand is invoked
  269.  * within the namespace, this procedure is called to resolve the
  270.  * command name.  If this procedure is able to resolve the name,
  271.  * it should return the status code TCL_OK, along with the
  272.  * corresponding Tcl_Command in the rPtr argument.  Otherwise,
  273.  * the procedure can return TCL_CONTINUE, and the command will
  274.  * be treated under the usual name resolution rules.  Or, it can
  275.  * return TCL_ERROR, and the command will be considered invalid.
  276.  *
  277.  * Variable resolution is handled by two procedures.  The first
  278.  * is called whenever a variable needs to be resolved at compile
  279.  * time:
  280.  *
  281.  *        typedef int (Tcl_ResolveCompiledVarProc) _ANSI_ARGS_((
  282.  *         Tcl_Interp* interp, CONST char* name, Tcl_Namespace *context,
  283.  *         Tcl_ResolvedVarInfo *rPtr));
  284.  *
  285.  *      If this procedure is able to resolve the name, it should return
  286.  *      the status code TCL_OK, along with variable resolution info in
  287.  *      the rPtr argument; this info will be used to set up compiled
  288.  * locals in the call frame at runtime.  The procedure may also
  289.  * return TCL_CONTINUE, and the variable will be treated under
  290.  * the usual name resolution rules.  Or, it can return TCL_ERROR,
  291.  * and the variable will be considered invalid.
  292.  *
  293.  * Another procedure is used whenever a variable needs to be
  294.  * resolved at runtime but it is not recognized as a compiled local.
  295.  * (For example, the variable may be requested via
  296.  * Tcl_FindNamespaceVar.) This procedure has the following type:
  297.  *
  298.  *   typedef int (Tcl_ResolveVarProc) _ANSI_ARGS_((
  299.  *         Tcl_Interp* interp, CONST char* name, Tcl_Namespace *context,
  300.  *         int flags, Tcl_Var *rPtr));
  301.  *
  302.  * This procedure is quite similar to the compile-time version.
  303.  * It returns the same status codes, but if variable resolution
  304.  * succeeds, this procedure returns a Tcl_Var directly via the
  305.  * rPtr argument.
  306.  *
  307.  * Results:
  308.  * Nothing.
  309.  *
  310.  * Side effects:
  311.  * Bumps the command epoch counter for the namespace, invalidating
  312.  * all command references in that namespace.  Also bumps the
  313.  * resolver epoch counter for the namespace, forcing all code
  314.  * in the namespace to be recompiled.
  315.  *
  316.  *----------------------------------------------------------------------
  317.  */
  318. void
  319. Tcl_SetNamespaceResolvers(namespacePtr, cmdProc, varProc, compiledVarProc)
  320.     Tcl_Namespace *namespacePtr; /* Namespace whose resolution rules
  321.  * are being modified. */
  322.     Tcl_ResolveCmdProc *cmdProc; /* Procedure for command resolution */
  323.     Tcl_ResolveVarProc *varProc; /* Procedure for variable resolution
  324.  * at runtime */
  325.     Tcl_ResolveCompiledVarProc *compiledVarProc;
  326. /* Procedure for variable resolution
  327.  * at compile time. */
  328. {
  329.     Namespace *nsPtr = (Namespace*)namespacePtr;
  330.     /*
  331.      *  Plug in the new command resolver, and bump the epoch counters
  332.      *  so that all code will have to be recompiled and all commands
  333.      *  will have to be resolved again using the new policy.
  334.      */
  335.     nsPtr->cmdResProc = cmdProc;
  336.     nsPtr->varResProc = varProc;
  337.     nsPtr->compiledVarResProc = compiledVarProc;
  338.     nsPtr->cmdRefEpoch++;
  339.     nsPtr->resolverEpoch++;
  340. }
  341. /*
  342.  *----------------------------------------------------------------------
  343.  *
  344.  * Tcl_GetNamespaceResolvers --
  345.  *
  346.  * Returns the current command/variable resolution procedures
  347.  * for a namespace.  By default, these procedures are NULL.
  348.  * New procedures can be installed by calling
  349.  * Tcl_SetNamespaceResolvers, to provide new name resolution
  350.  * rules.
  351.  *
  352.  * Results:
  353.  * Returns non-zero if any name resolution procedures have been
  354.  * assigned to this namespace; also returns pointers to the
  355.  * procedures in the Tcl_ResolverInfo structure.  Returns zero
  356.  * otherwise.
  357.  *
  358.  * Side effects:
  359.  * None.
  360.  *
  361.  *----------------------------------------------------------------------
  362.  */
  363. int
  364. Tcl_GetNamespaceResolvers(namespacePtr, resInfoPtr)
  365.     Tcl_Namespace *namespacePtr; /* Namespace whose resolution rules
  366.  * are being modified. */
  367.     Tcl_ResolverInfo *resInfoPtr; /* Returns: pointers for all
  368.  * name resolution procedures
  369.  * assigned to this namespace. */
  370. {
  371.     Namespace *nsPtr = (Namespace*)namespacePtr;
  372.     resInfoPtr->cmdResProc = nsPtr->cmdResProc;
  373.     resInfoPtr->varResProc = nsPtr->varResProc;
  374.     resInfoPtr->compiledVarResProc = nsPtr->compiledVarResProc;
  375.     if (nsPtr->cmdResProc != NULL ||
  376.         nsPtr->varResProc != NULL ||
  377.         nsPtr->compiledVarResProc != NULL) {
  378. return 1;
  379.     }
  380.     return 0;
  381. }