Annotation of micropolis/src/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-1992 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: /user6/ouster/tcl/RCS/tclBasic.c,v 1.131 92/06/21 14:09:41 ouster Exp $ SPRITE (Berkeley)";
        !            20: #endif
        !            21: 
        !            22: #include "tclint.h"
        !            23: 
        !            24: /*
        !            25:  * The following structure defines all of the commands in the Tcl core,
        !            26:  * and the C procedures that execute them.
        !            27:  */
        !            28: 
        !            29: typedef struct {
        !            30:     char *name;                        /* Name of command. */
        !            31:     Tcl_CmdProc *proc;         /* Procedure that executes command. */
        !            32: } CmdInfo;
        !            33: 
        !            34: /*
        !            35:  * Built-in commands, and the procedures associated with them:
        !            36:  */
        !            37: 
        !            38: static CmdInfo builtInCmds[] = {
        !            39:     /*
        !            40:      * Commands in the generic core:
        !            41:      */
        !            42: 
        !            43:     {"append",         Tcl_AppendCmd},
        !            44:     {"array",          Tcl_ArrayCmd},
        !            45:     {"break",          Tcl_BreakCmd},
        !            46:     {"case",           Tcl_CaseCmd},
        !            47:     {"catch",          Tcl_CatchCmd},
        !            48:     {"concat",         Tcl_ConcatCmd},
        !            49:     {"continue",       Tcl_ContinueCmd},
        !            50:     {"error",          Tcl_ErrorCmd},
        !            51:     {"eval",           Tcl_EvalCmd},
        !            52:     {"expr",           Tcl_ExprCmd},
        !            53:     {"for",            Tcl_ForCmd},
        !            54:     {"foreach",                Tcl_ForeachCmd},
        !            55:     {"format",         Tcl_FormatCmd},
        !            56:     {"global",         Tcl_GlobalCmd},
        !            57:     {"if",             Tcl_IfCmd},
        !            58:     {"incr",           Tcl_IncrCmd},
        !            59:     {"info",           Tcl_InfoCmd},
        !            60:     {"join",           Tcl_JoinCmd},
        !            61:     {"lappend",                Tcl_LappendCmd},
        !            62:     {"lindex",         Tcl_LindexCmd},
        !            63:     {"linsert",                Tcl_LinsertCmd},
        !            64:     {"list",           Tcl_ListCmd},
        !            65:     {"llength",                Tcl_LlengthCmd},
        !            66:     {"lrange",         Tcl_LrangeCmd},
        !            67:     {"lreplace",       Tcl_LreplaceCmd},
        !            68:     {"lsearch",                Tcl_LsearchCmd},
        !            69:     {"lsort",          Tcl_LsortCmd},
        !            70:     {"proc",           Tcl_ProcCmd},
        !            71:     {"regexp",         Tcl_RegexpCmd},
        !            72:     {"regsub",         Tcl_RegsubCmd},
        !            73:     {"rename",         Tcl_RenameCmd},
        !            74:     {"return",         Tcl_ReturnCmd},
        !            75:     {"scan",           Tcl_ScanCmd},
        !            76:     {"set",            Tcl_SetCmd},
        !            77:     {"split",          Tcl_SplitCmd},
        !            78:     {"string",         Tcl_StringCmd},
        !            79:     {"trace",          Tcl_TraceCmd},
        !            80:     {"unset",          Tcl_UnsetCmd},
        !            81:     {"uplevel",                Tcl_UplevelCmd},
        !            82:     {"upvar",          Tcl_UpvarCmd},
        !            83:     {"while",          Tcl_WhileCmd},
        !            84: 
        !            85:     /*
        !            86:      * Commands in the UNIX core:
        !            87:      */
        !            88: 
        !            89: #ifndef TCL_GENERIC_ONLY
        !            90:     {"cd",             Tcl_CdCmd},
        !            91:     {"close",          Tcl_CloseCmd},
        !            92:     {"eof",            Tcl_EofCmd},
        !            93:     {"exec",           Tcl_ExecCmd},
        !            94:     {"exit",           Tcl_ExitCmd},
        !            95:     {"file",           Tcl_FileCmd},
        !            96:     {"flush",          Tcl_FlushCmd},
        !            97:     {"gets",           Tcl_GetsCmd},
        !            98:     {"glob",           Tcl_GlobCmd},
        !            99:     {"open",           Tcl_OpenCmd},
        !           100:     {"puts",           Tcl_PutsCmd},
        !           101:     {"pwd",            Tcl_PwdCmd},
        !           102:     {"read",           Tcl_ReadCmd},
        !           103:     {"seek",           Tcl_SeekCmd},
        !           104:     {"source",         Tcl_SourceCmd},
        !           105:     {"tell",           Tcl_TellCmd},
        !           106:     {"time",           Tcl_TimeCmd},
        !           107: #endif /* TCL_GENERIC_ONLY */
        !           108:     {NULL,             (Tcl_CmdProc *) NULL}
        !           109: };
        !           110: 
        !           111: /*
        !           112:  *----------------------------------------------------------------------
        !           113:  *
        !           114:  * Tcl_CreateInterp --
        !           115:  *
        !           116:  *     Create a new TCL command interpreter.
        !           117:  *
        !           118:  * Results:
        !           119:  *     The return value is a token for the interpreter, which may be
        !           120:  *     used in calls to procedures like Tcl_CreateCmd, Tcl_Eval, or
        !           121:  *     Tcl_DeleteInterp.
        !           122:  *
        !           123:  * Side effects:
        !           124:  *     The command interpreter is initialized with an empty variable
        !           125:  *     table and the built-in commands.
        !           126:  *
        !           127:  *----------------------------------------------------------------------
        !           128:  */
        !           129: 
        !           130: Tcl_Interp *
        !           131: Tcl_CreateInterp()
        !           132: {
        !           133:     register Interp *iPtr;
        !           134:     register Command *cmdPtr;
        !           135:     register CmdInfo *cmdInfoPtr;
        !           136:     int i;
        !           137: 
        !           138:     iPtr = (Interp *) ckalloc(sizeof(Interp));
        !           139:     iPtr->result = iPtr->resultSpace;
        !           140:     iPtr->freeProc = 0;
        !           141:     iPtr->errorLine = 0;
        !           142:     Tcl_InitHashTable(&iPtr->commandTable, TCL_STRING_KEYS);
        !           143:     Tcl_InitHashTable(&iPtr->globalTable, TCL_STRING_KEYS);
        !           144:     iPtr->numLevels = 0;
        !           145:     iPtr->framePtr = NULL;
        !           146:     iPtr->varFramePtr = NULL;
        !           147:     iPtr->activeTracePtr = NULL;
        !           148:     iPtr->numEvents = 0;
        !           149:     iPtr->events = NULL;
        !           150:     iPtr->curEvent = 0;
        !           151:     iPtr->curEventNum = 0;
        !           152:     iPtr->revPtr = NULL;
        !           153:     iPtr->historyFirst = NULL;
        !           154:     iPtr->revDisables = 1;
        !           155:     iPtr->evalFirst = iPtr->evalLast = NULL;
        !           156:     iPtr->appendResult = NULL;
        !           157:     iPtr->appendAvl = 0;
        !           158:     iPtr->appendUsed = 0;
        !           159:     iPtr->numFiles = 0;
        !           160:     iPtr->filePtrArray = NULL;
        !           161:     for (i = 0; i < NUM_REGEXPS; i++) {
        !           162:        iPtr->patterns[i] = NULL;
        !           163:        iPtr->patLengths[i] = -1;
        !           164:        iPtr->regexps[i] = NULL;
        !           165:     }
        !           166:     iPtr->cmdCount = 0;
        !           167:     iPtr->noEval = 0;
        !           168:     iPtr->scriptFile = NULL;
        !           169:     iPtr->flags = 0;
        !           170:     iPtr->tracePtr = NULL;
        !           171:     iPtr->resultSpace[0] = 0;
        !           172: 
        !           173:     /*
        !           174:      * Create the built-in commands.  Do it here, rather than calling
        !           175:      * Tcl_CreateCommand, because it's faster (there's no need to
        !           176:      * check for a pre-existing command by the same name).
        !           177:      */
        !           178: 
        !           179:     for (cmdInfoPtr = builtInCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) {
        !           180:        int new;
        !           181:        Tcl_HashEntry *hPtr;
        !           182: 
        !           183:        hPtr = Tcl_CreateHashEntry(&iPtr->commandTable,
        !           184:                cmdInfoPtr->name, &new);
        !           185:        if (new) {
        !           186:            cmdPtr = (Command *) ckalloc(sizeof(Command));
        !           187:            cmdPtr->proc = cmdInfoPtr->proc;
        !           188:            cmdPtr->clientData = (ClientData) NULL;
        !           189:            cmdPtr->deleteProc = NULL;
        !           190:            Tcl_SetHashValue(hPtr, cmdPtr);
        !           191:        }
        !           192:     }
        !           193: 
        !           194: #ifndef TCL_GENERIC_ONLY
        !           195:     TclSetupEnv((Tcl_Interp *) iPtr);
        !           196: #endif
        !           197: 
        !           198:     return (Tcl_Interp *) iPtr;
        !           199: }
        !           200: 
        !           201: /*
        !           202:  *----------------------------------------------------------------------
        !           203:  *
        !           204:  * Tcl_DeleteInterp --
        !           205:  *
        !           206:  *     Delete an interpreter and free up all of the resources associated
        !           207:  *     with it.
        !           208:  *
        !           209:  * Results:
        !           210:  *     None.
        !           211:  *
        !           212:  * Side effects:
        !           213:  *     The interpreter is destroyed.  The caller should never again
        !           214:  *     use the interp token.
        !           215:  *
        !           216:  *----------------------------------------------------------------------
        !           217:  */
        !           218: 
        !           219: void
        !           220: Tcl_DeleteInterp(interp)
        !           221:     Tcl_Interp *interp;                /* Token for command interpreter (returned
        !           222:                                 * by a previous call to Tcl_CreateInterp). */
        !           223: {
        !           224:     Interp *iPtr = (Interp *) interp;
        !           225:     Tcl_HashEntry *hPtr;
        !           226:     Tcl_HashSearch search;
        !           227:     register Command *cmdPtr;
        !           228:     int i;
        !           229: 
        !           230:     /*
        !           231:      * If the interpreter is in use, delay the deletion until later.
        !           232:      */
        !           233: 
        !           234:     iPtr->flags |= DELETED;
        !           235:     if (iPtr->numLevels != 0) {
        !           236:        return;
        !           237:     }
        !           238: 
        !           239:     /*
        !           240:      * Free up any remaining resources associated with the
        !           241:      * interpreter.
        !           242:      */
        !           243: 
        !           244:     for (hPtr = Tcl_FirstHashEntry(&iPtr->commandTable, &search);
        !           245:            hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
        !           246:        cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
        !           247:        if (cmdPtr->deleteProc != NULL) { 
        !           248:            (*cmdPtr->deleteProc)(cmdPtr->clientData);
        !           249:        }
        !           250:        ckfree((char *) cmdPtr);
        !           251:     }
        !           252:     Tcl_DeleteHashTable(&iPtr->commandTable);
        !           253:     TclDeleteVars(iPtr, &iPtr->globalTable);
        !           254:     if (iPtr->events != NULL) {
        !           255:        int i;
        !           256: 
        !           257:        for (i = 0; i < iPtr->numEvents; i++) {
        !           258:            ckfree(iPtr->events[i].command);
        !           259:        }
        !           260:        ckfree((char *) iPtr->events);
        !           261:     }
        !           262:     while (iPtr->revPtr != NULL) {
        !           263:        HistoryRev *nextPtr = iPtr->revPtr->nextPtr;
        !           264: 
        !           265:        ckfree((char *) iPtr->revPtr);
        !           266:        iPtr->revPtr = nextPtr;
        !           267:     }
        !           268:     if (iPtr->appendResult != NULL) {
        !           269:        ckfree(iPtr->appendResult);
        !           270:     }
        !           271: #ifndef TCL_GENERIC_ONLY
        !           272:     if (iPtr->numFiles > 0) {
        !           273:        for (i = 0; i < iPtr->numFiles; i++) {
        !           274:            OpenFile *filePtr;
        !           275:     
        !           276:            filePtr = iPtr->filePtrArray[i];
        !           277:            if (filePtr == NULL) {
        !           278:                continue;
        !           279:            }
        !           280:            if (i >= 3) {
        !           281:                fclose(filePtr->f);
        !           282:                if (filePtr->f2 != NULL) {
        !           283:                    fclose(filePtr->f2);
        !           284:                }
        !           285:                if (filePtr->numPids > 0) {
        !           286:                    Tcl_DetachPids(filePtr->numPids, filePtr->pidPtr);
        !           287:                    ckfree((char *) filePtr->pidPtr);
        !           288:                }
        !           289:            }
        !           290:            ckfree((char *) filePtr);
        !           291:        }
        !           292:        ckfree((char *) iPtr->filePtrArray);
        !           293:     }
        !           294: #endif
        !           295:     for (i = 0; i < NUM_REGEXPS; i++) {
        !           296:        if (iPtr->patterns[i] == NULL) {
        !           297:            break;
        !           298:        }
        !           299:        ckfree(iPtr->patterns[i]);
        !           300:        ckfree((char *) iPtr->regexps[i]);
        !           301:     }
        !           302:     while (iPtr->tracePtr != NULL) {
        !           303:        Trace *nextPtr = iPtr->tracePtr->nextPtr;
        !           304: 
        !           305:        ckfree((char *) iPtr->tracePtr);
        !           306:        iPtr->tracePtr = nextPtr;
        !           307:     }
        !           308:     ckfree((char *) iPtr);
        !           309: }
        !           310: 
        !           311: /*
        !           312:  *----------------------------------------------------------------------
        !           313:  *
        !           314:  * Tcl_CreateCommand --
        !           315:  *
        !           316:  *     Define a new command in a command table.
        !           317:  *
        !           318:  * Results:
        !           319:  *     None.
        !           320:  *
        !           321:  * Side effects:
        !           322:  *     If a command named cmdName already exists for interp, it is
        !           323:  *     deleted.  In the future, when cmdName is seen as the name of
        !           324:  *     a command by Tcl_Eval, proc will be called.  When the command
        !           325:  *     is deleted from the table, deleteProc will be called.  See the
        !           326:  *     manual entry for details on the calling sequence.
        !           327:  *
        !           328:  *----------------------------------------------------------------------
        !           329:  */
        !           330: 
        !           331: void
        !           332: Tcl_CreateCommand(interp, cmdName, proc, clientData, deleteProc)
        !           333:     Tcl_Interp *interp;                /* Token for command interpreter (returned
        !           334:                                 * by a previous call to Tcl_CreateInterp). */
        !           335:     char *cmdName;             /* Name of command. */
        !           336:     Tcl_CmdProc *proc;         /* Command procedure to associate with
        !           337:                                 * cmdName. */
        !           338:     ClientData clientData;     /* Arbitrary one-word value to pass to proc. */
        !           339:     Tcl_CmdDeleteProc *deleteProc;
        !           340:                                /* If not NULL, gives a procedure to call when
        !           341:                                 * this command is deleted. */
        !           342: {
        !           343:     Interp *iPtr = (Interp *) interp;
        !           344:     register Command *cmdPtr;
        !           345:     Tcl_HashEntry *hPtr;
        !           346:     int new;
        !           347: 
        !           348:     hPtr = Tcl_CreateHashEntry(&iPtr->commandTable, cmdName, &new);
        !           349:     if (!new) {
        !           350:        /*
        !           351:         * Command already exists:  delete the old one.
        !           352:         */
        !           353: 
        !           354:        cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
        !           355:        if (cmdPtr->deleteProc != NULL) {
        !           356:            (*cmdPtr->deleteProc)(cmdPtr->clientData);
        !           357:        }
        !           358:     } else {
        !           359:        cmdPtr = (Command *) ckalloc(sizeof(Command));
        !           360:        Tcl_SetHashValue(hPtr, cmdPtr);
        !           361:     }
        !           362:     cmdPtr->proc = proc;
        !           363:     cmdPtr->clientData = clientData;
        !           364:     cmdPtr->deleteProc = deleteProc;
        !           365: }
        !           366: 
        !           367: /*
        !           368:  *----------------------------------------------------------------------
        !           369:  *
        !           370:  * Tcl_DeleteCommand --
        !           371:  *
        !           372:  *     Remove the given command from the given interpreter.
        !           373:  *
        !           374:  * Results:
        !           375:  *     0 is returned if the command was deleted successfully.
        !           376:  *     -1 is returned if there didn't exist a command by that
        !           377:  *     name.
        !           378:  *
        !           379:  * Side effects:
        !           380:  *     CmdName will no longer be recognized as a valid command for
        !           381:  *     interp.
        !           382:  *
        !           383:  *----------------------------------------------------------------------
        !           384:  */
        !           385: 
        !           386: int
        !           387: Tcl_DeleteCommand(interp, cmdName)
        !           388:     Tcl_Interp *interp;                /* Token for command interpreter (returned
        !           389:                                 * by a previous call to Tcl_CreateInterp). */
        !           390:     char *cmdName;             /* Name of command to remove. */
        !           391: {
        !           392:     Interp *iPtr = (Interp *) interp;
        !           393:     Tcl_HashEntry *hPtr;
        !           394:     Command *cmdPtr;
        !           395: 
        !           396:     hPtr = Tcl_FindHashEntry(&iPtr->commandTable, cmdName);
        !           397:     if (hPtr == NULL) {
        !           398:        return -1;
        !           399:     }
        !           400:     cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
        !           401:     if (cmdPtr->deleteProc != NULL) {
        !           402:        (*cmdPtr->deleteProc)(cmdPtr->clientData);
        !           403:     }
        !           404:     ckfree((char *) cmdPtr);
        !           405:     Tcl_DeleteHashEntry(hPtr);
        !           406:     return 0;
        !           407: }
        !           408: 
        !           409: /*
        !           410:  *-----------------------------------------------------------------
        !           411:  *
        !           412:  * Tcl_Eval --
        !           413:  *
        !           414:  *     Parse and execute a command in the Tcl language.
        !           415:  *
        !           416:  * Results:
        !           417:  *     The return value is one of the return codes defined in tcl.hd
        !           418:  *     (such as TCL_OK), and interp->result contains a string value
        !           419:  *     to supplement the return code.  The value of interp->result
        !           420:  *     will persist only until the next call to Tcl_Eval:  copy it or
        !           421:  *     lose it! *TermPtr is filled in with the character just after
        !           422:  *     the last one that was part of the command (usually a NULL
        !           423:  *     character or a closing bracket).
        !           424:  *
        !           425:  * Side effects:
        !           426:  *     Almost certainly;  depends on the command.
        !           427:  *
        !           428:  *-----------------------------------------------------------------
        !           429:  */
        !           430: 
        !           431: int
        !           432: Tcl_Eval(interp, cmd, flags, termPtr)
        !           433:     Tcl_Interp *interp;                /* Token for command interpreter (returned
        !           434:                                 * by a previous call to Tcl_CreateInterp). */
        !           435:     char *cmd;                 /* Pointer to TCL command to interpret. */
        !           436:     int flags;                 /* OR-ed combination of flags like
        !           437:                                 * TCL_BRACKET_TERM and TCL_RECORD_BOUNDS. */
        !           438:     char **termPtr;            /* If non-NULL, fill in the address it points
        !           439:                                 * to with the address of the char. just after
        !           440:                                 * the last one that was part of cmd.  See
        !           441:                                 * the man page for details on this. */
        !           442: {
        !           443:     /*
        !           444:      * The storage immediately below is used to generate a copy
        !           445:      * of the command, after all argument substitutions.  Pv will
        !           446:      * contain the argv values passed to the command procedure.
        !           447:      */
        !           448: 
        !           449: #   define NUM_CHARS 200
        !           450:     char copyStorage[NUM_CHARS];
        !           451:     ParseValue pv;
        !           452:     char *oldBuffer;
        !           453: 
        !           454:     /*
        !           455:      * This procedure generates an (argv, argc) array for the command,
        !           456:      * It starts out with stack-allocated space but uses dynamically-
        !           457:      * allocated storage to increase it if needed.
        !           458:      */
        !           459: 
        !           460: #   define NUM_ARGS 10
        !           461:     char *(argStorage[NUM_ARGS]);
        !           462:     char **argv = argStorage;
        !           463:     int argc;
        !           464:     int argSize = NUM_ARGS;
        !           465: 
        !           466:     register char *src;                        /* Points to current character
        !           467:                                         * in cmd. */
        !           468:     char termChar;                     /* Return when this character is found
        !           469:                                         * (either ']' or '\0').  Zero means
        !           470:                                         * that newlines terminate commands. */
        !           471:     int result;                                /* Return value. */
        !           472:     register Interp *iPtr = (Interp *) interp;
        !           473:     Tcl_HashEntry *hPtr;
        !           474:     Command *cmdPtr;
        !           475:     char *dummy;                       /* Make termPtr point here if it was
        !           476:                                         * originally NULL. */
        !           477:     char *cmdStart;                    /* Points to first non-blank char. in
        !           478:                                         * command (used in calling trace
        !           479:                                         * procedures). */
        !           480:     char *ellipsis = "";               /* Used in setting errorInfo variable;
        !           481:                                         * set to "..." to indicate that not
        !           482:                                         * all of offending command is included
        !           483:                                         * in errorInfo.  "" means that the
        !           484:                                         * command is all there. */
        !           485:     register Trace *tracePtr;
        !           486: 
        !           487:     /*
        !           488:      * Initialize the result to an empty string and clear out any
        !           489:      * error information.  This makes sure that we return an empty
        !           490:      * result if there are no commands in the command string.
        !           491:      */
        !           492: 
        !           493:     Tcl_FreeResult((Tcl_Interp *) iPtr);
        !           494:     iPtr->result = iPtr->resultSpace;
        !           495:     iPtr->resultSpace[0] = 0;
        !           496:     result = TCL_OK;
        !           497: 
        !           498:     /*
        !           499:      * Check depth of nested calls to Tcl_Eval:  if this gets too large,
        !           500:      * it's probably because of an infinite loop somewhere.
        !           501:      */
        !           502: 
        !           503:     iPtr->numLevels++;
        !           504:     if (iPtr->numLevels > MAX_NESTING_DEPTH) {
        !           505:        iPtr->numLevels--;
        !           506:        iPtr->result =  "too many nested calls to Tcl_Eval (infinite loop?)";
        !           507:        return TCL_ERROR;
        !           508:     }
        !           509: 
        !           510:     /*
        !           511:      * Initialize the area in which command copies will be assembled.
        !           512:      */
        !           513: 
        !           514:     pv.buffer = copyStorage;
        !           515:     pv.end = copyStorage + NUM_CHARS - 1;
        !           516:     pv.expandProc = TclExpandParseValue;
        !           517:     pv.clientData = (ClientData) NULL;
        !           518: 
        !           519:     src = cmd;
        !           520:     if (flags & TCL_BRACKET_TERM) {
        !           521:        termChar = ']';
        !           522:     } else {
        !           523:        termChar = 0;
        !           524:     }
        !           525:     if (termPtr == NULL) {
        !           526:        termPtr = &dummy;
        !           527:     }
        !           528:     *termPtr = src;
        !           529:     cmdStart = src;
        !           530: 
        !           531:     /*
        !           532:      * There can be many sub-commands (separated by semi-colons or
        !           533:      * newlines) in one command string.  This outer loop iterates over
        !           534:      * individual commands.
        !           535:      */
        !           536: 
        !           537:     while (*src != termChar) {
        !           538:        iPtr->flags &= ~(ERR_IN_PROGRESS | ERROR_CODE_SET);
        !           539: 
        !           540:        /*
        !           541:         * Skim off leading white space and semi-colons, and skip
        !           542:         * comments.
        !           543:         */
        !           544: 
        !           545:        while (1) {
        !           546:            register char c = *src;
        !           547: 
        !           548:            if ((CHAR_TYPE(c) != TCL_SPACE) && (c != ';') && (c != '\n')) {
        !           549:                break;
        !           550:            }
        !           551:            src += 1;
        !           552:        }
        !           553:        if (*src == '#') {
        !           554:            for (src++; *src != 0; src++) {
        !           555:                if (*src == '\n') {
        !           556:                    src++;
        !           557:                    break;
        !           558:                }
        !           559:            }
        !           560:            continue;
        !           561:        }
        !           562:        cmdStart = src;
        !           563: 
        !           564:        /*
        !           565:         * Parse the words of the command, generating the argc and
        !           566:         * argv for the command procedure.  May have to call
        !           567:         * TclParseWords several times, expanding the argv array
        !           568:         * between calls.
        !           569:         */
        !           570: 
        !           571:        pv.next = oldBuffer = pv.buffer;
        !           572:        argc = 0;
        !           573:        while (1) {
        !           574:            int newArgs, maxArgs;
        !           575:            char **newArgv;
        !           576:            int i;
        !           577: 
        !           578:            /*
        !           579:             * Note:  the "- 2" below guarantees that we won't use the
        !           580:             * last two argv slots here.  One is for a NULL pointer to
        !           581:             * mark the end of the list, and the other is to leave room
        !           582:             * for inserting the command name "unknown" as the first
        !           583:             * argument (see below).
        !           584:             */
        !           585: 
        !           586:            maxArgs = argSize - argc - 2;
        !           587:            result = TclParseWords((Tcl_Interp *) iPtr, src, flags,
        !           588:                    maxArgs, termPtr, &newArgs, &argv[argc], &pv);
        !           589:            src = *termPtr;
        !           590:            if (result != TCL_OK) {
        !           591:                ellipsis = "...";
        !           592:                goto done;
        !           593:            }
        !           594: 
        !           595:            /*
        !           596:             * Careful!  Buffer space may have gotten reallocated while
        !           597:             * parsing words.  If this happened, be sure to update all
        !           598:             * of the older argv pointers to refer to the new space.
        !           599:             */
        !           600: 
        !           601:            if (oldBuffer != pv.buffer) {
        !           602:                int i;
        !           603: 
        !           604:                for (i = 0; i < argc; i++) {
        !           605:                    argv[i] = pv.buffer + (argv[i] - oldBuffer);
        !           606:                }
        !           607:                oldBuffer = pv.buffer;
        !           608:            }
        !           609:            argc += newArgs;
        !           610:            if (newArgs < maxArgs) {
        !           611:                argv[argc] = (char *) NULL;
        !           612:                break;
        !           613:            }
        !           614: 
        !           615:            /*
        !           616:             * Args didn't all fit in the current array.  Make it bigger.
        !           617:             */
        !           618: 
        !           619:            argSize *= 2;
        !           620:            newArgv = (char **)
        !           621:                    ckalloc((unsigned) argSize * sizeof(char *));
        !           622:            for (i = 0; i < argc; i++) {
        !           623:                newArgv[i] = argv[i];
        !           624:            }
        !           625:            if (argv != argStorage) {
        !           626:                ckfree((char *) argv);
        !           627:            }
        !           628:            argv = newArgv;
        !           629:        }
        !           630: 
        !           631:        /*
        !           632:         * If this is an empty command (or if we're just parsing
        !           633:         * commands without evaluating them), then just skip to the
        !           634:         * next command.
        !           635:         */
        !           636: 
        !           637:        if ((argc == 0) || iPtr->noEval) {
        !           638:            continue;
        !           639:        }
        !           640:        argv[argc] = NULL;
        !           641: 
        !           642:        /*
        !           643:         * Save information for the history module, if needed.
        !           644:         */
        !           645: 
        !           646:        if (flags & TCL_RECORD_BOUNDS) {
        !           647:            iPtr->evalFirst = cmdStart;
        !           648:            iPtr->evalLast = src-1;
        !           649:        }
        !           650: 
        !           651:        /*
        !           652:         * Find the procedure to execute this command.  If there isn't
        !           653:         * one, then see if there is a command "unknown".  If so,
        !           654:         * invoke it instead, passing it the words of the original
        !           655:         * command as arguments.
        !           656:         */
        !           657: 
        !           658:        hPtr = Tcl_FindHashEntry(&iPtr->commandTable, argv[0]);
        !           659:        if (hPtr == NULL) {
        !           660:            int i;
        !           661: 
        !           662:            hPtr = Tcl_FindHashEntry(&iPtr->commandTable, "unknown");
        !           663:            if (hPtr == NULL) {
        !           664:                Tcl_ResetResult(interp);
        !           665:                Tcl_AppendResult(interp, "invalid command name: \"",
        !           666:                        argv[0], "\"", (char *) NULL);
        !           667:                result = TCL_ERROR;
        !           668:                goto done;
        !           669:            }
        !           670:            for (i = argc; i >= 0; i--) {
        !           671:                argv[i+1] = argv[i];
        !           672:            }
        !           673:            argv[0] = "unknown";
        !           674:            argc++;
        !           675:        }
        !           676:        cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
        !           677: 
        !           678:        /*
        !           679:         * Call trace procedures, if any.
        !           680:         */
        !           681: 
        !           682:        for (tracePtr = iPtr->tracePtr; tracePtr != NULL;
        !           683:                tracePtr = tracePtr->nextPtr) {
        !           684:            char saved;
        !           685: 
        !           686:            if (tracePtr->level < iPtr->numLevels) {
        !           687:                continue;
        !           688:            }
        !           689:            saved = *src;
        !           690:            *src = 0;
        !           691:            (*tracePtr->proc)(tracePtr->clientData, interp, iPtr->numLevels,
        !           692:                    cmdStart, cmdPtr->proc, cmdPtr->clientData, argc, argv);
        !           693:            *src = saved;
        !           694:        }
        !           695: 
        !           696:        /*
        !           697:         * At long last, invoke the command procedure.  Reset the
        !           698:         * result to its default empty value first (it could have
        !           699:         * gotten changed by earlier commands in the same command
        !           700:         * string).
        !           701:         */
        !           702: 
        !           703:        iPtr->cmdCount++;
        !           704:        Tcl_FreeResult(iPtr);
        !           705:        iPtr->result = iPtr->resultSpace;
        !           706:        iPtr->resultSpace[0] = 0;
        !           707:        result = (*cmdPtr->proc)(cmdPtr->clientData, interp, argc, argv);
        !           708:        if (result != TCL_OK) {
        !           709:            break;
        !           710:        }
        !           711:     }
        !           712: 
        !           713:     /*
        !           714:      * Free up any extra resources that were allocated.
        !           715:      */
        !           716: 
        !           717:     done:
        !           718:     if (pv.buffer != copyStorage) {
        !           719:        ckfree((char *) pv.buffer);
        !           720:     }
        !           721:     if (argv != argStorage) {
        !           722:        ckfree((char *) argv);
        !           723:     }
        !           724:     iPtr->numLevels--;
        !           725:     if (iPtr->numLevels == 0) {
        !           726:        if (result == TCL_RETURN) {
        !           727:            result = TCL_OK;
        !           728:        }
        !           729:        if ((result != TCL_OK) && (result != TCL_ERROR)) {
        !           730:            Tcl_ResetResult(interp);
        !           731:            if (result == TCL_BREAK) {
        !           732:                iPtr->result = "invoked \"break\" outside of a loop";
        !           733:            } else if (result == TCL_CONTINUE) {
        !           734:                iPtr->result = "invoked \"continue\" outside of a loop";
        !           735:            } else {
        !           736:                iPtr->result = iPtr->resultSpace;
        !           737:                sprintf(iPtr->resultSpace, "command returned bad code: %d",
        !           738:                        result);
        !           739:            }
        !           740:            result = TCL_ERROR;
        !           741:        }
        !           742:        if (iPtr->flags & DELETED) {
        !           743:            Tcl_DeleteInterp(interp);
        !           744:        }
        !           745:     }
        !           746: 
        !           747:     /*
        !           748:      * If an error occurred, record information about what was being
        !           749:      * executed when the error occurred.
        !           750:      */
        !           751: 
        !           752:     if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
        !           753:        int numChars;
        !           754:        register char *p;
        !           755: 
        !           756:        /*
        !           757:         * Compute the line number where the error occurred.
        !           758:         */
        !           759: 
        !           760:        iPtr->errorLine = 1;
        !           761:        for (p = cmd; p != cmdStart; p++) {
        !           762:            if (*p == '\n') {
        !           763:                iPtr->errorLine++;
        !           764:            }
        !           765:        }
        !           766:        for ( ; isspace(*p) || (*p == ';'); p++) {
        !           767:            if (*p == '\n') {
        !           768:                iPtr->errorLine++;
        !           769:            }
        !           770:        }
        !           771: 
        !           772:        /*
        !           773:         * Figure out how much of the command to print in the error
        !           774:         * message (up to a certain number of characters, or up to
        !           775:         * the first new-line).
        !           776:         */
        !           777: 
        !           778:        numChars = src - cmdStart;
        !           779:        if (numChars > (NUM_CHARS-50)) {
        !           780:            numChars = NUM_CHARS-50;
        !           781:            ellipsis = " ...";
        !           782:        }
        !           783: 
        !           784:        if (!(iPtr->flags & ERR_IN_PROGRESS)) {
        !           785:            sprintf(copyStorage, "\n    while executing\n\"%.*s%s\"",
        !           786:                    numChars, cmdStart, ellipsis);
        !           787:        } else {
        !           788:            sprintf(copyStorage, "\n    invoked from within\n\"%.*s%s\"",
        !           789:                    numChars, cmdStart, ellipsis);
        !           790:        }
        !           791:        Tcl_AddErrorInfo(interp, copyStorage);
        !           792:        iPtr->flags &= ~ERR_ALREADY_LOGGED;
        !           793:     } else {
        !           794:        iPtr->flags &= ~ERR_ALREADY_LOGGED;
        !           795:     }
        !           796:     return result;
        !           797: }
        !           798: 
        !           799: /*
        !           800:  *----------------------------------------------------------------------
        !           801:  *
        !           802:  * Tcl_CreateTrace --
        !           803:  *
        !           804:  *     Arrange for a procedure to be called to trace command execution.
        !           805:  *
        !           806:  * Results:
        !           807:  *     The return value is a token for the trace, which may be passed
        !           808:  *     to Tcl_DeleteTrace to eliminate the trace.
        !           809:  *
        !           810:  * Side effects:
        !           811:  *     From now on, proc will be called just before a command procedure
        !           812:  *     is called to execute a Tcl command.  Calls to proc will have the
        !           813:  *     following form:
        !           814:  *
        !           815:  *     void
        !           816:  *     proc(clientData, interp, level, command, cmdProc, cmdClientData,
        !           817:  *             argc, argv)
        !           818:  *         ClientData clientData;
        !           819:  *         Tcl_Interp *interp;
        !           820:  *         int level;
        !           821:  *         char *command;
        !           822:  *         int (*cmdProc)();
        !           823:  *         ClientData cmdClientData;
        !           824:  *         int argc;
        !           825:  *         char **argv;
        !           826:  *     {
        !           827:  *     }
        !           828:  *
        !           829:  *     The clientData and interp arguments to proc will be the same
        !           830:  *     as the corresponding arguments to this procedure.  Level gives
        !           831:  *     the nesting level of command interpretation for this interpreter
        !           832:  *     (0 corresponds to top level).  Command gives the ASCII text of
        !           833:  *     the raw command, cmdProc and cmdClientData give the procedure that
        !           834:  *     will be called to process the command and the ClientData value it
        !           835:  *     will receive, and argc and argv give the arguments to the
        !           836:  *     command, after any argument parsing and substitution.  Proc
        !           837:  *     does not return a value.
        !           838:  *
        !           839:  *----------------------------------------------------------------------
        !           840:  */
        !           841: 
        !           842: Tcl_Trace
        !           843: Tcl_CreateTrace(interp, level, proc, clientData)
        !           844:     Tcl_Interp *interp;                /* Interpreter in which to create the trace. */
        !           845:     int level;                 /* Only call proc for commands at nesting level
        !           846:                                 * <= level (1 => top level). */
        !           847:     Tcl_CmdTraceProc *proc;    /* Procedure to call before executing each
        !           848:                                 * command. */
        !           849:     ClientData clientData;     /* Arbitrary one-word value to pass to proc. */
        !           850: {
        !           851:     register Trace *tracePtr;
        !           852:     register Interp *iPtr = (Interp *) interp;
        !           853: 
        !           854:     tracePtr = (Trace *) ckalloc(sizeof(Trace));
        !           855:     tracePtr->level = level;
        !           856:     tracePtr->proc = proc;
        !           857:     tracePtr->clientData = clientData;
        !           858:     tracePtr->nextPtr = iPtr->tracePtr;
        !           859:     iPtr->tracePtr = tracePtr;
        !           860: 
        !           861:     return (Tcl_Trace) tracePtr;
        !           862: }
        !           863: 
        !           864: /*
        !           865:  *----------------------------------------------------------------------
        !           866:  *
        !           867:  * Tcl_DeleteTrace --
        !           868:  *
        !           869:  *     Remove a trace.
        !           870:  *
        !           871:  * Results:
        !           872:  *     None.
        !           873:  *
        !           874:  * Side effects:
        !           875:  *     From now on there will be no more calls to the procedure given
        !           876:  *     in trace.
        !           877:  *
        !           878:  *----------------------------------------------------------------------
        !           879:  */
        !           880: 
        !           881: void
        !           882: Tcl_DeleteTrace(interp, trace)
        !           883:     Tcl_Interp *interp;                /* Interpreter that contains trace. */
        !           884:     Tcl_Trace trace;           /* Token for trace (returned previously by
        !           885:                                 * Tcl_CreateTrace). */
        !           886: {
        !           887:     register Interp *iPtr = (Interp *) interp;
        !           888:     register Trace *tracePtr = (Trace *) trace;
        !           889:     register Trace *tracePtr2;
        !           890: 
        !           891:     if (iPtr->tracePtr == tracePtr) {
        !           892:        iPtr->tracePtr = tracePtr->nextPtr;
        !           893:        ckfree((char *) tracePtr);
        !           894:     } else {
        !           895:        for (tracePtr2 = iPtr->tracePtr; tracePtr2 != NULL;
        !           896:                tracePtr2 = tracePtr2->nextPtr) {
        !           897:            if (tracePtr2->nextPtr == tracePtr) {
        !           898:                tracePtr2->nextPtr = tracePtr->nextPtr;
        !           899:                ckfree((char *) tracePtr);
        !           900:                return;
        !           901:            }
        !           902:        }
        !           903:     }
        !           904: }
        !           905: 
        !           906: /*
        !           907:  *----------------------------------------------------------------------
        !           908:  *
        !           909:  * Tcl_AddErrorInfo --
        !           910:  *
        !           911:  *     Add information to a message being accumulated that describes
        !           912:  *     the current error.
        !           913:  *
        !           914:  * Results:
        !           915:  *     None.
        !           916:  *
        !           917:  * Side effects:
        !           918:  *     The contents of message are added to the "errorInfo" variable.
        !           919:  *     If Tcl_Eval has been called since the current value of errorInfo
        !           920:  *     was set, errorInfo is cleared before adding the new message.
        !           921:  *
        !           922:  *----------------------------------------------------------------------
        !           923:  */
        !           924: 
        !           925: void
        !           926: Tcl_AddErrorInfo(interp, message)
        !           927:     Tcl_Interp *interp;                /* Interpreter to which error information
        !           928:                                 * pertains. */
        !           929:     char *message;             /* Message to record. */
        !           930: {
        !           931:     register Interp *iPtr = (Interp *) interp;
        !           932: 
        !           933:     /*
        !           934:      * If an error is already being logged, then the new errorInfo
        !           935:      * is the concatenation of the old info and the new message.
        !           936:      * If this is the first piece of info for the error, then the
        !           937:      * new errorInfo is the concatenation of the message in
        !           938:      * interp->result and the new message.
        !           939:      */
        !           940: 
        !           941:     if (!(iPtr->flags & ERR_IN_PROGRESS)) {
        !           942:        Tcl_SetVar2(interp, "errorInfo", (char *) NULL, interp->result,
        !           943:                TCL_GLOBAL_ONLY);
        !           944:        iPtr->flags |= ERR_IN_PROGRESS;
        !           945: 
        !           946:        /*
        !           947:         * If the errorCode variable wasn't set by the code that generated
        !           948:         * the error, set it to "NONE".
        !           949:         */
        !           950: 
        !           951:        if (!(iPtr->flags & ERROR_CODE_SET)) {
        !           952:            (void) Tcl_SetVar2(interp, "errorCode", (char *) NULL, "NONE",
        !           953:                    TCL_GLOBAL_ONLY);
        !           954:        }
        !           955:     }
        !           956:     Tcl_SetVar2(interp, "errorInfo", (char *) NULL, message,
        !           957:            TCL_GLOBAL_ONLY|TCL_APPEND_VALUE);
        !           958: }
        !           959: 
        !           960: /*
        !           961:  *----------------------------------------------------------------------
        !           962:  *
        !           963:  * Tcl_VarEval --
        !           964:  *
        !           965:  *     Given a variable number of string arguments, concatenate them
        !           966:  *     all together and execute the result as a Tcl command.
        !           967:  *
        !           968:  * Results:
        !           969:  *     A standard Tcl return result.  An error message or other
        !           970:  *     result may be left in interp->result.
        !           971:  *
        !           972:  * Side effects:
        !           973:  *     Depends on what was done by the command.
        !           974:  *
        !           975:  *----------------------------------------------------------------------
        !           976:  */
        !           977: int
        !           978: Tcl_VarEval(Tcl_Interp *interp, ...)
        !           979: {
        !           980:     va_list argList;
        !           981: #define FIXED_SIZE 200
        !           982:     char fixedSpace[FIXED_SIZE+1];
        !           983:     int spaceAvl, spaceUsed, length;
        !           984:     char *string, *cmd;
        !           985:     int result;
        !           986: 
        !           987:     /*
        !           988:      * Copy the strings one after the other into a single larger
        !           989:      * string.  Use stack-allocated space for small commands, but if
        !           990:      * the commands gets too large than call ckalloc to create the
        !           991:      * space.
        !           992:      */
        !           993: 
        !           994:     va_start(argList, interp);
        !           995:     spaceAvl = FIXED_SIZE;
        !           996:     spaceUsed = 0;
        !           997:     cmd = fixedSpace;
        !           998:     while (1) {
        !           999:        string = va_arg(argList, char *);
        !          1000:        if (string == NULL) {
        !          1001:            break;
        !          1002:        }
        !          1003:        length = strlen(string);
        !          1004:        if ((spaceUsed + length) > spaceAvl) {
        !          1005:            char *new;
        !          1006: 
        !          1007:            spaceAvl = spaceUsed + length;
        !          1008:            spaceAvl += spaceAvl/2;
        !          1009:            new = ckalloc((unsigned) spaceAvl);
        !          1010:            memcpy((VOID *) new, (VOID *) cmd, spaceUsed);
        !          1011:            if (cmd != fixedSpace) {
        !          1012:                ckfree(cmd);
        !          1013:            }
        !          1014:            cmd = new;
        !          1015:        }
        !          1016:        strcpy(cmd + spaceUsed, string);
        !          1017:        spaceUsed += length;
        !          1018:     }
        !          1019:     va_end(argList);
        !          1020:     cmd[spaceUsed] = '\0';
        !          1021: 
        !          1022:     result = Tcl_Eval(interp, cmd, 0, (char **) NULL);
        !          1023:     if (cmd != fixedSpace) {
        !          1024:        ckfree(cmd);
        !          1025:     }
        !          1026:     return result;
        !          1027: }
        !          1028: 
        !          1029: /*
        !          1030:  *----------------------------------------------------------------------
        !          1031:  *
        !          1032:  * Tcl_GlobalEval --
        !          1033:  *
        !          1034:  *     Evaluate a command at global level in an interpreter.
        !          1035:  *
        !          1036:  * Results:
        !          1037:  *     A standard Tcl result is returned, and interp->result is
        !          1038:  *     modified accordingly.
        !          1039:  *
        !          1040:  * Side effects:
        !          1041:  *     The command string is executed in interp, and the execution
        !          1042:  *     is carried out in the variable context of global level (no
        !          1043:  *     procedures active), just as if an "uplevel #0" command were
        !          1044:  *     being executed.
        !          1045:  *
        !          1046:  *----------------------------------------------------------------------
        !          1047:  */
        !          1048: 
        !          1049: int
        !          1050: Tcl_GlobalEval(interp, command)
        !          1051:     Tcl_Interp *interp;                /* Interpreter in which to evaluate command. */
        !          1052:     char *command;             /* Command to evaluate. */
        !          1053: {
        !          1054:     register Interp *iPtr = (Interp *) interp;
        !          1055:     int result;
        !          1056:     CallFrame *savedVarFramePtr;
        !          1057: 
        !          1058:     savedVarFramePtr = iPtr->varFramePtr;
        !          1059:     iPtr->varFramePtr = NULL;
        !          1060:     result = Tcl_Eval(interp, command, 0, (char **) NULL);
        !          1061:     iPtr->varFramePtr = savedVarFramePtr;
        !          1062:     return result;
        !          1063: }

unix.superglobalmegacorp.com

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