os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclMain.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /* 
     2  * tclMain.c --
     3  *
     4  *	Main program for Tcl shells and other Tcl-based applications.
     5  *
     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.  
    10  *
    11  * See the file "license.terms" for information on usage and redistribution
    12  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    13  *
    14  * RCS: @(#) $Id: tclMain.c,v 1.20.2.3 2006/05/05 18:08:58 dgp Exp $
    15  */
    16 
    17 #include "tcl.h"
    18 #include "tclInt.h"
    19 #if defined(__SYMBIAN32__)    
    20 #include "tclPort.h"
    21 #include "tclSymbianGlobals.h"
    22 #include "tclIntPlatDecls.h"
    23 #endif
    24 
    25 # undef TCL_STORAGE_CLASS
    26 # define TCL_STORAGE_CLASS DLLEXPORT
    27 
    28 /*
    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).
    32  */
    33 
    34 #if !defined(MAC_TCL)
    35 # if !defined(__SYMBIAN32__)    
    36 extern int		isatty _ANSI_ARGS_((int fd));
    37 # endif
    38 #else
    39 #include <unistd.h>
    40 #endif
    41 
    42 static Tcl_Obj *tclStartupScriptPath = NULL;
    43 
    44 static Tcl_MainLoopProc *mainLoopProc = NULL;
    45 
    46 /* 
    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.
    50  */
    51 
    52 typedef enum {
    53     PROMPT_NONE,	/* Print no prompt */
    54     PROMPT_START,	/* Print prompt for command start */
    55     PROMPT_CONTINUE	/* Print prompt for command continuation */
    56 } PromptType;
    57 
    58 typedef struct InteractiveState {
    59     Tcl_Channel input;		/* The standard input channel from which
    60 				 * lines are read. */
    61     int tty;                    /* Non-zero means standard input is a 
    62 				 * terminal-like device.  Zero means it's
    63 				 * a file. */
    64     Tcl_Obj *commandPtr;	/* Used to assemble lines of input into
    65 				 * Tcl commands. */
    66     PromptType prompt;		/* Next prompt to print */
    67     Tcl_Interp *interp;		/* Interpreter that evaluates interactive
    68 				 * commands. */
    69 } InteractiveState;
    70 
    71 /*
    72  * Forward declarations for procedures defined later in this file.
    73  */
    74 
    75 static void		Prompt _ANSI_ARGS_((Tcl_Interp *interp,
    76 			    PromptType *promptPtr));
    77 static void		StdinProc _ANSI_ARGS_((ClientData clientData,
    78 			    int mask));
    79 /*
    80  *----------------------------------------------------------------------
    81  *
    82  * TclSetStartupScriptPath --
    83  *
    84  *	Primes the startup script VFS path, used to override the
    85  *      command line processing.
    86  *
    87  * Results:
    88  *	None. 
    89  *
    90  * Side effects:
    91  *	This procedure initializes the VFS path of the Tcl script to
    92  *      run at startup.
    93  *
    94  *----------------------------------------------------------------------
    95  */
    96 void TclSetStartupScriptPath(pathPtr)
    97     Tcl_Obj *pathPtr;
    98 {
    99     if (tclStartupScriptPath != NULL) {
   100 	Tcl_DecrRefCount(tclStartupScriptPath);
   101     }
   102     tclStartupScriptPath = pathPtr;
   103     if (tclStartupScriptPath != NULL) {
   104 	Tcl_IncrRefCount(tclStartupScriptPath);
   105     }
   106 }
   107 
   108 
   109 /*
   110  *----------------------------------------------------------------------
   111  *
   112  * TclGetStartupScriptPath --
   113  *
   114  *	Gets the startup script VFS path, used to override the
   115  *      command line processing.
   116  *
   117  * Results:
   118  *	The startup script VFS path, NULL if none has been set.
   119  *
   120  * Side effects:
   121  *	None.
   122  *
   123  *----------------------------------------------------------------------
   124  */
   125 Tcl_Obj *TclGetStartupScriptPath()
   126 {
   127     return tclStartupScriptPath;
   128 }
   129 
   130 
   131 /*
   132  *----------------------------------------------------------------------
   133  *
   134  * TclSetStartupScriptFileName --
   135  *
   136  *	Primes the startup script file name, used to override the
   137  *      command line processing.
   138  *
   139  * Results:
   140  *	None. 
   141  *
   142  * Side effects:
   143  *	This procedure initializes the file name of the Tcl script to
   144  *      run at startup.
   145  *
   146  *----------------------------------------------------------------------
   147  */
   148 void TclSetStartupScriptFileName(fileName)
   149     CONST char *fileName;
   150 {
   151     Tcl_Obj *pathPtr = Tcl_NewStringObj(fileName,-1);
   152     TclSetStartupScriptPath(pathPtr);
   153 }
   154 
   155 
   156 /*
   157  *----------------------------------------------------------------------
   158  *
   159  * TclGetStartupScriptFileName --
   160  *
   161  *	Gets the startup script file name, used to override the
   162  *      command line processing.
   163  *
   164  * Results:
   165  *	The startup script file name, NULL if none has been set.
   166  *
   167  * Side effects:
   168  *	None.
   169  *
   170  *----------------------------------------------------------------------
   171  */
   172 CONST char *TclGetStartupScriptFileName()
   173 {
   174     Tcl_Obj *pathPtr = TclGetStartupScriptPath();
   175 
   176     if (pathPtr == NULL) {
   177 	return NULL;
   178     }
   179     return Tcl_GetString(pathPtr);
   180 }
   181 
   182 
   183 
   184 /*
   185  *----------------------------------------------------------------------
   186  *
   187  * Tcl_Main --
   188  *
   189  *	Main program for tclsh and most other Tcl-based applications.
   190  *
   191  * Results:
   192  *	None. This procedure never returns (it exits the process when
   193  *	it's done).
   194  *
   195  * Side effects:
   196  *	This procedure initializes the Tcl world and then starts
   197  *	interpreting commands;  almost anything could happen, depending
   198  *	on the script being interpreted.
   199  *
   200  *----------------------------------------------------------------------
   201  */
   202 
   203 void
   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. */
   212 {
   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;
   217     Tcl_Interp *interp;
   218     Tcl_DString appName;
   219     Tcl_Obj *objPtr;
   220     
   221 #if defined(__SYMBIAN32__)    
   222     int isChildProcess = 0;  
   223     int oldArgc = 0;
   224 #endif  
   225     Tcl_FindExecutable(argv[0]);
   226     interp = Tcl_CreateInterp();
   227     
   228 #if defined(__SYMBIAN32__)    
   229     if (ChildProcessInit(&argc, &argv))
   230  	  {
   231  	  oldArgc = argc;
   232  	  argc = argc-4;	
   233  	  isChildProcess = 1;
   234  	  }
   235  #endif    
   236     
   237     Tcl_InitMemory(interp);
   238 
   239     /*
   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.
   243      */
   244 
   245     if (TclGetStartupScriptPath() == NULL) {
   246 	if ((argc > 1) && (argv[1][0] != '-')) {
   247 	    TclSetStartupScriptFileName(argv[1]);
   248 	    argc--;
   249 	    argv++;
   250 	}
   251     }
   252 
   253     if (TclGetStartupScriptPath() == NULL) {
   254 	Tcl_ExternalToUtfDString(NULL, argv[0], -1, &appName);
   255     } else {
   256 	TclSetStartupScriptFileName(Tcl_ExternalToUtfDString(NULL,
   257 		TclGetStartupScriptFileName(), -1, &appName));
   258     }
   259     Tcl_SetVar(interp, "argv0", Tcl_DStringValue(&appName), TCL_GLOBAL_ONLY);
   260     Tcl_DStringFree(&appName);
   261     argc--;
   262     argv++;
   263 
   264     objPtr = Tcl_NewIntObj(argc);
   265     Tcl_IncrRefCount(objPtr);
   266     Tcl_SetVar2Ex(interp, "argc", NULL, objPtr, TCL_GLOBAL_ONLY);
   267     Tcl_DecrRefCount(objPtr);
   268     
   269     argvPtr = Tcl_NewListObj(0, NULL);
   270     while (argc--) {
   271 	Tcl_DString ds;
   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);
   276     }
   277     Tcl_IncrRefCount(argvPtr);
   278     Tcl_SetVar2Ex(interp, "argv", NULL, argvPtr, TCL_GLOBAL_ONLY);
   279     Tcl_DecrRefCount(argvPtr);
   280 
   281     /*
   282      * Set the "tcl_interactive" variable.
   283      */
   284 
   285     tty = isatty(0);
   286     Tcl_SetVar(interp, "tcl_interactive",
   287 	    ((TclGetStartupScriptPath() == NULL) && tty) ? "1" : "0",
   288 	    TCL_GLOBAL_ONLY);
   289     
   290     /*
   291      * Invoke application-specific initialization.
   292      */
   293 
   294     Tcl_Preserve((ClientData) interp);
   295     if ((*appInitProc)(interp) != TCL_OK) {
   296 	errChannel = Tcl_GetStdChannel(TCL_STDERR);
   297 	if (errChannel) {
   298 	    Tcl_WriteChars(errChannel,
   299 		    "application-specific initialization failed: ", -1);
   300 	    Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));
   301 	    Tcl_WriteChars(errChannel, "\n", 1);
   302 	}
   303     }
   304     if (Tcl_InterpDeleted(interp)) {
   305 	goto done;
   306     }
   307 
   308     /*
   309      * If a script file was specified then just source that file
   310      * and quit.
   311      */
   312 
   313     if (TclGetStartupScriptPath() != NULL) {
   314 	code = Tcl_FSEvalFile(interp, TclGetStartupScriptPath());
   315 	if (code != TCL_OK) {
   316 	    errChannel = Tcl_GetStdChannel(TCL_STDERR);
   317 	    if (errChannel) {
   318 
   319 		/*
   320 		 * The following statement guarantees that the errorInfo
   321 		 * variable is set properly.
   322 		 */
   323 
   324 		Tcl_AddErrorInfo(interp, "");
   325 		Tcl_WriteObj(errChannel, Tcl_GetVar2Ex(interp, "errorInfo",
   326 			NULL, TCL_GLOBAL_ONLY));
   327 		Tcl_WriteChars(errChannel, "\n", 1);
   328 	    }
   329 	    exitCode = 1;
   330 	}
   331 	goto done;
   332     }
   333 
   334     /*
   335      * We're running interactively.  Source a user-specific startup
   336      * file if the application specified one and if the file exists.
   337      */
   338 
   339     Tcl_SourceRCFile(interp);
   340 
   341     /*
   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.
   345      */
   346 
   347     commandPtr = Tcl_NewObj();
   348     Tcl_IncrRefCount(commandPtr);
   349 
   350     /*
   351      * Get a new value for tty if anyone writes to ::tcl_interactive
   352      */
   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) {
   358 	    if (tty) {
   359 		Prompt(interp, &prompt);
   360 		if (Tcl_InterpDeleted(interp)) {
   361 		    break;
   362 		}
   363 		inChannel = Tcl_GetStdChannel(TCL_STDIN);
   364 		if (inChannel == (Tcl_Channel) NULL) {
   365 	            break;
   366 		}
   367 	    }
   368 	    if (Tcl_IsShared(commandPtr)) {
   369 		Tcl_DecrRefCount(commandPtr);
   370 		commandPtr = Tcl_DuplicateObj(commandPtr);
   371 		Tcl_IncrRefCount(commandPtr);
   372 	    }
   373             length = Tcl_GetsObj(inChannel, commandPtr);
   374 	    if (length < 0) {
   375 		if (Tcl_InputBlocked(inChannel)) {
   376 
   377 		    /*
   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
   383 		     * on stdin instead.
   384 		     */
   385 
   386 		    continue;
   387 		}
   388 
   389 		/* 
   390 		 * Either EOF, or an error on stdin; we're done
   391 		 */
   392 
   393 		break;
   394 	    }
   395 
   396             /*
   397              * Add the newline removed by Tcl_GetsObj back to the string.
   398              */
   399 
   400 	    if (Tcl_IsShared(commandPtr)) {
   401 		Tcl_DecrRefCount(commandPtr);
   402 		commandPtr = Tcl_DuplicateObj(commandPtr);
   403 		Tcl_IncrRefCount(commandPtr);
   404 	    }
   405 	    Tcl_AppendToObj(commandPtr, "\n", 1);
   406 	    if (!TclObjCommandComplete(commandPtr)) {
   407 		prompt = PROMPT_CONTINUE;
   408 		continue;
   409 	    }
   410 
   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) {
   420 		if (errChannel) {
   421 		    Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));
   422 		    Tcl_WriteChars(errChannel, "\n", 1);
   423 		}
   424 	    } else if (tty) {
   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);
   431 		}
   432 		Tcl_DecrRefCount(resultPtr);
   433 	    }
   434 	} else {	/* (mainLoopProc != NULL) */
   435 	    /*
   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.
   439 	     */
   440 
   441 	    InteractiveState *isPtr = NULL;
   442 
   443 	    if (inChannel) {
   444 	        if (tty) {
   445 		    Prompt(interp, &prompt);
   446 	        }
   447 		isPtr = (InteractiveState *) 
   448 			ckalloc((int) sizeof(InteractiveState));
   449 		isPtr->input = inChannel;
   450 		isPtr->tty = tty;
   451 		isPtr->commandPtr = commandPtr;
   452 		isPtr->prompt = prompt;
   453 		isPtr->interp = interp;
   454 
   455 		Tcl_UnlinkVar(interp, "tcl_interactive");
   456 		Tcl_LinkVar(interp, "tcl_interactive", (char *) &(isPtr->tty),
   457 			TCL_LINK_BOOLEAN);
   458 
   459 		Tcl_CreateChannelHandler(inChannel, TCL_READABLE, StdinProc,
   460 			(ClientData) isPtr);
   461 	    }
   462 
   463 	    (*mainLoopProc)();
   464 	    mainLoopProc = NULL;
   465 
   466 	    if (inChannel) {
   467 		tty = isPtr->tty;
   468 		Tcl_UnlinkVar(interp, "tcl_interactive");
   469 		Tcl_LinkVar(interp, "tcl_interactive", (char *) &tty,
   470 			TCL_LINK_BOOLEAN);
   471 		prompt = isPtr->prompt;
   472 		commandPtr = isPtr->commandPtr;
   473 		if (isPtr->input != (Tcl_Channel) NULL) {
   474 		    Tcl_DeleteChannelHandler(isPtr->input, StdinProc,
   475 			    (ClientData) isPtr);
   476 		}
   477 		ckfree((char *)isPtr);
   478 	    }
   479 	    inChannel = Tcl_GetStdChannel(TCL_STDIN);
   480 	    outChannel = Tcl_GetStdChannel(TCL_STDOUT);
   481 	    errChannel = Tcl_GetStdChannel(TCL_STDERR);
   482 	}
   483 #ifdef TCL_MEM_DEBUG
   484 
   485 	/*
   486 	 * This code here only for the (unsupported and deprecated)
   487 	 * [checkmem] command.
   488 	 */
   489 
   490 	if (tclMemDumpFileName != NULL) {
   491 	    mainLoopProc = NULL;
   492 	    Tcl_DeleteInterp(interp);
   493 	}
   494 #endif
   495     }
   496 
   497     done:
   498     if ((exitCode == 0) && (mainLoopProc != NULL)) {
   499 
   500 	/*
   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.
   504 	 */
   505 
   506 	(*mainLoopProc)();
   507 	mainLoopProc = NULL;
   508     }
   509     if (commandPtr != NULL) {
   510 	Tcl_DecrRefCount(commandPtr);
   511     }
   512 
   513 #if defined(__SYMBIAN32__)
   514     ChildProcessCleanup(isChildProcess, oldArgc, argv);	  
   515 #else
   516     close (TCL_STDIN);
   517     close (TCL_STDOUT);
   518     close (TCL_STDERR); //every process has a error file
   519 #endif
   520 
   521     /*
   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.
   525      */
   526 
   527     if (!Tcl_InterpDeleted(interp)) {
   528 	char buffer[TCL_INTEGER_SPACE + 5];
   529         sprintf(buffer, "exit %d", exitCode);
   530         Tcl_Eval(interp, buffer);
   531 
   532         /*
   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
   536          * and exit.
   537          */
   538 
   539         if (!Tcl_InterpDeleted(interp)) {
   540             Tcl_DeleteInterp(interp);
   541         }
   542     }
   543     TclSetStartupScriptPath(NULL);
   544 
   545     /*
   546      * If we get here, the master interp has been deleted.  Allow
   547      * its destruction with the last matching Tcl_Release.
   548      */
   549 
   550     Tcl_Release((ClientData) interp);
   551     Tcl_Exit(exitCode);
   552 }
   553 
   554 /*
   555  *---------------------------------------------------------------
   556  *
   557  * Tcl_SetMainLoop --
   558  *
   559  *	Sets an alternative main loop procedure.
   560  *
   561  * Results:
   562  *	Returns the previously defined main loop procedure.
   563  *
   564  * Side effects:
   565  *	This procedure will be called before Tcl exits, allowing for
   566  *	the creation of an event loop.
   567  *
   568  *---------------------------------------------------------------
   569  */
   570 
   571 EXPORT_C void
   572 Tcl_SetMainLoop(proc)
   573     Tcl_MainLoopProc *proc;
   574 {
   575     mainLoopProc = proc;
   576 }
   577 
   578 /*
   579  *----------------------------------------------------------------------
   580  *
   581  * StdinProc --
   582  *
   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.
   587  *
   588  * Results:
   589  *	None.
   590  *
   591  * Side effects:
   592  *	Could be almost arbitrary, depending on the command that's
   593  *	typed.
   594  *
   595  *----------------------------------------------------------------------
   596  */
   597 
   598     /* ARGSUSED */
   599 static void
   600 StdinProc(clientData, mask)
   601     ClientData clientData;		/* The state of interactive cmd line */
   602     int mask;				/* Not used. */
   603 {
   604     InteractiveState *isPtr = (InteractiveState *) clientData;
   605     Tcl_Channel chan = isPtr->input;
   606     Tcl_Obj *commandPtr = isPtr->commandPtr;
   607     Tcl_Interp *interp = isPtr->interp;
   608     int code, length;
   609 
   610     if (Tcl_IsShared(commandPtr)) {
   611 	Tcl_DecrRefCount(commandPtr);
   612 	commandPtr = Tcl_DuplicateObj(commandPtr);
   613 	Tcl_IncrRefCount(commandPtr);
   614     }
   615     length = Tcl_GetsObj(chan, commandPtr);
   616     if (length < 0) {
   617 	if (Tcl_InputBlocked(chan)) {
   618 	    return;
   619 	}
   620 	if (isPtr->tty) {
   621 	    /*
   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.
   625 	     */
   626 	    Tcl_Exit(0);
   627 	}
   628 	Tcl_DeleteChannelHandler(chan, StdinProc, (ClientData) isPtr);
   629 	return;
   630     }
   631 
   632     if (Tcl_IsShared(commandPtr)) {
   633 	Tcl_DecrRefCount(commandPtr);
   634 	commandPtr = Tcl_DuplicateObj(commandPtr);
   635 	Tcl_IncrRefCount(commandPtr);
   636     }
   637     Tcl_AppendToObj(commandPtr, "\n", 1);
   638     if (!TclObjCommandComplete(commandPtr)) {
   639         isPtr->prompt = PROMPT_CONTINUE;
   640         goto prompt;
   641     }
   642     isPtr->prompt = PROMPT_START;
   643 
   644     /*
   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.
   650      */
   651 
   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,
   660 		(ClientData) isPtr);
   661     }
   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);
   667 	}
   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);
   676 	}
   677 	Tcl_DecrRefCount(resultPtr);
   678     }
   679 
   680     /*
   681      * If a tty stdin is still around, output a prompt.
   682      */
   683 
   684     prompt:
   685     if (isPtr->tty && (isPtr->input != (Tcl_Channel) NULL)) {
   686 	Prompt(interp, &(isPtr->prompt));
   687 	isPtr->input = Tcl_GetStdChannel(TCL_STDIN);
   688     }
   689 }
   690 
   691 /*
   692  *----------------------------------------------------------------------
   693  *
   694  * Prompt --
   695  *
   696  *	Issue a prompt on standard output, or invoke a script
   697  *	to issue the prompt.
   698  *
   699  * Results:
   700  *	None.
   701  *
   702  * Side effects:
   703  *	A prompt gets output, and a Tcl script may be evaluated
   704  *	in interp.
   705  *
   706  *----------------------------------------------------------------------
   707  */
   708 
   709 static void
   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. */
   715 {
   716     Tcl_Obj *promptCmdPtr;
   717     int code;
   718     Tcl_Channel outChannel, errChannel;
   719 
   720     if (*promptPtr == PROMPT_NONE) {
   721 	return;
   722     }
   723 
   724     promptCmdPtr = Tcl_GetVar2Ex(interp,
   725 	    ((*promptPtr == PROMPT_CONTINUE) ? "tcl_prompt2" : "tcl_prompt1"),
   726 	    NULL, TCL_GLOBAL_ONLY);
   727     if (Tcl_InterpDeleted(interp)) {
   728 	return;
   729     }
   730     if (promptCmdPtr == NULL) {
   731 	defaultPrompt:
   732 	outChannel = Tcl_GetStdChannel(TCL_STDOUT);
   733 	if ((*promptPtr == PROMPT_START)
   734 		&& (outChannel != (Tcl_Channel) NULL)) {
   735 	    Tcl_WriteChars(outChannel, "% ", 2);
   736 	}
   737     } else {
   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);
   746             }
   747 	    goto defaultPrompt;
   748 	}
   749     }
   750     outChannel = Tcl_GetStdChannel(TCL_STDOUT);
   751     if (outChannel != (Tcl_Channel) NULL) {
   752 	Tcl_Flush(outChannel);
   753     }
   754     *promptPtr = PROMPT_NONE;
   755 }