Annotation of researchv10no/cmd/worm/scsi/tcl/tclBasic.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * tclBasic.c --
        !             3:  *
        !             4:  *     Contains the basic facilities for TCL command interpretation,
        !             5:  *     including interpreter creation and deletion, command creation
        !             6:  *     and deletion, and command parsing and execution.
        !             7:  *
        !             8:  * Copyright 1987, 1990 Regents of the University of California
        !             9:  * Permission to use, copy, modify, and distribute this
        !            10:  * software and its documentation for any purpose and without
        !            11:  * fee is hereby granted, provided that the above copyright
        !            12:  * notice appear in all copies.  The University of California
        !            13:  * makes no representations about the suitability of this
        !            14:  * software for any purpose.  It is provided "as is" without
        !            15:  * express or implied warranty.
        !            16:  */
        !            17: 
        !            18: #ifndef lint
        !            19: static char rcsid[] = "$Header: /sprite/src/lib/tcl/RCS/tclBasic.c,v 1.72 90/03/29 10:36:39 ouster Exp $ SPRITE (Berkeley)";
        !            20: #pragma ref rcsid
        !            21: #endif not lint
        !            22: 
        !            23: #define        _POSIX_SOURCE
        !            24: 
        !            25: #include <stdio.h>
        !            26: #include <ctype.h>
        !            27: #include <stdlib.h>
        !            28: #include <string.h>
        !            29: #include "tclInt.h"
        !            30: 
        !            31: /*
        !            32:  * Built-in commands, and the procedures associated with them:
        !            33:  */
        !            34: 
        !            35: static char *builtInCmds[] = {
        !            36:     "break",
        !            37:     "case",
        !            38:     "catch",
        !            39:     "concat",
        !            40:     "continue",
        !            41:     "error",
        !            42:     "eval",
        !            43:     "exec",
        !            44:     "expr",
        !            45:     "file",
        !            46:     "for",
        !            47:     "foreach",
        !            48:     "format",
        !            49:     "glob",
        !            50:     "global",
        !            51:     "if",
        !            52:     "index",
        !            53:     "info",
        !            54:     "length",
        !            55:     "list",
        !            56:     "print",
        !            57:     "proc",
        !            58:     "range",
        !            59:     "rename",
        !            60:     "return",
        !            61:     "scan",
        !            62:     "set",
        !            63:     "source",
        !            64:     "string",
        !            65:     "time",
        !            66:     "uplevel",
        !            67:     NULL
        !            68: };
        !            69: 
        !            70: static int (*(builtInProcs[]))(ClientData , Tcl_Interp *, int , char **) = {
        !            71:     Tcl_BreakCmd,
        !            72:     Tcl_CaseCmd,
        !            73:     Tcl_CatchCmd,
        !            74:     Tcl_ConcatCmd,
        !            75:     Tcl_ContinueCmd,
        !            76:     Tcl_ErrorCmd,
        !            77:     Tcl_EvalCmd,
        !            78:     Tcl_ExecCmd,
        !            79:     Tcl_ExprCmd,
        !            80:     Tcl_FileCmd,
        !            81:     Tcl_ForCmd,
        !            82:     Tcl_ForeachCmd,
        !            83:     Tcl_FormatCmd,
        !            84:     Tcl_GlobCmd,
        !            85:     Tcl_GlobalCmd,
        !            86:     Tcl_IfCmd,
        !            87:     Tcl_IndexCmd,
        !            88:     Tcl_InfoCmd,
        !            89:     Tcl_LengthCmd,
        !            90:     Tcl_ListCmd,
        !            91:     Tcl_PrintCmd,
        !            92:     Tcl_ProcCmd,
        !            93:     Tcl_RangeCmd,
        !            94:     Tcl_RenameCmd,
        !            95:     Tcl_ReturnCmd,
        !            96:     Tcl_ScanCmd,
        !            97:     Tcl_SetCmd,
        !            98:     Tcl_SourceCmd,
        !            99:     Tcl_StringCmd,
        !           100:     Tcl_TimeCmd,
        !           101:     Tcl_UplevelCmd,
        !           102:     NULL
        !           103: };
        !           104: 
        !           105: /*
        !           106:  *----------------------------------------------------------------------
        !           107:  *
        !           108:  * Tcl_CreateInterp --
        !           109:  *
        !           110:  *     Create a new TCL command interpreter.
        !           111:  *
        !           112:  * Results:
        !           113:  *     The return value is a token for the interpreter, which may be
        !           114:  *     used in calls to procedures like Tcl_CreateCmd, Tcl_Eval, or
        !           115:  *     Tcl_DeleteInterp.
        !           116:  *
        !           117:  * Side effects:
        !           118:  *     The command interpreter is initialized with an empty variable
        !           119:  *     table and the built-in commands.
        !           120:  *
        !           121:  *----------------------------------------------------------------------
        !           122:  */
        !           123: 
        !           124: Tcl_Interp *
        !           125: Tcl_CreateInterp()
        !           126: {
        !           127:     register Interp *iPtr;
        !           128:     register char **namePtr;
        !           129:     register int (**procPtr)();
        !           130:     register Command *cmdPtr;
        !           131: 
        !           132:     iPtr = (Interp *) malloc(sizeof(Interp));
        !           133:     iPtr->result = iPtr->resultSpace;
        !           134:     iPtr->dynamic = 0;
        !           135:     iPtr->errorLine = 0;
        !           136:     iPtr->commandPtr = NULL;
        !           137:     iPtr->globalPtr = NULL;
        !           138:     iPtr->numLevels = 0;
        !           139:     iPtr->framePtr = NULL;
        !           140:     iPtr->varFramePtr = NULL;
        !           141:     iPtr->numEvents = 0;
        !           142:     iPtr->events = NULL;
        !           143:     iPtr->curEvent = 0;
        !           144:     iPtr->curEventNum = 0;
        !           145:     iPtr->revPtr = NULL;
        !           146:     iPtr->historyFirst = NULL;
        !           147:     iPtr->evalFirst = iPtr->evalLast = NULL;
        !           148:     iPtr->cmdCount = 0;
        !           149:     iPtr->noEval = 0;
        !           150:     iPtr->flags = 0;
        !           151:     iPtr->tracePtr = NULL;
        !           152:     iPtr->callbackPtr = NULL;
        !           153:     iPtr->resultSpace[0] = 0;
        !           154: 
        !           155:     /*
        !           156:      * Create the built-in commands.  Do it here, rather than calling
        !           157:      * Tcl_CreateCommand, because it's faster (there's no need to
        !           158:      * check for a pre-existing command by the same name).
        !           159:      */
        !           160: 
        !           161:     for (namePtr = builtInCmds, procPtr = builtInProcs;
        !           162:            *namePtr != NULL; namePtr++, procPtr++) {
        !           163:        cmdPtr = (Command *) malloc(CMD_SIZE(strlen(*namePtr)));
        !           164:        cmdPtr->proc = *procPtr;
        !           165:        cmdPtr->clientData = (ClientData) NULL;
        !           166:        cmdPtr->deleteProc = NULL;
        !           167:        cmdPtr->nextPtr = iPtr->commandPtr;
        !           168:        iPtr->commandPtr = cmdPtr;
        !           169:        strcpy(cmdPtr->name, *namePtr);
        !           170:     }
        !           171: 
        !           172:     return (Tcl_Interp *) iPtr;
        !           173: }
        !           174: 
        !           175: /*
        !           176:  *--------------------------------------------------------------
        !           177:  *
        !           178:  * Tcl_WatchInterp --
        !           179:  *
        !           180:  *     Arrange for a procedure to be called before a given
        !           181:  *     interpreter is deleted.
        !           182:  *
        !           183:  * Results:
        !           184:  *     None.
        !           185:  *
        !           186:  * Side effects:
        !           187:  *     When Tcl_DeleteInterp is invoked to delete interp,
        !           188:  *     proc will be invoked.  See the manual entry for
        !           189:  *     details.
        !           190:  *
        !           191:  *--------------------------------------------------------------
        !           192:  */
        !           193: 
        !           194: void
        !           195: Tcl_WatchInterp(interp, proc, clientData)
        !           196:     Tcl_Interp *interp;                /* Interpreter to watch. */
        !           197:     void (*proc)();            /* Procedure to call when interpreter
        !           198:                                 * is about to be deleted. */
        !           199:     ClientData clientData;     /* One-word value to pass to proc. */
        !           200: {
        !           201:     register InterpCallback *icPtr;
        !           202:     Interp *iPtr = (Interp *) interp;
        !           203: 
        !           204:     icPtr = (InterpCallback *) malloc(sizeof(InterpCallback));
        !           205:     icPtr->proc = proc;
        !           206:     icPtr->clientData = clientData;
        !           207:     icPtr->nextPtr = iPtr->callbackPtr;
        !           208:     iPtr->callbackPtr = icPtr;
        !           209: }
        !           210: 
        !           211: /*
        !           212:  *----------------------------------------------------------------------
        !           213:  *
        !           214:  * Tcl_DeleteInterp --
        !           215:  *
        !           216:  *     Delete an interpreter and free up all of the resources associated
        !           217:  *     with it.
        !           218:  *
        !           219:  * Results:
        !           220:  *     None.
        !           221:  *
        !           222:  * Side effects:
        !           223:  *     The interpreter is destroyed.  The caller should never again
        !           224:  *     use the interp token.
        !           225:  *
        !           226:  *----------------------------------------------------------------------
        !           227:  */
        !           228: 
        !           229: void
        !           230: Tcl_DeleteInterp(interp)
        !           231:     Tcl_Interp *interp;                /* Token for command interpreter (returned
        !           232:                                 * by a previous call to Tcl_CreateInterp). */
        !           233: {
        !           234:     Interp *iPtr = (Interp *) interp;
        !           235:     register Command *cmdPtr;
        !           236:     register Trace *tracePtr;
        !           237:     register InterpCallback *icPtr;
        !           238: 
        !           239:     /*
        !           240:      * If the interpreter is in use, delay the deletion until later.
        !           241:      */
        !           242: 
        !           243:     iPtr->flags |= DELETED;
        !           244:     if (iPtr->numLevels != 0) {
        !           245:        return;
        !           246:     }
        !           247: 
        !           248:     /*
        !           249:      * Invoke callbacks, if there's anyone who wants to know about
        !           250:      * the interpreter deletion.
        !           251:      */
        !           252: 
        !           253:     for (icPtr = iPtr->callbackPtr; icPtr != NULL;
        !           254:            icPtr = icPtr->nextPtr) {
        !           255:        (*icPtr->proc)(icPtr->clientData, interp);
        !           256:        free((char *) icPtr);
        !           257:     }
        !           258: 
        !           259:     /*
        !           260:      * Free up any remaining resources associated with the
        !           261:      * interpreter.
        !           262:      */
        !           263: 
        !           264:     for (cmdPtr = iPtr->commandPtr; cmdPtr != NULL;
        !           265:            cmdPtr = cmdPtr->nextPtr) {
        !           266:        if (cmdPtr->deleteProc != NULL) { 
        !           267:            (*cmdPtr->deleteProc)(cmdPtr->clientData);
        !           268:        }
        !           269:        free((char *) cmdPtr);
        !           270:     }
        !           271:     iPtr->commandPtr = NULL;
        !           272:     TclDeleteVars(iPtr);
        !           273:     if (iPtr->events != NULL) {
        !           274:        free((char *) iPtr->events);
        !           275:     }
        !           276:     while (iPtr->revPtr != NULL) {
        !           277:        free((char *) iPtr->revPtr);
        !           278:        iPtr->revPtr = iPtr->revPtr->nextPtr;
        !           279:     }
        !           280:     for (tracePtr = iPtr->tracePtr; tracePtr != NULL;
        !           281:            tracePtr = tracePtr->nextPtr) {
        !           282:        free((char *) tracePtr);
        !           283:     }
        !           284:     free((char *) iPtr);
        !           285: }
        !           286: 
        !           287: /*
        !           288:  *----------------------------------------------------------------------
        !           289:  *
        !           290:  * Tcl_CreateCommand --
        !           291:  *
        !           292:  *     Define a new command in a command table.
        !           293:  *
        !           294:  * Results:
        !           295:  *     None.
        !           296:  *
        !           297:  * Side effects:
        !           298:  *     If a command named cmdName already exists for interp, it is
        !           299:  *     deleted.  In the future, when cmdName is seen as the name of
        !           300:  *     a command by Tcl_Eval, proc will be called with the following
        !           301:  *     syntax:
        !           302:  *
        !           303:  *     int
        !           304:  *     proc(clientData, interp, argc, argv)
        !           305:  *         ClientData clientData;
        !           306:  *         Tcl_Interp *interp;
        !           307:  *         int argc;
        !           308:  *         char **argv;
        !           309:  *     {
        !           310:  *     }
        !           311:  *
        !           312:  *     The clientData and interp arguments are the same as the corresponding
        !           313:  *     arguments passed to this procedure.  Argc and argv describe the
        !           314:  *     arguments to the command, in the usual UNIX fashion.  Proc must
        !           315:  *     return a code like TCL_OK or TCL_ERROR.  It can also set interp->result
        !           316:  *     ("" is the default value if proc doesn't set it) and interp->dynamic (0
        !           317:  *     is the default).  See tcl.h for more information on these variables.
        !           318:  *
        !           319:  *     When the command is deleted from the table, deleteProc will be called
        !           320:  *     in the following way:
        !           321:  *
        !           322:  *     void
        !           323:  *     deleteProc(clientData)
        !           324:  *         ClientData clientData;
        !           325:  *     {
        !           326:  *     }
        !           327:  *
        !           328:  *     DeleteProc allows command implementors to perform their own cleanup
        !           329:  *     when commands (or interpreters) are deleted.
        !           330:  *
        !           331:  *----------------------------------------------------------------------
        !           332:  */
        !           333: 
        !           334: void
        !           335: Tcl_CreateCommand(interp, cmdName, proc, clientData, deleteProc)
        !           336:     Tcl_Interp *interp;                /* Token for command interpreter (returned
        !           337:                                 * by a previous call to Tcl_CreateInterp). */
        !           338:     char *cmdName;             /* Name of command. */
        !           339:     int (*proc)();             /* Command procedure to associate with
        !           340:                                 * cmdName. */
        !           341:     ClientData clientData;     /* Arbitrary one-word value to pass to proc. */
        !           342:     void (*deleteProc)();      /* If not NULL, gives a procedure to call when
        !           343:                                 * this command is deleted. */
        !           344: {
        !           345:     Interp *iPtr = (Interp *) interp;
        !           346:     register Command *cmdPtr;
        !           347: 
        !           348:     Tcl_DeleteCommand(interp, cmdName);
        !           349:     cmdPtr = (Command *) malloc(CMD_SIZE(strlen(cmdName)));
        !           350:     cmdPtr->proc = proc;
        !           351:     cmdPtr->clientData = clientData;
        !           352:     cmdPtr->deleteProc = deleteProc;
        !           353:     cmdPtr->nextPtr = iPtr->commandPtr;
        !           354:     iPtr->commandPtr = cmdPtr;
        !           355:     strcpy(cmdPtr->name, cmdName);
        !           356: }
        !           357: 
        !           358: /*
        !           359:  *----------------------------------------------------------------------
        !           360:  *
        !           361:  * Tcl_DeleteCommand --
        !           362:  *
        !           363:  *     Remove the given command from the given interpreter.
        !           364:  *
        !           365:  * Results:
        !           366:  *     None.
        !           367:  *
        !           368:  * Side effects:
        !           369:  *     CmdName will no longer be recognized as a valid command for
        !           370:  *     interp.
        !           371:  *
        !           372:  *----------------------------------------------------------------------
        !           373:  */
        !           374: 
        !           375: void
        !           376: Tcl_DeleteCommand(interp, cmdName)
        !           377:     Tcl_Interp *interp;                /* Token for command interpreter (returned
        !           378:                                 * by a previous call to Tcl_CreateInterp). */
        !           379:     char *cmdName;             /* Name of command to remove. */
        !           380: {
        !           381:     Interp *iPtr = (Interp *) interp;
        !           382:     Command *cmdPtr;
        !           383: 
        !           384:     cmdPtr = TclFindCmd(iPtr, cmdName, 0);
        !           385:     if (cmdPtr != NULL) {
        !           386:        if (cmdPtr->deleteProc != NULL) {
        !           387:            (*cmdPtr->deleteProc)(cmdPtr->clientData);
        !           388:        }
        !           389:        iPtr->commandPtr = cmdPtr->nextPtr;
        !           390:        free((char *) cmdPtr);
        !           391:     }
        !           392: }
        !           393: 
        !           394: /*
        !           395:  *-----------------------------------------------------------------
        !           396:  *
        !           397:  * Tcl_Eval --
        !           398:  *
        !           399:  *     Parse and execute a command in the Tcl language.
        !           400:  *
        !           401:  * Results:
        !           402:  *     The return value is one of the return codes defined in
        !           403:  *     tcl.h (such as TCL_OK), and interp->result contains a string
        !           404:  *     value to supplement the return code.  The value of interp->result
        !           405:  *     will persist only until the next call to Tcl_Eval:  copy it
        !           406:  *     or lose it!
        !           407:  *
        !           408:  * Side effects:
        !           409:  *     Almost certainly;  depends on the command.
        !           410:  *
        !           411:  *-----------------------------------------------------------------
        !           412:  */
        !           413: 
        !           414: int
        !           415: Tcl_Eval(interp, cmd, flags, termPtr)
        !           416:     Tcl_Interp *interp;                /* Token for command interpreter (returned
        !           417:                                 * by a previous call to Tcl_CreateInterp). */
        !           418:     char *cmd;                 /* Pointer to TCL command to interpret. */
        !           419:     int flags;                 /* OR-ed combination of flags like
        !           420:                                 * TCL_BRACKET_TERM and TCL_RECORD_BOUNDS. */
        !           421:     char **termPtr;            /* If non-NULL, fill in the address it points
        !           422:                                 * to with the address of the char. just after
        !           423:                                 * the last one that was part of cmd.  See
        !           424:                                 * the man page for details on this. */
        !           425: {
        !           426:     /*
        !           427:      * While processing the command, make a local copy of
        !           428:      * the command characters.  This is needed in order to
        !           429:      * terminate each argument with a null character, replace
        !           430:      * backslashed-characters, etc.  The copy starts out in
        !           431:      * a static string (for speed) but gets expanded into
        !           432:      * dynamically-allocated strings if necessary.  The constant
        !           433:      * BUFFER indicates how much space there must be in the copy
        !           434:      * in order to pass through the main loop below (e.g., must
        !           435:      * have space to copy both a backslash and its following
        !           436:      * characters).
        !           437:      */
        !           438: 
        !           439: #   define NUM_CHARS 200
        !           440: #   define BUFFER 5
        !           441:     char copyStorage[NUM_CHARS];
        !           442:     char *copy = copyStorage;  /* Pointer to current copy. */
        !           443:     int copySize = NUM_CHARS;  /* Size of current copy. */
        !           444:     register char *dst;                /* Points to next place to copy
        !           445:                                 * a character. */
        !           446:     char *limit;               /* When dst gets here, must make
        !           447:                                 * the copy larger. */
        !           448: 
        !           449:     /*
        !           450:      * This procedure generates an (argv, argc) array for the command,
        !           451:      * It starts out with stack-allocated space but uses dynamically-
        !           452:      * allocated storage to increase it if needed.
        !           453:      */
        !           454: 
        !           455: #   define NUM_ARGS 10
        !           456:     char *(argStorage[NUM_ARGS]);
        !           457:     char **argv = argStorage;
        !           458:     int argc;
        !           459:     int argSize = NUM_ARGS;
        !           460: 
        !           461:     int openBraces = 0;                        /* Curent brace nesting level. */
        !           462:     int openQuote = 0;                 /* Non-zero means quoted arg
        !           463:                                         * in progress. */
        !           464: 
        !           465:     register char *src;                        /* Points to current character
        !           466:                                         * in cmd. */
        !           467:     char termChar;                     /* Return when this character is found
        !           468:                                         * (either ']' or '\0').  Zero means
        !           469:                                         * that newlines terminate commands. */
        !           470:     char *argStart;                    /* Location in cmd of first                                                      * non-separator character in
        !           471:                                         * current argument;  it's
        !           472:                                         * used to eliminate multiple
        !           473:                                         * separators between args and
        !           474:                                         * extra separators after last
        !           475:                                         * arg in command. */
        !           476:     int result = TCL_OK;               /* Return value. */
        !           477:     int i;
        !           478:     register Interp *iPtr = (Interp *) interp;
        !           479:     Command *cmdPtr;
        !           480:     char *tmp;
        !           481:     char *dummy;                       /* Make termPtr point here if it was
        !           482:                                         * originally NULL. */
        !           483:     char *syntaxMsg;
        !           484:     char *syntaxPtr;                   /* Points to "relevant" character
        !           485:                                         * for syntax violations. */
        !           486:     char *cmdStart;                    /* Points to first non-blank char. in
        !           487:                                         * command (used in calling trace
        !           488:                                         * procedures). */
        !           489:     register Trace *tracePtr;
        !           490: 
        !           491:     /*
        !           492:      * Set up the result so that if there's no command at all in
        !           493:      * the string then this procedure will return TCL_OK.
        !           494:      */
        !           495: 
        !           496:     if (iPtr->dynamic) {
        !           497:        free((char *) iPtr->result);
        !           498:        iPtr->dynamic = 0;
        !           499:     }
        !           500:     iPtr->result = iPtr->resultSpace;
        !           501:     iPtr->resultSpace[0] = 0;
        !           502: 
        !           503:     /*
        !           504:      * Check depth of nested calls to Tcl_Eval:  if this gets too large,
        !           505:      * it's probably because of an infinite loop somewhere (e.g. self-
        !           506:      * recursive history invocation).
        !           507:      */
        !           508: 
        !           509:     iPtr->numLevels++;
        !           510:     if (iPtr->numLevels > MAX_NESTING_DEPTH) {
        !           511:        iPtr->result =  "too many nested calls to Tcl_Eval (infinite loop?)";
        !           512:        return TCL_ERROR;
        !           513:     }
        !           514: 
        !           515:     src = cmd;
        !           516:     result = TCL_OK;
        !           517:     if (flags & TCL_BRACKET_TERM) {
        !           518:        termChar = ']';
        !           519:     } else {
        !           520:        termChar = 0;
        !           521:     }
        !           522:     if (termPtr == NULL) {
        !           523:        termPtr = &dummy;
        !           524:     }
        !           525: 
        !           526:     /*
        !           527:      * There can be many sub-commands (separated by semi-colons or
        !           528:      * newlines) in one command string.  This outer loop iterates over
        !           529:      * the inner commands.
        !           530:      */
        !           531: 
        !           532:     for (*termPtr = src; *src != termChar; *termPtr = src) {
        !           533: 
        !           534:        /*
        !           535:         * Skim off leading white space and semi-colons, and skip comments.
        !           536:         */
        !           537: 
        !           538:        while (isspace(*src) || (*src == ';')) {
        !           539:            src += 1;
        !           540:        }
        !           541:        if (*src == '#') {
        !           542:            for (src++; *src != 0; src++) {
        !           543:                if (*src == '\n') {
        !           544:                    src++;
        !           545:                    break;
        !           546:                }
        !           547:            }
        !           548:            continue;
        !           549:        }
        !           550: 
        !           551:        /*
        !           552:         * Set up the first argument (the command name).  Note that
        !           553:         * the arg pointer gets set up BEFORE the first real character
        !           554:         * of the argument has been found.
        !           555:         */
        !           556:     
        !           557:        dst = copy;
        !           558:        argc = 0;
        !           559:        limit = copy + copySize - BUFFER;
        !           560:        argv[0] = dst;
        !           561:        argStart = cmdStart = src;
        !           562: 
        !           563:        /*
        !           564:         * Skim off the command name and arguments by looping over
        !           565:         * characters and processing each one according to its type.
        !           566:         */
        !           567:     
        !           568:        while (1) {
        !           569:            switch (*src) {
        !           570:     
        !           571:                /*
        !           572:                 * All braces are treated as normal characters
        !           573:                 * unless the first character of the argument is an
        !           574:                 * open brace.  In that case, braces nest and
        !           575:                 * the argument terminates when all braces are matched.
        !           576:                 * Internal braces are also copied like normal chars.
        !           577:                 */
        !           578:     
        !           579:                case '{': {
        !           580:                    if (!openBraces && !openQuote && (dst == argv[argc])) {
        !           581:                        syntaxPtr = src;
        !           582:                        openBraces = 1;
        !           583:                        break;
        !           584:                    }
        !           585:                    *dst = '{'; dst++;
        !           586:                    if (openBraces > 0) {
        !           587:                        openBraces++;
        !           588:                    }
        !           589:                    break;
        !           590:                }
        !           591: 
        !           592:                case '}': {
        !           593:                    if (openBraces == 1) {
        !           594:                        openBraces = 0;
        !           595:                        if (!isspace(src[1]) && (src[1] != termChar) &&
        !           596:                                (src[1] != 0) && (src[1] != ';')) {
        !           597:                            syntaxPtr = src;
        !           598:                            syntaxMsg = "extra characters after close-brace";
        !           599:                            goto syntaxError;
        !           600:                        }
        !           601:                    } else {
        !           602:                        *dst = '}'; dst++;
        !           603:                        if (openBraces > 0) {
        !           604:                            openBraces--;
        !           605:                        }
        !           606:                    }
        !           607:                    break;
        !           608:                }
        !           609: 
        !           610:                case '"': {
        !           611:                    if (!openQuote) {
        !           612:                        if (openBraces || (dst != argv[argc])) {
        !           613:                            *dst = '"'; dst++;
        !           614:                            break;
        !           615:                        }
        !           616:                        syntaxPtr = src;
        !           617:                        openQuote = 1;
        !           618:                    } else {
        !           619:                        openQuote = 0;
        !           620:                        if (!isspace(src[1]) && (src[1] != termChar) &&
        !           621:                                (src[1] != 0) && (src[1] != ';')) {
        !           622:                            syntaxPtr = src;
        !           623:                            syntaxMsg = "extra characters after close-quote";
        !           624:                            goto syntaxError;
        !           625:                        }
        !           626:                    }
        !           627:                    break;
        !           628:                }
        !           629:     
        !           630:                case '[': {
        !           631:     
        !           632:                    /*
        !           633:                     * Open bracket: if not in middle of braces, then execute
        !           634:                     * following command and substitute result into argument.
        !           635:                     */
        !           636: 
        !           637:                    if (openBraces != 0) {
        !           638:                        *dst = '['; dst++;
        !           639:                    } else {
        !           640:                        int length;
        !           641:     
        !           642:                        result = Tcl_Eval(interp, src+1,
        !           643:                                TCL_BRACKET_TERM | (flags & TCL_RECORD_BOUNDS),
        !           644:                                &tmp);
        !           645:                        src = tmp;
        !           646:                        if (result != TCL_OK) {
        !           647:                            goto done;
        !           648:                        }
        !           649:     
        !           650:                        /*
        !           651:                         * Copy the return value into the current argument.
        !           652:                         * May have to enlarge the argument storage.  When
        !           653:                         * enlarging, get more than enough to reduce the
        !           654:                         * likelihood of having to enlarge again.  This code
        !           655:                         * is used for $-processing also.
        !           656:                         */
        !           657: 
        !           658:                        copyResult:
        !           659:                        length = strlen(iPtr->result);
        !           660:                        if ((limit - dst) < length) {
        !           661:                            char *newCopy;
        !           662:                            int delta;
        !           663: 
        !           664:                            copySize = length + 10 + dst - copy;
        !           665:                            newCopy = (char *) malloc((unsigned) copySize);
        !           666:                            bcopy(copy, newCopy, (dst-copy));
        !           667:                            delta = newCopy - copy;
        !           668:                            dst += delta;
        !           669:                            for (i = 0; i <= argc; i++) {
        !           670:                                argv[i] += delta;
        !           671:                            }
        !           672:                            if (copy != copyStorage) {
        !           673:                                free((char *) copy);
        !           674:                            }
        !           675:                            copy = newCopy;
        !           676:                            limit = newCopy + copySize - BUFFER;
        !           677:                        }
        !           678:                        bcopy(iPtr->result, dst, length);
        !           679:                        dst += length;
        !           680:                    }
        !           681:                    break;
        !           682:                }
        !           683: 
        !           684:                case '$': {
        !           685:                    if (openBraces != 0) {
        !           686:                        *dst = '$'; dst++;
        !           687:                    } else {
        !           688:                        char *value;
        !           689: 
        !           690:                        /*
        !           691:                         * Parse off a variable name and copy its value.
        !           692:                         */
        !           693:     
        !           694:                        value = Tcl_ParseVar(interp, src, &tmp);
        !           695:                        if (value == NULL) {
        !           696:                            result = TCL_ERROR;
        !           697:                            goto done;
        !           698:                        }
        !           699:                        if (iPtr->dynamic) {
        !           700:                            free((char *) iPtr->result);
        !           701:                            iPtr->dynamic = 0;
        !           702:                        }
        !           703:                        iPtr->result = value;
        !           704:                        src = tmp-1;
        !           705:                        goto copyResult;
        !           706:                    }
        !           707:                    break;
        !           708:                }
        !           709: 
        !           710:                case ']': {
        !           711:                    if ((openBraces == 0) && (termChar == ']')) {
        !           712:                        goto cmdComplete;
        !           713:                    }
        !           714:                    *dst = ']'; dst++;
        !           715:                    break;
        !           716:                }
        !           717: 
        !           718:                case ';': {
        !           719:                    if (!openBraces && !openQuote) {
        !           720:                        goto cmdComplete;
        !           721:                    }
        !           722:                    *dst = *src; dst++;
        !           723:                    break;
        !           724:                }
        !           725:     
        !           726:                case '\n': {
        !           727: 
        !           728:                    /*
        !           729:                     * A newline can be either a command terminator
        !           730:                     * or a space character.  If it's a space character,
        !           731:                     * just fall through to the space code below.
        !           732:                     */
        !           733:     
        !           734:                    if (!openBraces && !openQuote && (termChar == 0)) {
        !           735:                        goto cmdComplete;
        !           736:                    }
        !           737:                }
        !           738: 
        !           739:                case '\r':
        !           740:                case ' ':
        !           741:                case '\t': {
        !           742:                    if (openBraces || openQuote) {
        !           743:     
        !           744:                        /*
        !           745:                         * Quoted space.  Copy it into the argument.
        !           746:                         */
        !           747: 
        !           748:                        *dst = *src; dst++;
        !           749:                    } else {
        !           750: 
        !           751:                        /*
        !           752:                         * Argument separator.  If there are many
        !           753:                         * separators in a row (src == argStart) just
        !           754:                         * ignore this separator.  Otherwise,
        !           755:                         * Null-terminate the current argument and
        !           756:                         * set up for the next one.
        !           757:                         */
        !           758: 
        !           759:                        if (src == argStart) {
        !           760:                            argStart = src+1;
        !           761:                            break;
        !           762:                        }
        !           763:                        argStart = src+1;
        !           764:                        *dst = 0;
        !           765:                        dst++; argc++;
        !           766: 
        !           767:                        /*
        !           768:                         * Make sure that the argument array is large enough
        !           769:                         * for the next argument plus a final NULL argument
        !           770:                         * pointer to terminate the list.
        !           771:                         */
        !           772: 
        !           773:                        if (argc >= argSize-1) {
        !           774:                            char **newArgs;
        !           775:     
        !           776:                            argSize *= 2;
        !           777:                            newArgs = (char **)
        !           778:                                    malloc((unsigned) argSize * sizeof(char *));
        !           779:                            for (i = 0; i < argc; i++) {
        !           780:                                newArgs[i] = argv[i];
        !           781:                            }
        !           782:                            if (argv != argStorage) {
        !           783:                                free((char *) argv);
        !           784:                            }
        !           785:                            argv = newArgs;
        !           786:                        }
        !           787:                        argv[argc] = dst;
        !           788:                        break;
        !           789:                    }
        !           790:                    break;
        !           791:                }
        !           792:     
        !           793:                case '\\': {
        !           794:                    int numRead;
        !           795: 
        !           796:                    /*
        !           797:                     * First of all, make the special check for
        !           798:                     * backslash followed by newline.  This can't
        !           799:                     * be processed in the normal fashion of
        !           800:                     * Tcl_Backslash because is maps to "nothing",
        !           801:                     * rather than to a character.
        !           802:                     */
        !           803: 
        !           804:                    if (src[1] == '\n') {
        !           805:                        if (argStart  == src) {
        !           806:                            argStart += 2;
        !           807:                        }
        !           808:                        src++;
        !           809:                        break;
        !           810:                    }
        !           811: 
        !           812:                    /*
        !           813:                     * If we're in an argument in braces then the
        !           814:                     * backslash doesn't get collapsed.  However,
        !           815:                     * whether we're in braces or not the characters
        !           816:                     * inside the backslash sequence must not receive
        !           817:                     * any additional processing:  make src point to
        !           818:                     * the last character of the sequence.
        !           819:                     */
        !           820: 
        !           821:                    *dst = Tcl_Backslash(src, &numRead);
        !           822:                    if (openBraces > 0) {
        !           823:                        for ( ; numRead > 0; src++, dst++, numRead--) {
        !           824:                            *dst = *src;
        !           825:                        }
        !           826:                        src--;
        !           827:                    } else {
        !           828:                        src += numRead-1;
        !           829:                        dst++;
        !           830:                    }
        !           831:                    break;
        !           832:                }
        !           833:     
        !           834:                case 0: {
        !           835: 
        !           836:                    /*
        !           837:                     * End of string.  Make sure that braces/quotes
        !           838:                     * were properly matched.  Also, it's only legal
        !           839:                     * to terminate a command by a null character if
        !           840:                     * termChar is zero.
        !           841:                     */
        !           842: 
        !           843:                    if (openQuote != 0) {
        !           844:                        syntaxMsg = "unmatched quote";
        !           845:                        goto syntaxError;
        !           846:                    }
        !           847:                    if (openBraces != 0) {
        !           848:                        syntaxMsg = "unmatched brace";
        !           849:                        goto syntaxError;
        !           850:                    }
        !           851:                    if (termChar == ']') {
        !           852:                        syntaxPtr = cmd;
        !           853:                        syntaxMsg = "missing close-bracket";
        !           854:                        goto syntaxError;
        !           855:                    }
        !           856:                    goto cmdComplete;
        !           857:                }
        !           858:     
        !           859:                default: {
        !           860:                    *dst = *src; dst++;
        !           861:                    break;
        !           862:                }
        !           863:            }
        !           864:            src += 1;
        !           865:     
        !           866:            /*
        !           867:             * Make sure that we're not running out of space in the
        !           868:             * string copy area.  If we are, allocate a larger area
        !           869:             * and copy the string.  Be sure to update all of the
        !           870:             * relevant pointers too.
        !           871:             */
        !           872:     
        !           873:            if (dst >= limit) {
        !           874:                char *newCopy;
        !           875:                int delta;
        !           876:     
        !           877:                copySize *= 2;
        !           878:                newCopy = (char *) malloc((unsigned) copySize);
        !           879:                bcopy(copy, newCopy, (dst-copy));
        !           880:                delta = newCopy - copy;
        !           881:                dst += delta;
        !           882:                for (i = 0; i <= argc; i++) {
        !           883:                    argv[i] += delta;
        !           884:                }
        !           885:                if (copy != copyStorage) {
        !           886:                    free((char *) copy);
        !           887:                }
        !           888:                copy = newCopy;
        !           889:                limit = newCopy + copySize - BUFFER;
        !           890:            }
        !           891:     
        !           892:        }
        !           893:     
        !           894:        /*
        !           895:         * Terminate the last argument and add a final NULL argument.  If
        !           896:         * the interpreter has been deleted then return;  if there's no
        !           897:         * command, then go on to the next iteration.
        !           898:         */
        !           899: 
        !           900:        cmdComplete:
        !           901:        if (iPtr->flags & DELETED) {
        !           902:            goto done;
        !           903:        }
        !           904:        if (src != argStart) {
        !           905:            *dst = 0;
        !           906:            argc++;
        !           907:        }
        !           908:        if ((argc == 0) || iPtr->noEval) {
        !           909:            continue;
        !           910:        }
        !           911:        argv[argc] = NULL;
        !           912: 
        !           913:        cmdPtr = TclFindCmd(iPtr, argv[0], 1);
        !           914:        if (cmdPtr == NULL) {
        !           915:            Tcl_Return(interp, (char *) NULL, TCL_STATIC);
        !           916:            sprintf(iPtr->result,
        !           917:                    "\"%.50s\" is an invalid command name %s",
        !           918:                    argv[0], "or ambiguous abbreviation");
        !           919:            result = TCL_ERROR;
        !           920:            goto done;
        !           921:        }
        !           922: 
        !           923:        /*
        !           924:         * Replace argv[0] with the full name of the command (in case
        !           925:         * argv[0] was an abbreviation).
        !           926:         */
        !           927: 
        !           928:        argv[0] = cmdPtr->name;
        !           929: 
        !           930:        /*
        !           931:         * Call trace procedures, if any.
        !           932:         */
        !           933: 
        !           934:        for (tracePtr = iPtr->tracePtr; tracePtr != NULL;
        !           935:                tracePtr = tracePtr->nextPtr) {
        !           936:            char saved;
        !           937: 
        !           938:            if (tracePtr->level < iPtr->numLevels) {
        !           939:                continue;
        !           940:            }
        !           941:            saved = *src;
        !           942:            *src = 0;
        !           943:            (*tracePtr->proc)(tracePtr->clientData, interp, iPtr->numLevels,
        !           944:                    cmdStart, cmdPtr->proc, cmdPtr->clientData, argc, argv);
        !           945:            *src = saved;
        !           946:        }
        !           947: 
        !           948:        /*
        !           949:         * Save information for the history module, if needed.
        !           950:         */
        !           951: 
        !           952:        if (flags & TCL_RECORD_BOUNDS) {
        !           953:            iPtr->evalFirst = cmdStart;
        !           954:            iPtr->evalLast = src;
        !           955:        } else {
        !           956:            iPtr->evalFirst = NULL;
        !           957:        }
        !           958: 
        !           959:        /*
        !           960:         * At long last, invoke the command procedure.  Reset the
        !           961:         * result to its default empty value first.
        !           962:         */
        !           963: 
        !           964:        iPtr->cmdCount++;
        !           965:        iPtr->flags &= ~ERR_IN_PROGRESS;
        !           966:        if (iPtr->dynamic) {
        !           967:            free((char *) iPtr->result);
        !           968:            iPtr->dynamic = 0;
        !           969:        }
        !           970:        iPtr->result = iPtr->resultSpace;
        !           971:        iPtr->resultSpace[0] = 0;
        !           972:        result = (*cmdPtr->proc)(cmdPtr->clientData, interp, argc, argv);
        !           973:        if (result != TCL_OK) {
        !           974:            break;
        !           975:        }
        !           976:     }
        !           977: 
        !           978:     /*
        !           979:      * Free up any extra resources that were allocated.
        !           980:      */
        !           981: 
        !           982:     done:
        !           983:     if (copy != copyStorage) {
        !           984:        free((char *) copy);
        !           985:     }
        !           986:     if (argv != argStorage) {
        !           987:        free((char *) argv);
        !           988:     }
        !           989:     iPtr->numLevels--;
        !           990:     if (iPtr->numLevels == 0) {
        !           991:        if (result == TCL_RETURN) {
        !           992:            result = TCL_OK;
        !           993:        }
        !           994:        if ((result != TCL_OK) && (result != TCL_ERROR)) {
        !           995:            Tcl_Return(interp, (char *) NULL, TCL_STATIC);
        !           996:            if (result == TCL_BREAK) {
        !           997:                iPtr->result = "invoked \"break\" outside of a loop";
        !           998:            } else if (result == TCL_CONTINUE) {
        !           999:                iPtr->result = "invoked \"continue\" outside of a loop";
        !          1000:            } else {
        !          1001:                iPtr->result = iPtr->resultSpace;
        !          1002:                sprintf(iPtr->resultSpace, "command returned bad code: %d",
        !          1003:                        result);
        !          1004:            }
        !          1005:            result = TCL_ERROR;
        !          1006:        }
        !          1007:        if (iPtr->flags & DELETED) {
        !          1008:            Tcl_DeleteInterp(interp);
        !          1009:        }
        !          1010:     }
        !          1011: 
        !          1012:     /*
        !          1013:      * If an error occurred, record information about what was being
        !          1014:      * executed when the error occurred.
        !          1015:      */
        !          1016: 
        !          1017:     if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
        !          1018:        int numChars;
        !          1019:        register char *p;
        !          1020:        char *ellipsis;
        !          1021: 
        !          1022:        /*
        !          1023:         * Compute the line number where the error occurred.
        !          1024:         */
        !          1025: 
        !          1026:        iPtr->errorLine = 1;
        !          1027:        for (p = cmd; p != cmdStart; p++) {
        !          1028:            if (*p == '\n') {
        !          1029:                iPtr->errorLine++;
        !          1030:            }
        !          1031:        }
        !          1032:        for ( ; isspace(*p) || (*p == ';'); p++) {
        !          1033:            if (*p == '\n') {
        !          1034:                iPtr->errorLine++;
        !          1035:            }
        !          1036:        }
        !          1037: 
        !          1038:        /*
        !          1039:         * Figure out how much of the command to print in the error
        !          1040:         * message (up to a certain number of characters, or up to
        !          1041:         * the first new-line).
        !          1042:         */
        !          1043: 
        !          1044:        ellipsis = "";
        !          1045:        p = strchr(cmdStart, '\n');
        !          1046:        if (p == NULL) {
        !          1047:            numChars = strlen(cmdStart);
        !          1048:        } else {
        !          1049:            numChars = p - cmdStart;
        !          1050:            if (p[1] != 0) {
        !          1051:                ellipsis = " ...";
        !          1052:            }
        !          1053:        }
        !          1054:        if (numChars > 40) {
        !          1055:            numChars = 40;
        !          1056:            ellipsis = " ...";
        !          1057:        }
        !          1058: 
        !          1059:        if (!(iPtr->flags & ERR_IN_PROGRESS)) {
        !          1060:            /*
        !          1061:             * This is the first piece of information being recorded
        !          1062:             * for this error.  Log the error message as well as the
        !          1063:             * command being executed.
        !          1064:             */
        !          1065: 
        !          1066:            if (strlen(iPtr->result) < 50) {
        !          1067:                sprintf(copyStorage,
        !          1068:                        "%s, while executing\n\"%.*s%s\"",
        !          1069:                        iPtr->result, numChars, cmdStart, ellipsis);
        !          1070:            } else {
        !          1071:                sprintf(copyStorage,
        !          1072:                        "%.50s..., while executing\n\"%.*s%s\"",
        !          1073:                        iPtr->result, numChars, cmdStart, ellipsis);
        !          1074:            }
        !          1075:        } else {
        !          1076:            sprintf(copyStorage, ", invoked from within\n\"%.*s%s\"",
        !          1077:                    numChars, cmdStart, ellipsis);
        !          1078:        }
        !          1079:        Tcl_AddErrorInfo(interp, copyStorage);
        !          1080:        iPtr->flags &= ~ERR_ALREADY_LOGGED;
        !          1081:     } else {
        !          1082:        iPtr->flags &= ~ERR_ALREADY_LOGGED;
        !          1083:     }
        !          1084:     return result;
        !          1085: 
        !          1086:     /*
        !          1087:      * Syntax error:  generate an error message.
        !          1088:      */
        !          1089: 
        !          1090:     syntaxError: {
        !          1091:        char *first, *last;
        !          1092: 
        !          1093:        Tcl_Return(interp, (char *) NULL, TCL_STATIC);
        !          1094:        for (first = syntaxPtr; ((first != cmd) && (first[-1] != '\n'));
        !          1095:                first--) {
        !          1096:            /* Null loop body. */
        !          1097:        }
        !          1098:        for (last = syntaxPtr; ((*last != 0) && (*last!= '\n')); last++) {
        !          1099:            /* Null loop body. */
        !          1100:        }
        !          1101:        if ((syntaxPtr - first) > 60) {
        !          1102:            first = syntaxPtr - 60;
        !          1103:        }
        !          1104:        if ((last - first) > 70) {
        !          1105:            last = first + 70;
        !          1106:        }
        !          1107:        if (last == first) {
        !          1108:            sprintf(iPtr->result, "%s", syntaxMsg);
        !          1109:        } else {
        !          1110:            sprintf(iPtr->result, "%s: '%.*s => %.*s'", syntaxMsg,
        !          1111:                    syntaxPtr-first, first, last-syntaxPtr, syntaxPtr);
        !          1112:        }
        !          1113:        result = TCL_ERROR;
        !          1114:     }
        !          1115: 
        !          1116:     goto done;
        !          1117: }
        !          1118: 
        !          1119: /*
        !          1120:  *----------------------------------------------------------------------
        !          1121:  *
        !          1122:  * Tcl_CreateTrace --
        !          1123:  *
        !          1124:  *     Arrange for a procedure to be called to trace command execution.
        !          1125:  *
        !          1126:  * Results:
        !          1127:  *     The return value is a token for the trace, which may be passed
        !          1128:  *     to Tcl_DeleteTrace to eliminate the trace.
        !          1129:  *
        !          1130:  * Side effects:
        !          1131:  *     From now on, proc will be called just before a command procedure
        !          1132:  *     is called to execute a Tcl command.  Calls to proc will have the
        !          1133:  *     following form:
        !          1134:  *
        !          1135:  *     void
        !          1136:  *     proc(clientData, interp, level, command, cmdProc, cmdClientData,
        !          1137:  *             argc, argv)
        !          1138:  *         ClientData clientData;
        !          1139:  *         Tcl_Interp *interp;
        !          1140:  *         int level;
        !          1141:  *         char *command;
        !          1142:  *         int (*cmdProc)();
        !          1143:  *         ClientData cmdClientData;
        !          1144:  *         int argc;
        !          1145:  *         char **argv;
        !          1146:  *     {
        !          1147:  *     }
        !          1148:  *
        !          1149:  *     The clientData and interp arguments to proc will be the same
        !          1150:  *     as the corresponding arguments to this procedure.  Level gives
        !          1151:  *     the nesting level of command interpretation for this interpreter
        !          1152:  *     (0 corresponds to top level).  Command gives the ASCII text of
        !          1153:  *     the raw command, cmdProc and cmdClientData give the procedure that
        !          1154:  *     will be called to process the command and the ClientData value it
        !          1155:  *     will receive, and argc and argv give the arguments to the
        !          1156:  *     command, after any argument parsing and substitution.  Proc
        !          1157:  *     does not return a value.
        !          1158:  *
        !          1159:  *----------------------------------------------------------------------
        !          1160:  */
        !          1161: 
        !          1162: Tcl_Trace
        !          1163: Tcl_CreateTrace(interp, level, proc, clientData)
        !          1164:     Tcl_Interp *interp;                /* Interpreter in which to create the trace. */
        !          1165:     int level;                 /* Only call proc for commands at nesting level
        !          1166:                                 * <= level (1 => top level). */
        !          1167:     void (*proc)();            /* Procedure to call before executing each
        !          1168:                                 * command. */
        !          1169:     ClientData clientData;     /* Arbitrary one-word value to pass to proc. */
        !          1170: {
        !          1171:     register Trace *tracePtr;
        !          1172:     register Interp *iPtr = (Interp *) interp;
        !          1173: 
        !          1174:     tracePtr = (Trace *) malloc(sizeof(Trace));
        !          1175:     tracePtr->level = level;
        !          1176:     tracePtr->proc = proc;
        !          1177:     tracePtr->clientData = clientData;
        !          1178:     tracePtr->nextPtr = iPtr->tracePtr;
        !          1179:     iPtr->tracePtr = tracePtr;
        !          1180: 
        !          1181:     return (Tcl_Trace) tracePtr;
        !          1182: }
        !          1183: 
        !          1184: /*
        !          1185:  *----------------------------------------------------------------------
        !          1186:  *
        !          1187:  * Tcl_DeleteTrace --
        !          1188:  *
        !          1189:  *     Remove a trace.
        !          1190:  *
        !          1191:  * Results:
        !          1192:  *     None.
        !          1193:  *
        !          1194:  * Side effects:
        !          1195:  *     From now on there will be no more calls to the procedure given
        !          1196:  *     in trace.
        !          1197:  *
        !          1198:  *----------------------------------------------------------------------
        !          1199:  */
        !          1200: 
        !          1201: void
        !          1202: Tcl_DeleteTrace(interp, trace)
        !          1203:     Tcl_Interp *interp;                /* Interpreter that contains trace. */
        !          1204:     Tcl_Trace trace;           /* Token for trace (returned previously by
        !          1205:                                 * Tcl_CreateTrace). */
        !          1206: {
        !          1207:     register Interp *iPtr = (Interp *) interp;
        !          1208:     register Trace *tracePtr = (Trace *) trace;
        !          1209:     register Trace *tracePtr2;
        !          1210: 
        !          1211:     if (iPtr->tracePtr == tracePtr) {
        !          1212:        iPtr->tracePtr = tracePtr->nextPtr;
        !          1213:        free((char *) tracePtr);
        !          1214:     } else {
        !          1215:        for (tracePtr2 = iPtr->tracePtr; tracePtr2 != NULL;
        !          1216:                tracePtr2 = tracePtr2->nextPtr) {
        !          1217:            if (tracePtr2->nextPtr == tracePtr) {
        !          1218:                tracePtr2->nextPtr = tracePtr->nextPtr;
        !          1219:                free((char *) tracePtr);
        !          1220:                return;
        !          1221:            }
        !          1222:        }
        !          1223:     }
        !          1224: }
        !          1225: 
        !          1226: /*
        !          1227:  *----------------------------------------------------------------------
        !          1228:  *
        !          1229:  * Tcl_AddErrorInfo --
        !          1230:  *
        !          1231:  *     Add information to a message being accumulated that describes
        !          1232:  *     the current error.
        !          1233:  *
        !          1234:  * Results:
        !          1235:  *     None.
        !          1236:  *
        !          1237:  * Side effects:
        !          1238:  *     The contents of message are added to the "errorInfo" variable.
        !          1239:  *     If Tcl_Eval has been called since the current value of errorInfo
        !          1240:  *     was set, errorInfo is cleared before adding the new message.
        !          1241:  *
        !          1242:  *----------------------------------------------------------------------
        !          1243:  */
        !          1244: 
        !          1245: void
        !          1246: Tcl_AddErrorInfo(interp, message)
        !          1247:     Tcl_Interp *interp;                /* Interpreter to which error information
        !          1248:                                 * pertains. */
        !          1249:     char *message;             /* Message to record. */
        !          1250: {
        !          1251:     register Interp *iPtr = (Interp *) interp;
        !          1252: 
        !          1253:     if (iPtr->flags & ERR_IN_PROGRESS) {
        !          1254:        int length;
        !          1255:        char *buffer, *oldVar;
        !          1256: 
        !          1257:        oldVar = Tcl_GetVar(interp, "errorInfo", 1);
        !          1258:        if (oldVar == NULL) {
        !          1259:            oldVar = "";
        !          1260:        }
        !          1261:        length = strlen(oldVar);
        !          1262:        buffer = malloc((unsigned) (length + strlen(message) + 1));
        !          1263:        strcpy(buffer, oldVar);
        !          1264:        strcpy(buffer+length, message);
        !          1265:        Tcl_SetVar(interp, "errorInfo", buffer, 1);
        !          1266:     } else {
        !          1267:        iPtr->flags |= ERR_IN_PROGRESS;
        !          1268:        Tcl_SetVar(interp, "errorInfo", message, 1);
        !          1269:     }
        !          1270: }
        !          1271: 
        !          1272: /*
        !          1273:  *----------------------------------------------------------------------
        !          1274:  *
        !          1275:  * TclFindCmd --
        !          1276:  *
        !          1277:  *     Find a particular command in an interpreter.
        !          1278:  *
        !          1279:  * Results:
        !          1280:  *     If the command doesn't exist in the table, or if it is an
        !          1281:  *     ambiguous abbreviation, then NULL is returned.  Otherwise
        !          1282:  *     the return value is a pointer to the command.  Unique
        !          1283:  *     abbreviations are allowed if abbrevOK is non-zero, but
        !          1284:  *     abbreviations take longer to look up (must scan the whole
        !          1285:  *     table twice).
        !          1286:  *
        !          1287:  * Side effects:
        !          1288:  *     If the command is found and is an exact match, it is relinked
        !          1289:  *     at the front of iPtr's command list so it will be found more
        !          1290:  *     quickly in the future.
        !          1291:  *
        !          1292:  *----------------------------------------------------------------------
        !          1293:  */
        !          1294: 
        !          1295: Command *
        !          1296: TclFindCmd(iPtr, cmdName, abbrevOK)
        !          1297:     Interp *iPtr;              /* Interpreter in which to search. */
        !          1298:     char *cmdName;             /* Desired command. */
        !          1299:     int abbrevOK;              /* Non-zero means permit abbreviations, if
        !          1300:                                 * not disallowed by "noAbbrevs" variable.
        !          1301:                                 * Zero means exact matches only. */
        !          1302: {
        !          1303:     register Command *prev;
        !          1304:     register Command *cur;
        !          1305:     register char c;
        !          1306:     Command *match;
        !          1307:     int length;
        !          1308:     char *varValue;
        !          1309: 
        !          1310:     /*
        !          1311:      * First check for an exact match.
        !          1312:      */
        !          1313: 
        !          1314:     c = *cmdName;
        !          1315:     for (prev = NULL, cur = iPtr->commandPtr; cur != NULL;
        !          1316:            prev = cur, cur = cur->nextPtr) {
        !          1317: 
        !          1318:        /*
        !          1319:         * Check the first character here before wasting time calling
        !          1320:         * strcmp.
        !          1321:         */
        !          1322: 
        !          1323:        if ((cur->name[0] == c) && (strcmp(cur->name, cmdName) == 0)) {
        !          1324:            if (prev != NULL) {
        !          1325:                prev->nextPtr = cur->nextPtr;
        !          1326:                cur->nextPtr = iPtr->commandPtr;
        !          1327:                iPtr->commandPtr = cur;
        !          1328:            }
        !          1329:            return cur;
        !          1330:        }
        !          1331:     }
        !          1332:     if (!abbrevOK) {
        !          1333:        return NULL;
        !          1334:     }
        !          1335:     varValue = Tcl_GetVar((Tcl_Interp *) iPtr, "noAbbrev", 1);
        !          1336:     if ((varValue != NULL) && (*varValue == '1')) {
        !          1337:        return NULL;
        !          1338:     }
        !          1339: 
        !          1340:     /*
        !          1341:      * No exact match.  Make a second pass to check for a unique
        !          1342:      * abbreviation.  Don't bother to pull the matching entry to
        !          1343:      * the front of the list, since we have to search the whole list
        !          1344:      * for abbreviations anyway.
        !          1345:      */
        !          1346: 
        !          1347:     length = strlen(cmdName);
        !          1348:     match = NULL;
        !          1349:     for (prev = NULL, cur = iPtr->commandPtr; cur != NULL;
        !          1350:            prev = cur, cur = cur->nextPtr) {
        !          1351:        if ((cur->name[0] == c) && (strncmp(cur->name, cmdName, length) == 0)) {
        !          1352:            if (match != NULL) {
        !          1353:                return NULL;
        !          1354:            }
        !          1355:            match = cur;
        !          1356:        }
        !          1357:     }
        !          1358:     return match;
        !          1359: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.