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.
sl@0
     1
/* 
sl@0
     2
 * tclMain.c --
sl@0
     3
 *
sl@0
     4
 *	Main program for Tcl shells and other Tcl-based applications.
sl@0
     5
 *
sl@0
     6
 * Copyright (c) 1988-1994 The Regents of the University of California.
sl@0
     7
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
sl@0
     8
 * Copyright (c) 2000 Ajuba Solutions.
sl@0
     9
 * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.  
sl@0
    10
 *
sl@0
    11
 * See the file "license.terms" for information on usage and redistribution
sl@0
    12
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    13
 *
sl@0
    14
 * RCS: @(#) $Id: tclMain.c,v 1.20.2.3 2006/05/05 18:08:58 dgp Exp $
sl@0
    15
 */
sl@0
    16
sl@0
    17
#include "tcl.h"
sl@0
    18
#include "tclInt.h"
sl@0
    19
#if defined(__SYMBIAN32__)    
sl@0
    20
#include "tclPort.h"
sl@0
    21
#include "tclSymbianGlobals.h"
sl@0
    22
#include "tclIntPlatDecls.h"
sl@0
    23
#endif
sl@0
    24
sl@0
    25
# undef TCL_STORAGE_CLASS
sl@0
    26
# define TCL_STORAGE_CLASS DLLEXPORT
sl@0
    27
sl@0
    28
/*
sl@0
    29
 * Declarations for various library procedures and variables (don't want
sl@0
    30
 * to include tclPort.h here, because people might copy this file out of
sl@0
    31
 * the Tcl source directory to make their own modified versions).
sl@0
    32
 */
sl@0
    33
sl@0
    34
#if !defined(MAC_TCL)
sl@0
    35
# if !defined(__SYMBIAN32__)    
sl@0
    36
extern int		isatty _ANSI_ARGS_((int fd));
sl@0
    37
# endif
sl@0
    38
#else
sl@0
    39
#include <unistd.h>
sl@0
    40
#endif
sl@0
    41
sl@0
    42
static Tcl_Obj *tclStartupScriptPath = NULL;
sl@0
    43
sl@0
    44
static Tcl_MainLoopProc *mainLoopProc = NULL;
sl@0
    45
sl@0
    46
/* 
sl@0
    47
 * Structure definition for information used to keep the state of
sl@0
    48
 * an interactive command processor that reads lines from standard
sl@0
    49
 * input and writes prompts and results to standard output.
sl@0
    50
 */
sl@0
    51
sl@0
    52
typedef enum {
sl@0
    53
    PROMPT_NONE,	/* Print no prompt */
sl@0
    54
    PROMPT_START,	/* Print prompt for command start */
sl@0
    55
    PROMPT_CONTINUE	/* Print prompt for command continuation */
sl@0
    56
} PromptType;
sl@0
    57
sl@0
    58
typedef struct InteractiveState {
sl@0
    59
    Tcl_Channel input;		/* The standard input channel from which
sl@0
    60
				 * lines are read. */
sl@0
    61
    int tty;                    /* Non-zero means standard input is a 
sl@0
    62
				 * terminal-like device.  Zero means it's
sl@0
    63
				 * a file. */
sl@0
    64
    Tcl_Obj *commandPtr;	/* Used to assemble lines of input into
sl@0
    65
				 * Tcl commands. */
sl@0
    66
    PromptType prompt;		/* Next prompt to print */
sl@0
    67
    Tcl_Interp *interp;		/* Interpreter that evaluates interactive
sl@0
    68
				 * commands. */
sl@0
    69
} InteractiveState;
sl@0
    70
sl@0
    71
/*
sl@0
    72
 * Forward declarations for procedures defined later in this file.
sl@0
    73
 */
sl@0
    74
sl@0
    75
static void		Prompt _ANSI_ARGS_((Tcl_Interp *interp,
sl@0
    76
			    PromptType *promptPtr));
sl@0
    77
static void		StdinProc _ANSI_ARGS_((ClientData clientData,
sl@0
    78
			    int mask));
sl@0
    79
/*
sl@0
    80
 *----------------------------------------------------------------------
sl@0
    81
 *
sl@0
    82
 * TclSetStartupScriptPath --
sl@0
    83
 *
sl@0
    84
 *	Primes the startup script VFS path, used to override the
sl@0
    85
 *      command line processing.
sl@0
    86
 *
sl@0
    87
 * Results:
sl@0
    88
 *	None. 
sl@0
    89
 *
sl@0
    90
 * Side effects:
sl@0
    91
 *	This procedure initializes the VFS path of the Tcl script to
sl@0
    92
 *      run at startup.
sl@0
    93
 *
sl@0
    94
 *----------------------------------------------------------------------
sl@0
    95
 */
sl@0
    96
void TclSetStartupScriptPath(pathPtr)
sl@0
    97
    Tcl_Obj *pathPtr;
