wasCSharpSQLite – Blame information for rev
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | #undef DEBUG |
2 | /* |
||
3 | * NamespaceCmd.java |
||
4 | * |
||
5 | * Copyright (c) 1993-1997 Lucent Technologies. |
||
6 | * Copyright (c) 1997 Sun Microsystems, Inc. |
||
7 | * Copyright (c) 1998-1999 by Scriptics Corporation. |
||
8 | * Copyright (c) 1999 Moses DeJong |
||
9 | * |
||
10 | * Originally implemented by |
||
11 | * Michael J. McLennan |
||
12 | * Bell Labs Innovations for Lucent Technologies |
||
13 | * mmclennan@lucent.com |
||
14 | * |
||
15 | * See the file "license.terms" for information on usage and |
||
16 | * redistribution of this file, and for a DISCLAIMER OF ALL |
||
17 | * WARRANTIES. |
||
18 | * |
||
19 | * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart |
||
20 | * |
||
21 | * RCS @(#) $Id: NamespaceCmd.java,v 1.12 2001/05/05 22:38:13 mdejong Exp $ |
||
22 | */ |
||
23 | using System; |
||
24 | using System.Collections; |
||
25 | using System.Text; |
||
26 | |||
27 | namespace tcl.lang |
||
28 | { |
||
29 | |||
30 | /// <summary> This class implements the built-in "namespace" command in Tcl. |
||
31 | /// See the user documentation for details on what it does. |
||
32 | /// </summary> |
||
33 | |||
34 | |||
35 | public class NamespaceCmd : InternalRep, Command |
||
36 | { |
||
37 | |||
38 | // Flag passed to getNamespaceForQualName to indicate that it should |
||
39 | // search for a namespace rather than a command or variable inside a |
||
40 | // namespace. Note that this flag's value must not conflict with the values |
||
41 | // of TCL.VarFlag.GLOBAL_ONLY, TCL.VarFlag.NAMESPACE_ONLY, or TCL.VarFlag.CREATE_NS_IF_UNKNOWN. |
||
42 | |||
43 | |||
44 | // Initial size of stack allocated space for tail list - used when resetting |
||
45 | // shadowed command references in the functin: TclResetShadowedCmdRefs. |
||
46 | |||
47 | //private static final int NUM_TRAIL_ELEMS = 5; |
||
48 | |||
49 | // Count of the number of namespaces created. This value is used as a |
||
50 | // unique id for each namespace. |
||
51 | |||
52 | private static long numNsCreated = 0; |
||
53 | private static Object nsMutex; |
||
54 | |||
55 | // |
||
56 | // Flags used to represent the status of a namespace: |
||
57 | // |
||
58 | // NS_DYING - 1 means deleteNamespace has been called to delete the |
||
59 | // namespace but there are still active call frames on the Tcl |
||
60 | // stack that refer to the namespace. When the last call frame |
||
61 | // referring to it has been popped, it's variables and command |
||
62 | // will be destroyed and it will be marked "dead" (NS_DEAD). |
||
63 | // The namespace can no longer be looked up by name. |
||
64 | // NS_DEAD - 1 means deleteNamespace has been called to delete the |
||
65 | // namespace and no call frames still refer to it. Its |
||
66 | // variables and command have already been destroyed. This bit |
||
67 | // allows the namespace resolution code to recognize that the |
||
68 | // namespace is "deleted". When the last namespaceName object |
||
69 | // in any byte code code unit that refers to the namespace has |
||
70 | // been freed (i.e., when the namespace's refCount is 0), the |
||
71 | // namespace's storage will be freed. |
||
72 | |||
73 | internal const int NS_DYING = 0x01; |
||
74 | internal const int NS_DEAD = 0x02; |
||
75 | |||
76 | |||
77 | // Flag passed to getNamespaceForQualName to have it create all namespace |
||
78 | // components of a namespace-qualified name that cannot be found. The new |
||
79 | // namespaces are created within their specified parent. Note that this |
||
80 | // flag's value must not conflict with the values of the flags |
||
81 | // TCL.VarFlag.GLOBAL_ONLY, TCL.VarFlag.NAMESPACE_ONLY, and TCL.VarFlag.FIND_ONLY_NS |
||
82 | |||
83 | // internal const int TCL.VarFlag.CREATE_NS_IF_UNKNOWN = 0x800; |
||
84 | |||
85 | |||
86 | // This value corresponds to the Tcl_Obj.otherValuePtr pointer used |
||
87 | // in the C version of Tcl 8.1. Use it to keep track of a ResolvedNsName. |
||
88 | |||
89 | private ResolvedNsName otherValue = null; |
||
90 | |||
91 | |||
92 | /* |
||
93 | *---------------------------------------------------------------------- |
||
94 | * |
||
95 | * Tcl_GetCurrentNamespace -> getCurrentNamespace |
||
96 | * |
||
97 | * Returns a reference to an interpreter's currently active namespace. |
||
98 | * |
||
99 | * Results: |
||
100 | * Returns a reference to the interpreter's current namespace. |
||
101 | * |
||
102 | * Side effects: |
||
103 | * None. |
||
104 | * |
||
105 | *---------------------------------------------------------------------- |
||
106 | */ |
||
107 | |||
108 | internal static Namespace getCurrentNamespace( Interp interp ) |
||
109 | { |
||
110 | if ( interp.varFrame != null ) |
||
111 | { |
||
112 | return interp.varFrame.ns; |
||
113 | } |
||
114 | else |
||
115 | { |
||
116 | return interp.globalNs; |
||
117 | } |
||
118 | } |
||
119 | |||
120 | /* |
||
121 | *---------------------------------------------------------------------- |
||
122 | * |
||
123 | * Tcl_GetGlobalNamespace -> getGlobalNamespace |
||
124 | * |
||
125 | * Returns a reference to an interpreter's global :: namespace. |
||
126 | * |
||
127 | * Results: |
||
128 | * Returns a reference to the specified interpreter's global namespace. |
||
129 | * |
||
130 | * Side effects: |
||
131 | * None. |
||
132 | * |
||
133 | *---------------------------------------------------------------------- |
||
134 | */ |
||
135 | |||
136 | internal static Namespace getGlobalNamespace( Interp interp ) |
||
137 | { |
||
138 | return interp.globalNs; |
||
139 | } |
||
140 | |||
141 | |||
142 | /* |
||
143 | *---------------------------------------------------------------------- |
||
144 | * |
||
145 | * Tcl_PushCallFrame -> pushCallFrame |
||
146 | * |
||
147 | * Pushes a new call frame onto the interpreter's Tcl call stack. |
||
148 | * Called when executing a Tcl procedure or a "namespace eval" or |
||
149 | * "namespace inscope" command. |
||
150 | * |
||
151 | * Results: |
||
152 | * Returns if successful, raises TclException if something goes wrong. |
||
153 | * |
||
154 | * Side effects: |
||
155 | * Modifies the interpreter's Tcl call stack. |
||
156 | * |
||
157 | *---------------------------------------------------------------------- |
||
158 | */ |
||
159 | |||
160 | internal static void pushCallFrame( Interp interp, CallFrame frame, Namespace namespace_Renamed, bool isProcCallFrame ) |
||
161 | // If true, the frame represents a |
||
162 | // called Tcl procedure and may have local |
||
163 | // vars. Vars will ordinarily be looked up |
||
164 | // in the frame. If new variables are |
||
165 | // created, they will be created in the |
||
166 | // frame. If false, the frame is for a |
||
167 | // "namespace eval" or "namespace inscope" |
||
168 | // command and var references are treated |
||
169 | // as references to namespace variables. |
||
170 | { |
||
171 | Namespace ns; |
||
172 | |||
173 | if ( namespace_Renamed == null ) |
||
174 | { |
||
175 | ns = getCurrentNamespace( interp ); |
||
176 | } |
||
177 | else |
||
178 | { |
||
179 | ns = namespace_Renamed; |
||
180 | if ( ( ns.flags & NS_DEAD ) != 0 ) |
||
181 | { |
||
182 | throw new TclRuntimeError( "Trying to push call frame for dead namespace" ); |
||
183 | } |
||
184 | } |
||
185 | |||
186 | ns.activationCount++; |
||
187 | frame.ns = ns; |
||
188 | frame.isProcCallFrame = isProcCallFrame; |
||
189 | frame.objv = null; |
||
190 | |||
191 | frame.caller = interp.frame; |
||
192 | frame.callerVar = interp.varFrame; |
||
193 | |||
194 | if ( interp.varFrame != null ) |
||
195 | { |
||
196 | frame.level = ( interp.varFrame.level + 1 ); |
||
197 | } |
||
198 | else |
||
199 | { |
||
200 | frame.level = 1; |
||
201 | } |
||
202 | |||
203 | // FIXME : does Jacl need a procPtr in the CallFrame class? |
||
204 | //frame.procPtr = null; // no called procedure |
||
205 | |||
206 | frame.varTable = null; // and no local variables |
||
207 | |||
208 | // Compiled locals are not part of Jacl's CallFrame |
||
209 | |||
210 | // Push the new call frame onto the interpreter's stack of procedure |
||
211 | // call frames making it the current frame. |
||
212 | |||
213 | interp.frame = frame; |
||
214 | interp.varFrame = frame; |
||
215 | } |
||
216 | |||
217 | |||
218 | |||
219 | /* |
||
220 | *---------------------------------------------------------------------- |
||
221 | * |
||
222 | * Tcl_PopCallFrame -> popCallFrame |
||
223 | * |
||
224 | * Removes a call frame from the Tcl call stack for the interpreter. |
||
225 | * Called to remove a frame previously pushed by Tcl_PushCallFrame. |
||
226 | * |
||
227 | * Results: |
||
228 | * None. |
||
229 | * |
||
230 | * Side effects: |
||
231 | * Modifies the call stack of the interpreter. Resets various fields of |
||
232 | * the popped call frame. If a namespace has been deleted and |
||
233 | * has no more activations on the call stack, the namespace is |
||
234 | * destroyed. |
||
235 | * |
||
236 | *---------------------------------------------------------------------- |
||
237 | */ |
||
238 | |||
239 | internal static void popCallFrame( Interp interp ) |
||
240 | { |
||
241 | CallFrame frame = interp.frame; |
||
242 | int saveErrFlag; |
||
243 | Namespace ns; |
||
244 | |||
245 | // It's important to remove the call frame from the interpreter's stack |
||
246 | // of call frames before deleting local variables, so that traces |
||
247 | // invoked by the variable deletion don't see the partially-deleted |
||
248 | // frame. |
||
249 | |||
250 | interp.frame = frame.caller; |
||
251 | interp.varFrame = frame.callerVar; |
||
252 | |||
253 | // Delete the local variables. As a hack, we save then restore the |
||
254 | // ERR_IN_PROGRESS flag in the interpreter. The problem is that there |
||
255 | // could be unset traces on the variables, which cause scripts to be |
||
256 | // evaluated. This will clear the ERR_IN_PROGRESS flag, losing stack |
||
257 | // trace information if the procedure was exiting with an error. The |
||
258 | // code below preserves the flag. Unfortunately, that isn't really |
||
259 | // enough: we really should preserve the errorInfo variable too |
||
260 | // (otherwise a nested error in the trace script will trash errorInfo). |
||
261 | // What's really needed is a general-purpose mechanism for saving and |
||
262 | // restoring interpreter state. |
||
263 | |||
264 | saveErrFlag = ( interp.flags & Parser.ERR_IN_PROGRESS ); |
||
265 | |||
266 | if ( frame.varTable != null ) |
||
267 | { |
||
268 | Var.deleteVars( interp, frame.varTable ); |
||
269 | frame.varTable = null; |
||
270 | } |
||
271 | |||
272 | interp.flags |= saveErrFlag; |
||
273 | |||
274 | // Decrement the namespace's count of active call frames. If the |
||
275 | // namespace is "dying" and there are no more active call frames, |
||
276 | // call Tcl_DeleteNamespace to destroy it. |
||
277 | |||
278 | ns = frame.ns; |
||
279 | ns.activationCount--; |
||
280 | if ( ( ( ns.flags & NS_DYING ) != 0 ) && ( ns.activationCount == 0 ) ) |
||
281 | { |
||
282 | deleteNamespace( ns ); |
||
283 | } |
||
284 | frame.ns = null; |
||
285 | } |
||
286 | |||
287 | /* |
||
288 | *---------------------------------------------------------------------- |
||
289 | * |
||
290 | * Tcl_CreateNamespace -- |
||
291 | * |
||
292 | * Creates a new namespace with the given name. If there is no |
||
293 | * active namespace (i.e., the interpreter is being initialized), |
||
294 | * the global :: namespace is created and returned. |
||
295 | * |
||
296 | * Results: |
||
297 | * Returns a reference to the new namespace if successful. If the |
||
298 | * namespace already exists or if another error occurs, this routine |
||
299 | * returns null, along with an error message in the interpreter's |
||
300 | * result object. |
||
301 | * |
||
302 | * Side effects: |
||
303 | * If the name contains "::" qualifiers and a parent namespace does |
||
304 | * not already exist, it is automatically created. |
||
305 | * |
||
306 | *---------------------------------------------------------------------- |
||
307 | */ |
||
308 | |||
309 | internal static Namespace createNamespace( Interp interp, string name, DeleteProc deleteProc ) |
||
310 | { |
||
311 | Namespace ns, ancestor; |
||
312 | Namespace parent; |
||
313 | Namespace globalNs = getGlobalNamespace( interp ); |
||
314 | string simpleName; |
||
315 | StringBuilder buffer1, buffer2; |
||
316 | |||
317 | // If there is no active namespace, the interpreter is being |
||
318 | // initialized. |
||
319 | |||
320 | if ( ( globalNs == null ) && ( interp.varFrame == null ) ) |
||
321 | { |
||
322 | // Treat this namespace as the global namespace, and avoid |
||
323 | // looking for a parent. |
||
324 | |||
325 | parent = null; |
||
326 | simpleName = ""; |
||
327 | } |
||
328 | else if ( name.Length == 0 ) |
||
329 | { |
||
330 | /* |
||
331 | TclObject tobj = interp.getResult(); |
||
332 | // FIXME : is there a test case to check this error result? |
||
333 | TclString.append(tobj, |
||
334 | "can't create namespace \"\": only global namespace can have empty name"); |
||
335 | */ |
||
336 | |||
337 | // FIXME : is there a test case to check this error result? |
||
338 | interp.setResult( "can't create namespace \"\": only global namespace can have empty name" ); |
||
339 | return null; |
||
340 | } |
||
341 | else |
||
342 | { |
||
343 | // Find the parent for the new namespace. |
||
344 | |||
345 | // Java does not support passing an address so we pass |
||
346 | // an array of size 1 and then assign arr[0] to the value |
||
347 | Namespace[] parentArr = new Namespace[1]; |
||
348 | Namespace[] dummyArr = new Namespace[1]; |
||
349 | string[] simpleArr = new string[1]; |
||
350 | |||
351 | getNamespaceForQualName( interp, name, null, ( TCL.VarFlag.CREATE_NS_IF_UNKNOWN | TCL.VarFlag.LEAVE_ERR_MSG ), parentArr, dummyArr, dummyArr, simpleArr ); |
||
352 | |||
353 | // Get the values out of the arrays! |
||
354 | parent = parentArr[0]; |
||
355 | simpleName = simpleArr[0]; |
||
356 | |||
357 | |||
358 | // If the unqualified name at the end is empty, there were trailing |
||
359 | // "::"s after the namespace's name which we ignore. The new |
||
360 | // namespace was already (recursively) created and is referenced |
||
361 | // by parent. |
||
362 | |||
363 | if ( simpleName.Length == 0 ) |
||
364 | { |
||
365 | return parent; |
||
366 | } |
||
367 | |||
368 | // Check for a bad namespace name and make sure that the name |
||
369 | // does not already exist in the parent namespace. |
||
370 | |||
371 | if ( parent.childTable[simpleName] != null ) |
||
372 | { |
||
373 | /* |
||
374 | TclObject tobj = interp.getResult(); |
||
375 | // FIXME : is there a test case to check this error result? |
||
376 | TclString.append(tobj, |
||
377 | "can't create namespace \"" + name + "\": already exists"); |
||
378 | */ |
||
379 | |||
380 | // FIXME : is there a test case to check this error result? |
||
381 | interp.setResult( "can't create namespace \"" + name + "\": already exists" ); |
||
382 | return null; |
||
383 | } |
||
384 | } |
||
385 | |||
386 | // Create the new namespace and root it in its parent. Increment the |
||
387 | // count of namespaces created. |
||
388 | |||
389 | ns = new Namespace(); |
||
390 | ns.name = simpleName; |
||
391 | ns.fullName = null; // set below |
||
392 | //ns.clientData = clientData; |
||
393 | ns.deleteProc = deleteProc; |
||
394 | ns.parent = parent; |
||
395 | ns.childTable = new Hashtable(); |
||
396 | lock ( nsMutex ) |
||
397 | { |
||
398 | numNsCreated++; |
||
399 | ns.nsId = numNsCreated; |
||
400 | } |
||
401 | ns.interp = interp; |
||
402 | ns.flags = 0; |
||
403 | ns.activationCount = 0; |
||
404 | // FIXME : there was a problem with the refcount because |
||
405 | // when the namespace was deleted the refocount was 0. |
||
406 | // We avoid this by just using a refcount of 1 for now. |
||
407 | // We can do ignore the refCount because GC will reclaim mem. |
||
408 | //ns.refCount = 0; |
||
409 | ns.refCount = 1; |
||
410 | ns.cmdTable = new Hashtable(); |
||
411 | ns.varTable = new Hashtable(); |
||
412 | ns.exportArray = null; |
||
413 | ns.numExportPatterns = 0; |
||
414 | ns.maxExportPatterns = 0; |
||
415 | |||
416 | // Jacl does not use these tcl compiler specific members |
||
417 | //ns.cmdRefEpoch = 0; |
||
418 | //ns.resolverEpoch = 0; |
||
419 | |||
420 | ns.resolver = null; |
||
421 | |||
422 | if ( parent != null ) |
||
423 | { |
||
424 | SupportClass.PutElement( parent.childTable, simpleName, ns ); |
||
425 | } |
||
426 | |||
427 | // Build the fully qualified name for this namespace. |
||
428 | |||
429 | buffer1 = new StringBuilder(); |
||
430 | buffer2 = new StringBuilder(); |
||
431 | for ( ancestor = ns; ancestor != null; ancestor = ancestor.parent ) |
||
432 | { |
||
433 | if ( ancestor != globalNs ) |
||
434 | { |
||
435 | buffer1.Append( "::" ); |
||
436 | buffer1.Append( ancestor.name ); |
||
437 | } |
||
438 | buffer1.Append( buffer2 ); |
||
439 | |||
440 | buffer2.Length = 0; |
||
441 | buffer2.Append( buffer1 ); |
||
442 | buffer1.Length = 0; |
||
443 | } |
||
444 | |||
445 | name = buffer2.ToString(); |
||
446 | ns.fullName = name; |
||
447 | |||
448 | // Return a reference to the new namespace. |
||
449 | |||
450 | return ns; |
||
451 | } |
||
452 | |||
453 | /* |
||
454 | *---------------------------------------------------------------------- |
||
455 | * |
||
456 | * Tcl_DeleteNamespace -> deleteNamespace |
||
457 | * |
||
458 | * Deletes a namespace and all of the commands, variables, and other |
||
459 | * namespaces within it. |
||
460 | * |
||
461 | * Results: |
||
462 | * None. |
||
463 | * |
||
464 | * Side effects: |
||
465 | * When a namespace is deleted, it is automatically removed as a |
||
466 | * child of its parent namespace. Also, all its commands, variables |
||
467 | * and child namespaces are deleted. |
||
468 | * |
||
469 | *---------------------------------------------------------------------- |
||
470 | */ |
||
471 | |||
472 | internal static void deleteNamespace( Namespace namespace_Renamed ) |
||
473 | { |
||
474 | Namespace ns = namespace_Renamed; |
||
475 | Interp interp = ns.interp; |
||
476 | Namespace globalNs = getGlobalNamespace( interp ); |
||
477 | |||
478 | // If the namespace is on the call frame stack, it is marked as "dying" |
||
479 | // (NS_DYING is OR'd into its flags): the namespace can't be looked up |
||
480 | // by name but its commands and variables are still usable by those |
||
481 | // active call frames. When all active call frames referring to the |
||
482 | // namespace have been popped from the Tcl stack, popCallFrame will |
||
483 | // call this procedure again to delete everything in the namespace. |
||
484 | // If no nsName objects refer to the namespace (i.e., if its refCount |
||
485 | // is zero), its commands and variables are deleted and the storage for |
||
486 | // its namespace structure is freed. Otherwise, if its refCount is |
||
487 | // nonzero, the namespace's commands and variables are deleted but the |
||
488 | // structure isn't freed. Instead, NS_DEAD is OR'd into the structure's |
||
489 | // flags to allow the namespace resolution code to recognize that the |
||
490 | // namespace is "deleted". |
||
491 | |||
492 | if ( ns.activationCount > 0 ) |
||
493 | { |
||
494 | ns.flags |= NS_DYING; |
||
495 | if ( ns.parent != null ) |
||
496 | { |
||
497 | ns.parent.childTable.Remove( ns.name ); |
||
498 | } |
||
499 | ns.parent = null; |
||
500 | } |
||
501 | else |
||
502 | { |
||
503 | // Delete the namespace and everything in it. If this is the global |
||
504 | // namespace, then clear it but don't free its storage unless the |
||
505 | // interpreter is being torn down. |
||
506 | |||
507 | teardownNamespace( ns ); |
||
508 | |||
509 | if ( ( ns != globalNs ) || ( ( interp.flags & Parser.DELETED ) != 0 ) ) |
||
510 | { |
||
511 | // If this is the global namespace, then it may have residual |
||
512 | // "errorInfo" and "errorCode" variables for errors that |
||
513 | // occurred while it was being torn down. Try to clear the |
||
514 | // variable list one last time. |
||
515 | |||
516 | Var.deleteVars( ns.interp, ns.varTable ); |
||
517 | |||
518 | ns.childTable.Clear(); |
||
519 | ns.cmdTable.Clear(); |
||
520 | |||
521 | // If the reference count is 0, then discard the namespace. |
||
522 | // Otherwise, mark it as "dead" so that it can't be used. |
||
523 | |||
524 | if ( ns.refCount == 0 ) |
||
525 | { |
||
526 | free( ns ); |
||
527 | } |
||
528 | else |
||
529 | { |
||
530 | ns.flags |= NS_DEAD; |
||
531 | } |
||
532 | } |
||
533 | } |
||
534 | } |
||
535 | |||
536 | |||
537 | /* |
||
538 | *---------------------------------------------------------------------- |
||
539 | * |
||
540 | * TclTeardownNamespace -> teardownNamespace |
||
541 | * |
||
542 | * Used internally to dismantle and unlink a namespace when it is |
||
543 | * deleted. Divorces the namespace from its parent, and deletes all |
||
544 | * commands, variables, and child namespaces. |
||
545 | * |
||
546 | * This is kept separate from Tcl_DeleteNamespace so that the global |
||
547 | * namespace can be handled specially. Global variables like |
||
548 | * "errorInfo" and "errorCode" need to remain intact while other |
||
549 | * namespaces and commands are torn down, in case any errors occur. |
||
550 | * |
||
551 | * Results: |
||
552 | * None. |
||
553 | * |
||
554 | * Side effects: |
||
555 | * Removes this namespace from its parent's child namespace hashtable. |
||
556 | * Deletes all commands, variables and namespaces in this namespace. |
||
557 | * If this is the global namespace, the "errorInfo" and "errorCode" |
||
558 | * variables are left alone and deleted later. |
||
559 | * |
||
560 | *---------------------------------------------------------------------- |
||
561 | */ |
||
562 | |||
563 | internal static void teardownNamespace( Namespace ns ) |
||
564 | { |
||
565 | Interp interp = ns.interp; |
||
566 | IEnumerator search; |
||
567 | Namespace globalNs = getGlobalNamespace( interp ); |
||
568 | int i; |
||
569 | |||
570 | // Start by destroying the namespace's variable table, |
||
571 | // since variables might trigger traces. |
||
572 | |||
573 | if ( ns == globalNs ) |
||
574 | { |
||
575 | // This is the global namespace, so be careful to preserve the |
||
576 | // "errorInfo" and "errorCode" variables. These might be needed |
||
577 | // later on if errors occur while deleting commands. We are careful |
||
578 | // to destroy and recreate the "errorInfo" and "errorCode" |
||
579 | // variables, in case they had any traces on them. |
||
580 | |||
581 | string errorInfoStr, errorCodeStr; |
||
582 | |||
583 | try |
||
584 | { |
||
585 | |||
586 | errorInfoStr = interp.getVar( "errorInfo", TCL.VarFlag.GLOBAL_ONLY ).ToString(); |
||
587 | } |
||
588 | catch ( TclException e ) |
||
589 | { |
||
590 | errorInfoStr = null; |
||
591 | } |
||
592 | |||
593 | try |
||
594 | { |
||
595 | |||
596 | errorCodeStr = interp.getVar( "errorCode", TCL.VarFlag.GLOBAL_ONLY ).ToString(); |
||
597 | } |
||
598 | catch ( TclException e ) |
||
599 | { |
||
600 | errorCodeStr = null; |
||
601 | } |
||
602 | |||
603 | Var.deleteVars( interp, ns.varTable ); |
||
604 | |||
605 | if ( (System.Object)errorInfoStr != null ) |
||
606 | { |
||
607 | try |
||
608 | { |
||
609 | interp.setVar( "errorInfo", errorInfoStr, TCL.VarFlag.GLOBAL_ONLY ); |
||
610 | } |
||
611 | catch ( TclException e ) |
||
612 | { |
||
613 | // ignore an exception while setting this var |
||
614 | } |
||
615 | } |
||
616 | if ( (System.Object)errorCodeStr != null ) |
||
617 | { |
||
618 | try |
||
619 | { |
||
620 | interp.setVar( "errorCode", errorCodeStr, TCL.VarFlag.GLOBAL_ONLY ); |
||
621 | } |
||
622 | catch ( TclException e ) |
||
623 | { |
||
624 | // ignore an exception while setting this var |
||
625 | } |
||
626 | } |
||
627 | } |
||
628 | else |
||
629 | { |
||
630 | // Variable table should be cleared. |
||
631 | Var.deleteVars( interp, ns.varTable ); |
||
632 | } |
||
633 | |||
634 | // Remove the namespace from its parent's child hashtable. |
||
635 | |||
636 | if ( ns.parent != null ) |
||
637 | { |
||
638 | ns.parent.childTable.Remove( ns.name ); |
||
639 | } |
||
640 | ns.parent = null; |
||
641 | |||
642 | // Delete all the child namespaces. |
||
643 | // |
||
644 | // BE CAREFUL: When each child is deleted, it will divorce |
||
645 | // itself from its parent. You can't traverse a hash table |
||
646 | // properly if its elements are being deleted. We use only |
||
647 | // the Tcl_FirstHashEntry function to be safe. |
||
648 | |||
649 | foreach ( Namespace childNs in new ArrayList( ns.childTable.Values ) ) |
||
650 | { |
||
651 | deleteNamespace( childNs ); |
||
652 | } |
||
653 | |||
654 | // Delete all commands in this namespace. Be careful when traversing the |
||
655 | // hash table: when each command is deleted, it removes itself from the |
||
656 | // command table. |
||
657 | |||
658 | // FIXME : double check that using an enumeration for a hashtable |
||
659 | // that changes is ok in Java! Also call deleteCommand... correctly! |
||
660 | foreach ( WrappedCommand cmd in new ArrayList( ns.cmdTable.Values ) ) |
||
661 | { |
||
662 | interp.deleteCommandFromToken( cmd ); |
||
663 | } |
||
664 | |||
665 | ns.cmdTable.Clear(); |
||
666 | |||
667 | // Free the namespace's export pattern array. |
||
668 | |||
669 | if ( ns.exportArray != null ) |
||
670 | { |
||
671 | ns.exportArray = null; |
||
672 | ns.numExportPatterns = 0; |
||
673 | ns.maxExportPatterns = 0; |
||
674 | } |
||
675 | |||
676 | // Callback invoked when namespace is deleted |
||
677 | |||
678 | if ( ns.deleteProc != null ) |
||
679 | { |
||
680 | ns.deleteProc.delete(); |
||
681 | } |
||
682 | ns.deleteProc = null; |
||
683 | |||
684 | // Reset the namespace's id field to ensure that this namespace won't |
||
685 | // be interpreted as valid by, e.g., the cache validation code for |
||
686 | // cached command references in Tcl_GetCommandFromObj. |
||
687 | |||
688 | ns.nsId = 0; |
||
689 | } |
||
690 | |||
691 | |||
692 | /* |
||
693 | *---------------------------------------------------------------------- |
||
694 | * |
||
695 | * NamespaceFree -> free |
||
696 | * |
||
697 | * Called after a namespace has been deleted, when its |
||
698 | * reference count reaches 0. Frees the data structure |
||
699 | * representing the namespace. |
||
700 | * |
||
701 | * Results: |
||
702 | * None. |
||
703 | * |
||
704 | * Side effects: |
||
705 | * None. |
||
706 | * |
||
707 | *---------------------------------------------------------------------- |
||
708 | */ |
||
709 | |||
710 | internal static void free( Namespace ns ) |
||
711 | { |
||
712 | // Most of the namespace's contents are freed when the namespace is |
||
713 | // deleted by Tcl_DeleteNamespace. All that remains is to free its names |
||
714 | // (for error messages), and the structure itself. |
||
715 | |||
716 | ns.name = null; |
||
717 | ns.fullName = null; |
||
718 | } |
||
719 | |||
720 | /* |
||
721 | *---------------------------------------------------------------------- |
||
722 | * |
||
723 | * Tcl_Export -> exportList |
||
724 | * |
||
725 | * Makes all the commands matching a pattern available to later be |
||
726 | * imported from the namespace specified by namespace (or the |
||
727 | * current namespace if namespace is null). The specified pattern is |
||
728 | * appended onto the namespace's export pattern list, which is |
||
729 | * optionally cleared beforehand. |
||
730 | * |
||
731 | * Results: |
||
732 | * Returns if successful, raises TclException if something goes wrong. |
||
733 | * |
||
734 | * Side effects: |
||
735 | * Appends the export pattern onto the namespace's export list. |
||
736 | * Optionally reset the namespace's export pattern list. |
||
737 | * |
||
738 | *---------------------------------------------------------------------- |
||
739 | */ |
||
740 | |||
741 | internal static void exportList( Interp interp, Namespace namespace_Renamed, string pattern, bool resetListFirst ) |
||
742 | { |
||
743 | int INIT_EXPORT_PATTERNS = 5; |
||
744 | Namespace ns, exportNs; |
||
745 | Namespace currNs = getCurrentNamespace( interp ); |
||
746 | string simplePattern, patternCpy; |
||
747 | int neededElems, len, i; |
||
748 | |||
749 | // If the specified namespace is null, use the current namespace. |
||
750 | |||
751 | if ( namespace_Renamed == null ) |
||
752 | { |
||
753 | ns = currNs; |
||
754 | } |
||
755 | else |
||
756 | { |
||
757 | ns = namespace_Renamed; |
||
758 | } |
||
759 | |||
760 | // If resetListFirst is true (nonzero), clear the namespace's export |
||
761 | // pattern list. |
||
762 | |||
763 | if ( resetListFirst ) |
||
764 | { |
||
765 | if ( ns.exportArray != null ) |
||
766 | { |
||
767 | for ( i = 0; i < ns.numExportPatterns; i++ ) |
||
768 | { |
||
769 | ns.exportArray[i] = null; |
||
770 | } |
||
771 | ns.exportArray = null; |
||
772 | ns.numExportPatterns = 0; |
||
773 | ns.maxExportPatterns = 0; |
||
774 | } |
||
775 | } |
||
776 | |||
777 | // Check that the pattern doesn't have namespace qualifiers. |
||
778 | |||
779 | // Java does not support passing an address so we pass |
||
780 | // an array of size 1 and then assign arr[0] to the value |
||
781 | Namespace[] exportNsArr = new Namespace[1]; |
||
782 | Namespace[] dummyArr = new Namespace[1]; |
||
783 | string[] simplePatternArr = new string[1]; |
||
784 | |||
785 | getNamespaceForQualName( interp, pattern, ns, TCL.VarFlag.LEAVE_ERR_MSG, exportNsArr, dummyArr, dummyArr, simplePatternArr ); |
||
786 | |||
787 | // get the values out of the arrays |
||
788 | |||
789 | exportNs = exportNsArr[0]; |
||
790 | simplePattern = simplePatternArr[0]; |
||
791 | |||
792 | if ( ( exportNs != ns ) || ( pattern.CompareTo( simplePattern ) != 0 ) ) |
||
793 | { |
||
794 | throw new TclException( interp, "invalid export pattern \"" + pattern + "\": pattern can't specify a namespace" ); |
||
795 | } |
||
796 | |||
797 | // Make sure there is room in the namespace's pattern array for the |
||
798 | // new pattern. |
||
799 | |||
800 | neededElems = ns.numExportPatterns + 1; |
||
801 | if ( ns.exportArray == null ) |
||
802 | { |
||
803 | ns.exportArray = new string[INIT_EXPORT_PATTERNS]; |
||
804 | ns.numExportPatterns = 0; |
||
805 | ns.maxExportPatterns = INIT_EXPORT_PATTERNS; |
||
806 | } |
||
807 | else if ( neededElems > ns.maxExportPatterns ) |
||
808 | { |
||
809 | int numNewElems = 2 * ns.maxExportPatterns; |
||
810 | string[] newArray = new string[numNewElems]; |
||
811 | Array.Copy( (System.Array)ns.exportArray, 0, (System.Array)newArray, 0, ns.numExportPatterns ); |
||
812 | ns.exportArray = newArray; |
||
813 | ns.maxExportPatterns = numNewElems; |
||
814 | } |
||
815 | |||
816 | // Add the pattern to the namespace's array of export patterns. |
||
817 | |||
818 | ns.exportArray[ns.numExportPatterns] = pattern; |
||
819 | ns.numExportPatterns++; |
||
820 | return; |
||
821 | } |
||
822 | |||
823 | |||
824 | /* |
||
825 | *---------------------------------------------------------------------- |
||
826 | * |
||
827 | * Tcl_AppendExportList -> appendExportList |
||
828 | * |
||
829 | * Appends onto the argument object the list of export patterns for the |
||
830 | * specified namespace. |
||
831 | * |
||
832 | * Results: |
||
833 | * The method will return when successful; in this case the object |
||
834 | * referenced by obj has each export pattern appended to it. If an |
||
835 | * error occurs, an exception and the interpreter's result |
||
836 | * holds an error message. |
||
837 | * |
||
838 | * Side effects: |
||
839 | * If necessary, the object referenced by obj is converted into |
||
840 | * a list object. |
||
841 | * |
||
842 | *---------------------------------------------------------------------- |
||
843 | */ |
||
844 | |||
845 | internal static void appendExportList( Interp interp, Namespace namespace_Renamed, TclObject obj ) |
||
846 | { |
||
847 | Namespace ns; |
||
848 | int i; |
||
849 | |||
850 | // If the specified namespace is null, use the current namespace. |
||
851 | |||
852 | if ( namespace_Renamed == null ) |
||
853 | { |
||
854 | ns = getCurrentNamespace( interp ); |
||
855 | } |
||
856 | else |
||
857 | { |
||
858 | ns = namespace_Renamed; |
||
859 | } |
||
860 | |||
861 | // Append the export pattern list onto objPtr. |
||
862 | |||
863 | for ( i = 0; i < ns.numExportPatterns; i++ ) |
||
864 | { |
||
865 | TclList.append( interp, obj, TclString.newInstance( ns.exportArray[i] ) ); |
||
866 | } |
||
867 | return; |
||
868 | } |
||
869 | |||
870 | |||
871 | /* |
||
872 | *---------------------------------------------------------------------- |
||
873 | * |
||
874 | * Tcl_Import -> importList |
||
875 | * |
||
876 | * Imports all of the commands matching a pattern into the namespace |
||
877 | * specified by namespace (or the current namespace if namespace |
||
878 | * is null). This is done by creating a new command (the "imported |
||
879 | * command") that points to the real command in its original namespace. |
||
880 | * |
||
881 | * If matching commands are on the autoload path but haven't been |
||
882 | * loaded yet, this command forces them to be loaded, then creates |
||
883 | * the links to them. |
||
884 | * |
||
885 | * Results: |
||
886 | * Returns if successful, raises TclException if something goes wrong. |
||
887 | * |
||
888 | * Side effects: |
||
889 | * Creates new commands in the importing namespace. These indirect |
||
890 | * calls back to the real command and are deleted if the real commands |
||
891 | * are deleted. |
||
892 | * |
||
893 | *---------------------------------------------------------------------- |
||
894 | */ |
||
895 | |||
896 | internal static void importList( Interp interp, Namespace namespace_Renamed, string pattern, bool allowOverwrite ) |
||
897 | { |
||
898 | Namespace ns, importNs; |
||
899 | Namespace currNs = getCurrentNamespace( interp ); |
||
900 | string simplePattern, cmdName; |
||
901 | IEnumerator search; |
||
902 | WrappedCommand cmd, realCmd; |
||
903 | ImportRef ref_Renamed; |
||
904 | WrappedCommand autoCmd, importedCmd; |
||
905 | ImportedCmdData data; |
||
906 | bool wasExported; |
||
907 | int i, result; |
||
908 | |||
909 | // If the specified namespace is null, use the current namespace. |
||
910 | |||
911 | if ( namespace_Renamed == null ) |
||
912 | { |
||
913 | ns = currNs; |
||
914 | } |
||
915 | else |
||
916 | { |
||
917 | ns = namespace_Renamed; |
||
918 | } |
||
919 | |||
920 | // First, invoke the "auto_import" command with the pattern |
||
921 | // being imported. This command is part of the Tcl library. |
||
922 | // It looks for imported commands in autoloaded libraries and |
||
923 | // loads them in. That way, they will be found when we try |
||
924 | // to create links below. |
||
925 | |||
926 | autoCmd = findCommand( interp, "auto_import", null, TCL.VarFlag.GLOBAL_ONLY ); |
||
927 | |||
928 | if ( autoCmd != null ) |
||
929 | { |
||
930 | TclObject[] objv = new TclObject[2]; |
||
931 | |||
932 | objv[0] = TclString.newInstance( "auto_import" ); |
||
933 | objv[0].preserve(); |
||
934 | objv[1] = TclString.newInstance( pattern ); |
||
935 | objv[1].preserve(); |
||
936 | |||
937 | cmd = autoCmd; |
||
938 | try |
||
939 | { |
||
940 | // Invoke the command with the arguments |
||
941 | cmd.cmd.cmdProc( interp, objv ); |
||
942 | } |
||
943 | finally |
||
944 | { |
||
945 | objv[0].release(); |
||
946 | objv[1].release(); |
||
947 | } |
||
948 | |||
949 | interp.resetResult(); |
||
950 | } |
||
951 | |||
952 | // From the pattern, find the namespace from which we are importing |
||
953 | // and get the simple pattern (no namespace qualifiers or ::'s) at |
||
954 | // the end. |
||
955 | |||
956 | if ( pattern.Length == 0 ) |
||
957 | { |
||
958 | throw new TclException( interp, "empty import pattern" ); |
||
959 | } |
||
960 | |||
961 | // Java does not support passing an address so we pass |
||
962 | // an array of size 1 and then assign arr[0] to the value |
||
963 | Namespace[] importNsArr = new Namespace[1]; |
||
964 | Namespace[] dummyArr = new Namespace[1]; |
||
965 | string[] simplePatternArr = new string[1]; |
||
966 | |||
967 | getNamespaceForQualName( interp, pattern, ns, TCL.VarFlag.LEAVE_ERR_MSG, importNsArr, dummyArr, dummyArr, simplePatternArr ); |
||
968 | |||
969 | importNs = importNsArr[0]; |
||
970 | simplePattern = simplePatternArr[0]; |
||
971 | |||
972 | if ( importNs == null ) |
||
973 | { |
||
974 | throw new TclException( interp, "unknown namespace in import pattern \"" + pattern + "\"" ); |
||
975 | } |
||
976 | if ( importNs == ns ) |
||
977 | { |
||
978 | if ( (System.Object)pattern == (System.Object)simplePattern ) |
||
979 | { |
||
980 | throw new TclException( interp, "no namespace specified in import pattern \"" + pattern + "\"" ); |
||
981 | } |
||
982 | else |
||
983 | { |
||
984 | throw new TclException( interp, "import pattern \"" + pattern + "\" tries to import from namespace \"" + importNs.name + "\" into itself" ); |
||
985 | } |
||
986 | } |
||
987 | |||
988 | // Scan through the command table in the source namespace and look for |
||
989 | // exported commands that match the string pattern. Create an "imported |
||
990 | // command" in the current namespace for each imported command; these |
||
991 | // commands redirect their invocations to the "real" command. |
||
992 | |||
993 | |||
994 | for ( search = importNs.cmdTable.Keys.GetEnumerator(); search.MoveNext(); ) |
||
995 | { |
||
996 | |||
997 | cmdName = ( (string)search.Current ); |
||
998 | if ( Util.stringMatch( cmdName, simplePattern ) ) |
||
999 | { |
||
1000 | // The command cmdName in the source namespace matches the |
||
1001 | // pattern. Check whether it was exported. If it wasn't, |
||
1002 | // we ignore it. |
||
1003 | |||
1004 | wasExported = false; |
||
1005 | for ( i = 0; i < importNs.numExportPatterns; i++ ) |
||
1006 | { |
||
1007 | if ( Util.stringMatch( cmdName, importNs.exportArray[i] ) ) |
||
1008 | { |
||
1009 | wasExported = true; |
||
1010 | break; |
||
1011 | } |
||
1012 | } |
||
1013 | if ( !wasExported ) |
||
1014 | { |
||
1015 | continue; |
||
1016 | } |
||
1017 | |||
1018 | // Unless there is a name clash, create an imported command |
||
1019 | // in the current namespace that refers to cmdPtr. |
||
1020 | |||
1021 | if ( ( ns.cmdTable[cmdName] == null ) || allowOverwrite ) |
||
1022 | { |
||
1023 | // Create the imported command and its client data. |
||
1024 | // To create the new command in the current namespace, |
||
1025 | // generate a fully qualified name for it. |
||
1026 | |||
1027 | StringBuilder ds; |
||
1028 | |||
1029 | ds = new StringBuilder(); |
||
1030 | ds.Append( ns.fullName ); |
||
1031 | if ( ns != interp.globalNs ) |
||
1032 | { |
||
1033 | ds.Append( "::" ); |
||
1034 | } |
||
1035 | ds.Append( cmdName ); |
||
1036 | |||
1037 | // Check whether creating the new imported command in the |
||
1038 | // current namespace would create a cycle of imported->real |
||
1039 | // command references that also would destroy an existing |
||
1040 | // "real" command already in the current namespace. |
||
1041 | |||
1042 | cmd = (WrappedCommand)importNs.cmdTable[cmdName]; |
||
1043 | |||
1044 | if ( cmd.cmd is ImportedCmdData ) |
||
1045 | { |
||
1046 | // This is actually an imported command, find |
||
1047 | // the real command it references |
||
1048 | realCmd = getOriginalCommand( cmd ); |
||
1049 | if ( ( realCmd != null ) && ( realCmd.ns == currNs ) && ( currNs.cmdTable[cmdName] != null ) ) |
||
1050 | { |
||
1051 | throw new TclException( interp, "import pattern \"" + pattern + "\" would create a loop containing command \"" + ds.ToString() + "\"" ); |
||
1052 | } |
||
1053 | } |
||
1054 | |||
1055 | data = new ImportedCmdData(); |
||
1056 | |||
1057 | // Create the imported command inside the interp |
||
1058 | interp.createCommand( ds.ToString(), data ); |
||
1059 | |||
1060 | // Lookup in the namespace for the new WrappedCommand |
||
1061 | importedCmd = findCommand( interp, ds.ToString(), ns, ( TCL.VarFlag.NAMESPACE_ONLY | TCL.VarFlag.LEAVE_ERR_MSG ) ); |
||
1062 | |||
1063 | data.realCmd = cmd; |
||
1064 | data.self = importedCmd; |
||
1065 | |||
1066 | // Create an ImportRef structure describing this new import |
||
1067 | // command and add it to the import ref list in the "real" |
||
1068 | // command. |
||
1069 | |||
1070 | ref_Renamed = new ImportRef(); |
||
1071 | ref_Renamed.importedCmd = importedCmd; |
||
1072 | ref_Renamed.next = cmd.importRef; |
||
1073 | cmd.importRef = ref_Renamed; |
||
1074 | } |
||
1075 | else |
||
1076 | { |
||
1077 | throw new TclException( interp, "can't import command \"" + cmdName + "\": already exists" ); |
||
1078 | } |
||
1079 | } |
||
1080 | } |
||
1081 | return; |
||
1082 | } |
||
1083 | |||
1084 | /* |
||
1085 | *---------------------------------------------------------------------- |
||
1086 | * |
||
1087 | * Tcl_ForgetImport -> forgetImport |
||
1088 | * |
||
1089 | * Deletes previously imported commands. Given a pattern that may |
||
1090 | * include the name of an exporting namespace, this procedure first |
||
1091 | * finds all matching exported commands. It then looks in the namespace |
||
1092 | * specified by namespace for any corresponding previously imported |
||
1093 | * commands, which it deletes. If namespace is null, commands are |
||
1094 | * deleted from the current namespace. |
||
1095 | * |
||
1096 | * Results: |
||
1097 | * Returns if successful, raises TclException if something goes wrong. |
||
1098 | * |
||
1099 | * Side effects: |
||
1100 | * May delete commands. |
||
1101 | * |
||
1102 | *---------------------------------------------------------------------- |
||
1103 | */ |
||
1104 | |||
1105 | internal static void forgetImport( Interp interp, Namespace namespace_Renamed, string pattern ) |
||
1106 | { |
||
1107 | Namespace ns, importNs, actualCtx; |
||
1108 | string simplePattern, cmdName; |
||
1109 | IEnumerator search; |
||
1110 | WrappedCommand cmd; |
||
1111 | |||
1112 | // If the specified namespace is null, use the current namespace. |
||
1113 | |||
1114 | if ( namespace_Renamed == null ) |
||
1115 | { |
||
1116 | ns = getCurrentNamespace( interp ); |
||
1117 | } |
||
1118 | else |
||
1119 | { |
||
1120 | ns = namespace_Renamed; |
||
1121 | } |
||
1122 | |||
1123 | // From the pattern, find the namespace from which we are importing |
||
1124 | // and get the simple pattern (no namespace qualifiers or ::'s) at |
||
1125 | // the end. |
||
1126 | |||
1127 | // Java does not support passing an address so we pass |
||
1128 | // an array of size 1 and then assign arr[0] to the value |
||
1129 | Namespace[] importNsArr = new Namespace[1]; |
||
1130 | Namespace[] dummyArr = new Namespace[1]; |
||
1131 | Namespace[] actualCtxArr = new Namespace[1]; |
||
1132 | string[] simplePatternArr = new string[1]; |
||
1133 | |||
1134 | getNamespaceForQualName( interp, pattern, ns, TCL.VarFlag.LEAVE_ERR_MSG, importNsArr, dummyArr, actualCtxArr, simplePatternArr ); |
||
1135 | |||
1136 | // get the values out of the arrays |
||
1137 | importNs = importNsArr[0]; |
||
1138 | actualCtx = actualCtxArr[0]; |
||
1139 | simplePattern = simplePatternArr[0]; |
||
1140 | |||
1141 | // FIXME : the above call passes TCL.VarFlag.LEAVE_ERR_MSG, but |
||
1142 | // it seems like this will be a problem when exception is raised! |
||
1143 | if ( importNs == null ) |
||
1144 | { |
||
1145 | throw new TclException( interp, "unknown namespace in namespace forget pattern \"" + pattern + "\"" ); |
||
1146 | } |
||
1147 | |||
1148 | // Scan through the command table in the source namespace and look for |
||
1149 | // exported commands that match the string pattern. If the current |
||
1150 | // namespace has an imported command that refers to one of those real |
||
1151 | // commands, delete it. |
||
1152 | |||
1153 | |||
1154 | for ( search = importNs.cmdTable.Keys.GetEnumerator(); search.MoveNext(); ) |
||
1155 | { |
||
1156 | |||
1157 | cmdName = ( (string)search.Current ); |
||
1158 | if ( Util.stringMatch( cmdName, simplePattern ) ) |
||
1159 | { |
||
1160 | cmd = (WrappedCommand)ns.cmdTable[cmdName]; |
||
1161 | if ( cmd != null ) |
||
1162 | { |
||
1163 | // cmd of same name in current namespace |
||
1164 | if ( cmd.cmd is ImportedCmdData ) |
||
1165 | { |
||
1166 | interp.deleteCommandFromToken( cmd ); |
||
1167 | } |
||
1168 | } |
||
1169 | } |
||
1170 | } |
||
1171 | return; |
||
1172 | } |
||
1173 | |||
1174 | |||
1175 | /* |
||
1176 | *---------------------------------------------------------------------- |
||
1177 | * |
||
1178 | * TclGetOriginalCommand -> getOriginalCommand |
||
1179 | * |
||
1180 | * An imported command is created in a namespace when a "real" command |
||
1181 | * is imported from another namespace. If the specified command is an |
||
1182 | * imported command, this procedure returns the original command it |
||
1183 | * refers to. |
||
1184 | * |
||
1185 | * Results: |
||
1186 | * If the command was imported into a sequence of namespaces a, b,...,n |
||
1187 | * where each successive namespace just imports the command from the |
||
1188 | * previous namespace, this procedure returns the Tcl_Command token in |
||
1189 | * the first namespace, a. Otherwise, if the specified command is not |
||
1190 | * an imported command, the procedure returns null. |
||
1191 | * |
||
1192 | * Side effects: |
||
1193 | * None. |
||
1194 | * |
||
1195 | *---------------------------------------------------------------------- |
||
1196 | */ |
||
1197 | |||
1198 | internal static WrappedCommand getOriginalCommand( WrappedCommand command ) |
||
1199 | { |
||
1200 | WrappedCommand cmd = command; |
||
1201 | ImportedCmdData data; |
||
1202 | |||
1203 | if ( !( cmd.cmd is ImportedCmdData ) ) |
||
1204 | { |
||
1205 | return null; |
||
1206 | } |
||
1207 | |||
1208 | while ( cmd.cmd is ImportedCmdData ) |
||
1209 | { |
||
1210 | data = (ImportedCmdData)cmd.cmd; |
||
1211 | cmd = data.realCmd; |
||
1212 | } |
||
1213 | return cmd; |
||
1214 | } |
||
1215 | |||
1216 | |||
1217 | /* |
||
1218 | *---------------------------------------------------------------------- |
||
1219 | * |
||
1220 | * InvokeImportedCmd -> invokeImportedCmd |
||
1221 | * |
||
1222 | * Invoked by Tcl whenever the user calls an imported command that |
||
1223 | * was created by Tcl_Import. Finds the "real" command (in another |
||
1224 | * namespace), and passes control to it. |
||
1225 | * |
||
1226 | * Results: |
||
1227 | * Returns if successful, raises TclException if something goes wrong. |
||
1228 | * |
||
1229 | * Side effects: |
||
1230 | * Returns a result in the interpreter's result object. If anything |
||
1231 | * goes wrong, the result object is set to an error message. |
||
1232 | * |
||
1233 | *---------------------------------------------------------------------- |
||
1234 | */ |
||
1235 | |||
1236 | internal static void invokeImportedCmd( Interp interp, ImportedCmdData data, TclObject[] objv ) |
||
1237 | { |
||
1238 | WrappedCommand realCmd = data.realCmd; |
||
1239 | realCmd.cmd.cmdProc( interp, objv ); |
||
1240 | } |
||
1241 | |||
1242 | |||
1243 | /* |
||
1244 | *---------------------------------------------------------------------- |
||
1245 | * |
||
1246 | * DeleteImportedCmd -> deleteImportedCmd |
||
1247 | * |
||
1248 | * Invoked by Tcl whenever an imported command is deleted. The "real" |
||
1249 | * command keeps a list of all the imported commands that refer to it, |
||
1250 | * so those imported commands can be deleted when the real command is |
||
1251 | * deleted. This procedure removes the imported command reference from |
||
1252 | * the real command's list, and frees up the memory associated with |
||
1253 | * the imported command. |
||
1254 | * |
||
1255 | * Results: |
||
1256 | * None. |
||
1257 | * |
||
1258 | * Side effects: |
||
1259 | * Removes the imported command from the real command's import list. |
||
1260 | * |
||
1261 | *---------------------------------------------------------------------- |
||
1262 | */ |
||
1263 | |||
1264 | internal static void deleteImportedCmd( ImportedCmdData data ) |
||
1265 | // The data object for this imported command |
||
1266 | { |
||
1267 | WrappedCommand realCmd = data.realCmd; |
||
1268 | WrappedCommand self = data.self; |
||
1269 | ImportRef ref_Renamed, prev; |
||
1270 | |||
1271 | prev = null; |
||
1272 | for ( ref_Renamed = realCmd.importRef; ref_Renamed != null; ref_Renamed = ref_Renamed.next ) |
||
1273 | { |
||
1274 | if ( ref_Renamed.importedCmd == self ) |
||
1275 | { |
||
1276 | // Remove ref from real command's list of imported commands |
||
1277 | // that refer to it. |
||
1278 | |||
1279 | if ( prev == null ) |
||
1280 | { |
||
1281 | // ref is first in list |
||
1282 | realCmd.importRef = ref_Renamed.next; |
||
1283 | } |
||
1284 | else |
||
1285 | { |
||
1286 | prev.next = ref_Renamed.next; |
||
1287 | } |
||
1288 | ref_Renamed = null; |
||
1289 | data = null; |
||
1290 | return; |
||
1291 | } |
||
1292 | prev = ref_Renamed; |
||
1293 | } |
||
1294 | |||
1295 | throw new TclRuntimeError( "DeleteImportedCmd: did not find cmd in real cmd's list of import references" ); |
||
1296 | } |
||
1297 | |||
1298 | /* |
||
1299 | *---------------------------------------------------------------------- |
||
1300 | * |
||
1301 | * TclGetNamespaceForQualName -> getNamespaceForQualName |
||
1302 | * |
||
1303 | * Given a qualified name specifying a command, variable, or namespace, |
||
1304 | * and a namespace in which to resolve the name, this procedure returns |
||
1305 | * a pointer to the namespace that contains the item. A qualified name |
||
1306 | * consists of the "simple" name of an item qualified by the names of |
||
1307 | * an arbitrary number of containing namespace separated by "::"s. If |
||
1308 | * the qualified name starts with "::", it is interpreted absolutely |
||
1309 | * from the global namespace. Otherwise, it is interpreted relative to |
||
1310 | * the namespace specified by cxtNsPtr if it is non-null. If cxtNsPtr |
||
1311 | * is null, the name is interpreted relative to the current namespace. |
||
1312 | * |
||
1313 | * A relative name like "foo::bar::x" can be found starting in either |
||
1314 | * the current namespace or in the global namespace. So each search |
||
1315 | * usually follows two tracks, and two possible namespaces are |
||
1316 | * returned. If the procedure sets either nsPtrPtr[0] or altNsPtrPtr[0] to |
||
1317 | * null, then that path failed. |
||
1318 | * |
||
1319 | * If "flags" contains TCL.VarFlag.GLOBAL_ONLY, the relative qualified name is |
||
1320 | * sought only in the global :: namespace. The alternate search |
||
1321 | * (also) starting from the global namespace is ignored and |
||
1322 | * altNsPtrPtr[0] is set null. |
||
1323 | * |
||
1324 | * If "flags" contains TCL.VarFlag.NAMESPACE_ONLY, the relative qualified |
||
1325 | * name is sought only in the namespace specified by cxtNsPtr. The |
||
1326 | * alternate search starting from the global namespace is ignored and |
||
1327 | * altNsPtrPtr[0] is set null. If both TCL.VarFlag.GLOBAL_ONLY and |
||
1328 | * TCL.VarFlag.NAMESPACE_ONLY are specified, TCL.VarFlag.GLOBAL_ONLY is ignored and |
||
1329 | * the search starts from the namespace specified by cxtNsPtr. |
||
1330 | * |
||
1331 | * If "flags" contains TCL.VarFlag.CREATE_NS_IF_UNKNOWN, all namespace |
||
1332 | * components of the qualified name that cannot be found are |
||
1333 | * automatically created within their specified parent. This makes sure |
||
1334 | * that functions like Tcl_CreateCommand always succeed. There is no |
||
1335 | * alternate search path, so altNsPtrPtr[0] is set null. |
||
1336 | * |
||
1337 | * If "flags" contains TCL.VarFlag.FIND_ONLY_NS, the qualified name is treated as a |
||
1338 | * reference to a namespace, and the entire qualified name is |
||
1339 | * followed. If the name is relative, the namespace is looked up only |
||
1340 | * in the current namespace. A pointer to the namespace is stored in |
||
1341 | * nsPtrPtr[0] and null is stored in simpleNamePtr[0]. Otherwise, if |
||
1342 | * TCL.VarFlag.FIND_ONLY_NS is not specified, only the leading components are |
||
1343 | * treated as namespace names, and a pointer to the simple name of the |
||
1344 | * final component is stored in simpleNamePtr[0]. |
||
1345 | * |
||
1346 | * Results: |
||
1347 | * It sets nsPtrPtr[0] and altNsPtrPtr[0] to point to the two possible |
||
1348 | * namespaces which represent the last (containing) namespace in the |
||
1349 | * qualified name. If the procedure sets either nsPtrPtr[0] or altNsPtrPtr[0] |
||
1350 | * to null, then the search along that path failed. The procedure also |
||
1351 | * stores a pointer to the simple name of the final component in |
||
1352 | * simpleNamePtr[0]. If the qualified name is "::" or was treated as a |
||
1353 | * namespace reference (TCL.VarFlag.FIND_ONLY_NS), the procedure stores a pointer |
||
1354 | * to the namespace in nsPtrPtr[0], null in altNsPtrPtr[0], and sets |
||
1355 | * simpleNamePtr[0] to an empty string. |
||
1356 | * |
||
1357 | * If there is an error, this procedure returns TCL_ERROR. If "flags" |
||
1358 | * contains TCL_LEAVE_ERR_MSG, an error message is returned in the |
||
1359 | * interpreter's result object. Otherwise, the interpreter's result |
||
1360 | * object is left unchanged. |
||
1361 | * |
||
1362 | * actualCxtPtrPtr[0] is set to the actual context namespace. It is |
||
1363 | * set to the input context namespace pointer in cxtNsPtr. If cxtNsPtr |
||
1364 | * is null, it is set to the current namespace context. |
||
1365 | * |
||
1366 | * Side effects: |
||
1367 | * If "flags" contains TCL.VarFlag.CREATE_NS_IF_UNKNOWN, new namespaces may be |
||
1368 | * created. |
||
1369 | * |
||
1370 | *---------------------------------------------------------------------- |
||
1371 | */ |
||
1372 | |||
1373 | internal static void getNamespaceForQualName( Interp interp, string qualName, Namespace cxtNsPtr, TCL.VarFlag flags, Namespace[] nsPtrPtr, Namespace[] altNsPtrPtr, Namespace[] actualCxtPtrPtr, string[] simpleNamePtr ) |
||
1374 | { |
||
1375 | |||
1376 | |||
1377 | // FIXME : remove extra method call checks when we are sure this works! |
||
1378 | |||
1379 | if ( true ) |
||
1380 | { |
||
1381 | // check invariants |
||
1382 | if ( ( nsPtrPtr == null ) || ( nsPtrPtr.Length != 1 ) ) |
||
1383 | { |
||
1384 | |||
1385 | throw new System.SystemException( "nsPtrPtr " + nsPtrPtr ); |
||
1386 | } |
||
1387 | if ( ( altNsPtrPtr == null ) || ( altNsPtrPtr.Length != 1 ) ) |
||
1388 | { |
||
1389 | |||
1390 | throw new System.SystemException( "altNsPtrPtr " + altNsPtrPtr ); |
||
1391 | } |
||
1392 | if ( ( actualCxtPtrPtr == null ) || ( actualCxtPtrPtr.Length != 1 ) ) |
||
1393 | { |
||
1394 | |||
1395 | throw new System.SystemException( "actualCxtPtrPtr " + actualCxtPtrPtr ); |
||
1396 | } |
||
1397 | if ( ( simpleNamePtr == null ) || ( simpleNamePtr.Length != 1 ) ) |
||
1398 | { |
||
1399 | |||
1400 | throw new System.SystemException( "simpleNamePtr " + simpleNamePtr ); |
||
1401 | } |
||
1402 | } |
||
1403 | |||
1404 | |||
1405 | |||
1406 | |||
1407 | Namespace ns = cxtNsPtr; |
||
1408 | Namespace altNs; |
||
1409 | Namespace globalNs = getGlobalNamespace( interp ); |
||
1410 | Namespace entryNs; |
||
1411 | string start, end; |
||
1412 | string nsName; |
||
1413 | int len; |
||
1414 | int start_ind, end_ind, name_len; |
||
1415 | |||
1416 | // Determine the context namespace ns in which to start the primary |
||
1417 | // search. If TCL.VarFlag.NAMESPACE_ONLY or TCL.VarFlag.FIND_ONLY_NS was specified, search |
||
1418 | // from the current namespace. If the qualName name starts with a "::" |
||
1419 | // or TCL.VarFlag.GLOBAL_ONLY was specified, search from the global |
||
1420 | // namespace. Otherwise, use the given namespace given in cxtNsPtr, or |
||
1421 | // if that is null, use the current namespace context. Note that we |
||
1422 | // always treat two or more adjacent ":"s as a namespace separator. |
||
1423 | |||
1424 | if ( ( flags & ( TCL.VarFlag.NAMESPACE_ONLY | TCL.VarFlag.FIND_ONLY_NS ) ) != 0 ) |
||
1425 | { |
||
1426 | ns = getCurrentNamespace( interp ); |
||
1427 | } |
||
1428 | else if ( ( flags & TCL.VarFlag.GLOBAL_ONLY ) != 0 ) |
||
1429 | { |
||
1430 | ns = globalNs; |
||
1431 | } |
||
1432 | else if ( ns == null ) |
||
1433 | { |
||
1434 | if ( interp.varFrame != null ) |
||
1435 | { |
||
1436 | ns = interp.varFrame.ns; |
||
1437 | } |
||
1438 | else |
||
1439 | { |
||
1440 | ns = interp.globalNs; |
||
1441 | } |
||
1442 | } |
||
1443 | |||
1444 | |||
1445 | |||
1446 | start_ind = 0; |
||
1447 | name_len = qualName.Length; |
||
1448 | |||
1449 | if ( ( name_len >= 2 ) && ( qualName[0] == ':' ) && ( qualName[1] == ':' ) ) |
||
1450 | { |
||
1451 | start_ind = 2; // skip over the initial :: |
||
1452 | |||
1453 | while ( ( start_ind < name_len ) && ( qualName[start_ind] == ':' ) ) |
||
1454 | { |
||
1455 | start_ind++; // skip over a subsequent : |
||
1456 | } |
||
1457 | |||
1458 | ns = globalNs; |
||
1459 | if ( start_ind >= name_len ) |
||
1460 | { |
||
1461 | // qualName is just two or more ":"s |
||
1462 | nsPtrPtr[0] = globalNs; |
||
1463 | altNsPtrPtr[0] = null; |
||
1464 | actualCxtPtrPtr[0] = globalNs; |
||
1465 | simpleNamePtr[0] = ""; // points to empty string |
||
1466 | return; |
||
1467 | } |
||
1468 | } |
||
1469 | actualCxtPtrPtr[0] = ns; |
||
1470 | |||
1471 | |||
1472 | // Start an alternate search path starting with the global namespace. |
||
1473 | // However, if the starting context is the global namespace, or if the |
||
1474 | // flag is set to search only the namespace cxtNs, ignore the |
||
1475 | // alternate search path. |
||
1476 | |||
1477 | |||
1478 | altNs = globalNs; |
||
1479 | if ( ( ns == globalNs ) || ( ( flags & ( TCL.VarFlag.NAMESPACE_ONLY | TCL.VarFlag.FIND_ONLY_NS ) ) != 0 ) ) |
||
1480 | { |
||
1481 | altNs = null; |
||
1482 | } |
||
1483 | |||
1484 | |||
1485 | // Loop to resolve each namespace qualifier in qualName. |
||
1486 | |||
1487 | end_ind = start_ind; |
||
1488 | |||
1489 | while ( start_ind < name_len ) |
||
1490 | { |
||
1491 | // Find the next namespace qualifier (i.e., a name ending in "::") |
||
1492 | // or the end of the qualified name (i.e., a name ending in "\0"). |
||
1493 | // Set len to the number of characters, starting from start, |
||
1494 | // in the name; set end to point after the "::"s or at the "\0". |
||
1495 | |||
1496 | len = 0; |
||
1497 | for ( end_ind = start_ind; end_ind < name_len; end_ind++ ) |
||
1498 | { |
||
1499 | if ( ( ( name_len - end_ind ) > 1 ) && ( qualName[end_ind] == ':' ) && ( qualName[end_ind + 1] == ':' ) ) |
||
1500 | { |
||
1501 | end_ind += 2; // skip over the initial :: |
||
1502 | while ( ( end_ind < name_len ) && ( qualName[end_ind] == ':' ) ) |
||
1503 | { |
||
1504 | end_ind++; // skip over a subsequent : |
||
1505 | } |
||
1506 | break; |
||
1507 | } |
||
1508 | len++; |
||
1509 | } |
||
1510 | |||
1511 | |||
1512 | if ( ( end_ind == name_len ) && !( ( end_ind - start_ind >= 2 ) && ( ( qualName[end_ind - 1] == ':' ) && ( qualName[end_ind - 2] == ':' ) ) ) ) |
||
1513 | { |
||
1514 | |||
1515 | // qualName ended with a simple name at start. If TCL.VarFlag.FIND_ONLY_NS |
||
1516 | // was specified, look this up as a namespace. Otherwise, |
||
1517 | // start is the name of a cmd or var and we are done. |
||
1518 | |||
1519 | if ( ( flags & TCL.VarFlag.FIND_ONLY_NS ) != 0 ) |
||
1520 | { |
||
1521 | // assign the string from start_ind to the end of the name string |
||
1522 | nsName = qualName.Substring( start_ind ); |
||
1523 | } |
||
1524 | else |
||
1525 | { |
||
1526 | nsPtrPtr[0] = ns; |
||
1527 | altNsPtrPtr[0] = altNs; |
||
1528 | simpleNamePtr[0] = qualName.Substring( start_ind ); |
||
1529 | return; |
||
1530 | } |
||
1531 | } |
||
1532 | else |
||
1533 | { |
||
1534 | // start points to the beginning of a namespace qualifier ending |
||
1535 | // in "::". Create new string with the namespace qualifier. |
||
1536 | |||
1537 | nsName = qualName.Substring( start_ind, ( start_ind + len ) - ( start_ind ) ); |
||
1538 | } |
||
1539 | |||
1540 | |||
1541 | |||
1542 | // Look up the namespace qualifier nsName in the current namespace |
||
1543 | // context. If it isn't found but TCL.VarFlag.CREATE_NS_IF_UNKNOWN is set, |
||
1544 | // create that qualifying namespace. This is needed for procedures |
||
1545 | // like Tcl_CreateCommand that cannot fail. |
||
1546 | |||
1547 | if ( ns != null ) |
||
1548 | { |
||
1549 | entryNs = (Namespace)ns.childTable[nsName]; |
||
1550 | if ( entryNs != null ) |
||
1551 | { |
||
1552 | ns = entryNs; |
||
1553 | } |
||
1554 | else if ( ( flags & TCL.VarFlag.CREATE_NS_IF_UNKNOWN ) != 0 ) |
||
1555 | { |
||
1556 | CallFrame frame = interp.newCallFrame(); |
||
1557 | |||
1558 | pushCallFrame( interp, frame, ns, false ); |
||
1559 | ns = createNamespace( interp, nsName, null ); |
||
1560 | |||
1561 | popCallFrame( interp ); |
||
1562 | if ( ns == null ) |
||
1563 | { |
||
1564 | throw new System.SystemException( "Could not create namespace " + nsName ); |
||
1565 | } |
||
1566 | } |
||
1567 | else |
||
1568 | { |
||
1569 | ns = null; // namespace not found and wasn't created |
||
1570 | } |
||
1571 | } |
||
1572 | |||
1573 | |||
1574 | // Look up the namespace qualifier in the alternate search path too. |
||
1575 | |||
1576 | if ( altNs != null ) |
||
1577 | { |
||
1578 | altNs = (Namespace)altNs.childTable[nsName]; |
||
1579 | } |
||
1580 | |||
1581 | // If both search paths have failed, return null results. |
||
1582 | |||
1583 | if ( ( ns == null ) && ( altNs == null ) ) |
||
1584 | { |
||
1585 | nsPtrPtr[0] = null; |
||
1586 | altNsPtrPtr[0] = null; |
||
1587 | simpleNamePtr[0] = null; |
||
1588 | return; |
||
1589 | } |
||
1590 | |||
1591 | start_ind = end_ind; |
||
1592 | } |
||
1593 | |||
1594 | |||
1595 | // We ignore trailing "::"s in a namespace name, but in a command or |
||
1596 | // variable name, trailing "::"s refer to the cmd or var named {}. |
||
1597 | |||
1598 | if ( ( ( flags & TCL.VarFlag.FIND_ONLY_NS ) != 0 ) || ( ( end_ind > start_ind ) && ( qualName[end_ind - 1] != ':' ) ) ) |
||
1599 | { |
||
1600 | simpleNamePtr[0] = null; // found namespace name |
||
1601 | } |
||
1602 | else |
||
1603 | { |
||
1604 | // FIXME : make sure this does not throw exception when end_ind is at the end of the string |
||
1605 | simpleNamePtr[0] = qualName.Substring( end_ind ); // found cmd/var: points to empty string |
||
1606 | } |
||
1607 | |||
1608 | |||
1609 | // As a special case, if we are looking for a namespace and qualName |
||
1610 | // is "" and the current active namespace (ns) is not the global |
||
1611 | // namespace, return null (no namespace was found). This is because |
||
1612 | // namespaces can not have empty names except for the global namespace. |
||
1613 | |||
1614 | if ( ( ( flags & TCL.VarFlag.FIND_ONLY_NS ) != 0 ) && ( name_len == 0 ) && ( ns != globalNs ) ) |
||
1615 | { |
||
1616 | ns = null; |
||
1617 | } |
||
1618 | |||
1619 | nsPtrPtr[0] = ns; |
||
1620 | altNsPtrPtr[0] = altNs; |
||
1621 | return; |
||
1622 | } |
||
1623 | |||
1624 | |||
1625 | /* |
||
1626 | *---------------------------------------------------------------------- |
||
1627 | * |
||
1628 | * Tcl_FindNamespace -> findNamespace |
||
1629 | * |
||
1630 | * Searches for a namespace. |
||
1631 | * |
||
1632 | * Results:T |
||
1633 | * Returns a reference to the namespace if it is found. Otherwise, |
||
1634 | * returns null and leaves an error message in the interpreter's |
||
1635 | * result object if "flags" contains TCL.VarFlag.LEAVE_ERR_MSG. |
||
1636 | * |
||
1637 | * Side effects: |
||
1638 | * None. |
||
1639 | * |
||
1640 | *---------------------------------------------------------------------- |
||
1641 | */ |
||
1642 | |||
1643 | internal static Namespace findNamespace( Interp interp, string name, Namespace contextNs, TCL.VarFlag flags ) |
||
1644 | { |
||
1645 | Namespace ns; |
||
1646 | |||
1647 | // Java does not support passing an address so we pass |
||
1648 | // an array of size 1 and then assign arr[0] to the value |
||
1649 | Namespace[] nsArr = new Namespace[1]; |
||
1650 | Namespace[] dummy1Arr = new Namespace[1]; |
||
1651 | string[] dummy2Arr = new string[1]; |
||
1652 | |||
1653 | // Find the namespace(s) that contain the specified namespace name. |
||
1654 | // Add the TCL.VarFlag.FIND_ONLY_NS flag to resolve the name all the way down |
||
1655 | // to its last component, a namespace. |
||
1656 | |||
1657 | getNamespaceForQualName( interp, name, contextNs, ( flags | TCL.VarFlag.FIND_ONLY_NS ), nsArr, dummy1Arr, dummy1Arr, dummy2Arr ); |
||
1658 | |||
1659 | |||
1660 | // Get the values out of the arrays! |
||
1661 | ns = nsArr[0]; |
||
1662 | |||
1663 | if ( ns != null ) |
||
1664 | { |
||
1665 | return ns; |
||
1666 | } |
||
1667 | else if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 ) |
||
1668 | { |
||
1669 | /* |
||
1670 | interp.resetResult(); |
||
1671 | TclString.append(interp.getResult(), "unknown namespace \"" + name + "\""); |
||
1672 | */ |
||
1673 | |||
1674 | // FIXME : is there a test case for this error? |
||
1675 | interp.setResult( "unknown namespace \"" + name + "\"" ); |
||
1676 | } |
||
1677 | return null; |
||
1678 | } |
||
1679 | |||
1680 | |||
1681 | |||
1682 | /* |
||
1683 | *---------------------------------------------------------------------- |
||
1684 | * |
||
1685 | * Tcl_FindCommand -> findCommand |
||
1686 | * |
||
1687 | * Searches for a command. |
||
1688 | * |
||
1689 | * Results: |
||
1690 | * Returns a token for the command if it is found. Otherwise, if it |
||
1691 | * can't be found or there is an error, returns null and leaves an |
||
1692 | * error message in the interpreter's result object if "flags" |
||
1693 | * contains TCL.VarFlag.LEAVE_ERR_MSG. |
||
1694 | * |
||
1695 | * Side effects: |
||
1696 | * None. |
||
1697 | * |
||
1698 | *---------------------------------------------------------------------- |
||
1699 | */ |
||
1700 | |||
1701 | internal static WrappedCommand findCommand( Interp interp, string name, Namespace contextNs, TCL.VarFlag flags ) |
||
1702 | { |
||
1703 | Interp.ResolverScheme res; |
||
1704 | Namespace cxtNs; |
||
1705 | Namespace[] ns = new Namespace[2]; |
||
1706 | string simpleName; |
||
1707 | int search; |
||
1708 | //int result; |
||
1709 | WrappedCommand cmd; |
||
1710 | |||
1711 | // If this namespace has a command resolver, then give it first |
||
1712 | // crack at the command resolution. If the interpreter has any |
||
1713 | // command resolvers, consult them next. The command resolver |
||
1714 | // procedures may return a Tcl_Command value, they may signal |
||
1715 | // to continue onward, or they may signal an error. |
||
1716 | |||
1717 | if ( ( flags & TCL.VarFlag.GLOBAL_ONLY ) != 0 ) |
||
1718 | { |
||
1719 | cxtNs = getGlobalNamespace( interp ); |
||
1720 | } |
||
1721 | else if ( contextNs != null ) |
||
1722 | { |
||
1723 | cxtNs = contextNs; |
||
1724 | } |
||
1725 | else |
||
1726 | { |
||
1727 | cxtNs = getCurrentNamespace( interp ); |
||
1728 | } |
||
1729 | |||
1730 | if ( cxtNs.resolver != null || interp.resolvers != null ) |
||
1731 | { |
||
1732 | try |
||
1733 | { |
||
1734 | if ( cxtNs.resolver != null ) |
||
1735 | { |
||
1736 | cmd = cxtNs.resolver.resolveCmd( interp, name, cxtNs, flags ); |
||
1737 | } |
||
1738 | else |
||
1739 | { |
||
1740 | cmd = null; |
||
1741 | } |
||
1742 | |||
1743 | if ( cmd == null && interp.resolvers != null ) |
||
1744 | { |
||
1745 | IEnumerator enum_Renamed = interp.resolvers.GetEnumerator(); |
||
1746 | while ( cmd == null && enum_Renamed.MoveNext() ) |
||
1747 | { |
||
1748 | res = (Interp.ResolverScheme)enum_Renamed.Current; |
||
1749 | cmd = res.resolver.resolveCmd( interp, name, cxtNs, flags ); |
||
1750 | } |
||
1751 | } |
||
1752 | |||
1753 | if ( cmd != null ) |
||
1754 | { |
||
1755 | return cmd; |
||
1756 | } |
||
1757 | } |
||
1758 | catch ( TclException e ) |
||
1759 | { |
||
1760 | return null; |
||
1761 | } |
||
1762 | } |
||
1763 | |||
1764 | // Java does not support passing an address so we pass |
||
1765 | // an array of size 1 and then assign arr[0] to the value |
||
1766 | Namespace[] ns0Arr = new Namespace[1]; |
||
1767 | Namespace[] ns1Arr = new Namespace[1]; |
||
1768 | Namespace[] cxtNsArr = new Namespace[1]; |
||
1769 | string[] simpleNameArr = new string[1]; |
||
1770 | |||
1771 | |||
1772 | // Find the namespace(s) that contain the command. |
||
1773 | |||
1774 | getNamespaceForQualName( interp, name, contextNs, flags, ns0Arr, ns1Arr, cxtNsArr, simpleNameArr ); |
||
1775 | |||
1776 | // Get the values out of the arrays! |
||
1777 | ns[0] = ns0Arr[0]; |
||
1778 | ns[1] = ns1Arr[0]; |
||
1779 | cxtNs = cxtNsArr[0]; |
||
1780 | simpleName = simpleNameArr[0]; |
||
1781 | |||
1782 | |||
1783 | |||
1784 | // Look for the command in the command table of its namespace. |
||
1785 | // Be sure to check both possible search paths: from the specified |
||
1786 | // namespace context and from the global namespace. |
||
1787 | |||
1788 | cmd = null; |
||
1789 | for ( search = 0; ( search < 2 ) && ( cmd == null ); search++ ) |
||
1790 | { |
||
1791 | if ( ( ns[search] != null ) && ( (System.Object)simpleName != null ) ) |
||
1792 | { |
||
1793 | cmd = (WrappedCommand)ns[search].cmdTable[simpleName]; |
||
1794 | } |
||
1795 | } |
||
1796 | if ( cmd != null ) |
||
1797 | { |
||
1798 | return cmd; |
||
1799 | } |
||
1800 | else if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 ) |
||
1801 | { |
||
1802 | throw new TclException( interp, "unknown command \"" + name + "\"" ); |
||
1803 | } |
||
1804 | |||
1805 | return null; |
||
1806 | } |
||
1807 | |||
1808 | |||
1809 | |||
1810 | /* |
||
1811 | *---------------------------------------------------------------------- |
||
1812 | * |
||
1813 | * Tcl_FindNamespaceVar -> findNamespaceVar |
||
1814 | * |
||
1815 | * Searches for a namespace variable, a variable not local to a |
||
1816 | * procedure. The variable can be either a scalar or an array, but |
||
1817 | * may not be an element of an array. |
||
1818 | * |
||
1819 | * Results: |
||
1820 | * Returns a token for the variable if it is found. Otherwise, if it |
||
1821 | * can't be found or there is an error, returns null and leaves an |
||
1822 | * error message in the interpreter's result object if "flags" |
||
1823 | * contains TCL.VarFlag.LEAVE_ERR_MSG. |
||
1824 | * |
||
1825 | * Side effects: |
||
1826 | * None. |
||
1827 | * |
||
1828 | *---------------------------------------------------------------------- |
||
1829 | */ |
||
1830 | |||
1831 | internal static Var findNamespaceVar( Interp interp, string name, Namespace contextNs, TCL.VarFlag flags ) |
||
1832 | { |
||
1833 | Interp.ResolverScheme res; |
||
1834 | Namespace cxtNs; |
||
1835 | Namespace[] ns = new Namespace[2]; |
||
1836 | string simpleName; |
||
1837 | int search; |
||
1838 | //int result; |
||
1839 | Var var; |
||
1840 | |||
1841 | // If this namespace has a variable resolver, then give it first |
||
1842 | // crack at the variable resolution. It may return a Tcl_Var |
||
1843 | // value, it may signal to continue onward, or it may signal |
||
1844 | // an error. |
||
1845 | |||
1846 | if ( ( flags & TCL.VarFlag.GLOBAL_ONLY ) != 0 ) |
||
1847 | { |
||
1848 | cxtNs = getGlobalNamespace( interp ); |
||
1849 | } |
||
1850 | else if ( contextNs != null ) |
||
1851 | { |
||
1852 | cxtNs = contextNs; |
||
1853 | } |
||
1854 | else |
||
1855 | { |
||
1856 | cxtNs = getCurrentNamespace( interp ); |
||
1857 | } |
||
1858 | |||
1859 | if ( cxtNs.resolver != null || interp.resolvers != null ) |
||
1860 | { |
||
1861 | try |
||
1862 | { |
||
1863 | if ( cxtNs.resolver != null ) |
||
1864 | { |
||
1865 | var = cxtNs.resolver.resolveVar( interp, name, cxtNs, flags ); |
||
1866 | } |
||
1867 | else |
||
1868 | { |
||
1869 | var = null; |
||
1870 | } |
||
1871 | |||
1872 | if ( var == null && interp.resolvers != null ) |
||
1873 | { |
||
1874 | IEnumerator enum_Renamed = interp.resolvers.GetEnumerator(); |
||
1875 | while ( var == null && enum_Renamed.MoveNext() ) |
||
1876 | { |
||
1877 | res = (Interp.ResolverScheme)enum_Renamed.Current; |
||
1878 | var = res.resolver.resolveVar( interp, name, cxtNs, flags ); |
||
1879 | } |
||
1880 | } |
||
1881 | |||
1882 | if ( var != null ) |
||
1883 | { |
||
1884 | return var; |
||
1885 | } |
||
1886 | } |
||
1887 | catch ( TclException e ) |
||
1888 | { |
||
1889 | return null; |
||
1890 | } |
||
1891 | } |
||
1892 | |||
1893 | // Java does not support passing an address so we pass |
||
1894 | // an array of size 1 and then assign arr[0] to the value |
||
1895 | Namespace[] ns0Arr = new Namespace[1]; |
||
1896 | Namespace[] ns1Arr = new Namespace[1]; |
||
1897 | Namespace[] cxtNsArr = new Namespace[1]; |
||
1898 | string[] simpleNameArr = new string[1]; |
||
1899 | |||
1900 | |||
1901 | // Find the namespace(s) that contain the variable. |
||
1902 | |||
1903 | getNamespaceForQualName( interp, name, contextNs, flags, ns0Arr, ns1Arr, cxtNsArr, simpleNameArr ); |
||
1904 | |||
1905 | // Get the values out of the arrays! |
||
1906 | ns[0] = ns0Arr[0]; |
||
1907 | ns[1] = ns1Arr[0]; |
||
1908 | cxtNs = cxtNsArr[0]; |
||
1909 | simpleName = simpleNameArr[0]; |
||
1910 | |||
1911 | |||
1912 | // Look for the variable in the variable table of its namespace. |
||
1913 | // Be sure to check both possible search paths: from the specified |
||
1914 | // namespace context and from the global namespace. |
||
1915 | |||
1916 | var = null; |
||
1917 | for ( search = 0; ( search < 2 ) && ( var == null ); search++ ) |
||
1918 | { |
||
1919 | if ( ( ns[search] != null ) && ( (System.Object)simpleName != null ) ) |
||
1920 | { |
||
1921 | var = (Var)ns[search].varTable[simpleName]; |
||
1922 | } |
||
1923 | } |
||
1924 | if ( var != null ) |
||
1925 | { |
||
1926 | return var; |
||
1927 | } |
||
1928 | else if ( ( flags & TCL.VarFlag.LEAVE_ERR_MSG ) != 0 ) |
||
1929 | { |
||
1930 | /* |
||
1931 | interp.resetResult(); |
||
1932 | TclString.append(interp.getResult(), "unknown variable \"" + name + "\""); |
||
1933 | */ |
||
1934 | |||
1935 | // FIXME : is there a test case for this error? |
||
1936 | interp.setResult( "unknown variable \"" + name + "\"" ); |
||
1937 | } |
||
1938 | return null; |
||
1939 | } |
||
1940 | |||
1941 | /* |
||
1942 | *---------------------------------------------------------------------- |
||
1943 | * |
||
1944 | * GetNamespaceFromObj -> getNamespaceFromObj |
||
1945 | * |
||
1946 | * Returns the namespace specified by the name in a TclObject. |
||
1947 | * |
||
1948 | * Results: |
||
1949 | * This method will return the Namespace object whose name |
||
1950 | * is stored in the obj argument. If the namespace can't be found, |
||
1951 | * a TclException is raised. |
||
1952 | * |
||
1953 | * Side effects: |
||
1954 | * May update the internal representation for the object, caching the |
||
1955 | * namespace reference. The next time this procedure is called, the |
||
1956 | * namespace value can be found quickly. |
||
1957 | * |
||
1958 | * If anything goes wrong, an error message is left in the |
||
1959 | * interpreter's result object. |
||
1960 | * |
||
1961 | *---------------------------------------------------------------------- |
||
1962 | */ |
||
1963 | |||
1964 | internal static Namespace getNamespaceFromObj( Interp interp, TclObject obj ) |
||
1965 | { |
||
1966 | ResolvedNsName resName; |
||
1967 | Namespace ns; |
||
1968 | Namespace currNs = getCurrentNamespace( interp ); |
||
1969 | int result; |
||
1970 | |||
1971 | // Get the internal representation, converting to a namespace type if |
||
1972 | // needed. The internal representation is a ResolvedNsName that points |
||
1973 | // to the actual namespace. |
||
1974 | |||
1975 | // FIXME : if NamespaceCmd is not the internal rep this needs to be changed! |
||
1976 | if ( !( obj.InternalRep is NamespaceCmd ) ) |
||
1977 | { |
||
1978 | setNsNameFromAny( interp, obj ); |
||
1979 | } |
||
1980 | resName = ( (NamespaceCmd)obj.InternalRep ).otherValue; |
||
1981 | |||
1982 | // Check the context namespace of the resolved symbol to make sure that |
||
1983 | // it is fresh. If not, then force another conversion to the namespace |
||
1984 | // type, to discard the old rep and create a new one. Note that we |
||
1985 | // verify that the namespace id of the cached namespace is the same as |
||
1986 | // the id when we cached it; this insures that the namespace wasn't |
||
1987 | // deleted and a new one created at the same address. |
||
1988 | |||
1989 | ns = null; |
||
1990 | if ( ( resName != null ) && ( resName.refNs == currNs ) && ( resName.nsId == resName.ns.nsId ) ) |
||
1991 | { |
||
1992 | ns = resName.ns; |
||
1993 | if ( ( ns.flags & NS_DEAD ) != 0 ) |
||
1994 | { |
||
1995 | ns = null; |
||
1996 | } |
||
1997 | } |
||
1998 | if ( ns == null ) |
||
1999 | { |
||
2000 | // try again |
||
2001 | setNsNameFromAny( interp, obj ); |
||
2002 | resName = ( (NamespaceCmd)obj.InternalRep ).otherValue; |
||
2003 | if ( resName != null ) |
||
2004 | { |
||
2005 | ns = resName.ns; |
||
2006 | if ( ( ns.flags & NS_DEAD ) != 0 ) |
||
2007 | { |
||
2008 | ns = null; |
||
2009 | } |
||
2010 | } |
||
2011 | } |
||
2012 | return ns; |
||
2013 | } |
||
2014 | |||
2015 | /// <summary>---------------------------------------------------------------------- |
||
2016 | /// |
||
2017 | /// Tcl_SetNamespaceResolvers -> setNamespaceResolver |
||
2018 | /// |
||
2019 | /// Sets the command/variable resolution object for a namespace, |
||
2020 | /// thereby changing the way that command/variable names are |
||
2021 | /// interpreted. This allows extension writers to support different |
||
2022 | /// name resolution schemes, such as those for object-oriented |
||
2023 | /// packages. |
||
2024 | /// |
||
2025 | /// Command resolution is handled by the following method: |
||
2026 | /// |
||
2027 | /// resolveCmd (Interp interp, String name, |
||
2028 | /// NamespaceCmd.Namespace context, int flags) |
||
2029 | /// throws TclException; |
||
2030 | /// |
||
2031 | /// Whenever a command is executed or NamespaceCmd.findCommand is invoked |
||
2032 | /// within the namespace, this method is called to resolve the |
||
2033 | /// command name. If this method is able to resolve the name, |
||
2034 | /// it should return the corresponding WrappedCommand. Otherwise, |
||
2035 | /// the procedure can return null, and the command will |
||
2036 | /// be treated under the usual name resolution rules. Or, it can |
||
2037 | /// throw a TclException, and the command will be considered invalid. |
||
2038 | /// |
||
2039 | /// Variable resolution is handled by the following method: |
||
2040 | /// |
||
2041 | /// resolveVar (Interp interp, String name, |
||
2042 | /// NamespaceCmd.Namespace context, int flags) |
||
2043 | /// throws TclException; |
||
2044 | /// |
||
2045 | /// If this method is able to resolve the name, it should return |
||
2046 | /// the variable as var object. The method may also |
||
2047 | /// return null, and the variable will be treated under the usual |
||
2048 | /// name resolution rules. Or, it can throw a TclException, |
||
2049 | /// and the variable will be considered invalid. |
||
2050 | /// |
||
2051 | /// Results: |
||
2052 | /// See above. |
||
2053 | /// |
||
2054 | /// Side effects: |
||
2055 | /// None. |
||
2056 | /// |
||
2057 | /// ---------------------------------------------------------------------- |
||
2058 | /// </summary> |
||
2059 | |||
2060 | internal static void setNamespaceResolver( Namespace namespace_Renamed, Resolver resolver ) |
||
2061 | // command and variable resolution |
||
2062 | { |
||
2063 | // Plug in the new command resolver. |
||
2064 | |||
2065 | namespace_Renamed.resolver = resolver; |
||
2066 | } |
||
2067 | |||
2068 | /// <summary>---------------------------------------------------------------------- |
||
2069 | /// |
||
2070 | /// Tcl_GetNamespaceResolvers -> getNamespaceResolver |
||
2071 | /// |
||
2072 | /// Returns the current command/variable resolution object |
||
2073 | /// for a namespace. By default, these objects are null. |
||
2074 | /// New objects can be installed by calling setNamespaceResolver, |
||
2075 | /// to provide new name resolution rules. |
||
2076 | /// |
||
2077 | /// Results: |
||
2078 | /// Returns the esolver object assigned to this namespace. |
||
2079 | /// Returns null otherwise. |
||
2080 | /// |
||
2081 | /// Side effects: |
||
2082 | /// None. |
||
2083 | /// |
||
2084 | /// ---------------------------------------------------------------------- |
||
2085 | /// </summary> |
||
2086 | |||
2087 | internal static Resolver getNamespaceResolver( Namespace namespace_Renamed ) |
||
2088 | // Namespace whose resolution rules |
||
2089 | // are being queried. |
||
2090 | { |
||
2091 | return namespace_Renamed.resolver; |
||
2092 | } |
||
2093 | |||
2094 | /* |
||
2095 | *---------------------------------------------------------------------- |
||
2096 | * |
||
2097 | * Tcl_NamespaceObjCmd -> cmdProc |
||
2098 | * |
||
2099 | * Invoked to implement the "namespace" command that creates, deletes, |
||
2100 | * or manipulates Tcl namespaces. Handles the following syntax: |
||
2101 | * |
||
2102 | * namespace children ?name? ?pattern? |
||
2103 | * namespace code arg |
||
2104 | * namespace current |
||
2105 | * namespace delete ?name name...? |
||
2106 | * namespace eval name arg ?arg...? |
||
2107 | * namespace export ?-clear? ?pattern pattern...? |
||
2108 | * namespace forget ?pattern pattern...? |
||
2109 | * namespace import ?-force? ?pattern pattern...? |
||
2110 | * namespace inscope name arg ?arg...? |
||
2111 | * namespace origin name |
||
2112 | * namespace parent ?name? |
||
2113 | * namespace qualifiers string |
||
2114 | * namespace tail string |
||
2115 | * namespace which ?-command? ?-variable? name |
||
2116 | * |
||
2117 | * Results: |
||
2118 | * Returns if the command is successful. Raises Exception if |
||
2119 | * anything goes wrong. |
||
2120 | * |
||
2121 | * Side effects: |
||
2122 | * Based on the subcommand name (e.g., "import"), this procedure |
||
2123 | * dispatches to a corresponding member commands in this class. |
||
2124 | * This method's side effects depend on whatever that subcommand does. |
||
2125 | *---------------------------------------------------------------------- |
||
2126 | */ |
||
2127 | |||
2128 | private static readonly string[] validCmds = new string[] { "children", "code", "current", "delete", "eval", "export", "forget", "import", "inscope", "origin", "parent", "qualifiers", "tail", "which" }; |
||
2129 | |||
2130 | private const int OPT_CHILDREN = 0; |
||
2131 | private const int OPT_CODE = 1; |
||
2132 | private const int OPT_CURRENT = 2; |
||
2133 | private const int OPT_DELETE = 3; |
||
2134 | private const int OPT_EVAL = 4; |
||
2135 | private const int OPT_EXPORT = 5; |
||
2136 | private const int OPT_FORGET = 6; |
||
2137 | private const int OPT_IMPORT = 7; |
||
2138 | private const int OPT_INSCOPE = 8; |
||
2139 | private const int OPT_ORIGIN = 9; |
||
2140 | private const int OPT_PARENT = 10; |
||
2141 | private const int OPT_QUALIFIERS = 11; |
||
2142 | private const int OPT_TAIL = 12; |
||
2143 | private const int OPT_WHICH = 13; |
||
2144 | |||
2145 | |||
2146 | public TCL.CompletionCode cmdProc( Interp interp, TclObject[] objv ) |
||
2147 | { |
||
2148 | |||
2149 | int i, opt; |
||
2150 | |||
2151 | if ( objv.Length < 2 ) |
||
2152 | { |
||
2153 | throw new TclNumArgsException( interp, 1, objv, "subcommand ?arg ...?" ); |
||
2154 | } |
||
2155 | |||
2156 | opt = TclIndex.get( interp, objv[1], validCmds, "option", 0 ); |
||
2157 | |||
2158 | switch ( opt ) |
||
2159 | { |
||
2160 | |||
2161 | case OPT_CHILDREN: |
||
2162 | { |
||
2163 | childrenCmd( interp, objv ); |
||
2164 | return TCL.CompletionCode.RETURN; |
||
2165 | } |
||
2166 | |||
2167 | case OPT_CODE: |
||
2168 | { |
||
2169 | codeCmd( interp, objv ); |
||
2170 | return TCL.CompletionCode.RETURN; |
||
2171 | } |
||
2172 | |||
2173 | case OPT_CURRENT: |
||
2174 | { |
||
2175 | currentCmd( interp, objv ); |
||
2176 | return TCL.CompletionCode.RETURN; |
||
2177 | } |
||
2178 | |||
2179 | case OPT_DELETE: |
||
2180 | { |
||
2181 | deleteCmd( interp, objv ); |
||
2182 | return TCL.CompletionCode.RETURN; |
||
2183 | } |
||
2184 | |||
2185 | case OPT_EVAL: |
||
2186 | { |
||
2187 | evalCmd( interp, objv ); |
||
2188 | return TCL.CompletionCode.RETURN; |
||
2189 | } |
||
2190 | |||
2191 | case OPT_EXPORT: |
||
2192 | { |
||
2193 | exportCmd( interp, objv ); |
||
2194 | return TCL.CompletionCode.RETURN; |
||
2195 | } |
||
2196 | |||
2197 | case OPT_FORGET: |
||
2198 | { |
||
2199 | forgetCmd( interp, objv ); |
||
2200 | return TCL.CompletionCode.RETURN; |
||
2201 | } |
||
2202 | |||
2203 | case OPT_IMPORT: |
||
2204 | { |
||
2205 | importCmd( interp, objv ); |
||
2206 | return TCL.CompletionCode.RETURN; |
||
2207 | } |
||
2208 | |||
2209 | case OPT_INSCOPE: |
||
2210 | { |
||
2211 | inscopeCmd( interp, objv ); |
||
2212 | return TCL.CompletionCode.RETURN; |
||
2213 | } |
||
2214 | |||
2215 | case OPT_ORIGIN: |
||
2216 | { |
||
2217 | originCmd( interp, objv ); |
||
2218 | return TCL.CompletionCode.RETURN; |
||
2219 | } |
||
2220 | |||
2221 | case OPT_PARENT: |
||
2222 | { |
||
2223 | parentCmd( interp, objv ); |
||
2224 | return TCL.CompletionCode.RETURN; |
||
2225 | } |
||
2226 | |||
2227 | case OPT_QUALIFIERS: |
||
2228 | { |
||
2229 | qualifiersCmd( interp, objv ); |
||
2230 | return TCL.CompletionCode.RETURN; |
||
2231 | } |
||
2232 | |||
2233 | case OPT_TAIL: |
||
2234 | { |
||
2235 | tailCmd( interp, objv ); |
||
2236 | return TCL.CompletionCode.RETURN; |
||
2237 | } |
||
2238 | |||
2239 | case OPT_WHICH: |
||
2240 | { |
||
2241 | whichCmd( interp, objv ); |
||
2242 | return TCL.CompletionCode.RETURN; |
||
2243 | } |
||
2244 | } // end switch(opt) |
||
2245 | return TCL.CompletionCode.RETURN; |
||
2246 | } |
||
2247 | |||
2248 | |||
2249 | /* |
||
2250 | *---------------------------------------------------------------------- |
||
2251 | * |
||
2252 | * NamespaceChildrenCmd -> childrenCmd |
||
2253 | * |
||
2254 | * Invoked to implement the "namespace children" command that returns a |
||
2255 | * list containing the fully-qualified names of the child namespaces of |
||
2256 | * a given namespace. Handles the following syntax: |
||
2257 | * |
||
2258 | * namespace children ?name? ?pattern? |
||
2259 | * |
||
2260 | * Results: |
||
2261 | * Nothing. |
||
2262 | * |
||
2263 | * Side effects: |
||
2264 | * Returns a result in the interpreter's result object. If anything |
||
2265 | * goes wrong, the result is an error message. |
||
2266 | * |
||
2267 | *---------------------------------------------------------------------- |
||
2268 | */ |
||
2269 | |||
2270 | private static void childrenCmd( Interp interp, TclObject[] objv ) |
||
2271 | { |
||
2272 | Namespace namespace_Renamed; |
||
2273 | Namespace ns; |
||
2274 | Namespace globalNs = getGlobalNamespace( interp ); |
||
2275 | string pattern = null; |
||
2276 | StringBuilder buffer; |
||
2277 | IEnumerator search; |
||
2278 | TclObject list, elem; |
||
2279 | |||
2280 | // Get a pointer to the specified namespace, or the current namespace. |
||
2281 | |||
2282 | if ( objv.Length == 2 ) |
||
2283 | { |
||
2284 | ns = getCurrentNamespace( interp ); |
||
2285 | } |
||
2286 | else if ( ( objv.Length == 3 ) || ( objv.Length == 4 ) ) |
||
2287 | { |
||
2288 | ns = getNamespaceFromObj( interp, objv[2] ); |
||
2289 | if ( ns == null ) |
||
2290 | { |
||
2291 | |||
2292 | throw new TclException( interp, "unknown namespace \"" + objv[2].ToString() + "\" in namespace children command" ); |
||
2293 | } |
||
2294 | } |
||
2295 | else |
||
2296 | { |
||
2297 | throw new TclNumArgsException( interp, 2, objv, "?name? ?pattern?" ); |
||
2298 | } |
||
2299 | |||
2300 | // Get the glob-style pattern, if any, used to narrow the search. |
||
2301 | |||
2302 | buffer = new StringBuilder(); |
||
2303 | if ( objv.Length == 4 ) |
||
2304 | { |
||
2305 | |||
2306 | string name = objv[3].ToString(); |
||
2307 | |||
2308 | if ( name.StartsWith( "::" ) ) |
||
2309 | { |
||
2310 | pattern = name; |
||
2311 | } |
||
2312 | else |
||
2313 | { |
||
2314 | buffer.Append( ns.fullName ); |
||
2315 | if ( ns != globalNs ) |
||
2316 | { |
||
2317 | buffer.Append( "::" ); |
||
2318 | } |
||
2319 | buffer.Append( name ); |
||
2320 | pattern = buffer.ToString(); |
||
2321 | } |
||
2322 | } |
||
2323 | |||
2324 | // Create a list containing the full names of all child namespaces |
||
2325 | // whose names match the specified pattern, if any. |
||
2326 | |||
2327 | list = TclList.newInstance(); |
||
2328 | foreach ( Namespace childNs in ns.childTable.Values ) |
||
2329 | { |
||
2330 | if ( ( (System.Object)pattern == null ) || Util.stringMatch( childNs.fullName, pattern ) ) |
||
2331 | { |
||
2332 | elem = TclString.newInstance( childNs.fullName ); |
||
2333 | TclList.append( interp, list, elem ); |
||
2334 | } |
||
2335 | } |
||
2336 | interp.setResult( list ); |
||
2337 | return; |
||
2338 | } |
||
2339 | |||
2340 | |||
2341 | /* |
||
2342 | *---------------------------------------------------------------------- |
||
2343 | * |
||
2344 | * NamespaceCodeCmd -> codeCmd |
||
2345 | * |
||
2346 | * Invoked to implement the "namespace code" command to capture the |
||
2347 | * namespace context of a command. Handles the following syntax: |
||
2348 | * |
||
2349 | * namespace code arg |
||
2350 | * |
||
2351 | * Here "arg" can be a list. "namespace code arg" produces a result |
||
2352 | * equivalent to that produced by the command |
||
2353 | * |
||
2354 | * list namespace inscope [namespace current] $arg |
||
2355 | * |
||
2356 | * However, if "arg" is itself a scoped value starting with |
||
2357 | * "namespace inscope", then the result is just "arg". |
||
2358 | * |
||
2359 | * Results: |
||
2360 | * Nothing. |
||
2361 | * |
||
2362 | * Side effects: |
||
2363 | * If anything goes wrong, this procedure returns an error |
||
2364 | * message as the result in the interpreter's result object. |
||
2365 | * |
||
2366 | *---------------------------------------------------------------------- |
||
2367 | */ |
||
2368 | |||
2369 | |||
2370 | private static void codeCmd( Interp interp, TclObject[] objv ) |
||
2371 | { |
||
2372 | Namespace currNs; |
||
2373 | TclObject list, obj; |
||
2374 | string arg, p; |
||
2375 | int length; |
||
2376 | int p_ind; |
||
2377 | |||
2378 | if ( objv.Length != 3 ) |
||
2379 | { |
||
2380 | throw new TclNumArgsException( interp, 2, objv, "arg" ); |
||
2381 | } |
||
2382 | |||
2383 | // If "arg" is already a scoped value, then return it directly. |
||
2384 | |||
2385 | |||
2386 | arg = objv[2].ToString(); |
||
2387 | length = arg.Length; |
||
2388 | |||
2389 | // FIXME : we need a test for this inscope code if there is not one already! |
||
2390 | if ( ( length > 17 ) && ( arg[0] == 'n' ) && arg.StartsWith( "namespace" ) ) |
||
2391 | { |
||
2392 | for ( p_ind = 9; ( p_ind < length ) && ( arg[p_ind] == ' ' ); p_ind++ ) |
||
2393 | { |
||
2394 | // empty body: skip over spaces |
||
2395 | } |
||
2396 | if ( ( ( length - p_ind ) >= 7 ) && ( arg[p_ind] == 'i' ) && arg.Substring( p_ind ).StartsWith( "inscope" ) ) |
||
2397 | { |
||
2398 | interp.setResult( objv[2] ); |
||
2399 | return; |
||
2400 | } |
||
2401 | } |
||
2402 | |||
2403 | // Otherwise, construct a scoped command by building a list with |
||
2404 | // "namespace inscope", the full name of the current namespace, and |
||
2405 | // the argument "arg". By constructing a list, we ensure that scoped |
||
2406 | // commands are interpreted properly when they are executed later, |
||
2407 | // by the "namespace inscope" command. |
||
2408 | |||
2409 | list = TclList.newInstance(); |
||
2410 | TclList.append( interp, list, TclString.newInstance( "namespace" ) ); |
||
2411 | TclList.append( interp, list, TclString.newInstance( "inscope" ) ); |
||
2412 | |||
2413 | currNs = getCurrentNamespace( interp ); |
||
2414 | if ( currNs == getGlobalNamespace( interp ) ) |
||
2415 | { |
||
2416 | obj = TclString.newInstance( "::" ); |
||
2417 | } |
||
2418 | else |
||
2419 | { |
||
2420 | obj = TclString.newInstance( currNs.fullName ); |
||
2421 | } |
||
2422 | |||
2423 | TclList.append( interp, list, obj ); |
||
2424 | TclList.append( interp, list, objv[2] ); |
||
2425 | |||
2426 | interp.setResult( list ); |
||
2427 | return; |
||
2428 | } |
||
2429 | |||
2430 | /* |
||
2431 | *---------------------------------------------------------------------- |
||
2432 | * |
||
2433 | * NamespaceCurrentCmd -> currentCmd |
||
2434 | * |
||
2435 | * Invoked to implement the "namespace current" command which returns |
||
2436 | * the fully-qualified name of the current namespace. Handles the |
||
2437 | * following syntax: |
||
2438 | * |
||
2439 | * namespace current |
||
2440 | * |
||
2441 | * Results: |
||
2442 | * Returns if successful, raises TclException if something goes wrong. |
||
2443 | * |
||
2444 | * Side effects: |
||
2445 | * Returns a result in the interpreter's result object. If anything |
||
2446 | * goes wrong, the result is an error message. |
||
2447 | * |
||
2448 | *---------------------------------------------------------------------- |
||
2449 | */ |
||
2450 | |||
2451 | private static void currentCmd( Interp interp, TclObject[] objv ) |
||
2452 | { |
||
2453 | |||
2454 | Namespace currNs; |
||
2455 | |||
2456 | if ( objv.Length != 2 ) |
||
2457 | { |
||
2458 | throw new TclNumArgsException( interp, 2, objv, null ); |
||
2459 | } |
||
2460 | |||
2461 | // The "real" name of the global namespace ("::") is the null string, |
||
2462 | // but we return "::" for it as a convenience to programmers. Note that |
||
2463 | // "" and "::" are treated as synonyms by the namespace code so that it |
||
2464 | // is still easy to do things like: |
||
2465 | // |
||
2466 | // namespace [namespace current]::bar { ... } |
||
2467 | |||
2468 | currNs = getCurrentNamespace( interp ); |
||
2469 | |||
2470 | if ( currNs == getGlobalNamespace( interp ) ) |
||
2471 | { |
||
2472 | // FIXME : appending to te result really screws everything up! |
||
2473 | // need to figure out how to disallow this! |
||
2474 | //TclString.append(interp.getResult(), "::"); |
||
2475 | interp.setResult( "::" ); |
||
2476 | } |
||
2477 | else |
||
2478 | { |
||
2479 | //TclString.append(interp.getResult(), currNs.fullName); |
||
2480 | interp.setResult( currNs.fullName ); |
||
2481 | } |
||
2482 | } |
||
2483 | |||
2484 | /* |
||
2485 | *---------------------------------------------------------------------- |
||
2486 | * |
||
2487 | * NamespaceDeleteCmd -> deleteCmd |
||
2488 | * |
||
2489 | * Invoked to implement the "namespace delete" command to delete |
||
2490 | * namespace(s). Handles the following syntax: |
||
2491 | * |
||
2492 | * namespace delete ?name name...? |
||
2493 | * |
||
2494 | * Each name identifies a namespace. It may include a sequence of |
||
2495 | * namespace qualifiers separated by "::"s. If a namespace is found, it |
||
2496 | * is deleted: all variables and procedures contained in that namespace |
||
2497 | * are deleted. If that namespace is being used on the call stack, it |
||
2498 | * is kept alive (but logically deleted) until it is removed from the |
||
2499 | * call stack: that is, it can no longer be referenced by name but any |
||
2500 | * currently executing procedure that refers to it is allowed to do so |
||
2501 | * until the procedure returns. If the namespace can't be found, this |
||
2502 | * procedure returns an error. If no namespaces are specified, this |
||
2503 | * command does nothing. |
||
2504 | * |
||
2505 | * Results: |
||
2506 | * Returns if successful, raises TclException if something goes wrong. |
||
2507 | * |
||
2508 | * Side effects: |
||
2509 | * Deletes the specified namespaces. If anything goes wrong, this |
||
2510 | * procedure returns an error message in the interpreter's |
||
2511 | * result object. |
||
2512 | * |
||
2513 | *---------------------------------------------------------------------- |
||
2514 | */ |
||
2515 | |||
2516 | private static void deleteCmd( Interp interp, TclObject[] objv ) |
||
2517 | { |
||
2518 | Namespace namespace_Renamed; |
||
2519 | string name; |
||
2520 | int i; |
||
2521 | |||
2522 | if ( objv.Length < 2 ) |
||
2523 | { |
||
2524 | throw new TclNumArgsException( interp, 2, objv, "?name name...?" ); |
||
2525 | } |
||
2526 | |||
2527 | // Destroying one namespace may cause another to be destroyed. Break |
||
2528 | // this into two passes: first check to make sure that all namespaces on |
||
2529 | // the command line are valid, and report any errors. |
||
2530 | |||
2531 | for ( i = 2; i < objv.Length; i++ ) |
||
2532 | { |
||
2533 | |||
2534 | name = objv[i].ToString(); |
||
2535 | namespace_Renamed = findNamespace( interp, name, null, 0 ); |
||
2536 | |||
2537 | if ( namespace_Renamed == null ) |
||
2538 | { |
||
2539 | |||
2540 | throw new TclException( interp, "unknown namespace \"" + objv[i].ToString() + "\" in namespace delete command" ); |
||
2541 | } |
||
2542 | } |
||
2543 | |||
2544 | // Okay, now delete each namespace. |
||
2545 | |||
2546 | for ( i = 2; i < objv.Length; i++ ) |
||
2547 | { |
||
2548 | |||
2549 | name = objv[i].ToString(); |
||
2550 | namespace_Renamed = findNamespace( interp, name, null, 0 ); |
||
2551 | |||
2552 | if ( namespace_Renamed != null ) |
||
2553 | { |
||
2554 | deleteNamespace( namespace_Renamed ); |
||
2555 | } |
||
2556 | } |
||
2557 | } |
||
2558 | |||
2559 | /* |
||
2560 | *---------------------------------------------------------------------- |
||
2561 | * |
||
2562 | * NamespaceEvalCmd -> evalCmd |
||
2563 | * |
||
2564 | * Invoked to implement the "namespace eval" command. Executes |
||
2565 | * commands in a namespace. If the namespace does not already exist, |
||
2566 | * it is created. Handles the following syntax: |
||
2567 | * |
||
2568 | * namespace eval name arg ?arg...? |
||
2569 | * |
||
2570 | * If more than one arg argument is specified, the command that is |
||
2571 | * executed is the result of concatenating the arguments together with |
||
2572 | * a space between each argument. |
||
2573 | * |
||
2574 | * Results: |
||
2575 | * Returns if successful, raises TclException if something goes wrong. |
||
2576 | * |
||
2577 | * Side effects: |
||
2578 | * Returns the result of the command in the interpreter's result |
||
2579 | * object. If anything goes wrong, this procedure returns an error |
||
2580 | * message as the result. |
||
2581 | * |
||
2582 | *---------------------------------------------------------------------- |
||
2583 | */ |
||
2584 | |||
2585 | private static void evalCmd( Interp interp, TclObject[] objv ) |
||
2586 | { |
||
2587 | Namespace namespace_Renamed; |
||
2588 | CallFrame frame; |
||
2589 | string cmd; |
||
2590 | string name; |
||
2591 | int length; |
||
2592 | |||
2593 | if ( objv.Length < 4 ) |
||
2594 | { |
||
2595 | throw new TclNumArgsException( interp, 2, objv, "name arg ?arg...?" ); |
||
2596 | } |
||
2597 | |||
2598 | // Try to resolve the namespace reference, caching the result in the |
||
2599 | // namespace object along the way. |
||
2600 | |||
2601 | namespace_Renamed = getNamespaceFromObj( interp, objv[2] ); |
||
2602 | |||
2603 | // If the namespace wasn't found, try to create it. |
||
2604 | |||
2605 | if ( namespace_Renamed == null ) |
||
2606 | { |
||
2607 | |||
2608 | name = objv[2].ToString(); |
||
2609 | namespace_Renamed = createNamespace( interp, name, null ); |
||
2610 | if ( namespace_Renamed == null ) |
||
2611 | { |
||
2612 | // FIXME : result hack, we get the interp result and throw it! |
||
2613 | |||
2614 | throw new TclException( interp, interp.getResult().ToString() ); |
||
2615 | } |
||
2616 | } |
||
2617 | |||
2618 | // Make the specified namespace the current namespace and evaluate |
||
2619 | // the command(s). |
||
2620 | |||
2621 | frame = interp.newCallFrame(); |
||
2622 | pushCallFrame( interp, frame, namespace_Renamed, false ); |
||
2623 | |||
2624 | try |
||
2625 | { |
||
2626 | if ( objv.Length == 4 ) |
||
2627 | { |
||
2628 | interp.eval( objv[3], 0 ); |
||
2629 | } |
||
2630 | else |
||
2631 | { |
||
2632 | cmd = Util.concat( 3, objv.Length, objv ); |
||
2633 | |||
2634 | // eval() will delete the object when it decrements its |
||
2635 | // refcount after eval'ing it. |
||
2636 | |||
2637 | interp.eval( cmd ); // do not pass TCL_EVAL_DIRECT, for compiler only |
||
2638 | } |
||
2639 | } |
||
2640 | catch ( TclException ex ) |
||
2641 | { |
||
2642 | if ( ex.getCompletionCode() == TCL.CompletionCode.ERROR ) |
||
2643 | { |
||
2644 | interp.addErrorInfo( "\n (in namespace eval \"" + namespace_Renamed.fullName + "\" script line " + interp.errorLine + ")" ); |
||
2645 | } |
||
2646 | throw ex; |
||
2647 | } |
||
2648 | finally |
||
2649 | { |
||
2650 | popCallFrame( interp ); |
||
2651 | } |
||
2652 | |||
2653 | return; |
||
2654 | } |
||
2655 | |||
2656 | |||
2657 | /* |
||
2658 | *---------------------------------------------------------------------- |
||
2659 | * |
||
2660 | * NamespaceExportCmd -> exportCmd |
||
2661 | * |
||
2662 | * Invoked to implement the "namespace export" command that specifies |
||
2663 | * which commands are exported from a namespace. The exported commands |
||
2664 | * are those that can be imported into another namespace using |
||
2665 | * "namespace import". Both commands defined in a namespace and |
||
2666 | * commands the namespace has imported can be exported by a |
||
2667 | * namespace. This command has the following syntax: |
||
2668 | * |
||
2669 | * namespace export ?-clear? ?pattern pattern...? |
||
2670 | * |
||
2671 | * Each pattern may contain "string match"-style pattern matching |
||
2672 | * special characters, but the pattern may not include any namespace |
||
2673 | * qualifiers: that is, the pattern must specify commands in the |
||
2674 | * current (exporting) namespace. The specified patterns are appended |
||
2675 | * onto the namespace's list of export patterns. |
||
2676 | * |
||
2677 | * To reset the namespace's export pattern list, specify the "-clear" |
||
2678 | * flag. |
||
2679 | * |
||
2680 | * If there are no export patterns and the "-clear" flag isn't given, |
||
2681 | * this command returns the namespace's current export list. |
||
2682 | * |
||
2683 | * Results: |
||
2684 | * Returns if successful, raises TclException if something goes wrong. |
||
2685 | * |
||
2686 | * Side effects: |
||
2687 | * Returns a result in the interpreter's result object. If anything |
||
2688 | * goes wrong, the result is an error message. |
||
2689 | * |
||
2690 | *---------------------------------------------------------------------- |
||
2691 | */ |
||
2692 | |||
2693 | |||
2694 | private static void exportCmd( Interp interp, TclObject[] objv ) |
||
2695 | { |
||
2696 | Namespace currNs = getCurrentNamespace( interp ); |
||
2697 | string pattern, inString; |
||
2698 | bool resetListFirst = false; |
||
2699 | int firstArg, patternCt, i; |
||
2700 | |||
2701 | if ( objv.Length < 2 ) |
||
2702 | { |
||
2703 | throw new TclNumArgsException( interp, 2, objv, "?-clear? ?pattern pattern...?" ); |
||
2704 | } |
||
2705 | |||
2706 | // Process the optional "-clear" argument. |
||
2707 | |||
2708 | firstArg = 2; |
||
2709 | if ( firstArg < objv.Length ) |
||
2710 | { |
||
2711 | |||
2712 | inString = objv[firstArg].ToString(); |
||
2713 | if ( inString.Equals( "-clear" ) ) |
||
2714 | { |
||
2715 | resetListFirst = true; |
||
2716 | firstArg++; |
||
2717 | } |
||
2718 | } |
||
2719 | |||
2720 | // If no pattern arguments are given, and "-clear" isn't specified, |
||
2721 | // return the namespace's current export pattern list. |
||
2722 | |||
2723 | patternCt = ( objv.Length - firstArg ); |
||
2724 | if ( patternCt == 0 ) |
||
2725 | { |
||
2726 | if ( firstArg > 2 ) |
||
2727 | { |
||
2728 | return; |
||
2729 | } |
||
2730 | else |
||
2731 | { |
||
2732 | // create list with export patterns |
||
2733 | TclObject list = TclList.newInstance(); |
||
2734 | appendExportList( interp, currNs, list ); |
||
2735 | interp.setResult( list ); |
||
2736 | return; |
||
2737 | } |
||
2738 | } |
||
2739 | |||
2740 | // Add each pattern to the namespace's export pattern list. |
||
2741 | |||
2742 | for ( i = firstArg; i < objv.Length; i++ ) |
||
2743 | { |
||
2744 | |||
2745 | pattern = objv[i].ToString(); |
||
2746 | exportList( interp, currNs, pattern, ( ( i == firstArg ) ? resetListFirst : false ) ); |
||
2747 | } |
||
2748 | return; |
||
2749 | } |
||
2750 | |||
2751 | |||
2752 | /* |
||
2753 | *---------------------------------------------------------------------- |
||
2754 | * |
||
2755 | * NamespaceForgetCmd -> forgetCmd |
||
2756 | * |
||
2757 | * Invoked to implement the "namespace forget" command to remove |
||
2758 | * imported commands from a namespace. Handles the following syntax: |
||
2759 | * |
||
2760 | * namespace forget ?pattern pattern...? |
||
2761 | * |
||
2762 | * Each pattern is a name like "foo::*" or "a::b::x*". That is, the |
||
2763 | * pattern may include the special pattern matching characters |
||
2764 | * recognized by the "string match" command, but only in the command |
||
2765 | * name at the end of the qualified name; the special pattern |
||
2766 | * characters may not appear in a namespace name. All of the commands |
||
2767 | * that match that pattern are checked to see if they have an imported |
||
2768 | * command in the current namespace that refers to the matched |
||
2769 | * command. If there is an alias, it is removed. |
||
2770 | * |
||
2771 | * Results: |
||
2772 | * Returns if successful, raises TclException if something goes wrong. |
||
2773 | * |
||
2774 | * Side effects: |
||
2775 | * Imported commands are removed from the current namespace. If |
||
2776 | * anything goes wrong, this procedure returns an error message in the |
||
2777 | * interpreter's result object. |
||
2778 | * |
||
2779 | *---------------------------------------------------------------------- |
||
2780 | */ |
||
2781 | |||
2782 | |||
2783 | private static void forgetCmd( Interp interp, TclObject[] objv ) |
||
2784 | { |
||
2785 | |||
2786 | string pattern; |
||
2787 | int i; |
||
2788 | |||
2789 | if ( objv.Length < 2 ) |
||
2790 | { |
||
2791 | throw new TclNumArgsException( interp, 2, objv, "?pattern pattern...?" ); |
||
2792 | } |
||
2793 | |||
2794 | for ( i = 2; i < objv.Length; i++ ) |
||
2795 | { |
||
2796 | |||
2797 | pattern = objv[i].ToString(); |
||
2798 | forgetImport( interp, null, pattern ); |
||
2799 | } |
||
2800 | return; |
||
2801 | } |
||
2802 | |||
2803 | |||
2804 | /* |
||
2805 | *---------------------------------------------------------------------- |
||
2806 | * |
||
2807 | * NamespaceImportCmd -> importCmd |
||
2808 | * |
||
2809 | * Invoked to implement the "namespace import" command that imports |
||
2810 | * commands into a namespace. Handles the following syntax: |
||
2811 | * |
||
2812 | * namespace import ?-force? ?pattern pattern...? |
||
2813 | * |
||
2814 | * Each pattern is a namespace-qualified name like "foo::*", |
||
2815 | * "a::b::x*", or "bar::p". That is, the pattern may include the |
||
2816 | * special pattern matching characters recognized by the "string match" |
||
2817 | * command, but only in the command name at the end of the qualified |
||
2818 | * name; the special pattern characters may not appear in a namespace |
||
2819 | * name. All of the commands that match the pattern and which are |
||
2820 | * exported from their namespace are made accessible from the current |
||
2821 | * namespace context. This is done by creating a new "imported command" |
||
2822 | * in the current namespace that points to the real command in its |
||
2823 | * original namespace; when the imported command is called, it invokes |
||
2824 | * the real command. |
||
2825 | * |
||
2826 | * If an imported command conflicts with an existing command, it is |
||
2827 | * treated as an error. But if the "-force" option is included, then |
||
2828 | * existing commands are overwritten by the imported commands. |
||
2829 | * |
||
2830 | * Results: |
||
2831 | * Returns if successful, raises TclException if something goes wrong. |
||
2832 | * |
||
2833 | * Side effects: |
||
2834 | * Adds imported commands to the current namespace. If anything goes |
||
2835 | * wrong, this procedure returns an error message in the interpreter's |
||
2836 | * result object. |
||
2837 | * |
||
2838 | *---------------------------------------------------------------------- |
||
2839 | */ |
||
2840 | |||
2841 | |||
2842 | private static void importCmd( Interp interp, TclObject[] objv ) |
||
2843 | { |
||
2844 | |||
2845 | bool allowOverwrite = false; |
||
2846 | string inString, pattern; |
||
2847 | int i; |
||
2848 | int firstArg; |
||
2849 | |||
2850 | if ( objv.Length < 2 ) |
||
2851 | { |
||
2852 | throw new TclNumArgsException( interp, 2, objv, "?-force? ?pattern pattern...?" ); |
||
2853 | } |
||
2854 | |||
2855 | // Skip over the optional "-force" as the first argument. |
||
2856 | |||
2857 | firstArg = 2; |
||
2858 | if ( firstArg < objv.Length ) |
||
2859 | { |
||
2860 | |||
2861 | inString = objv[firstArg].ToString(); |
||
2862 | if ( inString.Equals( "-force" ) ) |
||
2863 | { |
||
2864 | allowOverwrite = true; |
||
2865 | firstArg++; |
||
2866 | } |
||
2867 | } |
||
2868 | |||
2869 | // Handle the imports for each of the patterns. |
||
2870 | |||
2871 | for ( i = firstArg; i < objv.Length; i++ ) |
||
2872 | { |
||
2873 | |||
2874 | pattern = objv[i].ToString(); |
||
2875 | importList( interp, null, pattern, allowOverwrite ); |
||
2876 | } |
||
2877 | return; |
||
2878 | } |
||
2879 | |||
2880 | |||
2881 | /* |
||
2882 | *---------------------------------------------------------------------- |
||
2883 | * |
||
2884 | * NamespaceInscopeCmd -> inscopeCmd |
||
2885 | * |
||
2886 | * Invoked to implement the "namespace inscope" command that executes a |
||
2887 | * script in the context of a particular namespace. This command is not |
||
2888 | * expected to be used directly by programmers; calls to it are |
||
2889 | * generated implicitly when programs use "namespace code" commands |
||
2890 | * to register callback scripts. Handles the following syntax: |
||
2891 | * |
||
2892 | * namespace inscope name arg ?arg...? |
||
2893 | * |
||
2894 | * The "namespace inscope" command is much like the "namespace eval" |
||
2895 | * command except that it has lappend semantics and the namespace must |
||
2896 | * already exist. It treats the first argument as a list, and appends |
||
2897 | * any arguments after the first onto the end as proper list elements. |
||
2898 | * For example, |
||
2899 | * |
||
2900 | * namespace inscope ::foo a b c d |
||
2901 | * |
||
2902 | * is equivalent to |
||
2903 | * |
||
2904 | * namespace eval ::foo [concat a [list b c d]] |
||
2905 | * |
||
2906 | * This lappend semantics is important because many callback scripts |
||
2907 | * are actually prefixes. |
||
2908 | * |
||
2909 | * Results: |
||
2910 | * Returns if successful, raises TclException if something goes wrong. |
||
2911 | * |
||
2912 | * Side effects: |
||
2913 | * Returns a result in the Tcl interpreter's result object. |
||
2914 | * |
||
2915 | *---------------------------------------------------------------------- |
||
2916 | */ |
||
2917 | |||
2918 | private static void inscopeCmd( Interp interp, TclObject[] objv ) |
||
2919 | { |
||
2920 | Namespace namespace_Renamed; |
||
2921 | CallFrame frame; |
||
2922 | int i, result; |
||
2923 | |||
2924 | if ( objv.Length < 4 ) |
||
2925 | { |
||
2926 | throw new TclNumArgsException( interp, 2, objv, "name arg ?arg...?" ); |
||
2927 | } |
||
2928 | |||
2929 | // Resolve the namespace reference. |
||
2930 | |||
2931 | namespace_Renamed = getNamespaceFromObj( interp, objv[2] ); |
||
2932 | if ( namespace_Renamed == null ) |
||
2933 | { |
||
2934 | |||
2935 | throw new TclException( interp, "unknown namespace \"" + objv[2].ToString() + "\" in inscope namespace command" ); |
||
2936 | } |
||
2937 | |||
2938 | // Make the specified namespace the current namespace. |
||
2939 | |||
2940 | frame = interp.newCallFrame(); |
||
2941 | pushCallFrame( interp, frame, namespace_Renamed, false ); |
||
2942 | |||
2943 | |||
2944 | // Execute the command. If there is just one argument, just treat it as |
||
2945 | // a script and evaluate it. Otherwise, create a list from the arguments |
||
2946 | // after the first one, then concatenate the first argument and the list |
||
2947 | // of extra arguments to form the command to evaluate. |
||
2948 | |||
2949 | try |
||
2950 | { |
||
2951 | if ( objv.Length == 4 ) |
||
2952 | { |
||
2953 | interp.eval( objv[3], 0 ); |
||
2954 | } |
||
2955 | else |
||
2956 | { |
||
2957 | TclObject[] concatObjv = new TclObject[2]; |
||
2958 | TclObject list; |
||
2959 | string cmd; |
||
2960 | |||
2961 | list = TclList.newInstance(); |
||
2962 | for ( i = 4; i < objv.Length; i++ ) |
||
2963 | { |
||
2964 | try |
||
2965 | { |
||
2966 | TclList.append( interp, list, objv[i] ); |
||
2967 | } |
||
2968 | catch ( TclException ex ) |
||
2969 | { |
||
2970 | list.release(); // free unneeded obj |
||
2971 | throw ex; |
||
2972 | } |
||
2973 | } |
||
2974 | |||
2975 | concatObjv[0] = objv[3]; |
||
2976 | concatObjv[1] = list; |
||
2977 | cmd = Util.concat( 0, 1, concatObjv ); |
||
2978 | interp.eval( cmd ); // do not pass TCL_EVAL_DIRECT, for compiler only |
||
2979 | list.release(); // we're done with the list object |
||
2980 | } |
||
2981 | } |
||
2982 | catch ( TclException ex ) |
||
2983 | { |
||
2984 | if ( ex.getCompletionCode() == TCL.CompletionCode.ERROR ) |
||
2985 | { |
||
2986 | interp.addErrorInfo( "\n (in namespace inscope \"" + namespace_Renamed.fullName + "\" script line " + interp.errorLine + ")" ); |
||
2987 | } |
||
2988 | throw ex; |
||
2989 | } |
||
2990 | finally |
||
2991 | { |
||
2992 | popCallFrame( interp ); |
||
2993 | } |
||
2994 | |||
2995 | return; |
||
2996 | } |
||
2997 | |||
2998 | |||
2999 | /* |
||
3000 | *---------------------------------------------------------------------- |
||
3001 | * |
||
3002 | * NamespaceOriginCmd -> originCmd |
||
3003 | * |
||
3004 | * Invoked to implement the "namespace origin" command to return the |
||
3005 | * fully-qualified name of the "real" command to which the specified |
||
3006 | * "imported command" refers. Handles the following syntax: |
||
3007 | * |
||
3008 | * namespace origin name |
||
3009 | * |
||
3010 | * Results: |
||
3011 | * An imported command is created in an namespace when that namespace |
||
3012 | * imports a command from another namespace. If a command is imported |
||
3013 | * into a sequence of namespaces a, b,...,n where each successive |
||
3014 | * namespace just imports the command from the previous namespace, this |
||
3015 | * command returns the fully-qualified name of the original command in |
||
3016 | * the first namespace, a. If "name" does not refer to an alias, its |
||
3017 | * fully-qualified name is returned. The returned name is stored in the |
||
3018 | * interpreter's result object. This procedure returns TCL_OK if |
||
3019 | * successful, and TCL_ERROR if anything goes wrong. |
||
3020 | * |
||
3021 | * Side effects: |
||
3022 | * If anything goes wrong, this procedure returns an error message in |
||
3023 | * the interpreter's result object. |
||
3024 | * |
||
3025 | *---------------------------------------------------------------------- |
||
3026 | */ |
||
3027 | |||
3028 | private static void originCmd( Interp interp, TclObject[] objv ) |
||
3029 | { |
||
3030 | WrappedCommand command, origCommand; |
||
3031 | |||
3032 | if ( objv.Length != 3 ) |
||
3033 | { |
||
3034 | throw new TclNumArgsException( interp, 2, objv, "name" ); |
||
3035 | } |
||
3036 | |||
3037 | // FIXME : is this the right way to search for a command? |
||
3038 | |||
3039 | //command = Tcl_GetCommandFromObj(interp, objv[2]); |
||
3040 | |||
3041 | command = NamespaceCmd.findCommand( interp, objv[2].ToString(), null, 0 ); |
||
3042 | |||
3043 | if ( command == null ) |
||
3044 | { |
||
3045 | |||
3046 | throw new TclException( interp, "invalid command name \"" + objv[2].ToString() + "\"" ); |
||
3047 | } |
||
3048 | |||
3049 | origCommand = getOriginalCommand( command ); |
||
3050 | if ( origCommand == null ) |
||
3051 | { |
||
3052 | // The specified command isn't an imported command. Return the |
||
3053 | // command's name qualified by the full name of the namespace it |
||
3054 | // was defined in. |
||
3055 | |||
3056 | interp.setResult( interp.getCommandFullName( command ) ); |
||
3057 | } |
||
3058 | else |
||
3059 | { |
||
3060 | interp.setResult( interp.getCommandFullName( origCommand ) ); |
||
3061 | } |
||
3062 | return; |
||
3063 | } |
||
3064 | |||
3065 | |||
3066 | /* |
||
3067 | *---------------------------------------------------------------------- |
||
3068 | * |
||
3069 | * NamespaceParentCmd -> parentCmd |
||
3070 | * |
||
3071 | * Invoked to implement the "namespace parent" command that returns the |
||
3072 | * fully-qualified name of the parent namespace for a specified |
||
3073 | * namespace. Handles the following syntax: |
||
3074 | * |
||
3075 | * namespace parent ?name? |
||
3076 | * |
||
3077 | * Results: |
||
3078 | * Returns if successful, raises TclException if something goes wrong. |
||
3079 | * |
||
3080 | * Side effects: |
||
3081 | * Returns a result in the interpreter's result object. If anything |
||
3082 | * goes wrong, the result is an error message. |
||
3083 | * |
||
3084 | *---------------------------------------------------------------------- |
||
3085 | */ |
||
3086 | |||
3087 | private static void parentCmd( Interp interp, TclObject[] objv ) |
||
3088 | { |
||
3089 | Namespace ns; |
||
3090 | |||
3091 | if ( objv.Length == 2 ) |
||
3092 | { |
||
3093 | ns = getCurrentNamespace( interp ); |
||
3094 | } |
||
3095 | else if ( objv.Length == 3 ) |
||
3096 | { |
||
3097 | ns = getNamespaceFromObj( interp, objv[2] ); |
||
3098 | if ( ns == null ) |
||
3099 | { |
||
3100 | |||
3101 | throw new TclException( interp, "unknown namespace \"" + objv[2].ToString() + "\" in namespace parent command" ); |
||
3102 | } |
||
3103 | } |
||
3104 | else |
||
3105 | { |
||
3106 | throw new TclNumArgsException( interp, 2, objv, "?name?" ); |
||
3107 | } |
||
3108 | |||
3109 | // Report the parent of the specified namespace. |
||
3110 | |||
3111 | if ( ns.parent != null ) |
||
3112 | { |
||
3113 | interp.setResult( ns.parent.fullName ); |
||
3114 | } |
||
3115 | } |
||
3116 | |||
3117 | |||
3118 | /* |
||
3119 | *---------------------------------------------------------------------- |
||
3120 | * |
||
3121 | * NamespaceQualifiersCmd -> qualifiersCmd |
||
3122 | * |
||
3123 | * Invoked to implement the "namespace qualifiers" command that returns |
||
3124 | * any leading namespace qualifiers in a string. These qualifiers are |
||
3125 | * namespace names separated by "::"s. For example, for "::foo::p" this |
||
3126 | * command returns "::foo", and for "::" it returns "". This command |
||
3127 | * is the complement of the "namespace tail" command. Note that this |
||
3128 | * command does not check whether the "namespace" names are, in fact, |
||
3129 | * the names of currently defined namespaces. Handles the following |
||
3130 | * syntax: |
||
3131 | * |
||
3132 | * namespace qualifiers string |
||
3133 | * |
||
3134 | * Results: |
||
3135 | * Returns if successful, raises TclException if something goes wrong. |
||
3136 | * |
||
3137 | * Side effects: |
||
3138 | * Returns a result in the interpreter's result object. If anything |
||
3139 | * goes wrong, the result is an error message. |
||
3140 | * |
||
3141 | *---------------------------------------------------------------------- |
||
3142 | */ |
||
3143 | |||
3144 | private static void qualifiersCmd( Interp interp, TclObject[] objv ) |
||
3145 | { |
||
3146 | string name; |
||
3147 | int p; |
||
3148 | |||
3149 | if ( objv.Length != 3 ) |
||
3150 | { |
||
3151 | throw new TclNumArgsException( interp, 2, objv, "string" ); |
||
3152 | } |
||
3153 | |||
3154 | // Find the end of the string, then work backward and find |
||
3155 | // the start of the last "::" qualifier. |
||
3156 | |||
3157 | |||
3158 | name = objv[2].ToString(); |
||
3159 | p = name.Length; |
||
3160 | |||
3161 | while ( --p >= 0 ) |
||
3162 | { |
||
3163 | if ( ( name[p] == ':' ) && ( p > 0 ) && ( name[p - 1] == ':' ) ) |
||
3164 | { |
||
3165 | p -= 2; // back up over the :: |
||
3166 | while ( ( p >= 0 ) && ( name[p] == ':' ) ) |
||
3167 | { |
||
3168 | p--; // back up over the preceeding : |
||
3169 | } |
||
3170 | break; |
||
3171 | } |
||
3172 | } |
||
3173 | |||
3174 | if ( p >= 0 ) |
||
3175 | { |
||
3176 | interp.setResult( name.Substring( 0, ( p + 1 ) - ( 0 ) ) ); |
||
3177 | } |
||
3178 | // When no result is set the empty string is the result |
||
3179 | return; |
||
3180 | } |
||
3181 | |||
3182 | |||
3183 | /* |
||
3184 | *---------------------------------------------------------------------- |
||
3185 | * |
||
3186 | * NamespaceTailCmd -> tailCmd |
||
3187 | * |
||
3188 | * Invoked to implement the "namespace tail" command that returns the |
||
3189 | * trailing name at the end of a string with "::" namespace |
||
3190 | * qualifiers. These qualifiers are namespace names separated by |
||
3191 | * "::"s. For example, for "::foo::p" this command returns "p", and for |
||
3192 | * "::" it returns "". This command is the complement of the "namespace |
||
3193 | * qualifiers" command. Note that this command does not check whether |
||
3194 | * the "namespace" names are, in fact, the names of currently defined |
||
3195 | * namespaces. Handles the following syntax: |
||
3196 | * |
||
3197 | * namespace tail string |
||
3198 | * |
||
3199 | * Results: |
||
3200 | * Returns if successful, raises TclException if something goes wrong. |
||
3201 | * |
||
3202 | * Side effects: |
||
3203 | * Returns a result in the interpreter's result object. If anything |
||
3204 | * goes wrong, the result is an error message. |
||
3205 | * |
||
3206 | *---------------------------------------------------------------------- |
||
3207 | */ |
||
3208 | |||
3209 | |||
3210 | private static void tailCmd( Interp interp, TclObject[] objv ) |
||
3211 | { |
||
3212 | string name; |
||
3213 | int p; |
||
3214 | |||
3215 | if ( objv.Length != 3 ) |
||
3216 | { |
||
3217 | throw new TclNumArgsException( interp, 2, objv, "string" ); |
||
3218 | } |
||
3219 | |||
3220 | // Find the end of the string, then work backward and find the |
||
3221 | // last "::" qualifier. |
||
3222 | |||
3223 | |||
3224 | name = objv[2].ToString(); |
||
3225 | p = name.Length; |
||
3226 | |||
3227 | while ( --p > 0 ) |
||
3228 | { |
||
3229 | if ( ( name[p] == ':' ) && ( name[p - 1] == ':' ) ) |
||
3230 | { |
||
3231 | p++; // just after the last "::" |
||
3232 | break; |
||
3233 | } |
||
3234 | } |
||
3235 | |||
3236 | if ( p >= 0 ) |
||
3237 | { |
||
3238 | interp.setResult( name.Substring( p ) ); |
||
3239 | } |
||
3240 | return; |
||
3241 | } |
||
3242 | |||
3243 | |||
3244 | /* |
||
3245 | *---------------------------------------------------------------------- |
||
3246 | * |
||
3247 | * NamespaceWhichCmd -> whichCmd |
||
3248 | * |
||
3249 | * Invoked to implement the "namespace which" command that returns the |
||
3250 | * fully-qualified name of a command or variable. If the specified |
||
3251 | * command or variable does not exist, it returns "". Handles the |
||
3252 | * following syntax: |
||
3253 | * |
||
3254 | * namespace which ?-command? ?-variable? name |
||
3255 | * |
||
3256 | * Results: |
||
3257 | * Returns if successful, raises TclException if something goes wrong. |
||
3258 | * |
||
3259 | * Side effects: |
||
3260 | * Returns a result in the interpreter's result object. If anything |
||
3261 | * goes wrong, the result is an error message. |
||
3262 | * |
||
3263 | *---------------------------------------------------------------------- |
||
3264 | */ |
||
3265 | |||
3266 | |||
3267 | private static void whichCmd( Interp interp, TclObject[] objv ) |
||
3268 | { |
||
3269 | string arg; |
||
3270 | WrappedCommand cmd; |
||
3271 | Var variable; |
||
3272 | int argIndex, lookup; |
||
3273 | |||
3274 | if ( objv.Length < 3 ) |
||
3275 | { |
||
3276 | throw new TclNumArgsException( interp, 2, objv, "?-command? ?-variable? name" ); |
||
3277 | } |
||
3278 | |||
3279 | // Look for a flag controlling the lookup. |
||
3280 | |||
3281 | argIndex = 2; |
||
3282 | lookup = 0; // assume command lookup by default |
||
3283 | |||
3284 | arg = objv[2].ToString(); |
||
3285 | if ( ( arg.Length > 1 ) && ( arg[0] == '-' ) ) |
||
3286 | { |
||
3287 | if ( arg.Equals( "-command" ) ) |
||
3288 | { |
||
3289 | lookup = 0; |
||
3290 | } |
||
3291 | else if ( arg.Equals( "-variable" ) ) |
||
3292 | { |
||
3293 | lookup = 1; |
||
3294 | } |
||
3295 | else |
||
3296 | { |
||
3297 | throw new TclNumArgsException( interp, 2, objv, "?-command? ?-variable? name" ); |
||
3298 | } |
||
3299 | argIndex = 3; |
||
3300 | } |
||
3301 | if ( objv.Length != ( argIndex + 1 ) ) |
||
3302 | { |
||
3303 | throw new TclNumArgsException( interp, 2, objv, "?-command? ?-variable? name" ); |
||
3304 | } |
||
3305 | |||
3306 | // FIXME : check that this implementation works! |
||
3307 | |||
3308 | switch ( lookup ) |
||
3309 | { |
||
3310 | |||
3311 | case 0: |
||
3312 | |||
3313 | arg = objv[argIndex].ToString(); |
||
3314 | |||
3315 | // FIXME : is this the right way to lookup a Command token? |
||
3316 | //cmd = Tcl_GetCommandFromObj(interp, objv[argIndex]); |
||
3317 | cmd = NamespaceCmd.findCommand( interp, arg, null, 0 ); |
||
3318 | |||
3319 | if ( cmd == null ) |
||
3320 | { |
||
3321 | return; // cmd not found, just return (no error) |
||
3322 | } |
||
3323 | interp.setResult( interp.getCommandFullName( cmd ) ); |
||
3324 | return; |
||
3325 | |||
3326 | |||
3327 | case 1: |
||
3328 | |||
3329 | arg = objv[argIndex].ToString(); |
||
3330 | variable = NamespaceCmd.findNamespaceVar( interp, arg, null, 0 ); |
||
3331 | if ( variable != null ) |
||
3332 | { |
||
3333 | interp.setResult( Var.getVariableFullName( interp, variable ) ); |
||
3334 | } |
||
3335 | return; |
||
3336 | } |
||
3337 | |||
3338 | return; |
||
3339 | } |
||
3340 | |||
3341 | |||
3342 | /* |
||
3343 | *---------------------------------------------------------------------- |
||
3344 | * |
||
3345 | * FreeNsNameInternalRep -> dispose |
||
3346 | * |
||
3347 | * Frees the resources associated with a object's internal |
||
3348 | * representation. See src/tcljava/tcl/lang/InternalRep.java |
||
3349 | * |
||
3350 | * Results: |
||
3351 | * None. |
||
3352 | * |
||
3353 | * Side effects: |
||
3354 | * Decrements the ref count of any Namespace structure pointed |
||
3355 | * to by the nsName's internal representation. If there are no more |
||
3356 | * references to the namespace, it's structure will be freed. |
||
3357 | * |
||
3358 | *---------------------------------------------------------------------- |
||
3359 | */ |
||
3360 | |||
3361 | public void dispose() |
||
3362 | { |
||
3363 | bool debug; |
||
3364 | System.Diagnostics.Debug.WriteLine( "dispose() called for namespace object " + ( otherValue == null ? null : otherValue.ns ) ); |
||
3365 | |||
3366 | ResolvedNsName resName = otherValue; |
||
3367 | Namespace ns; |
||
3368 | |||
3369 | // Decrement the reference count of the namespace. If there are no |
||
3370 | // more references, free it up. |
||
3371 | |||
3372 | if ( resName != null ) |
||
3373 | { |
||
3374 | resName.refCount--; |
||
3375 | if ( resName.refCount == 0 ) |
||
3376 | { |
||
3377 | |||
3378 | // Decrement the reference count for the cached namespace. If |
||
3379 | // the namespace is dead, and there are no more references to |
||
3380 | // it, free it. |
||
3381 | |||
3382 | ns = resName.ns; |
||
3383 | ns.refCount--; |
||
3384 | if ( ( ns.refCount == 0 ) && ( ( ns.flags & NS_DEAD ) != 0 ) ) |
||
3385 | { |
||
3386 | free( ns ); |
||
3387 | } |
||
3388 | otherValue = null; |
||
3389 | } |
||
3390 | } |
||
3391 | } |
||
3392 | |||
3393 | |||
3394 | /* |
||
3395 | *---------------------------------------------------------------------- |
||
3396 | * |
||
3397 | * DupNsNameInternalRep -> duplicate |
||
3398 | * |
||
3399 | * Get a copy of this Object for copy-on-write |
||
3400 | * operations. We just increment its useCount and return the same |
||
3401 | * ReflectObject because ReflectObject's cannot be modified, so |
||
3402 | * they don't need copy-on-write protections. |
||
3403 | * |
||
3404 | * Results: |
||
3405 | * None. |
||
3406 | * |
||
3407 | * Side effects: |
||
3408 | * None. |
||
3409 | * |
||
3410 | *---------------------------------------------------------------------- |
||
3411 | */ |
||
3412 | |||
3413 | public InternalRep duplicate() |
||
3414 | { |
||
3415 | System.Diagnostics.Debug.WriteLine( "duplicate() called for namespace object " + ( otherValue == null ? null : otherValue.ns ) ); |
||
3416 | |||
3417 | ResolvedNsName resName = otherValue; |
||
3418 | |||
3419 | if ( resName != null ) |
||
3420 | { |
||
3421 | resName.refCount++; |
||
3422 | } |
||
3423 | |||
3424 | return this; |
||
3425 | } |
||
3426 | |||
3427 | |||
3428 | /* |
||
3429 | *---------------------------------------------------------------------- |
||
3430 | * |
||
3431 | * SetNsNameFromAny -> setNsNameFromAny |
||
3432 | * |
||
3433 | * Attempt to generate a nsName internal representation for a |
||
3434 | * TclObject. |
||
3435 | * |
||
3436 | * Results: |
||
3437 | * Returns if the value could be converted to a proper |
||
3438 | * namespace reference. Otherwise, raises TclException. |
||
3439 | * |
||
3440 | * Side effects: |
||
3441 | * If successful, the object is made a nsName object. Its internal rep |
||
3442 | * is set to point to a ResolvedNsName, which contains a cached pointer |
||
3443 | * to the Namespace. Reference counts are kept on both the |
||
3444 | * ResolvedNsName and the Namespace, so we can keep track of their |
||
3445 | * usage and free them when appropriate. |
||
3446 | * |
||
3447 | *---------------------------------------------------------------------- |
||
3448 | */ |
||
3449 | |||
3450 | private static void setNsNameFromAny( Interp interp, TclObject tobj ) |
||
3451 | { |
||
3452 | string name; |
||
3453 | Namespace ns; |
||
3454 | ResolvedNsName resName; |
||
3455 | |||
3456 | // Java does not support passing an address so we pass |
||
3457 | // an array of size 1 and then assign arr[0] to the value |
||
3458 | Namespace[] nsArr = new Namespace[1]; |
||
3459 | Namespace[] dummy1Arr = new Namespace[1]; |
||
3460 | string[] dummy2Arr = new string[1]; |
||
3461 | |||
3462 | // Get the string representation. |
||
3463 | |||
3464 | name = tobj.ToString(); |
||
3465 | |||
3466 | // Look for the namespace "name" in the current namespace. If there is |
||
3467 | // an error parsing the (possibly qualified) name, return an error. |
||
3468 | // If the namespace isn't found, we convert the object to an nsName |
||
3469 | // object with a null ResolvedNsName internal rep. |
||
3470 | |||
3471 | getNamespaceForQualName( interp, name, null, TCL.VarFlag.FIND_ONLY_NS, nsArr, dummy1Arr, dummy1Arr, dummy2Arr ); |
||
3472 | |||
3473 | |||
3474 | // Get the values out of the arrays! |
||
3475 | ns = nsArr[0]; |
||
3476 | |||
3477 | // If we found a namespace, then create a new ResolvedNsName structure |
||
3478 | // that holds a reference to it. |
||
3479 | |||
3480 | if ( ns != null ) |
||
3481 | { |
||
3482 | Namespace currNs = getCurrentNamespace( interp ); |
||
3483 | |||
3484 | ns.refCount++; |
||
3485 | resName = new ResolvedNsName(); |
||
3486 | resName.ns = ns; |
||
3487 | resName.nsId = ns.nsId; |
||
3488 | resName.refNs = currNs; |
||
3489 | resName.refCount = 1; |
||
3490 | } |
||
3491 | else |
||
3492 | { |
||
3493 | resName = null; |
||
3494 | } |
||
3495 | |||
3496 | // By setting the new internal rep we free up the old one. |
||
3497 | |||
3498 | // FIXME : should a NamespaceCmd wrap a ResolvedNsName? |
||
3499 | // this is confusing because it seems like the C code uses |
||
3500 | // a ResolvedNsName like it is the InternalRep. |
||
3501 | |||
3502 | NamespaceCmd wrap = new NamespaceCmd(); |
||
3503 | wrap.otherValue = resName; |
||
3504 | tobj.InternalRep = wrap; |
||
3505 | |||
3506 | return; |
||
3507 | } |
||
3508 | |||
3509 | |||
3510 | /* |
||
3511 | *---------------------------------------------------------------------- |
||
3512 | * |
||
3513 | * UpdateStringOfNsName -> toString |
||
3514 | * |
||
3515 | * Return the string representation for a nsName object. |
||
3516 | * This method is called only by TclObject.toString() |
||
3517 | * when TclObject.stringRep is null. |
||
3518 | * |
||
3519 | * Results: |
||
3520 | * None. |
||
3521 | * |
||
3522 | * Side effects: |
||
3523 | * None. |
||
3524 | * |
||
3525 | *---------------------------------------------------------------------- |
||
3526 | */ |
||
3527 | |||
3528 | public override string ToString() |
||
3529 | { |
||
3530 | bool debug; |
||
3531 | |||
3532 | System.Diagnostics.Debug.WriteLine( "toString() called for namespace object " + ( otherValue == null ? null : otherValue.ns ) ); |
||
3533 | |||
3534 | ResolvedNsName resName = otherValue; |
||
3535 | Namespace ns; |
||
3536 | string name = ""; |
||
3537 | |||
3538 | if ( ( resName != null ) && ( resName.nsId == resName.ns.nsId ) ) |
||
3539 | { |
||
3540 | ns = resName.ns; |
||
3541 | if ( ( ns.flags & NS_DEAD ) != 0 ) |
||
3542 | { |
||
3543 | ns = null; |
||
3544 | } |
||
3545 | if ( ns != null ) |
||
3546 | { |
||
3547 | name = ns.fullName; |
||
3548 | } |
||
3549 | } |
||
3550 | |||
3551 | return name; |
||
3552 | } |
||
3553 | |||
3554 | |||
3555 | // This interface is used to provide a callback when a namespace is deleted |
||
3556 | // (ported Tcl_NamespaceDeleteProc to NamespaceCmd.DeleteProc) |
||
3557 | |||
3558 | internal interface DeleteProc |
||
3559 | { |
||
3560 | void delete(); |
||
3561 | } |
||
3562 | |||
3563 | |||
3564 | // This structure contains a cached pointer to a namespace that is the |
||
3565 | // result of resolving the namespace's name in some other namespace. It is |
||
3566 | // the internal representation for a nsName object. It contains the |
||
3567 | // pointer along with some information that is used to check the cached |
||
3568 | // pointer's validity. (ported Tcl_Namespace to NamespaceCmd.Namespace) |
||
3569 | |||
3570 | public class Namespace |
||
3571 | { |
||
3572 | internal string name; // The namespace's simple (unqualified) |
||
3573 | // name. This contains no ::'s. The name of |
||
3574 | // the global namespace is "" although "::" |
||
3575 | // is an synonym. |
||
3576 | |||
3577 | internal string fullName; // The namespace's fully qualified name. |
||
3578 | // This starts with ::. |
||
3579 | |||
3580 | internal DeleteProc deleteProc; // method to invoke when namespace is deleted |
||
3581 | |||
3582 | internal Namespace parent; // reference to the namespace that contains |
||
3583 | // this one. null is this is the global namespace. |
||
3584 | |||
3585 | internal Hashtable childTable; // Contains any child namespaces. Indexed |
||
3586 | // by strings; values are references to |
||
3587 | // Namespace objects |
||
3588 | |||
3589 | internal long nsId; // Unique id for the namespace. |
||
3590 | internal Interp interp; // The interpreter containing this namespace. |
||
3591 | |||
3592 | internal int flags; // OR-ed combination of the namespace |
||
3593 | // status flags NS_DYING and NS_DEAD (listed below) |
||
3594 | |||
3595 | internal int activationCount; // Number of "activations" or active call |
||
3596 | // frames for this namespace that are on |
||
3597 | // the Tcl call stack. The namespace won't |
||
3598 | // be freed until activationCount becomes zero. |
||
3599 | |||
3600 | internal int refCount; // Count of references by nsName |
||
3601 | // objects. The namespace can't be freed |
||
3602 | // until refCount becomes zero. |
||
3603 | |||
3604 | internal Hashtable cmdTable; // Contains all the commands currently |
||
3605 | // registered in the namespace. Indexed by |
||
3606 | // strings; values have type (WrappedCommand). |
||
3607 | // Commands imported by Tcl_Import have |
||
3608 | // Command structures that point (via an |
||
3609 | // ImportedCmdRef structure) to the |
||
3610 | // Command structure in the source |
||
3611 | // namespace's command table. |
||
3612 | |||
3613 | internal Hashtable varTable; // Contains all the (global) variables |
||
3614 | // currently in this namespace. Indexed |
||
3615 | // by strings; values have type (Var). |
||
3616 | |||
3617 | internal string[] exportArray; // Reference to an array of string patterns |
||
3618 | // specifying which commands are exported. |
||
3619 | // A pattern may include "string match" |
||
3620 | // style wildcard characters to specify |
||
3621 | // multiple commands; however, no namespace |
||
3622 | // qualifiers are allowed. null if no |
||
3623 | // export patterns are registered. |
||
3624 | |||
3625 | internal int numExportPatterns; // Number of export patterns currently |
||
3626 | // registered using "namespace export". |
||
3627 | |||
3628 | internal int maxExportPatterns; // Mumber of export patterns for which |
||
3629 | // space is currently allocated. |
||
3630 | |||
3631 | |||
3632 | internal Resolver resolver; |
||
3633 | // If non-null, this object overrides the |
||
3634 | // usual command and variable resolution |
||
3635 | // mechanism in Tcl. This procedure is invoked |
||
3636 | // within findCommand and findNamespaceVar to |
||
3637 | // resolve all command and variable references |
||
3638 | // within the namespace. |
||
3639 | |||
3640 | // When printing out a Namespace use the full namespace name string |
||
3641 | |||
3642 | public override string ToString() |
||
3643 | { |
||
3644 | return fullName; |
||
3645 | } |
||
3646 | } |
||
3647 | |||
3648 | |||
3649 | // (ported ResolvedNsName to NamespaceCmd.ResolvedNsName) |
||
3650 | |||
3651 | internal class ResolvedNsName |
||
3652 | { |
||
3653 | internal Namespace ns; // reference to namespace object |
||
3654 | internal long nsId; // sPtr's unique namespace id. Used to |
||
3655 | // verify that ns is still valid |
||
3656 | // (e.g., it's possible that the namespace |
||
3657 | // was deleted and a new one created at |
||
3658 | // the same address). |
||
3659 | |||
3660 | internal Namespace refNs; // reference to the namespace containing the |
||
3661 | // reference (not the namespace that |
||
3662 | // contains the referenced namespace). |
||
3663 | internal int refCount; // Reference count: 1 for each nsName |
||
3664 | // object that has a pointer to this |
||
3665 | // ResolvedNsName structure as its internal |
||
3666 | // rep. This structure can be freed when |
||
3667 | // refCount becomes zero. |
||
3668 | } |
||
3669 | static NamespaceCmd() |
||
3670 | { |
||
3671 | nsMutex = new System.Object(); |
||
3672 | } |
||
3673 | } |
||
3674 | } |