os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclMain.c
Update contrib.
4 * Main program for Tcl shells and other Tcl-based applications.
6 * Copyright (c) 1988-1994 The Regents of the University of California.
7 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
8 * Copyright (c) 2000 Ajuba Solutions.
9 * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 * RCS: @(#) $Id: tclMain.c,v 1.20.2.3 2006/05/05 18:08:58 dgp Exp $
19 #if defined(__SYMBIAN32__)
21 #include "tclSymbianGlobals.h"
22 #include "tclIntPlatDecls.h"
25 # undef TCL_STORAGE_CLASS
26 # define TCL_STORAGE_CLASS DLLEXPORT
29 * Declarations for various library procedures and variables (don't want
30 * to include tclPort.h here, because people might copy this file out of
31 * the Tcl source directory to make their own modified versions).
35 # if !defined(__SYMBIAN32__)
36 extern int isatty _ANSI_ARGS_((int fd));
42 static Tcl_Obj *tclStartupScriptPath = NULL;
44 static Tcl_MainLoopProc *mainLoopProc = NULL;
47 * Structure definition for information used to keep the state of
48 * an interactive command processor that reads lines from standard
49 * input and writes prompts and results to standard output.
53 PROMPT_NONE, /* Print no prompt */
54 PROMPT_START, /* Print prompt for command start */
55 PROMPT_CONTINUE /* Print prompt for command continuation */
58 typedef struct InteractiveState {
59 Tcl_Channel input; /* The standard input channel from which
61 int tty; /* Non-zero means standard input is a
62 * terminal-like device. Zero means it's
64 Tcl_Obj *commandPtr; /* Used to assemble lines of input into
66 PromptType prompt; /* Next prompt to print */
67 Tcl_Interp *interp; /* Interpreter that evaluates interactive
72 * Forward declarations for procedures defined later in this file.
75 static void Prompt _ANSI_ARGS_((Tcl_Interp *interp,
76 PromptType *promptPtr));
77 static void StdinProc _ANSI_ARGS_((ClientData clientData,
80 *----------------------------------------------------------------------
82 * TclSetStartupScriptPath --
84 * Primes the startup script VFS path, used to override the
85 * command line processing.
91 * This procedure initializes the VFS path of the Tcl script to
94 *----------------------------------------------------------------------
96 void TclSetStartupScriptPath(pathPtr)
99 if (tclStartupScriptPath != NULL) {
100 Tcl_DecrRefCount(tclStartupScriptPath);
102 tclStartupScriptPath = pathPtr;
103 if (tclStartupScriptPath != NULL) {
104 Tcl_IncrRefCount(tclStartupScriptPath);
110 *----------------------------------------------------------------------
112 * TclGetStartupScriptPath --
114 * Gets the startup script VFS path, used to override the
115 * command line processing.
118 * The startup script VFS path, NULL if none has been set.
123 *----------------------------------------------------------------------
125 Tcl_Obj *TclGetStartupScriptPath()
127 return tclStartupScriptPath;
132 *----------------------------------------------------------------------
134 * TclSetStartupScriptFileName --
136 * Primes the startup script file name, used to override the
137 * command line processing.
143 * This procedure initializes the file name of the Tcl script to
146 *----------------------------------------------------------------------
148 void TclSetStartupScriptFileName(fileName)
149 CONST char *fileName;
151 Tcl_Obj *pathPtr = Tcl_NewStringObj(fileName,-1);
152 TclSetStartupScriptPath(pathPtr);
157 *----------------------------------------------------------------------
159 * TclGetStartupScriptFileName --
161 * Gets the startup script file name, used to override the
162 * command line processing.
165 * The startup script file name, NULL if none has been set.
170 *----------------------------------------------------------------------
172 CONST char *TclGetStartupScriptFileName()
174 Tcl_Obj *pathPtr = TclGetStartupScriptPath();
176 if (pathPtr == NULL) {
179 return Tcl_GetString(pathPtr);
185 *----------------------------------------------------------------------
189 * Main program for tclsh and most other Tcl-based applications.
192 * None. This procedure never returns (it exits the process when
196 * This procedure initializes the Tcl world and then starts
197 * interpreting commands; almost anything could happen, depending
198 * on the script being interpreted.
200 *----------------------------------------------------------------------
204 Tcl_Main(argc, argv, appInitProc)
205 int argc; /* Number of arguments. */
206 char **argv; /* Array of argument strings. */
207 Tcl_AppInitProc *appInitProc;
208 /* Application-specific initialization
209 * procedure to call after most
210 * initialization but before starting to
211 * execute commands. */
213 Tcl_Obj *resultPtr, *argvPtr, *commandPtr = NULL;
214 PromptType prompt = PROMPT_START;
215 int code, length, tty, exitCode = 0;
216 Tcl_Channel inChannel, outChannel, errChannel;
221 #if defined(__SYMBIAN32__)
222 int isChildProcess = 0;
225 Tcl_FindExecutable(argv[0]);
226 interp = Tcl_CreateInterp();
228 #if defined(__SYMBIAN32__)
229 if (ChildProcessInit(&argc, &argv))
237 Tcl_InitMemory(interp);
240 * Make command-line arguments available in the Tcl variables "argc"
241 * and "argv". If the first argument doesn't start with a "-" then
242 * strip it off and use it as the name of a script file to process.
245 if (TclGetStartupScriptPath() == NULL) {
246 if ((argc > 1) && (argv[1][0] != '-')) {
247 TclSetStartupScriptFileName(argv[1]);
253 if (TclGetStartupScriptPath() == NULL) {
254 Tcl_ExternalToUtfDString(NULL, argv[0], -1, &appName);
256 TclSetStartupScriptFileName(Tcl_ExternalToUtfDString(NULL,
257 TclGetStartupScriptFileName(), -1, &appName));
259 Tcl_SetVar(interp, "argv0", Tcl_DStringValue(&appName), TCL_GLOBAL_ONLY);
260 Tcl_DStringFree(&appName);
264 objPtr = Tcl_NewIntObj(argc);
265 Tcl_IncrRefCount(objPtr);
266 Tcl_SetVar2Ex(interp, "argc", NULL, objPtr, TCL_GLOBAL_ONLY);
267 Tcl_DecrRefCount(objPtr);
269 argvPtr = Tcl_NewListObj(0, NULL);
272 Tcl_ExternalToUtfDString(NULL, *argv++, -1, &ds);
273 Tcl_ListObjAppendElement(NULL, argvPtr, Tcl_NewStringObj(
274 Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)));
275 Tcl_DStringFree(&ds);
277 Tcl_IncrRefCount(argvPtr);
278 Tcl_SetVar2Ex(interp, "argv", NULL, argvPtr, TCL_GLOBAL_ONLY);
279 Tcl_DecrRefCount(argvPtr);
282 * Set the "tcl_interactive" variable.
286 Tcl_SetVar(interp, "tcl_interactive",
287 ((TclGetStartupScriptPath() == NULL) && tty) ? "1" : "0",
291 * Invoke application-specific initialization.
294 Tcl_Preserve((ClientData) interp);
295 if ((*appInitProc)(interp) != TCL_OK) {
296 errChannel = Tcl_GetStdChannel(TCL_STDERR);
298 Tcl_WriteChars(errChannel,
299 "application-specific initialization failed: ", -1);
300 Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));
301 Tcl_WriteChars(errChannel, "\n", 1);
304 if (Tcl_InterpDeleted(interp)) {
309 * If a script file was specified then just source that file
313 if (TclGetStartupScriptPath() != NULL) {
314 code = Tcl_FSEvalFile(interp, TclGetStartupScriptPath());
315 if (code != TCL_OK) {
316 errChannel = Tcl_GetStdChannel(TCL_STDERR);
320 * The following statement guarantees that the errorInfo
321 * variable is set properly.
324 Tcl_AddErrorInfo(interp, "");
325 Tcl_WriteObj(errChannel, Tcl_GetVar2Ex(interp, "errorInfo",
326 NULL, TCL_GLOBAL_ONLY));
327 Tcl_WriteChars(errChannel, "\n", 1);
335 * We're running interactively. Source a user-specific startup
336 * file if the application specified one and if the file exists.
339 Tcl_SourceRCFile(interp);
342 * Process commands from stdin until there's an end-of-file. Note
343 * that we need to fetch the standard channels again after every
344 * eval, since they may have been changed.
347 commandPtr = Tcl_NewObj();
348 Tcl_IncrRefCount(commandPtr);
351 * Get a new value for tty if anyone writes to ::tcl_interactive
353 Tcl_LinkVar(interp, "tcl_interactive", (char *) &tty, TCL_LINK_BOOLEAN);
354 inChannel = Tcl_GetStdChannel(TCL_STDIN);
355 outChannel = Tcl_GetStdChannel(TCL_STDOUT);
356 while ((inChannel != (Tcl_Channel) NULL) && !Tcl_InterpDeleted(interp)) {
357 if (mainLoopProc == NULL) {
359 Prompt(interp, &prompt);
360 if (Tcl_InterpDeleted(interp)) {
363 inChannel = Tcl_GetStdChannel(TCL_STDIN);
364 if (inChannel == (Tcl_Channel) NULL) {
368 if (Tcl_IsShared(commandPtr)) {
369 Tcl_DecrRefCount(commandPtr);
370 commandPtr = Tcl_DuplicateObj(commandPtr);
371 Tcl_IncrRefCount(commandPtr);
373 length = Tcl_GetsObj(inChannel, commandPtr);
375 if (Tcl_InputBlocked(inChannel)) {
378 * This can only happen if stdin has been set to
379 * non-blocking. In that case cycle back and try
380 * again. This sets up a tight polling loop (since
381 * we have no event loop running). If this causes
382 * bad CPU hogging, we might try toggling the blocking
390 * Either EOF, or an error on stdin; we're done
397 * Add the newline removed by Tcl_GetsObj back to the string.
400 if (Tcl_IsShared(commandPtr)) {
401 Tcl_DecrRefCount(commandPtr);
402 commandPtr = Tcl_DuplicateObj(commandPtr);
403 Tcl_IncrRefCount(commandPtr);
405 Tcl_AppendToObj(commandPtr, "\n", 1);
406 if (!TclObjCommandComplete(commandPtr)) {
407 prompt = PROMPT_CONTINUE;
411 prompt = PROMPT_START;
412 code = Tcl_RecordAndEvalObj(interp, commandPtr, TCL_EVAL_GLOBAL);
413 inChannel = Tcl_GetStdChannel(TCL_STDIN);
414 outChannel = Tcl_GetStdChannel(TCL_STDOUT);
415 errChannel = Tcl_GetStdChannel(TCL_STDERR);
416 Tcl_DecrRefCount(commandPtr);
417 commandPtr = Tcl_NewObj();
418 Tcl_IncrRefCount(commandPtr);
419 if (code != TCL_OK) {
421 Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));
422 Tcl_WriteChars(errChannel, "\n", 1);
425 resultPtr = Tcl_GetObjResult(interp);
426 Tcl_IncrRefCount(resultPtr);
427 Tcl_GetStringFromObj(resultPtr, &length);
428 if ((length > 0) && outChannel) {
429 Tcl_WriteObj(outChannel, resultPtr);
430 Tcl_WriteChars(outChannel, "\n", 1);
432 Tcl_DecrRefCount(resultPtr);
434 } else { /* (mainLoopProc != NULL) */
436 * If a main loop has been defined while running interactively,
437 * we want to start a fileevent based prompt by establishing a
438 * channel handler for stdin.
441 InteractiveState *isPtr = NULL;
445 Prompt(interp, &prompt);
447 isPtr = (InteractiveState *)
448 ckalloc((int) sizeof(InteractiveState));
449 isPtr->input = inChannel;
451 isPtr->commandPtr = commandPtr;
452 isPtr->prompt = prompt;
453 isPtr->interp = interp;
455 Tcl_UnlinkVar(interp, "tcl_interactive");
456 Tcl_LinkVar(interp, "tcl_interactive", (char *) &(isPtr->tty),
459 Tcl_CreateChannelHandler(inChannel, TCL_READABLE, StdinProc,
468 Tcl_UnlinkVar(interp, "tcl_interactive");
469 Tcl_LinkVar(interp, "tcl_interactive", (char *) &tty,
471 prompt = isPtr->prompt;
472 commandPtr = isPtr->commandPtr;
473 if (isPtr->input != (Tcl_Channel) NULL) {
474 Tcl_DeleteChannelHandler(isPtr->input, StdinProc,
477 ckfree((char *)isPtr);
479 inChannel = Tcl_GetStdChannel(TCL_STDIN);
480 outChannel = Tcl_GetStdChannel(TCL_STDOUT);
481 errChannel = Tcl_GetStdChannel(TCL_STDERR);
486 * This code here only for the (unsupported and deprecated)
487 * [checkmem] command.
490 if (tclMemDumpFileName != NULL) {
492 Tcl_DeleteInterp(interp);
498 if ((exitCode == 0) && (mainLoopProc != NULL)) {
501 * If everything has gone OK so far, call the main loop proc,
502 * if it exists. Packages (like Tk) can set it to start processing
503 * events at this point.
509 if (commandPtr != NULL) {
510 Tcl_DecrRefCount(commandPtr);
513 #if defined(__SYMBIAN32__)
514 ChildProcessCleanup(isChildProcess, oldArgc, argv);
518 close (TCL_STDERR); //every process has a error file
522 * Rather than calling exit, invoke the "exit" command so that
523 * users can replace "exit" with some other command to do additional
524 * cleanup on exit. The Tcl_Eval call should never return.
527 if (!Tcl_InterpDeleted(interp)) {
528 char buffer[TCL_INTEGER_SPACE + 5];
529 sprintf(buffer, "exit %d", exitCode);
530 Tcl_Eval(interp, buffer);
533 * If Tcl_Eval returns, trying to eval [exit], something
534 * unusual is happening. Maybe interp has been deleted;
535 * maybe [exit] was redefined. We still want to cleanup
539 if (!Tcl_InterpDeleted(interp)) {
540 Tcl_DeleteInterp(interp);
543 TclSetStartupScriptPath(NULL);
546 * If we get here, the master interp has been deleted. Allow
547 * its destruction with the last matching Tcl_Release.
550 Tcl_Release((ClientData) interp);
555 *---------------------------------------------------------------
559 * Sets an alternative main loop procedure.
562 * Returns the previously defined main loop procedure.
565 * This procedure will be called before Tcl exits, allowing for
566 * the creation of an event loop.
568 *---------------------------------------------------------------
572 Tcl_SetMainLoop(proc)
573 Tcl_MainLoopProc *proc;
579 *----------------------------------------------------------------------
583 * This procedure is invoked by the event dispatcher whenever
584 * standard input becomes readable. It grabs the next line of
585 * input characters, adds them to a command being assembled, and
586 * executes the command if it's complete.
592 * Could be almost arbitrary, depending on the command that's
595 *----------------------------------------------------------------------
600 StdinProc(clientData, mask)
601 ClientData clientData; /* The state of interactive cmd line */
602 int mask; /* Not used. */
604 InteractiveState *isPtr = (InteractiveState *) clientData;
605 Tcl_Channel chan = isPtr->input;
606 Tcl_Obj *commandPtr = isPtr->commandPtr;
607 Tcl_Interp *interp = isPtr->interp;
610 if (Tcl_IsShared(commandPtr)) {
611 Tcl_DecrRefCount(commandPtr);
612 commandPtr = Tcl_DuplicateObj(commandPtr);
613 Tcl_IncrRefCount(commandPtr);
615 length = Tcl_GetsObj(chan, commandPtr);
617 if (Tcl_InputBlocked(chan)) {
622 * Would be better to find a way to exit the mainLoop?
623 * Or perhaps evaluate [exit]? Leaving as is for now due
624 * to compatibility concerns.
628 Tcl_DeleteChannelHandler(chan, StdinProc, (ClientData) isPtr);
632 if (Tcl_IsShared(commandPtr)) {
633 Tcl_DecrRefCount(commandPtr);
634 commandPtr = Tcl_DuplicateObj(commandPtr);
635 Tcl_IncrRefCount(commandPtr);
637 Tcl_AppendToObj(commandPtr, "\n", 1);
638 if (!TclObjCommandComplete(commandPtr)) {
639 isPtr->prompt = PROMPT_CONTINUE;
642 isPtr->prompt = PROMPT_START;
645 * Disable the stdin channel handler while evaluating the command;
646 * otherwise if the command re-enters the event loop we might
647 * process commands from stdin before the current command is
648 * finished. Among other things, this will trash the text of the
649 * command being evaluated.
652 Tcl_CreateChannelHandler(chan, 0, StdinProc, (ClientData) isPtr);
653 code = Tcl_RecordAndEvalObj(interp, commandPtr, TCL_EVAL_GLOBAL);
654 isPtr->input = chan = Tcl_GetStdChannel(TCL_STDIN);
655 Tcl_DecrRefCount(commandPtr);
656 isPtr->commandPtr = commandPtr = Tcl_NewObj();
657 Tcl_IncrRefCount(commandPtr);
658 if (chan != (Tcl_Channel) NULL) {
659 Tcl_CreateChannelHandler(chan, TCL_READABLE, StdinProc,
662 if (code != TCL_OK) {
663 Tcl_Channel errChannel = Tcl_GetStdChannel(TCL_STDERR);
664 if (errChannel != (Tcl_Channel) NULL) {
665 Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));
666 Tcl_WriteChars(errChannel, "\n", 1);
668 } else if (isPtr->tty) {
669 Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
670 Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT);
671 Tcl_IncrRefCount(resultPtr);
672 Tcl_GetStringFromObj(resultPtr, &length);
673 if ((length >0) && (outChannel != (Tcl_Channel) NULL)) {
674 Tcl_WriteObj(outChannel, resultPtr);
675 Tcl_WriteChars(outChannel, "\n", 1);
677 Tcl_DecrRefCount(resultPtr);
681 * If a tty stdin is still around, output a prompt.
685 if (isPtr->tty && (isPtr->input != (Tcl_Channel) NULL)) {
686 Prompt(interp, &(isPtr->prompt));
687 isPtr->input = Tcl_GetStdChannel(TCL_STDIN);
692 *----------------------------------------------------------------------
696 * Issue a prompt on standard output, or invoke a script
697 * to issue the prompt.
703 * A prompt gets output, and a Tcl script may be evaluated
706 *----------------------------------------------------------------------
710 Prompt(interp, promptPtr)
711 Tcl_Interp *interp; /* Interpreter to use for prompting. */
712 PromptType *promptPtr; /* Points to type of prompt to print.
713 * Filled with PROMPT_NONE after a
714 * prompt is printed. */
716 Tcl_Obj *promptCmdPtr;
718 Tcl_Channel outChannel, errChannel;
720 if (*promptPtr == PROMPT_NONE) {
724 promptCmdPtr = Tcl_GetVar2Ex(interp,
725 ((*promptPtr == PROMPT_CONTINUE) ? "tcl_prompt2" : "tcl_prompt1"),
726 NULL, TCL_GLOBAL_ONLY);
727 if (Tcl_InterpDeleted(interp)) {
730 if (promptCmdPtr == NULL) {
732 outChannel = Tcl_GetStdChannel(TCL_STDOUT);
733 if ((*promptPtr == PROMPT_START)
734 && (outChannel != (Tcl_Channel) NULL)) {
735 Tcl_WriteChars(outChannel, "% ", 2);
738 code = Tcl_EvalObjEx(interp, promptCmdPtr, TCL_EVAL_GLOBAL);
739 if (code != TCL_OK) {
740 Tcl_AddErrorInfo(interp,
741 "\n (script that generates prompt)");
742 errChannel = Tcl_GetStdChannel(TCL_STDERR);
743 if (errChannel != (Tcl_Channel) NULL) {
744 Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));
745 Tcl_WriteChars(errChannel, "\n", 1);
750 outChannel = Tcl_GetStdChannel(TCL_STDOUT);
751 if (outChannel != (Tcl_Channel) NULL) {
752 Tcl_Flush(outChannel);
754 *promptPtr = PROMPT_NONE;