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