wasCSharpSQLite – Blame information for rev 4

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using tcl.lang;
5 using System.Reflection;
6  
7 class csTCL
8 {
9 /*
10 ** 2009 July 17
11 **
12 ** The author disclaims copyright to this source code. In place of
13 ** a legal notice, here is a blessing:
14 **
15 ** May you do good and not evil.
16 ** May you find forgiveness for yourself and forgive others.
17 ** May you share freely, never taking more than you give.
18 **
19 *************************************************************************
20 ** This file contains code to implement the "sqlite" test harness
21 ** which runs TCL commands for testing the C#-SQLite port.
22 **
23 ** $Header$
24 */
25 public static void Main(string[] args)
26 {
27 // Array of command-line argument strings.
28 {
29 string fileName = null;
30  
31 // Create the interpreter. This will also create the built-in
32 // Tcl commands.
33  
34 Interp interp = new Interp();
35  
36 // Make command-line arguments available in the Tcl variables "argc"
37 // and "argv". If the first argument doesn't start with a "-" then
38 // strip it off and use it as the name of a script file to process.
39 // We also set the argv0 and TCL.Tcl_interactive vars here.
40  
41 if ((args.Length > 0) && !(args[0].StartsWith("-")))
42 {
43 fileName = args[0];
44 }
45  
46 TclObject argv = TclList.newInstance();
47 argv.preserve();
48 try
49 {
50 int i = 0;
51 int argc = args.Length;
52 if ((System.Object)fileName == null)
53 {
54 interp.setVar("argv0", "tcl.lang.Shell", TCL.VarFlag.GLOBAL_ONLY);
55 interp.setVar("tcl_interactive", "1", TCL.VarFlag.GLOBAL_ONLY);
56 }
57 else
58 {
59 interp.setVar("argv0", fileName, TCL.VarFlag.GLOBAL_ONLY);
60 interp.setVar("tcl_interactive", "0", TCL.VarFlag.GLOBAL_ONLY);
61 i++;
62 argc--;
63 }
64 for (; i < args.Length; i++)
65 {
66 TclList.append(interp, argv, TclString.newInstance(args[i]));
67 }
68 interp.setVar("argv", argv, TCL.VarFlag.GLOBAL_ONLY);
69 interp.setVar("argc", System.Convert.ToString(argc), TCL.VarFlag.GLOBAL_ONLY);
70 }
71 catch (TclException e)
72 {
73 throw new TclRuntimeError("unexpected TclException: " + e.Message);
74 }
75 finally
76 {
77 argv.release();
78 }
79  
80 // Normally we would do application specific initialization here.
81 // However, that feature is not currently supported.
82 // If a script file was specified then just source that file
83 // and quit.
84  
85 Console.WriteLine("C#-TCL version " + Assembly.GetExecutingAssembly().GetName().Version.ToString());
86 Console.WriteLine("==============================================================");
87 Console.WriteLine("");
88  
89 if ((System.Object)fileName != null)
90 {
91 try
92 {
93 interp.evalFile(fileName);
94 }
95 catch (TclException e)
96 {
97 TCL.CompletionCode code = e.getCompletionCode();
98 if (code == TCL.CompletionCode.RETURN)
99 {
100 code = interp.updateReturnInfo();
101 if (code != TCL.CompletionCode.OK)
102 {
103 System.Console.Error.WriteLine("command returned bad code: " + code);
104 if (tcl.lang.ConsoleThread.debug) System.Diagnostics.Debug.WriteLine("command returned bad code: " + code);
105 }
106 }
107 else if (code == TCL.CompletionCode.ERROR)
108 {
109 System.Console.Error.WriteLine(interp.getResult().ToString());
110 if (tcl.lang.ConsoleThread.debug) System.Diagnostics.Debug.WriteLine(interp.getResult().ToString());
111 System.Diagnostics.Debug.Assert(false, interp.getResult().ToString());
112 }
113 else
114 {
115 System.Console.Error.WriteLine("command returned bad code: " + code);
116 if (tcl.lang.ConsoleThread.debug) System.Diagnostics.Debug.WriteLine("command returned bad code: " + code);
117 }
118 }
119  
120 // Note that if the above interp.evalFile() returns the main
121 // thread will exit. This may bring down the VM and stop
122 // the execution of Tcl.
123 //
124 // If the script needs to handle events, it must call
125 // vwait or do something similar.
126 //
127 // Note that the script can create AWT widgets. This will
128 // start an AWT event handling thread and keep the VM up. However,
129 // the interpreter thread (the same as the main thread) would
130 // have exited and no Tcl scripts can be executed.
131  
132 interp.dispose();
133  
134 System.Environment.Exit(0);
135 }
136  
137 if ((System.Object)fileName == null)
138 {
139 // We are running in interactive mode. Start the ConsoleThread
140 // that loops, grabbing stdin and passing it to the interp.
141  
142 ConsoleThread consoleThread = new ConsoleThread(interp);
143 consoleThread.IsBackground = true;
144 consoleThread.Start();
145  
146 // Loop forever to handle user input events in the command line.
147  
148 Notifier notifier = interp.getNotifier();
149 while (true)
150 {
151 // process events until "exit" is called.
152  
153 notifier.doOneEvent(TCL.ALL_EVENTS);
154 }
155 }
156 }
157 }
158 }
159  
160 namespace tcl.lang
161 {
162 class ConsoleThread : SupportClass.ThreadClass
163 {
164 private class AnonymousClassTclEvent : TclEvent
165 {
166 public AnonymousClassTclEvent(string command, ConsoleThread enclosingInstance)
167 {
168 InitBlock(command, enclosingInstance);
169 }
170 private void InitBlock(string command, ConsoleThread enclosingInstance)
171 {
172 this.command = command;
173 this.enclosingInstance = enclosingInstance;
174 }
175 private string command;
176 private ConsoleThread enclosingInstance;
177 public ConsoleThread Enclosing_Instance
178 {
179 get
180 {
181 return enclosingInstance;
182 }
183  
184 }
185 public override int processEvent(int flags)
186 {
187  
188 // See if the command is a complete Tcl command
189  
190 if (Interp.commandComplete(command))
191 {
192 if (tcl.lang.ConsoleThread.debug)
193 {
194 WriteLine("line was a complete command");
195 }
196  
197 bool eval_exception = true;
198 TclObject commandObj = TclString.newInstance(command);
199  
200 try
201 {
202 commandObj.preserve();
203 Enclosing_Instance.interp.recordAndEval(commandObj, 0);
204 eval_exception = false;
205 }
206 catch (TclException e)
207 {
208 if (tcl.lang.ConsoleThread.debug)
209 {
210 WriteLine("eval returned exceptional condition");
211 }
212  
213 TCL.CompletionCode code = e.getCompletionCode();
214 switch (code)
215 {
216  
217 case TCL.CompletionCode.ERROR:
218  
219 Enclosing_Instance.putLine(Enclosing_Instance.err, Enclosing_Instance.interp.getResult().ToString());
220 break;
221  
222 case TCL.CompletionCode.BREAK:
223 Enclosing_Instance.putLine(Enclosing_Instance.err, "invoked \"break\" outside of a loop");
224 break;
225  
226 case TCL.CompletionCode.CONTINUE:
227 Enclosing_Instance.putLine(Enclosing_Instance.err, "invoked \"continue\" outside of a loop");
228 break;
229  
230 default:
231 Enclosing_Instance.putLine(Enclosing_Instance.err, "command returned bad code: " + code);
232 break;
233  
234 }
235 }
236 finally
237 {
238 commandObj.release();
239 }
240  
241 if (!eval_exception)
242 {
243 if (tcl.lang.ConsoleThread.debug)
244 {
245 WriteLine("eval returned normally");
246 }
247  
248  
249 string evalResult = Enclosing_Instance.interp.getResult().ToString();
250  
251 if (tcl.lang.ConsoleThread.debug)
252 {
253 WriteLine("eval result was \"" + evalResult + "\"");
254 }
255  
256 if (evalResult.Length > 0)
257 {
258 Enclosing_Instance.putLine(Enclosing_Instance.out_Renamed, evalResult);
259 }
260 }
261  
262 // Empty out the incoming command buffer
263 Enclosing_Instance.sbuf.Length = 0;
264  
265 // See if the user set a custom shell prompt for the next command
266  
267 TclObject prompt;
268  
269 try
270 {
271 prompt = Enclosing_Instance.interp.getVar("tcl_prompt1", TCL.VarFlag.GLOBAL_ONLY);
272 }
273 catch (TclException e)
274 {
275 prompt = null;
276 }
277 if (prompt != null)
278 {
279 try
280 {
281  
282 Enclosing_Instance.interp.eval(prompt.ToString(), TCL.EVAL_GLOBAL);
283 }
284 catch (TclException e)
285 {
286 Enclosing_Instance.put(Enclosing_Instance.out_Renamed, "% ");
287 }
288 }
289 else
290 {
291 Enclosing_Instance.put(Enclosing_Instance.out_Renamed, "% ");
292 }
293  
294 return 1;
295 }
296 else
297 {
298 // Interp.commandComplete() returned false
299  
300 if (tcl.lang.ConsoleThread.debug)
301 {
302 WriteLine("line was not a complete command");
303 }
304  
305 // We don't have a complete command yet. Print out a level 2
306 // prompt message and wait for further inputs.
307  
308 TclObject prompt;
309  
310 try
311 {
312 prompt = Enclosing_Instance.interp.getVar("tcl_prompt2", TCL.VarFlag.GLOBAL_ONLY);
313 }
314 catch (TclException)
315 {
316 prompt = null;
317 }
318 if (prompt != null)
319 {
320 try
321 {
322  
323 Enclosing_Instance.interp.eval(prompt.ToString(), TCL.EVAL_GLOBAL);
324 }
325 catch (TclException e)
326 {
327 Enclosing_Instance.put(Enclosing_Instance.out_Renamed, "");
328 }
329 }
330 else
331 {
332 Enclosing_Instance.put(Enclosing_Instance.out_Renamed, "");
333 }
334  
335 return 1;
336 }
337 } // end processEvent method
338 }
339  
340 // Interpreter associated with this console thread.
341  
342 internal Interp interp;
343  
344 // Collect the user input in this buffer until it forms a complete Tcl
345 // command.
346  
347 internal System.Text.StringBuilder sbuf;
348  
349 // Used to for interactive input/output
350  
351 private Channel out_Renamed;
352 private Channel err;
353  
354 // set to true to get extra debug output
355 public const bool debug = true;
356  
357 // used to keep track of wether or not System.in.available() works
358 private static bool sysInAvailableWorks = false;
359  
360 internal ConsoleThread(Interp i)
361 {
362 Name = "ConsoleThread";
363 interp = i;
364 sbuf = new System.Text.StringBuilder(100);
365  
366 out_Renamed = TclIO.getStdChannel(StdChannel.STDOUT);
367 err = TclIO.getStdChannel(StdChannel.STDERR);
368 }
369 override public void Run()
370 {
371 if (debug)
372 {
373 WriteLine("entered ConsoleThread run() method");
374 }
375  
376  
377 put(out_Renamed, "% ");
378  
379 while (true)
380 {
381 // Loop forever to collect user inputs in a StringBuffer.
382 // When we have a complete command, then execute it and print
383 // out the results.
384 //
385 // The loop is broken under two conditions: (1) when EOF is
386 // received inside getLine(). (2) when the "exit" command is
387 // executed in the script.
388  
389 getLine();
390 string command = sbuf.ToString();
391  
392 if (debug)
393 {
394 WriteLine("got line from console");
395 WriteLine("\"" + command + "\"");
396 }
397  
398 // When interacting with the interpreter, one must
399 // be careful to never call a Tcl method from
400 // outside of the event loop thread. If we did
401 // something like just call interp.eval() it
402 // could crash the whole process because two
403 // threads might write over each other.
404  
405 // The only safe way to interact with Tcl is
406 // to create an event and add it to the thread
407 // safe event queue.
408  
409 TclEvent Tevent = new AnonymousClassTclEvent(command, this); // end TclEvent innerclass
410  
411 // Add the event to the thread safe event queue
412 interp.getNotifier().queueEvent(Tevent, TCL.QUEUE_TAIL);
413  
414 // Tell this thread to wait until the event has been processed.
415 Tevent.sync();
416 }
417 }
418 private static void WriteLine(string s)
419 {
420 System.Console.Out.WriteLine(s);
421 if (debug) System.Diagnostics.Debug.WriteLine(s);
422 }
423 private void getLine()
424 {
425 sbuf.Append(Console.In.ReadLine());
426 }
427 private void putLine(Channel channel, string s)
428 // The String to print.
429 {
430 try
431 {
432 channel.write(interp, s);
433 channel.write(interp, "\n");
434 channel.flush(interp);
435 }
436 catch (System.IO.IOException ex)
437 {
438 System.Console.Error.WriteLine("IOException in Shell.putLine()");
439 SupportClass.WriteStackTrace(ex, System.Console.Error);
440 }
441 catch (TclException ex)
442 {
443 System.Console.Error.WriteLine("TclException in Shell.putLine()");
444 SupportClass.WriteStackTrace(ex, System.Console.Error);
445 }
446 }
447 private void put(Channel channel, string s)
448 // The String to print.
449 {
450 try
451 {
452 channel.write(interp, s);
453 channel.flush(interp);
454 }
455 catch (System.IO.IOException ex)
456 {
457 System.Console.Error.WriteLine("IOException in Shell.put()");
458 SupportClass.WriteStackTrace(ex, System.Console.Error);
459 }
460 catch (TclException ex)
461 {
462 System.Console.Error.WriteLine("TclException in Shell.put()");
463 SupportClass.WriteStackTrace(ex, System.Console.Error);
464 }
465 }
466 static ConsoleThread()
467 {
468 {
469 try
470 {
471 // There is no way to tell whether System.in will block AWT
472 // threads, so we assume it does block if we can use
473 // System.in.available().
474  
475 long available = 0;
476 // HACK ATK
477 // available = System.Console.In.Length - System.Console.In.Position;
478 int generatedAux5 = (int)available;
479 sysInAvailableWorks = true;
480 }
481 catch (System.Exception e)
482 {
483 // If System.in.available() causes an exception -- it's probably
484 // no supported on this platform (e.g. MS Java SDK). We assume
485 // sysInAvailableWorks is false and let the user suffer ...
486 }
487  
488 // Sun's JDK 1.2 on Windows systems is screwed up, it does not
489 // echo chars to the console unless blocking IO is used.
490 // For this reason we need to use blocking IO under Windows.
491  
492 if (Util.Windows)
493 {
494 sysInAvailableWorks = false;
495 }
496 if (debug)
497 {
498 WriteLine("sysInAvailableWorks = " + sysInAvailableWorks);
499 }
500 }
501 }
502 } // end of class ConsoleThread
503 }