wasCSharpSQLite – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*
2 * InterpSlaveCmd.java --
3 *
4 * Implements the built-in "interp" Tcl command.
5 *
6 * Copyright (c) 2000 Christian Krone.
7 *
8 * See the file "license.terms" for information on usage and
9 * redistribution of this file, and for a DISCLAIMER OF ALL
10 * WARRANTIES.
11 *
12 * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
13 *
14 * RCS @(#) $Id: InterpSlaveCmd.java,v 1.1 2000/08/20 06:08:43 mo Exp $
15 *
16 */
17 using System;
18 using System.Collections;
19  
20 namespace tcl.lang
21 {
22  
23 /// <summary> This class implements the slave interpreter commands, which are created
24 /// in response to the built-in "interp create" command in Tcl.
25 ///
26 /// It is also used by the "interp" command to record and find information
27 /// about slave interpreters. Maps from a command name in the master to
28 /// information about a slave interpreter, e.g. what aliases are defined
29 /// in it.
30 /// </summary>
31  
32 class InterpSlaveCmd : CommandWithDispose, AssocData
33 {
34  
35 private static readonly string[] options = new string[] { "alias", "aliases", "eval", "expose", "hide", "hidden", "issafe", "invokehidden", "marktrusted" };
36 private const int OPT_ALIAS = 0;
37 private const int OPT_ALIASES = 1;
38 private const int OPT_EVAL = 2;
39 private const int OPT_EXPOSE = 3;
40 private const int OPT_HIDE = 4;
41 private const int OPT_HIDDEN = 5;
42 private const int OPT_ISSAFE = 6;
43 private const int OPT_INVOKEHIDDEN = 7;
44 private const int OPT_MARKTRUSTED = 8;
45  
46 private static readonly string[] hiddenOptions = new string[] { "-global", "--" };
47 private const int OPT_HIDDEN_GLOBAL = 0;
48 private const int OPT_HIDDEN_LAST = 1;
49  
50 // Master interpreter for this slave.
51  
52 internal Interp masterInterp;
53  
54 // Hash entry in masters slave table for this slave interpreter.
55 // Used to find this record, and used when deleting the slave interpreter
56 // to delete it from the master's table.
57  
58 internal string path;
59  
60 // The slave interpreter.
61  
62 internal Interp slaveInterp;
63  
64 // Interpreter object command.
65  
66 internal WrappedCommand interpCmd;
67 public TCL.CompletionCode cmdProc( Interp interp, TclObject[] objv )
68 {
69 if ( objv.Length < 2 )
70 {
71 throw new TclNumArgsException( interp, 1, objv, "cmd ?arg ...?" );
72 }
73 int cmd = TclIndex.get( interp, objv[1], options, "option", 0 );
74  
75 switch ( cmd )
76 {
77  
78 case OPT_ALIAS:
79 if ( objv.Length == 3 )
80 {
81 InterpAliasCmd.describe( interp, slaveInterp, objv[2] );
82 return TCL.CompletionCode.RETURN;
83 }
84  
85 if ( "".Equals( objv[3].ToString() ) )
86 {
87 if ( objv.Length == 4 )
88 {
89 InterpAliasCmd.delete( interp, slaveInterp, objv[2] );
90 return TCL.CompletionCode.RETURN;
91 }
92 }
93 else
94 {
95 InterpAliasCmd.create( interp, slaveInterp, interp, objv[2], objv[3], 4, objv );
96 return TCL.CompletionCode.RETURN;
97 }
98 throw new TclNumArgsException( interp, 2, objv, "aliasName ?targetName? ?args..?" );
99  
100 case OPT_ALIASES:
101 InterpAliasCmd.list( interp, slaveInterp );
102 break;
103  
104 case OPT_EVAL:
105 if ( objv.Length < 3 )
106 {
107 throw new TclNumArgsException( interp, 2, objv, "arg ?arg ...?" );
108 }
109 eval( interp, slaveInterp, 2, objv );
110 break;
111  
112 case OPT_EXPOSE:
113 if ( objv.Length < 3 || objv.Length > 4 )
114 {
115 throw new TclNumArgsException( interp, 2, objv, "hiddenCmdName ?cmdName?" );
116 }
117 expose( interp, slaveInterp, 2, objv );
118 break;
119  
120 case OPT_HIDE:
121 if ( objv.Length < 3 || objv.Length > 4 )
122 {
123 throw new TclNumArgsException( interp, 2, objv, "cmdName ?hiddenCmdName?" );
124 }
125 hide( interp, slaveInterp, 2, objv );
126 break;
127  
128 case OPT_HIDDEN:
129 if ( objv.Length != 2 )
130 {
131 throw new TclNumArgsException( interp, 2, objv, null );
132 }
133 InterpSlaveCmd.hidden( interp, slaveInterp );
134 break;
135  
136 case OPT_ISSAFE:
137 interp.setResult( slaveInterp.isSafe );
138 break;
139  
140 case OPT_INVOKEHIDDEN:
141 bool global = false;
142 int i;
143 for ( i = 2; i < objv.Length; i++ )
144 {
145  
146 if ( objv[i].ToString()[0] != '-' )
147 {
148 break;
149 }
150 int index = TclIndex.get( interp, objv[i], hiddenOptions, "option", 0 );
151 if ( index == OPT_HIDDEN_GLOBAL )
152 {
153 global = true;
154 }
155 else
156 {
157 i++;
158 break;
159 }
160 }
161 if ( objv.Length - i < 1 )
162 {
163 throw new TclNumArgsException( interp, 2, objv, "?-global? ?--? cmd ?arg ..?" );
164 }
165 InterpSlaveCmd.invokeHidden( interp, slaveInterp, global, i, objv );
166 break;
167  
168 case OPT_MARKTRUSTED:
169 if ( objv.Length != 2 )
170 {
171 throw new TclNumArgsException( interp, 2, objv, null );
172 }
173 markTrusted( interp, slaveInterp );
174 break;
175 }
176 return TCL.CompletionCode.RETURN;
177 }
178 /// <summary>----------------------------------------------------------------------
179 ///
180 /// disposeCmd --
181 ///
182 /// Invoked when an object command for a slave interpreter is deleted;
183 /// cleans up all state associated with the slave interpreter and destroys
184 /// the slave interpreter.
185 ///
186 /// Results:
187 /// None.
188 ///
189 /// Side effects:
190 /// Cleans up all state associated with the slave interpreter and
191 /// destroys the slave interpreter.
192 ///
193 /// ----------------------------------------------------------------------
194 /// </summary>
195  
196 public void disposeCmd()
197 {
198 // Unlink the slave from its master interpreter.
199  
200 SupportClass.HashtableRemove( masterInterp.slaveTable, path );
201  
202 // Set to null so that when the InterpInfo is cleaned up in the slave
203 // it does not try to delete the command causing all sorts of grief.
204 // See SlaveRecordDeleteProc().
205  
206 interpCmd = null;
207  
208 if ( slaveInterp != null )
209 {
210 slaveInterp.dispose();
211 }
212 }
213 public void disposeAssocData( Interp interp )
214 // Current interpreter.
215 {
216 // There shouldn't be any commands left.
217  
218 if ( !( interp.slaveTable.Count == 0 ) )
219 {
220 System.Console.Error.WriteLine( "InterpInfoDeleteProc: still exist commands" );
221 }
222 interp.slaveTable = null;
223  
224 // Tell any interps that have aliases to this interp that they should
225 // delete those aliases. If the other interp was already dead, it
226 // would have removed the target record already.
227  
228 // TODO ATK
229 foreach ( WrappedCommand slaveCmd in new ArrayList( interp.targetTable.Keys ) )
230 {
231 Interp slaveInterp = (Interp)interp.targetTable[slaveCmd];
232 slaveInterp.deleteCommandFromToken( slaveCmd );
233 }
234 interp.targetTable = null;
235  
236 if ( interp.interpChanTable != null )
237 {
238 foreach ( Channel channel in new ArrayList( interp.interpChanTable.Values ) )
239 {
240 TclIO.unregisterChannel( interp, channel );
241 }
242 }
243  
244 if ( interp.slave.interpCmd != null )
245 {
246 // Tcl_DeleteInterp() was called on this interpreter, rather
247 // "interp delete" or the equivalent deletion of the command in the
248 // master. First ensure that the cleanup callback doesn't try to
249 // delete the interp again.
250  
251 interp.slave.slaveInterp = null;
252 interp.slave.masterInterp.deleteCommandFromToken( interp.slave.interpCmd );
253 }
254  
255 // There shouldn't be any aliases left.
256  
257 if ( !( interp.aliasTable.Count == 0 ) )
258 {
259 System.Console.Error.WriteLine( "InterpInfoDeleteProc: still exist aliases" );
260 }
261 interp.aliasTable = null;
262 }
263 internal static Interp create( Interp interp, TclObject path, bool safe )
264 {
265 Interp masterInterp;
266 string pathString;
267  
268 TclObject[] objv = TclList.getElements( interp, path );
269  
270 if ( objv.Length < 2 )
271 {
272 masterInterp = interp;
273  
274 pathString = path.ToString();
275 }
276 else
277 {
278 TclObject obj = TclList.newInstance();
279  
280 TclList.insert( interp, obj, 0, objv, 0, objv.Length - 2 );
281 masterInterp = InterpCmd.getInterp( interp, obj );
282  
283 pathString = objv[objv.Length - 1].ToString();
284 }
285 if ( !safe )
286 {
287 safe = masterInterp.isSafe;
288 }
289  
290 if ( masterInterp.slaveTable.ContainsKey( pathString ) )
291 {
292 throw new TclException( interp, "interpreter named \"" + pathString + "\" already exists, cannot create" );
293 }
294  
295 Interp slaveInterp = new Interp();
296 InterpSlaveCmd slave = new InterpSlaveCmd();
297  
298 slaveInterp.slave = slave;
299 slaveInterp.setAssocData( "InterpSlaveCmd", slave );
300  
301 slave.masterInterp = masterInterp;
302 slave.path = pathString;
303 slave.slaveInterp = slaveInterp;
304  
305 masterInterp.createCommand( pathString, slaveInterp.slave );
306 slaveInterp.slave.interpCmd = NamespaceCmd.findCommand( masterInterp, pathString, null, 0 );
307  
308 SupportClass.PutElement( masterInterp.slaveTable, pathString, slaveInterp.slave );
309  
310 slaveInterp.setVar( "tcl_interactive", "0", TCL.VarFlag.GLOBAL_ONLY );
311  
312 // Inherit the recursion limit.
313  
314 slaveInterp.maxNestingDepth = masterInterp.maxNestingDepth;
315  
316 if ( safe )
317 {
318 try
319 {
320 makeSafe( slaveInterp );
321 }
322 catch ( TclException e )
323 {
324 SupportClass.WriteStackTrace( e, Console.Error );
325 }
326 }
327 else
328 {
329 //Tcl_Init(slaveInterp);
330 }
331  
332 return slaveInterp;
333 }
334 internal static void eval( Interp interp, Interp slaveInterp, int objIx, TclObject[] objv )
335 {
336 TCL.CompletionCode result;
337  
338 slaveInterp.preserve();
339 slaveInterp.allowExceptions();
340  
341 try
342 {
343 if ( objIx + 1 == objv.Length )
344 {
345 slaveInterp.eval( objv[objIx], 0 );
346 }
347 else
348 {
349 TclObject obj = TclList.newInstance();
350 for ( int ix = objIx; ix < objv.Length; ix++ )
351 {
352 TclList.append( interp, obj, objv[ix] );
353 }
354 obj.preserve();
355 slaveInterp.eval( obj, 0 );
356 obj.release();
357 }
358 result = slaveInterp.returnCode;
359 }
360 catch ( TclException e )
361 {
362 result = e.getCompletionCode();
363 }
364  
365 slaveInterp.release();
366 interp.transferResult( slaveInterp, result );
367 }
368 internal static void expose( Interp interp, Interp slaveInterp, int objIx, TclObject[] objv )
369 {
370 if ( interp.isSafe )
371 {
372 throw new TclException( interp, "permission denied: " + "safe interpreter cannot expose commands" );
373 }
374  
375 int nameIdx = objv.Length - objIx == 1 ? objIx : objIx + 1;
376  
377 try
378 {
379  
380 slaveInterp.exposeCommand( objv[objIx].ToString(), objv[nameIdx].ToString() );
381 }
382 catch ( TclException e )
383 {
384 interp.transferResult( slaveInterp, e.getCompletionCode() );
385 throw;
386 }
387 }
388 internal static void hide( Interp interp, Interp slaveInterp, int objIx, TclObject[] objv )
389 {
390 if ( interp.isSafe )
391 {
392 throw new TclException( interp, "permission denied: " + "safe interpreter cannot hide commands" );
393 }
394  
395 int nameIdx = objv.Length - objIx == 1 ? objIx : objIx + 1;
396  
397 try
398 {
399  
400 slaveInterp.hideCommand( objv[objIx].ToString(), objv[nameIdx].ToString() );
401 }
402 catch ( TclException e )
403 {
404 interp.transferResult( slaveInterp, e.getCompletionCode() );
405 throw;
406 }
407 }
408 internal static void hidden( Interp interp, Interp slaveInterp )
409 {
410 if ( slaveInterp.hiddenCmdTable == null )
411 {
412 return;
413 }
414  
415 TclObject result = TclList.newInstance();
416 interp.setResult( result );
417  
418 IEnumerator hiddenCmds = slaveInterp.hiddenCmdTable.Keys.GetEnumerator();
419 while ( hiddenCmds.MoveNext() )
420 {
421 string cmdName = (string)hiddenCmds.Current;
422 TclList.append( interp, result, TclString.newInstance( cmdName ) );
423 }
424 }
425 internal static void invokeHidden( Interp interp, Interp slaveInterp, bool global, int objIx, TclObject[] objv )
426 {
427 TCL.CompletionCode result;
428  
429 if ( interp.isSafe )
430 {
431 throw new TclException( interp, "not allowed to " + "invoke hidden commands from safe interpreter" );
432 }
433  
434 slaveInterp.preserve();
435 slaveInterp.allowExceptions();
436  
437 TclObject[] localObjv = new TclObject[objv.Length - objIx];
438 for ( int i = 0; i < objv.Length - objIx; i++ )
439 {
440 localObjv[i] = objv[i + objIx];
441 }
442  
443 try
444 {
445 if ( global )
446 {
447 slaveInterp.invokeGlobal( localObjv, Interp.INVOKE_HIDDEN );
448 }
449 else
450 {
451 slaveInterp.invoke( localObjv, Interp.INVOKE_HIDDEN );
452 }
453 result = slaveInterp.returnCode;
454 }
455 catch ( TclException e )
456 {
457 result = e.getCompletionCode();
458 }
459  
460 slaveInterp.release();
461 interp.transferResult( slaveInterp, result );
462 }
463 internal static void markTrusted( Interp interp, Interp slaveInterp )
464 {
465 if ( interp.isSafe )
466 {
467 throw new TclException( interp, "permission denied: " + "safe interpreter cannot mark trusted" );
468 }
469 slaveInterp.isSafe = false;
470 }
471 private static void makeSafe( Interp interp )
472 {
473 Channel chan; // Channel to remove from safe interpreter.
474  
475 interp.hideUnsafeCommands();
476  
477 interp.isSafe = true;
478  
479 // Unsetting variables : (which should not have been set
480 // in the first place, but...)
481  
482 // No env array in a safe slave.
483  
484 try
485 {
486 interp.unsetVar( "env", TCL.VarFlag.GLOBAL_ONLY );
487 }
488 catch ( TclException e )
489 {
490 }
491  
492 // Remove unsafe parts of tcl_platform
493  
494 try
495 {
496 interp.unsetVar( "tcl_platform", "os", TCL.VarFlag.GLOBAL_ONLY );
497 }
498 catch ( TclException e )
499 {
500 }
501 try
502 {
503 interp.unsetVar( "tcl_platform", "osVersion", TCL.VarFlag.GLOBAL_ONLY );
504 }
505 catch ( TclException e )
506 {
507 }
508 try
509 {
510 interp.unsetVar( "tcl_platform", "machine", TCL.VarFlag.GLOBAL_ONLY );
511 }
512 catch ( TclException e )
513 {
514 }
515 try
516 {
517 interp.unsetVar( "tcl_platform", "user", TCL.VarFlag.GLOBAL_ONLY );
518 }
519 catch ( TclException e )
520 {
521 }
522  
523 // Unset path informations variables
524 // (the only one remaining is [info nameofexecutable])
525  
526 try
527 {
528 interp.unsetVar( "tclDefaultLibrary", TCL.VarFlag.GLOBAL_ONLY );
529 }
530 catch ( TclException e )
531 {
532 }
533 try
534 {
535 interp.unsetVar( "tcl_library", TCL.VarFlag.GLOBAL_ONLY );
536 }
537 catch ( TclException e )
538 {
539 }
540 try
541 {
542 interp.unsetVar( "tcl_pkgPath", TCL.VarFlag.GLOBAL_ONLY );
543 }
544 catch ( TclException e )
545 {
546 }
547  
548 // Remove the standard channels from the interpreter; safe interpreters
549 // do not ordinarily have access to stdin, stdout and stderr.
550 //
551 // NOTE: These channels are not added to the interpreter by the
552 // Tcl_CreateInterp call, but may be added later, by another I/O
553 // operation. We want to ensure that the interpreter does not have
554 // these channels even if it is being made safe after being used for
555 // some time..
556  
557 chan = TclIO.getStdChannel( StdChannel.STDIN );
558 if ( chan != null )
559 {
560 TclIO.unregisterChannel( interp, chan );
561 }
562 chan = TclIO.getStdChannel( StdChannel.STDOUT );
563 if ( chan != null )
564 {
565 TclIO.unregisterChannel( interp, chan );
566 }
567 chan = TclIO.getStdChannel( StdChannel.STDERR );
568 if ( chan != null )
569 {
570 TclIO.unregisterChannel( interp, chan );
571 }
572 }
573 } // end InterpSlaveCmd
574 }