sl@0
    98
{
sl@0
    99
    if (tclStartupScriptPath != NULL) {
sl@0
   100
	Tcl_DecrRefCount(tclStartupScriptPath);
sl@0
   101
    }
sl@0
   102
    tclStartupScriptPath = pathPtr;
sl@0
   103
    if (tclStartupScriptPath != NULL) {
sl@0
   104
	Tcl_IncrRefCount(tclStartupScriptPath);
sl@0
   105
    }
sl@0
   106
}
sl@0
   107
sl@0
   108
sl@0
   109
/*
sl@0
   110
 *----------------------------------------------------------------------
sl@0
   111
 *
sl@0
   112
 * TclGetStartupScriptPath --
sl@0
   113
 *
sl@0
   114
 *	Gets the startup script VFS path, used to override the
sl@0
   115
 *      command line processing.
sl@0
   116
 *
sl@0
   117
 * Results:
sl@0
   118
 *	The startup script VFS path, NULL if none has been set.
sl@0
   119
 *
sl@0
   120
 * Side effects:
sl@0
   121
 *	None.
sl@0
   122
 *
sl@0
   123
 *----------------------------------------------------------------------
sl@0
   124
 */
sl@0
   125
Tcl_Obj *TclGetStartupScriptPath()
sl@0
   126
{
sl@0
   127
    return tclStartupScriptPath;
sl@0
   128
}
sl@0
   129
sl@0
   130
sl@0
   131
/*
sl@0
   132
 *----------------------------------------------------------------------
sl@0
   133
 *
sl@0
   134
 * TclSetStartupScriptFileName --
sl@0
   135
 *
sl@0
   136
 *	Primes the startup script file name, used to override the
sl@0
   137
 *      command line processing.
sl@0
   138
 *
sl@0
   139
 * Results:
sl@0
   140
 *	None. 
sl@0
   141
 *
sl@0
   142
 * Side effects:
sl@0
   143
 *	This procedure initializes the file name of the Tcl script to
sl@0
   144
 *      run at startup.
sl@0
   145
 *
sl@0
   146
 *----------------------------------------------------------------------
sl@0
   147
 */
sl@0
   148
void TclSetStartupScriptFileName(fileName)
sl@0
   149
    CONST char *fileName;
sl@0
   150
{
sl@0
   151
    Tcl_Obj *pathPtr = Tcl_NewStringObj(fileName,-1);
sl@0
   152
    TclSetStartupScriptPath(pathPtr);
sl@0
   153
}
sl@0
   154
sl@0
   155

sl@0
   156
/*
sl@0
   157
 *----------------------------------------------------------------------
sl@0
   158
 *
sl@0
   159
 * TclGetStartupScriptFileName --
sl@0
   160
 *
sl@0
   161
 *	Gets the startup script file name, used to override the
sl@0
   162
 *      command line processing.
sl@0
   163
 *
sl@0
   164
 * Results:
sl@0
   165
 *	The startup script file name, NULL if none has been set.
sl@0
   166
 *
sl@0
   167
 * Side effects:
sl@0
   168
 *	None.
sl@0
   169
 *
sl@0
   170
 *----------------------------------------------------------------------
sl@0
   171
 */
sl@0
   172
CONST char *TclGetStartupScriptFileName()
sl@0
   173
{
sl@0
   174
    Tcl_Obj *pathPtr = TclGetStartupScriptPath();
sl@0
   175
sl@0
   176
    if (pathPtr == NULL) {
sl@0
   177
	return NULL;
sl@0
   178
    }
sl@0
   179
    return Tcl_GetString(pathPtr);
sl@0
   180
}
sl@0
   181
sl@0
   182
sl@0
   183

sl@0
   184
/*
sl@0
   185
 *----------------------------------------------------------------------
sl@0
   186
 *
sl@0
   187
 * Tcl_Main --
sl@0
   188
 *
sl@0
   189
 *	Main program for tclsh and most other Tcl-based applications.
sl@0
   190
 *
sl@0
   191
 * Results:
sl@0
   192
 *	None. This procedure never returns (it exits the process when
sl@0
   193
 *	it's done).
sl@0
   194
 *
sl@0
   195
 * Side effects:
sl@0
   196
 *	This procedure initializes the Tcl world and then starts
sl@0
   197
 *	interpreting commands;  almost anything could happen, depending
sl@0
   198
 *	on the script being interpreted.
sl@0
   199
 *
sl@0
   200
 *----------------------------------------------------------------------
sl@0
   201
 */
sl@0
   202
sl@0
   203
void
sl@0
   204
Tcl_Main(argc, argv, appInitProc)
sl@0
   205
    int argc;			/* Number of arguments. */
sl@0
   206
    char **argv;		/* Array of argument strings. */
sl@0
   207
    Tcl_AppInitProc *appInitProc;
sl@0
   208
				/* Application-specific initialization
sl@0
   209
				 * procedure to call after most
sl@0
   210
				 * initialization but before starting to
sl@0
   211
				 * execute commands. */
