wasCSharpSQLite – Rev 1
?pathlinks?
/*
* AfterCmd.java --
*
* Implements the built-in "after" Tcl command.
*
* Copyright (c) 1997 Cornell University.
* Copyright (c) 1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and
* redistribution of this file, and for a DISCLAIMER OF ALL
* WARRANTIES.
*
* Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
*
* RCS @(#) $Id: AfterCmd.java,v 1.2 2002/04/12 21:00:26 mdejong Exp $
*
*/
using System;
using System.Collections;
namespace tcl.lang
{
/*
* This class implements the built-in "after" command in Tcl.
*/
class AfterCmd : Command
{
/*
* The list of handler are stored as AssocData in the interp.
*/
internal AfterAssocData assocData = null;
/*
* Valid command options.
*/
private static readonly string[] validOpts = new string[] { "cancel", "idle", "info" };
internal const int OPT_CANCEL = 0;
internal const int OPT_IDLE = 1;
internal const int OPT_INFO = 2;
public TCL.CompletionCode cmdProc( Interp interp, TclObject[] argv )
{
int i;
Notifier notifier = (Notifier)interp.getNotifier();
Object info;
if ( assocData == null )
{
/*
* Create the "after" information associated for this
* interpreter, if it doesn't already exist.
*/
assocData = (AfterAssocData)interp.getAssocData( "tclAfter" );
if ( assocData == null )
{
assocData = new AfterAssocData( this );
interp.setAssocData( "tclAfter", assocData );
}
}
if ( argv.Length < 2 )
{
throw new TclNumArgsException( interp, 1, argv, "option ?arg arg ...?" );
}
/*
* First lets see if the command was passed a number as the first argument.
*/
bool isNumber = false;
int ms = 0;
if ( argv[1].InternalRep is TclInteger )
{
ms = TclInteger.get( interp, argv[1] );
isNumber = true;
}
else
{
string s = argv[1].ToString();
if ( ( s.Length > 0 ) && ( System.Char.IsDigit( s[0] ) ) )
{
ms = TclInteger.get( interp, argv[1] );
isNumber = true;
}
}
if ( isNumber )
{
if ( ms < 0 )
{
ms = 0;
}
if ( argv.Length == 2 )
{
/*
* Sleep for at least the given milliseconds and return.
*/
long endTime = System.DateTime.Now.Ticks / 10000 + ms;
while ( true )
{
try
{
System.Threading.Thread.Sleep( ms );
return TCL.CompletionCode.RETURN;
}
catch ( System.Threading.ThreadInterruptedException e )
{
/*
* We got interrupted. Sleep again if we havn't slept
* long enough yet.
*/
long sysTime = System.DateTime.Now.Ticks / 10000;
if ( sysTime >= endTime )
{
return TCL.CompletionCode.RETURN;
}
ms = (int)( endTime - sysTime );
continue;
}
}
}
TclObject cmd = getCmdObject( argv );
cmd.preserve();
assocData.lastAfterId++;
TimerInfo timerInfo = new TimerInfo( this, notifier, ms );
timerInfo.interp = interp;
timerInfo.command = cmd;
timerInfo.id = assocData.lastAfterId;
assocData.handlers.Add( timerInfo );
interp.setResult( "after#" + timerInfo.id );
return TCL.CompletionCode.RETURN;
}
/*
* If it's not a number it must be a subcommand.
*/
int index;
try
{
index = TclIndex.get( interp, argv[1], validOpts, "option", 0 );
}
catch ( TclException e )
{
throw new TclException( interp, "bad argument \"" + argv[1] + "\": must be cancel, idle, info, or a number" );
}
switch ( index )
{
case OPT_CANCEL:
if ( argv.Length < 3 )
{
throw new TclNumArgsException( interp, 2, argv, "id|command" );
}
TclObject arg = getCmdObject( argv );
arg.preserve();
/*
* Search the timer/idle handler by id or by command.
*/
info = null;
for ( i = 0; i < assocData.handlers.Count; i++ )
{
Object obj = assocData.handlers[i];
if ( obj is TimerInfo )
{
TclObject cmd = ( (TimerInfo)obj ).command;
if ( ( cmd == arg ) || cmd.ToString().Equals( arg.ToString() ) )
{
info = obj;
break;
}
}
else
{
TclObject cmd = ( (IdleInfo)obj ).command;
if ( ( cmd == arg ) || cmd.ToString().Equals( arg.ToString() ) )
{
info = obj;
break;
}
}
}
if ( info == null )
{
info = getAfterEvent( arg.ToString() );
}
arg.release();
/*
* Cancel the handler.
*/
if ( info != null )
{
if ( info is TimerInfo )
{
( (TimerInfo)info ).cancel();
( (TimerInfo)info ).command.release();
}
else
{
( (IdleInfo)info ).cancel();
( (IdleInfo)info ).command.release();
}
SupportClass.VectorRemoveElement( assocData.handlers, info );
}
break;
case OPT_IDLE:
if ( argv.Length < 3 )
{
throw new TclNumArgsException( interp, 2, argv, "script script ..." );
}
TclObject cmd2 = getCmdObject( argv );
cmd2.preserve();
assocData.lastAfterId++;
IdleInfo idleInfo = new IdleInfo( this, notifier );
idleInfo.interp = interp;
idleInfo.command = cmd2;
idleInfo.id = assocData.lastAfterId;
assocData.handlers.Add( idleInfo );
interp.setResult( "after#" + idleInfo.id );
break;
case OPT_INFO:
if ( argv.Length == 2 )
{
/*
* No id is given. Return a list of current after id's.
*/
TclObject list = TclList.newInstance();
for ( i = 0; i < assocData.handlers.Count; i++ )
{
int id;
Object obj = assocData.handlers[i];
if ( obj is TimerInfo )
{
id = ( (TimerInfo)obj ).id;
}
else
{
id = ( (IdleInfo)obj ).id;
}
TclList.append( interp, list, TclString.newInstance( "after#" + id ) );
}
interp.resetResult();
interp.setResult( list );
return TCL.CompletionCode.RETURN;
}
if ( argv.Length != 3 )
{
throw new TclNumArgsException( interp, 2, argv, "?id?" );
}
/*
* Return command and type of the given after id.
*/
info = getAfterEvent( argv[2].ToString() );
if ( info == null )
{
throw new TclException( interp, "event \"" + argv[2] + "\" doesn't exist" );
}
TclObject list2 = TclList.newInstance();
TclList.append( interp, list2, ( ( info is TimerInfo ) ? ( (TimerInfo)info ).command : ( (IdleInfo)info ).command ) );
TclList.append( interp, list2, TclString.newInstance( ( info is TimerInfo ) ? "timer" : "idle" ) );
interp.resetResult();
interp.setResult( list2 );
break;
}
return TCL.CompletionCode.RETURN;
}
private TclObject getCmdObject( TclObject[] argv )
// Argument list passed to the "after" command.
{
if ( argv.Length == 3 )
{
return argv[2];
}
else
{
TclObject cmd = TclString.newInstance( Util.concat( 2, argv.Length - 1, argv ) );
return cmd;
}
}
private Object getAfterEvent( string inString )
// Textual identifier for after event, such
// as "after#6".
{
if ( !inString.StartsWith( "after#" ) )
{
return null;
}
StrtoulResult res = Util.strtoul( inString, 6, 10 );
if ( res.errno != 0 )
{
return null;
}
for ( int i = 0; i < assocData.handlers.Count; i++ )
{
Object obj = assocData.handlers[i];
if ( obj is TimerInfo )
{
if ( ( (TimerInfo)obj ).id == res.value )
{
return obj;
}
}
else
{
if ( ( (IdleInfo)obj ).id == res.value )
{
return obj;
}
}
}
return null;
}
internal class AfterAssocData : AssocData
{
public AfterAssocData( AfterCmd enclosingInstance )
{
InitBlock( enclosingInstance );
}
private void InitBlock( AfterCmd enclosingInstance )
{
this.enclosingInstance = enclosingInstance;
handlers = new ArrayList( 10 );
}
private AfterCmd enclosingInstance;
public AfterCmd Enclosing_Instance
{
get
{
return enclosingInstance;
}
}
/*
* The set of handlers created but not yet fired.
*/
internal ArrayList handlers;
/*
* Timer identifier of most recently created timer.
*/
internal int lastAfterId = 0;
public void disposeAssocData( Interp interp )
// The interpreter in which this AssocData
// instance is registered in.
{
for ( int i = Enclosing_Instance.assocData.handlers.Count - 1; i >= 0; i-- )
{
Object info = Enclosing_Instance.assocData.handlers[i];
Enclosing_Instance.assocData.handlers.RemoveAt( i );
if ( info is TimerInfo )
{
( (TimerInfo)info ).cancel();
( (TimerInfo)info ).command.release();
}
else
{
( (IdleInfo)info ).cancel();
( (IdleInfo)info ).command.release();
}
}
Enclosing_Instance.assocData = null;
}
} // end AfterCmd.AfterAssocData
internal class TimerInfo : TimerHandler
{
private void InitBlock( AfterCmd enclosingInstance )
{
this.enclosingInstance = enclosingInstance;
}
private AfterCmd enclosingInstance;
public AfterCmd Enclosing_Instance
{
get
{
return enclosingInstance;
}
}
/*
* Interpreter in which the script should be executed.
*/
internal Interp interp;
/*
* Command to execute when the timer fires.
*/
internal TclObject command;
/*
* Integer identifier for command; used to cancel it.
*/
internal int id;
internal TimerInfo( AfterCmd enclosingInstance, Notifier n, int milliseconds )
: base( n, milliseconds )
{
InitBlock( enclosingInstance );
}
public override void processTimerEvent()
{
try
{
SupportClass.VectorRemoveElement( Enclosing_Instance.assocData.handlers, this );
interp.eval( command, TCL.EVAL_GLOBAL );
}
catch ( TclException e )
{
interp.addErrorInfo( "\n (\"after\" script)" );
interp.backgroundError();
}
finally
{
command.release();
command = null;
}
}
} // end AfterCmd.AfterInfo
internal class IdleInfo : IdleHandler
{
private void InitBlock( AfterCmd enclosingInstance )
{
this.enclosingInstance = enclosingInstance;
}
private AfterCmd enclosingInstance;
public AfterCmd Enclosing_Instance
{
get
{
return enclosingInstance;
}
}
/*
* Interpreter in which the script should be executed.
*/
internal Interp interp;
/*
* Command to execute when the idle event fires.
*/
internal TclObject command;
/*
* Integer identifier for command; used to cancel it.
*/
internal int id;
internal IdleInfo( AfterCmd enclosingInstance, Notifier n )
: base( n )
{
InitBlock( enclosingInstance );
}
public override void processIdleEvent()
{
try
{
SupportClass.VectorRemoveElement( Enclosing_Instance.assocData.handlers, this );
interp.eval( command, TCL.EVAL_GLOBAL );
}
catch ( TclException e )
{
interp.addErrorInfo( "\n (\"after\" script)" );
interp.backgroundError();
}
finally
{
command.release();
command = null;
}
}
} // end AfterCmd.AfterInfo
} // end AfterCmd
}