Annotation of researchv10no/cmd/worm/scsi/tcl/tclBasic.c, revision 1.1.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.