wasCSharpSQLite – Blame information for rev

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*
2 * AfterCmd.java --
3 *
4 * Implements the built-in "after" Tcl command.
5 *
6 * Copyright (c) 1997 Cornell University.
7 * Copyright (c) 1997 Sun Microsystems, Inc.
8 *
9 * See the file "license.terms" for information on usage and
10 * redistribution of this file, and for a DISCLAIMER OF ALL
11 * WARRANTIES.
12 *
13 * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
14 *
15 * RCS @(#) $Id: AfterCmd.java,v 1.2 2002/04/12 21:00:26 mdejong Exp $
16 *
17 */
18 using System;
19 using System.Collections;
20  
21  
22 namespace tcl.lang
23 {
24  
25 /*
26 * This class implements the built-in "after" command in Tcl.
27 */
28  
29 class AfterCmd : Command
30 {
31  
32 /*
33 * The list of handler are stored as AssocData in the interp.
34 */
35  
36 internal AfterAssocData assocData = null;
37  
38 /*
39 * Valid command options.
40 */
41  
42 private static readonly string[] validOpts = new string[] { "cancel", "idle", "info" };
43  
44 internal const int OPT_CANCEL = 0;
45 internal const int OPT_IDLE = 1;
46 internal const int OPT_INFO = 2;
47  
48 public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv )
49 {
50 int i;
51 Notifier notifier = (Notifier)interp.getNotifier();
52 Object info;
53  
54 if ( assocData == null )
55 {
56 /*
57 * Create the "after" information associated for this
58 * interpreter, if it doesn't already exist.
59 */
60  
61 assocData = (AfterAssocData)interp.getAssocData( "tclAfter" );
62 if ( assocData == null )
63 {
64 assocData = new AfterAssocData( this );
65 interp.setAssocData( "tclAfter", assocData );
66 }
67 }
68  
69 if ( argv.Length < 2 )
70 {
71 throw new TclNumArgsException( interp, 1, argv, "option ?arg arg ...?" );
72 }
73  
74 /*
75 * First lets see if the command was passed a number as the first argument.
76 */
77  
78 bool isNumber = false;
79 int ms = 0;
80  
81 if ( argv[1].InternalRep is TclInteger )
82 {
83 ms = TclInteger.get( interp, argv[1] );
84 isNumber = true;
85 }
86 else
87 {
88 string s = argv[1].ToString();
89 if ( ( s.Length > 0 ) && ( System.Char.IsDigit( s[0] ) ) )
90 {
91 ms = TclInteger.get( interp, argv[1] );
92 isNumber = true;
93 }
94 }
95  
96 if ( isNumber )
97 {
98 if ( ms < 0 )
99 {
100 ms = 0;
101 }
102 if ( argv.Length == 2 )
103 {
104 /*
105 * Sleep for at least the given milliseconds and return.
106 */
107  
108 long endTime = System.DateTime.Now.Ticks / 10000 + ms;
109 while ( true )
110 {
111 try
112 {
113 System.Threading.Thread.Sleep( ms );
114 return TCL.CompletionCode.RETURN;
115 }
116 catch ( System.Threading.ThreadInterruptedException e )
117 {
118 /*
119 * We got interrupted. Sleep again if we havn't slept
120 * long enough yet.
121 */
122  
123 long sysTime = System.DateTime.Now.Ticks / 10000;
124 if ( sysTime >= endTime )
125 {
126 return TCL.CompletionCode.RETURN;
127 }
128 ms = (int)( endTime - sysTime );
129 continue;
130 }
131 }
132 }
133  
134 TclObject cmd = getCmdObject( argv );
135 cmd.preserve();
136  
137 assocData.lastAfterId++;
138 TimerInfo timerInfo = new TimerInfo( this, notifier, ms );
139 timerInfo.interp = interp;
140 timerInfo.command = cmd;
141 timerInfo.id = assocData.lastAfterId;
142  
143 assocData.handlers.Add( timerInfo );
144  
145 interp.setResult( "after#" + timerInfo.id );
146  
147 return TCL.CompletionCode.RETURN;
148 }
149  
150 /*
151 * If it's not a number it must be a subcommand.
152 */
153  
154 int index;
155  
156 try
157 {
158 index = TclIndex.get( interp, argv[1], validOpts, "option", 0 );
159 }
160 catch ( TclException e )
161 {
162 throw new TclException( interp, "bad argument \"" + argv[1] + "\": must be cancel, idle, info, or a number" );
163 }
164  
165 switch ( index )
166 {
167  
168 case OPT_CANCEL:
169 if ( argv.Length < 3 )
170 {
171 throw new TclNumArgsException( interp, 2, argv, "id|command" );
172 }
173  
174 TclObject arg = getCmdObject( argv );
175 arg.preserve();
176  
177 /*
178 * Search the timer/idle handler by id or by command.
179 */
180  
181 info = null;
182 for ( i = 0; i < assocData.handlers.Count; i++ )
183 {
184 Object obj = assocData.handlers[i];
185 if ( obj is TimerInfo )
186 {
187 TclObject cmd = ( (TimerInfo)obj ).command;
188  
189 if ( ( cmd == arg ) || cmd.ToString().Equals( arg.ToString() ) )
190 {
191 info = obj;
192 break;
193 }
194 }
195 else
196 {
197 TclObject cmd = ( (IdleInfo)obj ).command;
198  
199 if ( ( cmd == arg ) || cmd.ToString().Equals( arg.ToString() ) )
200 {
201 info = obj;
202 break;
203 }
204 }
205 }
206 if ( info == null )
207 {
208  
209 info = getAfterEvent( arg.ToString() );
210 }
211 arg.release();
212  
213 /*
214 * Cancel the handler.
215 */
216  
217 if ( info != null )
218 {
219 if ( info is TimerInfo )
220 {
221 ( (TimerInfo)info ).cancel();
222 ( (TimerInfo)info ).command.release();
223 }
224 else
225 {
226 ( (IdleInfo)info ).cancel();
227 ( (IdleInfo)info ).command.release();
228 }
229  
230 SupportClass.VectorRemoveElement( assocData.handlers, info );
231 }
232 break;
233  
234  
235 case OPT_IDLE:
236 if ( argv.Length < 3 )
237 {
238 throw new TclNumArgsException( interp, 2, argv, "script script ..." );
239 }
240  
241 TclObject cmd2 = getCmdObject( argv );
242 cmd2.preserve();
243 assocData.lastAfterId++;
244  
245 IdleInfo idleInfo = new IdleInfo( this, notifier );
246 idleInfo.interp = interp;
247 idleInfo.command = cmd2;
248 idleInfo.id = assocData.lastAfterId;
249  
250 assocData.handlers.Add( idleInfo );
251  
252 interp.setResult( "after#" + idleInfo.id );
253 break;
254  
255  
256 case OPT_INFO:
257 if ( argv.Length == 2 )
258 {
259 /*
260 * No id is given. Return a list of current after id's.
261 */
262  
263 TclObject list = TclList.newInstance();
264 for ( i = 0; i < assocData.handlers.Count; i++ )
265 {
266 int id;
267 Object obj = assocData.handlers[i];
268 if ( obj is TimerInfo )
269 {
270 id = ( (TimerInfo)obj ).id;
271 }
272 else
273 {
274 id = ( (IdleInfo)obj ).id;
275 }
276 TclList.append( interp, list, TclString.newInstance( "after#" + id ) );
277 }
278 interp.resetResult();
279 interp.setResult( list );
280 return TCL.CompletionCode.RETURN;
281 }
282 if ( argv.Length != 3 )
283 {
284 throw new TclNumArgsException( interp, 2, argv, "?id?" );
285 }
286  
287 /*
288 * Return command and type of the given after id.
289 */
290  
291  
292 info = getAfterEvent( argv[2].ToString() );
293 if ( info == null )
294 {
295  
296 throw new TclException( interp, "event \"" + argv[2] + "\" doesn't exist" );
297 }
298 TclObject list2 = TclList.newInstance();
299 TclList.append( interp, list2, ( ( info is TimerInfo ) ? ( (TimerInfo)info ).command : ( (IdleInfo)info ).command ) );
300 TclList.append( interp, list2, TclString.newInstance( ( info is TimerInfo ) ? "timer" : "idle" ) );
301  
302 interp.resetResult();
303 interp.setResult( list2 );
304 break;
305 }
306 return TCL.CompletionCode.RETURN;
307 }
308 private TclObject getCmdObject( TclObject[] argv )
309 // Argument list passed to the "after" command.
310 {
311 if ( argv.Length == 3 )
312 {
313 return argv[2];
314 }
315 else
316 {
317 TclObject cmd = TclString.newInstance( Util.concat( 2, argv.Length - 1, argv ) );
318 return cmd;
319 }
320 }
321 private Object getAfterEvent( string inString )
322 // Textual identifier for after event, such
323 // as "after#6".
324 {
325 if ( !inString.StartsWith( "after#" ) )
326 {
327 return null;
328 }
329  
330 StrtoulResult res = Util.strtoul( inString, 6, 10 );
331 if ( res.errno != 0 )
332 {
333 return null;
334 }
335  
336 for ( int i = 0; i < assocData.handlers.Count; i++ )
337 {
338 Object obj = assocData.handlers[i];
339 if ( obj is TimerInfo )
340 {
341 if ( ( (TimerInfo)obj ).id == res.value )
342 {
343 return obj;
344 }
345 }
346 else
347 {
348 if ( ( (IdleInfo)obj ).id == res.value )
349 {
350 return obj;
351 }
352 }
353 }
354  
355 return null;
356 }
357 internal class AfterAssocData : AssocData
358 {
359 public AfterAssocData( AfterCmd enclosingInstance )
360 {
361 InitBlock( enclosingInstance );
362 }
363 private void InitBlock( AfterCmd enclosingInstance )
364 {
365 this.enclosingInstance = enclosingInstance;
366 handlers = new ArrayList( 10 );
367 }
368 private AfterCmd enclosingInstance;
369 public AfterCmd Enclosing_Instance
370 {
371 get
372 {
373 return enclosingInstance;
374 }
375  
376 }
377  
378 /*
379 * The set of handlers created but not yet fired.
380 */
381  
382 internal ArrayList handlers;
383  
384 /*
385 * Timer identifier of most recently created timer.
386 */
387  
388 internal int lastAfterId = 0;
389  
390 public void disposeAssocData( Interp interp )
391 // The interpreter in which this AssocData
392 // instance is registered in.
393 {
394 for ( int i = Enclosing_Instance.assocData.handlers.Count - 1; i >= 0; i-- )
395 {
396 Object info = Enclosing_Instance.assocData.handlers[i];
397 Enclosing_Instance.assocData.handlers.RemoveAt( i );
398 if ( info is TimerInfo )
399 {
400 ( (TimerInfo)info ).cancel();
401 ( (TimerInfo)info ).command.release();
402 }
403 else
404 {
405 ( (IdleInfo)info ).cancel();
406 ( (IdleInfo)info ).command.release();
407 }
408 }
409 Enclosing_Instance.assocData = null;
410 }
411 } // end AfterCmd.AfterAssocData
412  
413 internal class TimerInfo : TimerHandler
414 {
415 private void InitBlock( AfterCmd enclosingInstance )
416 {
417 this.enclosingInstance = enclosingInstance;
418 }
419 private AfterCmd enclosingInstance;
420 public AfterCmd Enclosing_Instance
421 {
422 get
423 {
424 return enclosingInstance;
425 }
426  
427 }
428  
429 /*
430 * Interpreter in which the script should be executed.
431 */
432  
433 internal Interp interp;
434  
435 /*
436 * Command to execute when the timer fires.
437 */
438  
439 internal TclObject command;
440  
441 /*
442 * Integer identifier for command; used to cancel it.
443 */
444  
445 internal int id;
446  
447 internal TimerInfo( AfterCmd enclosingInstance, Notifier n, int milliseconds )
448 : base( n, milliseconds )
449 {
450 InitBlock( enclosingInstance );
451 }
452 public override void processTimerEvent()
453 {
454 try
455 {
456 SupportClass.VectorRemoveElement( Enclosing_Instance.assocData.handlers, this );
457 interp.eval( command, TCL.EVAL_GLOBAL );
458 }
459 catch ( TclException e )
460 {
461 interp.addErrorInfo( "\n (\"after\" script)" );
462 interp.backgroundError();
463 }
464 finally
465 {
466 command.release();
467 command = null;
468 }
469 }
470 } // end AfterCmd.AfterInfo
471  
472 internal class IdleInfo : IdleHandler
473 {
474 private void InitBlock( AfterCmd enclosingInstance )
475 {
476 this.enclosingInstance = enclosingInstance;
477 }
478 private AfterCmd enclosingInstance;
479 public AfterCmd Enclosing_Instance
480 {
481 get
482 {
483 return enclosingInstance;
484 }
485  
486 }
487  
488 /*
489 * Interpreter in which the script should be executed.
490 */
491  
492 internal Interp interp;
493  
494 /*
495 * Command to execute when the idle event fires.
496 */
497  
498 internal TclObject command;
499  
500 /*
501 * Integer identifier for command; used to cancel it.
502 */
503  
504 internal int id;
505  
506 internal IdleInfo( AfterCmd enclosingInstance, Notifier n )
507 : base( n )
508 {
509 InitBlock( enclosingInstance );
510 }
511 public override void processIdleEvent()
512 {
513 try
514 {
515 SupportClass.VectorRemoveElement( Enclosing_Instance.assocData.handlers, this );
516 interp.eval( command, TCL.EVAL_GLOBAL );
517 }
518 catch ( TclException e )
519 {
520 interp.addErrorInfo( "\n (\"after\" script)" );
521 interp.backgroundError();
522 }
523 finally
524 {
525 command.release();
526 command = null;
527 }
528 }
529 } // end AfterCmd.AfterInfo
530 } // end AfterCmd
531 }