sl@0
   212
{
sl@0
   213
    Tcl_Obj *resultPtr, *argvPtr, *commandPtr = NULL;
sl@0
   214
    PromptType prompt = PROMPT_START;
sl@0
   215
    int code, length, tty, exitCode = 0;
sl@0
   216
    Tcl_Channel inChannel, outChannel, errChannel;
sl@0
   217
    Tcl_Interp *interp;
sl@0
   218
    Tcl_DString appName;
sl@0
   219
    Tcl_Obj *objPtr;
sl@0
   220
    
sl@0
   221
#if defined(__SYMBIAN32__)    
sl@0
   222
    int isChildProcess = 0;  
sl@0
   223
    int oldArgc = 0;
sl@0
   224
#endif  
sl@0
   225
    Tcl_FindExecutable(argv[0]);
sl@0
   226
    interp = Tcl_CreateInterp();
sl@0
   227
    
sl@0
   228
#if defined(__SYMBIAN32__)    
sl@0
   229
    if (ChildProcessInit(&argc, &argv))
sl@0
   230
 	  {
sl@0
   231
 	  oldArgc = argc;
sl@0
   232
 	  argc = argc-4;	
sl@0
   233
 	  isChildProcess = 1;
sl@0
   234
 	  }
sl@0
   235
 #endif    
sl@0
   236
    
sl@0
   237
    Tcl_InitMemory(interp);
sl@0
   238
sl@0
   239
    /*
sl@0
   240
     * Make command-line arguments available in the Tcl variables "argc"
sl@0
   241
     * and "argv".  If the first argument doesn't start with a "-" then
sl@0
   242
     * strip it off and use it as the name of a script file to process.
sl@0
   243
     */
sl@0
   244
sl@0
   245
    if (TclGetStartupScriptPath() == NULL) {
sl@0
   246
	if ((argc > 1) && (argv[1][0] != '-')) {
sl@0
   247
	    TclSetStartupScriptFileName(argv[1]);
sl@0
   248
	    argc--;
sl@0
   249
	    argv++;
sl@0
   250
	}
sl@0
   251
    }
sl@0
   252
sl@0
   253
    if (TclGetStartupScriptPath() == NULL) {
sl@0
   254
	Tcl_ExternalToUtfDString(NULL, argv[0], -1, &appName);
sl@0
   255
    } else {
sl@0
   256
	TclSetStartupScriptFileName(Tcl_ExternalToUtfDString(NULL,
sl@0
   257
		TclGetStartupScriptFileName(), -1, &appName));
sl@0
   258
    }
sl@0
   259
    Tcl_SetVar(interp, "argv0", Tcl_DStringValue(&appName), TCL_GLOBAL_ONLY);
sl@0
   260
    Tcl_DStringFree(&appName);
sl@0
   261
    argc--;
sl@0
   262
    argv++;
sl@0
   263
sl@0
   264
    objPtr = Tcl_NewIntObj(argc);
sl@0
   265
    Tcl_IncrRefCount(objPtr);
sl@0
   266
    Tcl_SetVar2Ex(interp, "argc", NULL, objPtr, TCL_GLOBAL_ONLY);
sl@0
   267
    Tcl_DecrRefCount(objPtr);
sl@0
   268
    
sl@0
   269
    argvPtr = Tcl_NewListObj(0, NULL);
sl@0
   270
    while (argc--) {
sl@0
   271
	Tcl_DString ds;
sl@0
   272
	Tcl_ExternalToUtfDString(NULL, *argv++, -1, &ds);
sl@0
   273
	Tcl_ListObjAppendElement(NULL, argvPtr, Tcl_NewStringObj(
sl@0
   274
		Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)));
sl@0
   275
	Tcl_DStringFree(&ds);
sl@0
   276
    }
sl@0
   277
    Tcl_IncrRefCount(argvPtr);
sl@0
   278
    Tcl_SetVar2Ex(interp, "argv", NULL, argvPtr, TCL_GLOBAL_ONLY);
sl@0
   279
    Tcl_DecrRefCount(argvPtr);
sl@0
   280
sl@0
   281
    /*
sl@0
   282
     * Set the "tcl_interactive" variable.
sl@0
   283
     */
sl@0
   284
sl@0
   285
    tty = isatty(0);
sl@0
   286
    Tcl_SetVar(interp, "tcl_interactive",
sl@0
   287
	    ((TclGetStartupScriptPath() == NULL) && tty) ? "1" : "0",
sl@0
   288
	    TCL_GLOBAL_ONLY);
sl@0
   289
    
sl@0
   290
    /*
sl@0
   291
     * Invoke application-specific initialization.
sl@0
   292
     */
sl@0
   293
sl@0
   294
    Tcl_Preserve((ClientData) interp);
sl@0
   295
    if ((*appInitProc)(interp) != TCL_OK) {
sl@0
   296
	errChannel = Tcl_GetStdChannel(TCL_STDERR);
sl@0
   297
	if (errChannel) {
sl@0
   298
	    Tcl_WriteChars(errChannel,
sl@0
   299
		    "application-specific initialization failed: ", -1);
sl@0
   300
	    Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));
