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