wasCSharpSQLite – Rev
?pathlinks?
using System;
using System.Text;
using Community.CsharpSqlite;
using tcl.lang;
using ClientData = System.Object;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
using System.IO;
using System.Diagnostics;
class Testing
{
/*
** 2009 July 17
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code to implement the "sqlite" test harness
** which runs TCL commands for testing the C#-SQLite port.
**
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
** C#-SQLite is an independent reimplementation of the SQLite software library
**
*************************************************************************
*/
public static void Main( string[] args )
{
// Array of command-line argument strings.
{
string fileName = null;
// Create the interpreter. This will also create the built-in
// Tcl commands.
Interp interp = new Interp();
// Make command-line arguments available in the Tcl variables "argc"
// and "argv". If the first argument doesn't start with a "-" then
// strip it off and use it as the name of a script file to process.
// We also set the argv0 and TCL.Tcl_interactive vars here.
if ( ( args.Length > 0 ) && !( args[0].StartsWith( "-" ) ) )
{
fileName = args[0];
}
TclObject argv = TclList.newInstance();
argv.preserve();
try
{
int i = 0;
int argc = args.Length;
if ( (System.Object)fileName == null )
{
interp.setVar( "argv0", "tcl.lang.Shell", TCL.VarFlag.GLOBAL_ONLY );
interp.setVar( "tcl_interactive", "1", TCL.VarFlag.GLOBAL_ONLY );
}
else
{
interp.setVar( "argv0", fileName, TCL.VarFlag.GLOBAL_ONLY );
interp.setVar( "tcl_interactive", "0", TCL.VarFlag.GLOBAL_ONLY );
i++;
argc--;
}
for ( ; i < args.Length; i++ )
{
TclList.append( interp, argv, TclString.newInstance( args[i] ) );
}
interp.setVar( "argv", argv, TCL.VarFlag.GLOBAL_ONLY );
interp.setVar( "argc", System.Convert.ToString( argc ), TCL.VarFlag.GLOBAL_ONLY );
}
catch ( TclException e )
{
throw new TclRuntimeError( "unexpected TclException: " + e.Message );
}
finally
{
argv.release();
}
init_all( interp );
TCL.Tcl_CreateObjCommand( interp, "load_testfixture_extensions", init_all_cmd, 0, null );
// Normally we would do application specific initialization here.
// However, that feature is not currently supported.
// If a script file was specified then just source that file
// and quit.
Console.WriteLine( " C#-SQLite version " + Sqlite3.sqlite3_version );
Console.WriteLine( "An independent reimplementation of the SQLite software library" );
Console.WriteLine( "==============================================================" );
Console.WriteLine( "" );
if ( (System.Object)fileName != null )
{
try
{
interp.evalFile( fileName );
}
catch ( TclException e )
{
TCL.CompletionCode code = e.getCompletionCode();
if ( code == TCL.CompletionCode.RETURN )
{
code = interp.updateReturnInfo();
if ( code != TCL.CompletionCode.OK )
{
System.Console.Error.WriteLine( "command returned bad code: " + code );
if ( tcl.lang.ConsoleThread.debug )
System.Diagnostics.Debug.WriteLine( "command returned bad code: " + code );
}
}
else if ( code == TCL.CompletionCode.ERROR )
{
System.Console.Error.WriteLine( interp.getResult().ToString() );
if ( tcl.lang.ConsoleThread.debug )
System.Diagnostics.Debug.WriteLine( interp.getResult().ToString() );
System.Diagnostics.Debug.Assert( false, interp.getResult().ToString() );
}
else if ( code != TCL.CompletionCode.EXIT )
{
System.Console.Error.WriteLine( "command returned bad code: " + code );
if ( tcl.lang.ConsoleThread.debug )
System.Diagnostics.Debug.WriteLine( "command returned bad code: " + code );
}
}
// Note that if the above interp.evalFile() returns the main
// thread will exit. This may bring down the VM and stop
// the execution of Tcl.
//
// If the script needs to handle events, it must call
// vwait or do something similar.
//
// Note that the script can create AWT widgets. This will
// start an AWT event handling thread and keep the VM up. However,
// the interpreter thread (the same as the main thread) would
// have exited and no Tcl scripts can be executed.
interp.dispose();
Sqlite3.sqlite3_shutdown();
System.Environment.Exit( 0 );
}
if ( (System.Object)fileName == null )
{
// We are running in interactive mode. Start the ConsoleThread
// that loops, grabbing stdin and passing it to the interp.
ConsoleThread consoleThread = new ConsoleThread( interp );
consoleThread.IsBackground = true;
consoleThread.Start();
// Loop forever to handle user input events in the command line.
Notifier notifier = interp.getNotifier();
while ( true )
{
// process events until "exit" is called.
notifier.doOneEvent( TCL.ALL_EVENTS );
}
}
}
}
#if SQLITE_TEST
//static void init_all(Tcl_Interp );
static int init_all_cmd(
ClientData cd,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
Tcl_Interp slave;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "SLAVE" );
return TCL.TCL_ERROR;
}
slave = TCL.Tcl_GetSlave( interp, TCL.Tcl_GetString( objv[1] ) );
if ( slave == null )
{
return TCL.TCL_ERROR;
}
init_all( slave );
return TCL.TCL_OK;
}
#endif
// Setup SQLIte specific object for routines
static void init_all( Interp interp )
{
Sqlite3.Sqlite3_Init( interp );
Sqlite3.Sqlitetestbackup_Init( interp );
Sqlite3.Sqlitetestfuzzer_Init( interp );
Sqlite3.Sqliteconfig_Init( interp );
Sqlite3.Sqlitetest_autoext_Init( interp );
Sqlite3.Sqlitetest_func_Init( interp );
Sqlite3.Sqlitetest_hexio_Init( interp );
Sqlite3.Sqlitetest_malloc_Init( interp );
Sqlite3.Sqlitetest_mutex_Init( interp );
Sqlite3.Sqlitetestintarray_Init( interp );
Sqlite3.Sqlitetestschema_Init( interp );
Sqlite3.SqlitetestStat_Init( interp );
Sqlite3.Sqlitetesttclvar_Init( interp );
Sqlite3.Sqlitetestwholenumber_Init( interp );
Sqlite3.Sqlitetest1_Init( interp );
Sqlite3.Sqlitetest2_Init( interp );
Sqlite3.Sqlitetest3_Init( interp );
Sqlite3.Sqlitetest8_Init( interp );
Sqlite3.Sqlitetest9_Init( interp );
Sqlite3.Md5_Init( interp );
}
}
namespace tcl.lang
{
class ConsoleThread : SupportClass.ThreadClass
{
private class AnonymousClassTclEvent : TclEvent
{
public AnonymousClassTclEvent( string command, ConsoleThread enclosingInstance )
{
InitBlock( command, enclosingInstance );
}
private void InitBlock( string command, ConsoleThread enclosingInstance )
{
this.command = command;
this.enclosingInstance = enclosingInstance;
}
private string command;
private ConsoleThread enclosingInstance;
public ConsoleThread Enclosing_Instance
{
get
{
return enclosingInstance;
}
}
public override int processEvent( int flags )
{
// See if the command is a complete Tcl command
if ( Interp.commandComplete( command ) )
{
if ( tcl.lang.ConsoleThread.debug )
{
WriteLine( "line was a complete command" );
}
bool eval_exception = true;
TclObject commandObj = TclString.newInstance( command );
try
{
commandObj.preserve();
Enclosing_Instance.interp.recordAndEval( commandObj, 0 );
eval_exception = false;
}
catch ( TclException e )
{
if ( tcl.lang.ConsoleThread.debug )
{
WriteLine( "eval returned exceptional condition" );
}
TCL.CompletionCode code = e.getCompletionCode();
switch ( code )
{
case TCL.CompletionCode.ERROR:
Enclosing_Instance.putLine( Enclosing_Instance.err, Enclosing_Instance.interp.getResult().ToString() );
break;
case TCL.CompletionCode.BREAK:
Enclosing_Instance.putLine( Enclosing_Instance.err, "invoked \"break\" outside of a loop" );
break;
case TCL.CompletionCode.CONTINUE:
Enclosing_Instance.putLine( Enclosing_Instance.err, "invoked \"continue\" outside of a loop" );
break;
default:
Enclosing_Instance.putLine( Enclosing_Instance.err, "command returned bad code: " + code );
break;
}
}
finally
{
commandObj.release();
}
if ( !eval_exception )
{
if ( tcl.lang.ConsoleThread.debug )
{
WriteLine( "eval returned normally" );
}
string evalResult = Enclosing_Instance.interp.getResult().ToString();
if ( tcl.lang.ConsoleThread.debug )
{
WriteLine( "eval result was \"" + evalResult + "\"" );
}
if ( evalResult.Length > 0 )
{
Enclosing_Instance.putLine( Enclosing_Instance.out_Renamed, evalResult );
}
}
// Empty out the incoming command buffer
Enclosing_Instance.sbuf.Length = 0;
// See if the user set a custom shell prompt for the next command
TclObject prompt;
try
{
prompt = Enclosing_Instance.interp.getVar( "tcl_prompt1", TCL.VarFlag.GLOBAL_ONLY );
}
catch ( TclException e )
{
prompt = null;
}
if ( prompt != null )
{
try
{
Enclosing_Instance.interp.eval( prompt.ToString(), TCL.EVAL_GLOBAL );
}
catch ( TclException e )
{
Enclosing_Instance.put( Enclosing_Instance.out_Renamed, "% " );
}
}
else
{
Enclosing_Instance.put( Enclosing_Instance.out_Renamed, "% " );
}
return 1;
}
else
{
// Interp.commandComplete() returned false
if ( tcl.lang.ConsoleThread.debug )
{
WriteLine( "line was not a complete command" );
}
// We don't have a complete command yet. Print out a level 2
// prompt message and wait for further inputs.
TclObject prompt;
try
{
prompt = Enclosing_Instance.interp.getVar( "tcl_prompt2", TCL.VarFlag.GLOBAL_ONLY );
}
catch ( TclException )
{
prompt = null;
}
if ( prompt != null )
{
try
{
Enclosing_Instance.interp.eval( prompt.ToString(), TCL.EVAL_GLOBAL );
}
catch ( TclException e )
{
Enclosing_Instance.put( Enclosing_Instance.out_Renamed, "" );
}
}
else
{
Enclosing_Instance.put( Enclosing_Instance.out_Renamed, "" );
}
return 1;
}
} // end processEvent method
}
// Interpreter associated with this console thread.
internal Interp interp;
// Collect the user input in this buffer until it forms a complete Tcl
// command.
internal StringBuilder sbuf;
// Used to for interactive input/output
private Channel out_Renamed;
private Channel err;
// set to true to get extra debug output
public static bool debug = true;
// used to keep track of wether or not System.in.available() works
private static bool sysInAvailableWorks = false;
internal ConsoleThread( Interp i )
{
Name = "ConsoleThread";
interp = i;
sbuf = new StringBuilder( 100 );
Debugger.Break();//TODO
//out_Renamed = Tcl_IO.getStdChannel( StdChannel.STDOUT );
//err = TCL.TclIO.getStdChannel( StdChannel.STDERR );
}
override public void Run()
{
if ( debug )
{
WriteLine( "entered ConsoleThread run() method" );
}
put( out_Renamed, "% " );
while ( true )
{
// Loop forever to collect user inputs in a StringBuffer.
// When we have a complete command, then execute it and print
// out the results.
//
// The loop is broken under two conditions: (1) when EOF is
// received inside getLine(). (2) when the "exit" command is
// executed in the script.
getLine();
string command = sbuf.ToString();
if ( debug )
{
WriteLine( "got line from console" );
WriteLine( "\"" + command + "\"" );
}
// When interacting with the interpreter, one must
// be careful to never call a Tcl method from
// outside of the event loop thread. If we did
// something like just call interp.eval() it
// could crash the whole process because two
// threads might write over each other.
// The only safe way to interact with Tcl is
// to create an event and add it to the thread
// safe event queue.
AnonymousClassTclEvent Tevent = new AnonymousClassTclEvent( command, this ); // end TclEvent innerclass
// Add the event to the thread safe event queue
interp.getNotifier().queueEvent( Tevent, TCL.QUEUE_TAIL );
// Tell this thread to wait until the event has been processed.
Tevent.sync();
}
}
private static void WriteLine( string s )
{
System.Console.Out.WriteLine( s );
if ( debug )
System.Diagnostics.Debug.WriteLine( s );
}
private void getLine()
{
sbuf.Append( Console.In.ReadLine() );
}
private void putLine( Channel channel, string s )
// The String to print.
{
try
{
channel.write( interp, s );
channel.write( interp, "\n" );
channel.flush( interp );
}
catch ( IOException ex )
{
System.Console.Error.WriteLine( "IOException in Shell.putLine()" );
SupportClass.WriteStackTrace( ex, System.Console.Error );
}
catch ( TclException ex )
{
System.Console.Error.WriteLine( "TclException in Shell.putLine()" );
SupportClass.WriteStackTrace( ex, System.Console.Error );
}
}
private void put( Channel channel, string s )
// The String to print.
{
try
{
channel.write( interp, s );
channel.flush( interp );
}
catch ( IOException ex )
{
System.Console.Error.WriteLine( "IOException in Shell.put()" );
SupportClass.WriteStackTrace( ex, System.Console.Error );
}
catch ( TclException ex )
{
System.Console.Error.WriteLine( "TclException in Shell.put()" );
SupportClass.WriteStackTrace( ex, System.Console.Error );
}
}
static ConsoleThread()
{
{
try
{
// There is no way to tell whether System.in will block AWT
// threads, so we assume it does block if we can use
// System.in.available().
long available = 0;
// HACK ATK
// available = System.Console.In.Length - System.Console.In.Position;
int generatedAux5 = (int)available;
sysInAvailableWorks = true;
}
catch ( System.Exception e )
{
// If System.in.available() causes an exception -- it's probably
// no supported on this platform (e.g. MS Java SDK). We assume
// sysInAvailableWorks is false and let the user suffer ...
}
// Sun's JDK 1.2 on Windows systems is screwed up, it does not
// echo chars to the console unless blocking IO is used.
// For this reason we need to use blocking IO under Windows.
if ( Util.Windows )
{
sysInAvailableWorks = false;
}
if ( debug )
{
WriteLine( "sysInAvailableWorks = " + sysInAvailableWorks );
}
}
}
} // end of class ConsoleThread
}