sl@0
   301
	    Tcl_WriteChars(errChannel, "\n", 1);
sl@0
   302
	}
sl@0
   303
    }
sl@0
   304
    if (Tcl_InterpDeleted(interp)) {
sl@0
   305
	goto done;
sl@0
   306
    }
sl@0
   307
sl@0
   308
    /*
sl@0
   309
     * If a script file was specified then just source that file
sl@0
   310
     * and quit.
sl@0
   311
     */
sl@0
   312
sl@0
   313
    if (TclGetStartupScriptPath() != NULL) {
sl@0
   314
	code = Tcl_FSEvalFile(interp, TclGetStartupScriptPath());
sl@0
   315
	if (code != TCL_OK) {
sl@0
   316
	    errChannel = Tcl_GetStdChannel(TCL_STDERR);
sl@0
   317
	    if (errChannel) {
sl@0
   318
sl@0
   319
		/*
sl@0
   320
		 * The following statement guarantees that the errorInfo
sl@0
   321
		 * variable is set properly.
sl@0
   322
		 */
sl@0
   323
sl@0
   324
		Tcl_AddErrorInfo(interp, "");
sl@0
   325
		Tcl_WriteObj(errChannel, Tcl_GetVar2Ex(interp, "errorInfo",
sl@0
   326
			NULL, TCL_GLOBAL_ONLY));
sl@0
   327
		Tcl_WriteChars(errChannel, "\n", 1);
sl@0
   328
	    }
sl@0
   329
	    exitCode = 1;
sl@0
   330
	}
sl@0
   331
	goto done;
sl@0
   332
    }
sl@0
   333
sl@0
   334
    /*
sl@0
   335
     * We're running interactively.  Source a user-specific startup
sl@0
   336
     * file if the application specified one and if the file exists.
sl@0
   337
     */
sl@0
   338
sl@0
   339
    Tcl_SourceRCFile(interp);
sl@0
   340
sl@0
   341
    /*
sl@0
   342
     * Process commands from stdin until there's an end-of-file.  Note
sl@0
   343
     * that we need to fetch the standard channels again after every
sl@0
   344
     * eval, since they may have been changed.
sl@0
   345
     */
sl@0
   346
sl@0
   347
    commandPtr = Tcl_NewObj();
sl@0
   348
    Tcl_IncrRefCount(commandPtr);
sl@0
   349
sl@0
   350
    /*
sl@0
   351
     * Get a new value for tty if anyone writes to ::tcl_interactive
sl@0
   352
     */
sl@0
   353
    Tcl_LinkVar(interp, "tcl_interactive", (char *) &tty, TCL_LINK_BOOLEAN);
sl@0
   354
    inChannel = Tcl_GetStdChannel(TCL_STDIN);
sl@0
   355
    outChannel = Tcl_GetStdChannel(TCL_STDOUT);
sl@0
   356
    while ((inChannel != (Tcl_Channel) NULL) && !Tcl_InterpDeleted(interp)) {
sl@0
   357
	if (mainLoopProc == NULL) {
sl@0
   358
	    if (tty) {
sl@0
   359
		Prompt(interp, &prompt);
sl@0
   360
		if (Tcl_InterpDeleted(interp)) {
sl@0
   361
		    break;
sl@0
   362
		}
sl@0
   363
		inChannel = Tcl_GetStdChannel(TCL_STDIN);
sl@0
   364
		if (inChannel == (Tcl_Channel) NULL) {
sl@0
   365
	            break;
sl@0
   366
		}
sl@0
   367
	    }
sl@0
   368
	    if (Tcl_IsShared(commandPtr)) {
sl@0
   369
		Tcl_DecrRefCount(commandPtr);
sl@0
   370
		commandPtr = Tcl_DuplicateObj(commandPtr);
sl@0
   371
		Tcl_IncrRefCount(commandPtr);
sl@0
   372
	    }
sl@0
   373
            length = Tcl_GetsObj(inChannel, commandPtr);
sl@0
   374
	    if (length < 0) {
sl@0
   375
		if (Tcl_InputBlocked(inChannel)) {
sl@0
   376
sl@0
   377
		    /*
sl@0
   378
		     * This can only happen if stdin has been set to
sl@0
   379
		     * non-blocking.  In that case cycle back and try
sl@0
   380
		     * again.  This sets up a tight polling loop (since
sl@0
   381
		     * we have no event loop running).  If this causes
sl@0
   382
		     * bad CPU hogging, we might try toggling the blocking
sl@0
   383
		     * on stdin instead.
sl@0
   384
		     */
sl@0
   385
sl@0
   386
		    continue;
sl@0
   387
		}
sl@0
   388
sl@0
   389
		/* 
sl@0
   390
		 * Either EOF, or an error on stdin; we're done
sl@0
   391
		 */
sl@0
   392
sl@0
   393
		break;
sl@0
   394
	    }
sl@0
   395
sl@0
   396
            /*
sl@0
   397
             * Add the newline removed by Tcl_GetsObj back to the string.
sl@0
   398
             */
sl@0
   399
sl@0
   400
	    if (Tcl_IsShared(commandPtr)) {
sl@0
   401
		Tcl_DecrRefCount(commandPtr);
sl@0
   402
		commandPtr = Tcl_DuplicateObj(commandPtr);
sl@0
   403
		Tcl_IncrRefCount(commandPtr);
sl@0
   404
	    }
sl@0
   405
	    Tcl_AppendToObj(commandPtr, "\n", 1);
sl@0
   406
	    if (!TclObjCommandComplete(commandPtr)) {
sl@0
   407
		prompt = PROMPT_CONTINUE;
sl@0
   408
		continue;
sl@0
   409
	    }
sl@0
   410
sl@0
   411
	    prompt = PROMPT_START;
sl@0
   412
	    code = Tcl_RecordAndEvalObj(interp, commandPtr, TCL_EVAL_GLOBAL);
sl@0
   413
	    inChannel = Tcl_GetStdChannel(TCL_STDIN);
sl@0
   414
	    outChannel = Tcl_GetStdChannel(TCL_STDOUT);
sl@0
   415
	    errChannel = Tcl_GetStdChannel(TCL_STDERR);
sl@0
   416
	    Tcl_DecrRefCount(commandPtr);
sl@0
   417
	    commandPtr = Tcl_NewObj();
sl@0
   418
	    Tcl_IncrRefCount(commandPtr);
sl@0
   419
	    if (code != TCL_OK) {
sl@0
   420
		if (errChannel) {
sl@0
   421
		    Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));
sl@0
   422
		    Tcl_WriteChars(errChannel, "\n", 1);
sl@0
   423
		}
sl@0
   424
	    } else if (tty) {
sl@0
   425
		resultPtr = Tcl_GetObjResult(interp);
sl@0
   426
		Tcl_IncrRefCount(resultPtr);
sl@0
   427
		Tcl_GetStringFromObj(resultPtr, &length);
sl@0
   428
		if ((length > 0) && outChannel) {
sl@0
   429
		    Tcl_WriteObj(outChannel, resultPtr);
sl@0
   430
		    Tcl_WriteChars(outChannel, "\n", 1);
sl@0
   431
		}
sl@0
   432
		Tcl_DecrRefCount(resultPtr);
sl@0
   433
	    }
sl@0
   434
	} else {	/* (mainLoopProc != NULL) */
sl@0
   435
	    /*
sl@0
   436
	     * If a main loop has been defined while running interactively,
sl@0
   437
	     * we want to start a fileevent based prompt by establishing a
sl@0
   438
	     * channel handler for stdin.
sl@0
   439
	     */
sl@0
   440
sl@0
   441
	    InteractiveState *isPtr = NULL;
sl@0
   442
sl@0
   443
	    if (inChannel) {
sl@0
   444
	        if (tty) {
sl@0
   445
		    Prompt(interp, &prompt);
sl@0
   446
	        }
sl@0
   447
		isPtr = (InteractiveState *) 
sl@0
   448
			ckalloc((int) sizeof(InteractiveState));
sl@0
   449
		isPtr->input = inChannel;
sl@0
   450
		isPtr->tty = tty;
sl@0
   451
		isPtr->commandPtr = commandPtr;
sl@0
   452
		isPtr->prompt = prompt;
sl@0
   453
		isPtr->interp = interp;
sl@0
   454
sl@0
   455
		Tcl_UnlinkVar(interp, "tcl_interactive");
sl@0
   456
		Tcl_LinkVar(interp, "tcl_interactive", (char *) &(isPtr->tty),
sl@0
   457
			TCL_LINK_BOOLEAN);
sl@0
   458
sl@0
   459
		Tcl_CreateChannelHandler(inChannel, TCL_READABLE, StdinProc,
sl@0
   460
			(ClientData) isPtr);
sl@0
   461
	    }
sl@0
   462
sl@0
   463
	    (*mainLoopProc)();
sl@0
   464
	    mainLoopProc = NULL;
sl@0
   465
sl@0
   466
	    if (inChannel) {
sl@0
   467
		tty = isPtr->tty;
sl@0
   468
		Tcl_UnlinkVar(interp, "tcl_interactive");
sl@0
   469
		Tcl_LinkVar(interp, "tcl_interactive", (char *) &tty,
sl@0
   470
			TCL_LINK_BOOLEAN);
sl@0
   471
		prompt = isPtr->prompt;
sl@0
   472
		commandPtr = isPtr->commandPtr;
sl@0
   473
		if (isPtr->input != (Tcl_Channel) NULL) {
sl@0
   474
		    Tcl_DeleteChannelHandler(isPtr->input, StdinProc,
sl@0
   475
			    (ClientData) isPtr);
sl@0
   476
		}
sl@0
   477
		ckfree((char *)isPtr);
sl@0
   478
	    }
sl@0
   479
	    inChannel = Tcl_GetStdChannel(TCL_STDIN);
sl@0
   480
	    outChannel = Tcl_GetStdChannel(TCL_STDOUT);
sl@0
   481
	    errChannel = Tcl_GetStdChannel(TCL_STDERR);
sl@0
   482
	}
sl@0
   483
#ifdef TCL_MEM_DEBUG
sl@0
   484
sl@0
   485
	/*
sl@0
   486
	 * This code here only for the (unsupported and deprecated)
sl@0
   487
	 * [checkmem] command.
sl@0
   488
	 */
sl@0
   489
sl@0
   490
	if (tclMemDumpFileName != NULL) {
sl@0
   491
	    mainLoopProc = NULL;
sl@0
   492
	    Tcl_DeleteInterp(interp);
sl@0
   493
	}
sl@0
   494
#endif
sl@0
   495
    }
sl@0
   496
sl@0
   497
    done:
sl@0
   498
    if ((exitCode == 0) && (mainLoopProc != NULL)) {
sl@0
   499
sl@0
   500
	/*
sl@0
   501
	 * If everything has gone OK so far, call the main loop proc,
sl@0
   502
	 * if it exists.  Packages (like Tk) can set it to start processing
sl@0
   503
	 * events at this point.
sl@0
   504
	 */
sl@0
   505
sl@0
   506
	(*mainLoopProc)();
sl@0
   507
	mainLoopProc = NULL;
sl@0
   508
    }
sl@0
   509
    if (commandPtr != NULL) {
sl@0
   510
	Tcl_DecrRefCount(commandPtr);
sl@0
   511
    }
sl@0
   512
sl@0
   513
#if defined(__SYMBIAN32__)
sl@0
   514
    ChildProcessCleanup(isChildProcess, oldArgc, argv);	  
sl@0
   515
#else
sl@0
   516
    close (TCL_STDIN);
sl@0
   517
    close (TCL_STDOUT);
sl@0
   518
    close (TCL_STDERR); //every process has a error file
sl@0
   519
#endif
sl@0
   520
sl@0
   521
    /*
sl@0
   522
     * Rather than calling exit, invoke the "exit" command so that
sl@0
   523
     * users can replace "exit" with some other command to do additional
sl@0
   524
     * cleanup on exit.  The Tcl_Eval call should never return.
sl@0
   525
     */
sl@0
   526
sl@0
   527
    if (!Tcl_InterpDeleted(interp)) {
sl@0
   528
	char buffer[TCL_INTEGER_SPACE + 5];
sl@0
   529
        sprintf(buffer, "exit %d", exitCode);
sl@0
   530
        Tcl_Eval(interp, buffer);
sl@0
   531
sl@0
   532
        /*
sl@0
   533
         * If Tcl_Eval returns, trying to eval [exit], something
sl@0
   534
         * unusual is happening.  Maybe interp has been deleted;
sl@0
   535
         * maybe [exit] was redefined.  We still want to cleanup
sl@0
   536
         * and exit.
sl@0
   537
         */
sl@0
   538
sl@0
   539
        if (!Tcl_InterpDeleted(interp)) {
sl@0
   540
            Tcl_DeleteInterp(interp);
sl@0
   541
        }
sl@0
   542
    }
sl@0
   543
    TclSetStartupScriptPath(NULL);
sl@0
   544
sl@0
   545
    /*
sl@0
   546
     * If we get here, the master interp has been deleted.  Allow
sl@0
   547
     * its destruction with the last matching Tcl_Release.
sl@0
   548
     */
sl@0
   549
sl@0
   550
    Tcl_Release((ClientData) interp);
sl@0
   551
    Tcl_Exit(exitCode);
sl@0
   552
}
sl@0
   553

sl@0
   554
/*
sl@0
   555
 *---------------------------------------------------------------
sl@0
   556
 *
sl@0
   557
 * Tcl_SetMainLoop --
sl@0
   558
 *
sl@0
   559
 *	Sets an alternative main loop procedure.
sl@0
   560
 *
sl@0
   561
 * Results:
sl@0
   562
 *	Returns the previously defined main loop procedure.
sl@0
   563
 *
sl@0
   564
 * Side effects:
sl@0
   565
 *	This procedure will be called before Tcl exits, allowing for
sl@0
   566
 *	the creation of an event loop.
sl@0
   567
 *
sl@0
   568
 *---------------------------------------------------------------
sl@0
   569
 */
sl@0
   570
sl@0
   571
EXPORT_C void
sl@0
   572
Tcl_SetMainLoop(proc)
sl@0
   573
    Tcl_MainLoopProc *proc;
sl@0
   574
{
sl@0
   575
    mainLoopProc = proc;
sl@0
   576
}
sl@0
   577

sl@0
   578
/*
sl@0
   579
 *----------------------------------------------------------------------
sl@0
   580
 *
sl@0
   581
 * StdinProc --
sl@0
   582
 *
sl@0
   583
 *	This procedure is invoked by the event dispatcher whenever
sl@0
   584
 *	standard input becomes readable.  It grabs the next line of
sl@0
   585
 *	input characters, adds them to a command being assembled, and
sl@0
   586
 *	executes the command if it's complete.
sl@0
   587
 *
sl@0
   588
 * Results:
sl@0
   589
 *	None.
sl@0
   590
 *
sl@0
   591
 * Side effects:
sl@0
   592
 *	Could be almost arbitrary, depending on the command that's
sl@0
   593
 *	typed.
sl@0
   594
 *
sl@0
   595
 *----------------------------------------------------------------------
sl@0
   596
 */
sl@0
   597
sl@0
   598
    /* ARGSUSED */
sl@0
   599
static void
sl@0
   600
StdinProc(clientData, mask)
sl@0
   601
    ClientData clientData;		/* The state of interactive cmd line */
sl@0
   602
    int mask;				/* Not used. */
sl@0
   603
{
sl@0
   604
    InteractiveState *isPtr = (InteractiveState *) clientData;
sl@0
   605
    Tcl_Channel chan = isPtr->input;
sl@0
   606
    Tcl_Obj *commandPtr = isPtr->commandPtr;
sl@0
   607
    Tcl_Interp *interp = isPtr->interp;
sl@0
   608
    int code, length;
sl@0
   609
sl@0
   610
    if (Tcl_IsShared(commandPtr)) {
sl@0
   611
	Tcl_DecrRefCount(commandPtr);
sl@0
   612
	commandPtr = Tcl_DuplicateObj(commandPtr);
sl@0
   613
	Tcl_IncrRefCount(commandPtr);
sl@0
   614
    }
sl@0
   615
    length = Tcl_GetsObj(chan, commandPtr);
sl@0
   616
    if (length < 0) {
sl@0
   617
	if (Tcl_InputBlocked(chan)) {
sl@0
   618
	    return;
sl@0
   619
	}
sl@0
   620
	if (isPtr->tty) {
sl@0
   621
	    /*
sl@0
   622
	     * Would be better to find a way to exit the mainLoop?
sl@0
   623
	     * Or perhaps evaluate [exit]?  Leaving as is for now due
sl@0
   624
	     * to compatibility concerns.
sl@0
   625
	     */
sl@0
   626
	    Tcl_Exit(0);
sl@0
   627
	}
sl@0
   628
	Tcl_DeleteChannelHandler(chan, StdinProc, (ClientData) isPtr);
sl@0
   629
	return;
sl@0
   630
    }
sl@0
   631
sl@0
   632
    if (Tcl_IsShared(commandPtr)) {
sl@0
   633
	Tcl_DecrRefCount(commandPtr);
sl@0
   634
	commandPtr = Tcl_DuplicateObj(commandPtr);
sl@0
   635
	Tcl_IncrRefCount(commandPtr);
sl@0
   636
    }
sl@0
   637
    Tcl_AppendToObj(commandPtr, "\n", 1);
sl@0
   638
    if (!TclObjCommandComplete(commandPtr)) {
sl@0
   639
        isPtr->prompt = PROMPT_CONTINUE;
sl@0
   640
        goto prompt;
sl@0
   641
    }
sl@0
   642
    isPtr->prompt = PROMPT_START;
sl@0
   643
sl@0
   644
    /*
sl@0
   645
     * Disable the stdin channel handler while evaluating the command;
sl@0
   646
     * otherwise if the command re-enters the event loop we might
sl@0
   647
     * process commands from stdin before the current command is
sl@0
   648
     * finished.  Among other things, this will trash the text of the
sl@0
   649
     * command being evaluated.
sl@0
   650
     */
sl@0
   651
sl@0
   652
    Tcl_CreateChannelHandler(chan, 0, StdinProc, (ClientData) isPtr);
sl@0
   653
    code = Tcl_RecordAndEvalObj(interp, commandPtr, TCL_EVAL_GLOBAL);
sl@0
   654
    isPtr->input = chan = Tcl_GetStdChannel(TCL_STDIN);
sl@0
   655
    Tcl_DecrRefCount(commandPtr);
sl@0
   656
    isPtr->commandPtr = commandPtr = Tcl_NewObj();
sl@0
   657
    Tcl_IncrRefCount(commandPtr);
sl@0
   658
    if (chan != (Tcl_Channel) NULL) {
sl@0
   659
	Tcl_CreateChannelHandler(chan, TCL_READABLE, StdinProc,
sl@0
   660
		(ClientData) isPtr);
sl@0
   661
    }
sl@0
   662
    if (code != TCL_OK) {
sl@0
   663
	Tcl_Channel errChannel = Tcl_GetStdChannel(TCL_STDERR);
sl@0
   664
	if (errChannel != (Tcl_Channel) NULL) {
sl@0
   665
	    Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));
sl@0
   666
	    Tcl_WriteChars(errChannel, "\n", 1);
sl@0
   667
	}
sl@0
   668
    } else if (isPtr->tty) {
sl@0
   669
	Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
sl@0
   670
	Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT);
sl@0
   671
	Tcl_IncrRefCount(resultPtr);
sl@0
   672
	Tcl_GetStringFromObj(resultPtr, &length);
sl@0
   673
	if ((length >0) && (outChannel != (Tcl_Channel) NULL)) {
sl@0
   674
	    Tcl_WriteObj(outChannel, resultPtr);
sl@0
   675
	    Tcl_WriteChars(outChannel, "\n", 1);
sl@0
   676
	}
sl@0
   677
	Tcl_DecrRefCount(resultPtr);
sl@0
   678
    }
sl@0
   679
sl@0
   680
    /*
sl@0
   681
     * If a tty stdin is still around, output a prompt.
sl@0
   682
     */
sl@0
   683
sl@0
   684
    prompt:
sl@0
   685
    if (isPtr->tty && (isPtr->input != (Tcl_Channel) NULL)) {
sl@0
   686
	Prompt(interp, &(isPtr->prompt));
sl@0
   687
	isPtr->input = Tcl_GetStdChannel(TCL_STDIN);
sl@0
   688
    }
sl@0
   689
}
sl@0
   690

sl@0
   691
/*
sl@0
   692
 *----------------------------------------------------------------------
sl@0
   693
 *
sl@0
   694
 * Prompt --
sl@0
   695
 *
sl@0
   696
 *	Issue a prompt on standard output, or invoke a script
sl@0
   697
 *	to issue the prompt.
sl@0
   698
 *
sl@0
   699
 * Results:
sl@0
   700
 *	None.
sl@0
   701
 *
sl@0
   702
 * Side effects:
sl@0
   703
 *	A prompt gets output, and a Tcl script may be evaluated
sl@0
   704
 *	in interp.
sl@0
   705
 *
sl@0
   706
 *----------------------------------------------------------------------
sl@0
   707
 */
sl@0
   708
sl@0
   709
static void
sl@0
   710
Prompt(interp, promptPtr)
sl@0
   711
    Tcl_Interp *interp;			/* Interpreter to use for prompting. */
sl@0
   712
    PromptType *promptPtr;		/* Points to type of prompt to print.
sl@0
   713
					 * Filled with PROMPT_NONE after a
sl@0
   714
					 * prompt is printed. */
sl@0
   715
{
sl@0
   716
    Tcl_Obj *promptCmdPtr;
sl@0
   717
    int code;
sl@0
   718
    Tcl_Channel outChannel, errChannel;
sl@0
   719
sl@0
   720
    if (*promptPtr == PROMPT_NONE) {
sl@0
   721
	return;
sl@0
   722
    }
sl@0
   723
sl@0
   724
    promptCmdPtr = Tcl_GetVar2Ex(interp,
sl@0
   725
	    ((*promptPtr == PROMPT_CONTINUE) ? "tcl_prompt2" : "tcl_prompt1"),
sl@0
   726
	    NULL, TCL_GLOBAL_ONLY);
sl@0
   727
    if (Tcl_InterpDeleted(interp)) {
sl@0
   728
	return;
sl@0
   729
    }
sl@0
   730
    if (promptCmdPtr == NULL) {
sl@0
   731
	defaultPrompt:
sl@0
   732
	outChannel = Tcl_GetStdChannel(TCL_STDOUT);
sl@0
   733
	if ((*promptPtr == PROMPT_START)
sl@0
   734
		&& (outChannel != (Tcl_Channel) NULL)) {
sl@0
   735
	    Tcl_WriteChars(outChannel, "% ", 2);
sl@0
   736
	}
sl@0
   737
    } else {
sl@0
   738
	code = Tcl_EvalObjEx(interp, promptCmdPtr, TCL_EVAL_GLOBAL);
sl@0
   739
	if (code != TCL_OK) {
sl@0
   740
	    Tcl_AddErrorInfo(interp,
sl@0
   741
		    "\n    (script that generates prompt)");
sl@0
   742
	    errChannel = Tcl_GetStdChannel(TCL_STDERR);
sl@0
   743
            if (errChannel != (Tcl_Channel) NULL) {
sl@0
   744
                Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp));
sl@0
   745
                Tcl_WriteChars(errChannel, "\n", 1);
sl@0
   746
            }
sl@0
   747
	    goto defaultPrompt;
sl@0
   748
	}
sl@0
   749
    }
sl@0
   750
    outChannel = Tcl_GetStdChannel(TCL_STDOUT);
sl@0
   751
    if (outChannel != (Tcl_Channel) NULL) {
sl@0
   752
	Tcl_Flush(outChannel);
sl@0
   753
    }
sl@0
   754
    *promptPtr = PROMPT_NONE;
sl@0
   755
}