Annotation of researchv10dc/cmd/worm/scsi/tcl/tclProc.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * tclProc.c --
        !             3:  *
        !             4:  *     This file contains routines that implement Tcl procedures and
        !             5:  *     variables.
        !             6:  *
        !             7:  * Copyright 1987 Regents of the University of California
        !             8:  * Permission to use, copy, modify, and distribute this
        !             9:  * software and its documentation for any purpose and without
        !            10:  * fee is hereby granted, provided that the above copyright
        !            11:  * notice appear in all copies.  The University of California
        !            12:  * makes no representations about the suitability of this
        !            13:  * software for any purpose.  It is provided "as is" without
        !            14:  * express or implied warranty.
        !            15:  */
        !            16: 
        !            17: #ifndef lint
        !            18: static char rcsid[] = "$Header: /sprite/src/lib/tcl/RCS/tclProc.c,v 1.35 90/03/29 10:55:16 ouster Exp $ SPRITE (Berkeley)";
        !            19: #pragma ref rcsid
        !            20: #endif not lint
        !            21: 
        !            22: #include <stdio.h>
        !            23: #include <stdlib.h>
        !            24: #include <string.h>
        !            25: #include <ctype.h>
        !            26: #include "tclInt.h"
        !            27: 
        !            28: /*
        !            29:  * Forward references to procedures defined later in this file:
        !            30:  */
        !            31: 
        !            32: extern Var *   FindVar();
        !            33: extern int     InterpProc();
        !            34: extern Var *   NewVar();
        !            35: extern void    ProcDeleteProc();
        !            36: 
        !            37: /*
        !            38:  *----------------------------------------------------------------------
        !            39:  *
        !            40:  * Tcl_ProcCmd --
        !            41:  *
        !            42:  *     This procedure is invoked to process the "proc" Tcl command.
        !            43:  *     See the user documentation for details on what it does.
        !            44:  *
        !            45:  * Results:
        !            46:  *     A standard Tcl result value.
        !            47:  *
        !            48:  * Side effects:
        !            49:  *     A new procedure gets created.
        !            50:  *
        !            51:  *----------------------------------------------------------------------
        !            52:  */
        !            53: 
        !            54:        /* ARGSUSED */
        !            55: int
        !            56: Tcl_ProcCmd(dummy, interp, argc, argv)
        !            57:     ClientData dummy;                  /* Not used. */
        !            58:     Tcl_Interp *interp;                        /* Current interpreter. */
        !            59:     int argc;                          /* Number of arguments. */
        !            60:     char **argv;                       /* Argument strings. */
        !            61: {
        !            62: #pragma ref dummy
        !            63:     register Interp *iPtr = (Interp *) interp;
        !            64:     register Proc *procPtr;
        !            65:     int result, argCount, i;
        !            66:     char **argArray;
        !            67: 
        !            68:     if (argc != 4) {
        !            69:        sprintf(iPtr->result,
        !            70:                "wrong # args: should be \"%.50s name args body\"",
        !            71:                argv[0]);
        !            72:        return TCL_ERROR;
        !            73:     }
        !            74: 
        !            75:     procPtr = (Proc *) malloc(sizeof(Proc));
        !            76:     procPtr->iPtr = iPtr;
        !            77:     procPtr->command = (char *) malloc((unsigned) strlen(argv[3]) + 1);
        !            78:     strcpy(procPtr->command, argv[3]);
        !            79:     procPtr->argPtr = NULL;
        !            80:     Tcl_CreateCommand(interp, argv[1], InterpProc,
        !            81:            (ClientData) procPtr, ProcDeleteProc);
        !            82: 
        !            83:     /*
        !            84:      * Break up the argument list into argument specifiers, then process
        !            85:      * each argument specifier.
        !            86:      */
        !            87: 
        !            88:     result = Tcl_SplitList(interp, argv[2], &argCount, &argArray);
        !            89:     if (result != TCL_OK) {
        !            90:        return result;
        !            91:     }
        !            92:     for (i = 0; i < argCount; i++) {
        !            93:        int fieldCount, nameLength, valueLength;
        !            94:        char **fieldValues;
        !            95:        register Var *argPtr;
        !            96: 
        !            97:        /*
        !            98:         * Now divide the specifier up into name and default.
        !            99:         */
        !           100: 
        !           101:        result = Tcl_SplitList(interp, argArray[i], &fieldCount,
        !           102:                &fieldValues);
        !           103:        if (result != TCL_OK) {
        !           104:            goto procError;
        !           105:        }
        !           106:        if (fieldCount > 2) {
        !           107:            sprintf(iPtr->result,
        !           108:                    "too many fields in argument specifier \"%.50s\"",
        !           109:                    argArray[i]);
        !           110:            result = TCL_ERROR;
        !           111:            goto procError;
        !           112:        }
        !           113:        if ((fieldCount == 0) || (*fieldValues[0] == 0)) {
        !           114:            sprintf(iPtr->result,
        !           115:                    "procedure \"%.50s\" has argument with no name", argv[1]);
        !           116:            result = TCL_ERROR;
        !           117:            goto procError;
        !           118:        }
        !           119:        nameLength = strlen(fieldValues[0]);
        !           120:        if (fieldCount == 2) {
        !           121:            valueLength = strlen(fieldValues[1]);
        !           122:        } else {
        !           123:            valueLength = 0;
        !           124:        }
        !           125:        if (procPtr->argPtr == NULL) {
        !           126:            argPtr = (Var *) malloc(VAR_SIZE(nameLength, valueLength));
        !           127:            procPtr->argPtr = argPtr;
        !           128:        } else {
        !           129:            argPtr->nextPtr = (Var *) malloc(VAR_SIZE(nameLength, valueLength));
        !           130:            argPtr = argPtr->nextPtr;
        !           131:        }
        !           132:        strcpy(argPtr->name, fieldValues[0]);
        !           133:        if (fieldCount == 2) {
        !           134:            argPtr->value = argPtr->name + nameLength + 1;
        !           135:            strcpy(argPtr->value, fieldValues[1]);
        !           136:        } else {
        !           137:            argPtr->value = NULL;
        !           138:        }
        !           139:        argPtr->valueLength = valueLength;
        !           140:        argPtr->flags = 0;
        !           141:        argPtr->nextPtr = NULL;
        !           142:        free((char *) fieldValues);
        !           143:     }
        !           144: 
        !           145:     free((char *) argArray);
        !           146:     return TCL_OK;
        !           147: 
        !           148:     procError:
        !           149:     free((char *) argArray);
        !           150:     return result;
        !           151: }
        !           152: 
        !           153: /*1
        !           154:  *----------------------------------------------------------------------
        !           155:  *
        !           156:  * Tcl_GetVar --
        !           157:  *
        !           158:  *     Return the value of a Tcl variable.
        !           159:  *
        !           160:  * Results:
        !           161:  *     The return value points to the current value of varName.  If
        !           162:  *     the variable is not defined in interp, either as a local or
        !           163:  *     global variable, then a NULL pointer is returned.  Note:  the
        !           164:  *     return value is only valid up until the next call to Tcl_SetVar;
        !           165:  *     if you depend on the value lasting longer than that, then make
        !           166:  *     yourself a private copy.
        !           167:  *
        !           168:  * Side effects:
        !           169:  *     None.
        !           170:  *
        !           171:  *----------------------------------------------------------------------
        !           172:  */
        !           173: 
        !           174: char *
        !           175: Tcl_GetVar(interp, varName, global)
        !           176:     Tcl_Interp *interp;                /* Command interpreter in which varName is
        !           177:                                 * to be looked up. */
        !           178:     char *varName;             /* Name of a variable in interp. */
        !           179:     int global;                        /* If non-zero, use only a global variable */
        !           180: {
        !           181:     Var *varPtr;
        !           182:     Interp *iPtr = (Interp *) interp;
        !           183: 
        !           184:     if (global || (iPtr->varFramePtr == NULL)) {
        !           185:        varPtr = FindVar(&iPtr->globalPtr, varName);
        !           186:     } else {
        !           187:        varPtr = FindVar(&iPtr->varFramePtr->varPtr, varName);
        !           188:     }
        !           189:     if (varPtr == NULL) {
        !           190:        return NULL;
        !           191:     }
        !           192:     if (varPtr->flags & VAR_GLOBAL) {
        !           193:        varPtr = varPtr->globalPtr;
        !           194:     }
        !           195:     if (varPtr->flags & VAR_DOESNT_EXIST) {
        !           196:        return NULL;
        !           197:     }
        !           198:     return varPtr->value;
        !           199: }
        !           200: 
        !           201: /*
        !           202:  *----------------------------------------------------------------------
        !           203:  *
        !           204:  * Tcl_SetVar --
        !           205:  *
        !           206:  *     Change the value of a variable.
        !           207:  *
        !           208:  * Results:
        !           209:  *     None.
        !           210:  *
        !           211:  * Side effects:
        !           212:  *     If varName is defined as a local or global variable in interp,
        !           213:  *     its value is changed to newValue.  If varName isn't currently
        !           214:  *     defined, then a new global variable by that name is created.
        !           215:  *
        !           216:  *----------------------------------------------------------------------
        !           217:  */
        !           218: 
        !           219: void
        !           220: Tcl_SetVar(interp, varName, newValue, global)
        !           221:     Tcl_Interp *interp;                /* Command interpreter in which varName is
        !           222:                                 * to be looked up. */
        !           223:     char *varName;             /* Name of a variable in interp. */
        !           224:     char *newValue;            /* New value for varName. */
        !           225:     int global;                        /* If non-zero, use only a global variable. */
        !           226: {
        !           227:     register Var *varPtr, **varListPtr;
        !           228:     register Interp *iPtr = (Interp *) interp;
        !           229:     int valueLength;
        !           230: 
        !           231:     if (global || (iPtr->varFramePtr == NULL)) {
        !           232:        varListPtr = &iPtr->globalPtr;
        !           233:     } else {
        !           234:        varListPtr = &iPtr->varFramePtr->varPtr;
        !           235:     }
        !           236:     varPtr = FindVar(varListPtr, varName);
        !           237:     if (varPtr == NULL) {
        !           238:        varPtr = NewVar(varName, newValue);
        !           239:        varPtr->nextPtr = *varListPtr;
        !           240:        *varListPtr = varPtr;
        !           241:     } else {
        !           242:        if (varPtr->flags & VAR_GLOBAL) {
        !           243:            varPtr = varPtr->globalPtr;
        !           244:        }
        !           245:        valueLength = strlen(newValue);
        !           246:        if (valueLength > varPtr->valueLength) {
        !           247:            if (varPtr->flags & VAR_DYNAMIC) {
        !           248:                free(varPtr->value);
        !           249:            }
        !           250:            varPtr->value = (char *) malloc((unsigned) valueLength + 1);
        !           251:            varPtr->flags |= VAR_DYNAMIC;
        !           252:            varPtr->valueLength = valueLength;
        !           253:        }
        !           254:        strcpy(varPtr->value, newValue);
        !           255:        varPtr->flags &= ~VAR_DOESNT_EXIST;
        !           256:     }
        !           257: }
        !           258: 
        !           259: /*
        !           260:  *----------------------------------------------------------------------
        !           261:  *
        !           262:  * Tcl_ParseVar --
        !           263:  *
        !           264:  *     Given a string starting with a $ sign, parse off a variable
        !           265:  *     name and return its value.
        !           266:  *
        !           267:  * Results:
        !           268:  *     The return value is the contents of the variable given by
        !           269:  *     the leading characters of string.  If termPtr isn't NULL,
        !           270:  *     *termPtr gets filled in with the address of the character
        !           271:  *     just after the last one in the variable specifier.  If the
        !           272:  *     variable doesn't exist, then the return value is NULL and
        !           273:  *     an error message will be left in interp->result.
        !           274:  *
        !           275:  * Side effects:
        !           276:  *     None.
        !           277:  *
        !           278:  *----------------------------------------------------------------------
        !           279:  */
        !           280: 
        !           281: char *
        !           282: Tcl_ParseVar(interp, string, termPtr)
        !           283:     Tcl_Interp *interp;                        /* Context for looking up variable. */
        !           284:     register char *string;             /* String containing variable name.
        !           285:                                         * First character must be "$". */
        !           286:     char **termPtr;                    /* If non-NULL, points to word to fill
        !           287:                                         * in with character just after last
        !           288:                                         * one in the variable specifier. */
        !           289: 
        !           290: {
        !           291:     char *name, c, *result;
        !           292: 
        !           293:     /*
        !           294:      * There are two cases:
        !           295:      * 1. The $ sign is followed by an open curly brace.  Then the variable
        !           296:      *    name is everything up to the next close curly brace.
        !           297:      * 2. The $ sign is not followed by an open curly brace.  Then the
        !           298:      *    variable name is everything up to the next character that isn't
        !           299:      *    a letter, digit, or underscore.
        !           300:      * 3. The $ sign is followed by something that isn't a letter, digit,
        !           301:      *    or underscore:  in this case, there is no variable name, and "$"
        !           302:      *    is returned.
        !           303:      */
        !           304: 
        !           305:     string++;
        !           306:     if (*string == '{') {
        !           307:        string++;
        !           308:        name = string;
        !           309:        while ((*string != '}') && (*string != 0)) {
        !           310:            string++;
        !           311:        }
        !           312:        if (termPtr != 0) {
        !           313:            if (*string != 0) {
        !           314:                *termPtr = string+1;
        !           315:            } else {
        !           316:                *termPtr = string;
        !           317:            }
        !           318:        }
        !           319:     } else {
        !           320:        name = string;
        !           321:        while (isalnum(*string) || (*string == '_')) {
        !           322:            string++;
        !           323:        }
        !           324:        if (termPtr != 0) {
        !           325:            *termPtr = string;
        !           326:        }
        !           327:        if (string == name) {
        !           328:            return "$";
        !           329:        }
        !           330:     }
        !           331: 
        !           332:     c = *string;
        !           333:     *string = 0;
        !           334:     result = Tcl_GetVar(interp, name, 0);
        !           335:     if (result == NULL) {
        !           336:        Tcl_Return(interp, (char *) NULL, TCL_STATIC);
        !           337:        sprintf(interp->result, "couldn't find variable \"%.50s\"", name);
        !           338:     }
        !           339:     *string = c;
        !           340:     return result;
        !           341: }
        !           342: 
        !           343: /*
        !           344:  *----------------------------------------------------------------------
        !           345:  *
        !           346:  * Tcl_SetCmd --
        !           347:  *
        !           348:  *     This procedure is invoked to process the "set" Tcl command.
        !           349:  *     See the user documentation for details on what it does.
        !           350:  *
        !           351:  * Results:
        !           352:  *     A standard Tcl result value.
        !           353:  *
        !           354:  * Side effects:
        !           355:  *     A variable's value may be changed.
        !           356:  *
        !           357:  *----------------------------------------------------------------------
        !           358:  */
        !           359: 
        !           360:        /* ARGSUSED */
        !           361: int
        !           362: Tcl_SetCmd(dummy, interp, argc, argv)
        !           363:     ClientData dummy;                  /* Not used. */
        !           364:     register Tcl_Interp *interp;       /* Current interpreter. */
        !           365:     int argc;                          /* Number of arguments. */
        !           366:     char **argv;                       /* Argument strings. */
        !           367: {
        !           368: #pragma ref dummy
        !           369:     if (argc == 2) {
        !           370:        char *value;
        !           371: 
        !           372:        value = Tcl_GetVar(interp, argv[1], 0);
        !           373:        if (value == NULL) {
        !           374:            sprintf(interp->result, "couldn't find variable \"%.50s\"",
        !           375:                    argv[1]);
        !           376:            return TCL_ERROR;
        !           377:        }
        !           378:        interp->result = value;
        !           379:        return TCL_OK;
        !           380:     } else if (argc == 3) {
        !           381:        Tcl_SetVar(interp, argv[1], argv[2], 0);
        !           382:        return TCL_OK;
        !           383:     } else {
        !           384:        sprintf(interp->result,
        !           385:                "wrong # args: should be \"%.50s varName [newValue]\"",
        !           386:                argv[0]);
        !           387:        return TCL_ERROR;
        !           388:     }
        !           389: }
        !           390: 
        !           391: /*
        !           392:  *----------------------------------------------------------------------
        !           393:  *
        !           394:  * Tcl_GlobalCmd --
        !           395:  *
        !           396:  *     This procedure is invoked to process the "global" Tcl command.
        !           397:  *     See the user documentation for details on what it does.
        !           398:  *
        !           399:  * Results:
        !           400:  *     A standard Tcl result value.
        !           401:  *
        !           402:  * Side effects:
        !           403:  *     See the user documentation.
        !           404:  *
        !           405:  *----------------------------------------------------------------------
        !           406:  */
        !           407: 
        !           408:        /* ARGSUSED */
        !           409: int
        !           410: Tcl_GlobalCmd(dummy, interp, argc, argv)
        !           411:     ClientData dummy;                  /* Not used. */
        !           412:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           413:     int argc;                          /* Number of arguments. */
        !           414:     char **argv;                       /* Argument strings. */
        !           415: {
        !           416: #pragma ref dummy
        !           417:     register Var *varPtr;
        !           418:     register Interp *iPtr = (Interp *) interp;
        !           419:     Var *gVarPtr;
        !           420: 
        !           421:     if (argc < 2) {
        !           422:        sprintf(iPtr->result,
        !           423:                "too few args:  should be \"%.50s varName varName ...\"",
        !           424:                argv[0]);
        !           425:        return TCL_ERROR;
        !           426:     }
        !           427:     if (iPtr->varFramePtr == NULL) {
        !           428:        return TCL_OK;
        !           429:     }
        !           430: 
        !           431:     for (argc--, argv++; argc > 0; argc--, argv++) {
        !           432:        gVarPtr = FindVar(&iPtr->globalPtr, *argv);
        !           433:        if (gVarPtr == NULL) {
        !           434:            gVarPtr = NewVar(*argv, "");
        !           435:            gVarPtr->nextPtr = iPtr->globalPtr;
        !           436:            iPtr->globalPtr = gVarPtr;
        !           437:            gVarPtr->flags |= VAR_DOESNT_EXIST;
        !           438:        }
        !           439:        varPtr = NewVar(*argv, "");
        !           440:        varPtr->flags |= VAR_GLOBAL;
        !           441:        varPtr->globalPtr = gVarPtr;
        !           442:        varPtr->nextPtr = iPtr->varFramePtr->varPtr;
        !           443:        iPtr->varFramePtr->varPtr = varPtr;
        !           444:     }
        !           445:     return TCL_OK;
        !           446: }
        !           447: 
        !           448: /*
        !           449:  *----------------------------------------------------------------------
        !           450:  *
        !           451:  * Tcl_UplevelCmd --
        !           452:  *
        !           453:  *     This procedure is invoked to process the "uplevel" Tcl command.
        !           454:  *     See the user documentation for details on what it does.
        !           455:  *
        !           456:  * Results:
        !           457:  *     A standard Tcl result value.
        !           458:  *
        !           459:  * Side effects:
        !           460:  *     See the user documentation.
        !           461:  *
        !           462:  *----------------------------------------------------------------------
        !           463:  */
        !           464: 
        !           465:        /* ARGSUSED */
        !           466: int
        !           467: Tcl_UplevelCmd(dummy, interp, argc, argv)
        !           468:     ClientData dummy;                  /* Not used. */
        !           469:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           470:     int argc;                          /* Number of arguments. */
        !           471:     char **argv;                       /* Argument strings. */
        !           472: {
        !           473: #pragma ref dummy
        !           474:     register Interp *iPtr = (Interp *) interp;
        !           475:     int level, result;
        !           476:     char *end, *levelArg;
        !           477:     CallFrame *savedVarFramePtr, *framePtr;
        !           478: 
        !           479:     if (argc < 2) {
        !           480:        uplevelSyntax:
        !           481:        sprintf(iPtr->result,
        !           482:                "too few args:  should be \"%.50s [level] command ...\"",
        !           483:                argv[0]);
        !           484:        return TCL_ERROR;
        !           485:     }
        !           486: 
        !           487:     /*
        !           488:      * Parse arguments to figure out which level to go to, and set
        !           489:      * argv and argc to refer to the command to execute at that level.
        !           490:      */
        !           491: 
        !           492:     levelArg = argv[1];
        !           493:     if (*levelArg == '#') {
        !           494:        level = strtoul(levelArg+1, &end, 10);
        !           495:        if ((end == (levelArg+1)) || (*end != '\0')) {
        !           496:            goto levelError;
        !           497:        }
        !           498:        argc -= 2;
        !           499:        argv += 2;
        !           500:     } else if (isdigit(*levelArg)) {
        !           501:        level = strtoul(levelArg, &end, 10);
        !           502:        if ((end == levelArg) || (*end != '\0')) {
        !           503:            goto levelError;
        !           504:        }
        !           505:        if (iPtr->varFramePtr == NULL) {
        !           506:            goto levelError;
        !           507:        }
        !           508:        level = iPtr->varFramePtr->level - level;
        !           509:        argc -= 2;
        !           510:        argv += 2;
        !           511:     } else {
        !           512:        if (iPtr->varFramePtr == NULL) {
        !           513:            goto levelError;
        !           514:        }
        !           515:        level = iPtr->varFramePtr->level - 1;
        !           516:        argc--;
        !           517:        argv++;
        !           518:     }
        !           519: 
        !           520:     /*
        !           521:      * Figure out which frame to use, and modify the interpreter so
        !           522:      * its variables come from that frame.
        !           523:      */
        !           524: 
        !           525:     savedVarFramePtr = iPtr->varFramePtr;
        !           526:     if (level == 0) {
        !           527:        iPtr->varFramePtr = NULL;
        !           528:     } else {
        !           529:        for (framePtr = savedVarFramePtr; framePtr != NULL;
        !           530:                framePtr = framePtr->callerVarPtr) {
        !           531:            if (framePtr->level == level) {
        !           532:                break;
        !           533:            }
        !           534:        }
        !           535:        if (framePtr == NULL) {
        !           536:            goto levelError;
        !           537:        }
        !           538:        iPtr->varFramePtr = framePtr;
        !           539:     }
        !           540: 
        !           541:     /*
        !           542:      * Execute the residual arguments as a command.
        !           543:      */
        !           544: 
        !           545:     if (argc == 0) {
        !           546:        goto uplevelSyntax;
        !           547:     }
        !           548:     if (argc == 1) {
        !           549:        result = Tcl_Eval(interp, argv[0], 0, (char **) NULL);
        !           550:     } else {
        !           551:        char *cmd;
        !           552: 
        !           553:        cmd = Tcl_Concat(argc, argv);
        !           554:        result = Tcl_Eval(interp, cmd, 0, (char **) NULL);
        !           555:     }
        !           556:     if (result == TCL_ERROR) {
        !           557:        char msg[60];
        !           558:        sprintf(msg, " (\"uplevel\" body line %d)", interp->errorLine);
        !           559:        Tcl_AddErrorInfo(interp, msg);
        !           560:     }
        !           561: 
        !           562:     /*
        !           563:      * Restore the variable frame, and return.
        !           564:      */
        !           565: 
        !           566:     iPtr->varFramePtr = savedVarFramePtr;
        !           567:     return result;
        !           568: 
        !           569:     levelError:
        !           570:     sprintf(iPtr->result, "bad level \"%.50s\"", levelArg);
        !           571:     return TCL_ERROR;
        !           572: }
        !           573: 
        !           574: /*
        !           575:  *----------------------------------------------------------------------
        !           576:  *
        !           577:  * TclFindProc --
        !           578:  *
        !           579:  *     Given the name of a procedure, return a pointer to the
        !           580:  *     record describing the procedure.
        !           581:  *
        !           582:  * Results:
        !           583:  *     NULL is returned if the name doesn't correspond to any
        !           584:  *     procedure.  Otherwise the return value is a pointer to
        !           585:  *     the procedure's record.
        !           586:  *
        !           587:  * Side effects:
        !           588:  *     None.
        !           589:  *
        !           590:  *----------------------------------------------------------------------
        !           591:  */
        !           592: 
        !           593: Proc *
        !           594: TclFindProc(iPtr, procName)
        !           595:     Interp *iPtr;              /* Interpreter in which to look. */
        !           596:     char *procName;            /* Name of desired procedure. */
        !           597: {
        !           598:     Command *cmdPtr;
        !           599: 
        !           600:     cmdPtr = TclFindCmd(iPtr, procName, 0);
        !           601:     if (cmdPtr == NULL) {
        !           602:        return NULL;
        !           603:     }
        !           604:     if (cmdPtr->proc != InterpProc) {
        !           605:        return NULL;
        !           606:     }
        !           607:     return (Proc *) cmdPtr->clientData;
        !           608: }
        !           609: 
        !           610: /*
        !           611:  *----------------------------------------------------------------------
        !           612:  *
        !           613:  * TclIsProc --
        !           614:  *
        !           615:  *     Tells whether a command is a Tcl procedure or not.
        !           616:  *
        !           617:  * Results:
        !           618:  *     If the given command is actuall a Tcl procedure, the
        !           619:  *     return value is the address of the record describing
        !           620:  *     the procedure.  Otherwise the return value is 0.
        !           621:  *
        !           622:  * Side effects:
        !           623:  *     None.
        !           624:  *
        !           625:  *----------------------------------------------------------------------
        !           626:  */
        !           627: 
        !           628: Proc *
        !           629: TclIsProc(cmdPtr)
        !           630:     Command *cmdPtr;           /* Command to test. */
        !           631: {
        !           632:     if (cmdPtr->proc == InterpProc) {
        !           633:        return (Proc *) cmdPtr->clientData;
        !           634:     }
        !           635:     return (Proc *) 0;
        !           636: }
        !           637: 
        !           638: /*
        !           639:  *----------------------------------------------------------------------
        !           640:  *
        !           641:  * TclDeleteVars --
        !           642:  *
        !           643:  *     This procedure is called as part of deleting an interpreter:
        !           644:  *     it recycles all the storage space associated with global
        !           645:  *     variables (the local ones should already have been deleted).
        !           646:  *
        !           647:  * Results:
        !           648:  *     None.
        !           649:  *
        !           650:  * Side effects:
        !           651:  *     Variables are deleted.
        !           652:  *
        !           653:  *----------------------------------------------------------------------
        !           654:  */
        !           655: 
        !           656: void
        !           657: TclDeleteVars(iPtr)
        !           658:     Interp *iPtr;              /* Interpreter to nuke. */
        !           659: {
        !           660:     register Var *varPtr;
        !           661: 
        !           662:     for (varPtr = iPtr->globalPtr; varPtr != NULL; varPtr = varPtr->nextPtr) {
        !           663:        if (varPtr->flags & VAR_DYNAMIC) {
        !           664:            free(varPtr->value);
        !           665:        }
        !           666:        free((char *) varPtr);
        !           667:     }
        !           668: }
        !           669: 
        !           670: /*
        !           671:  *----------------------------------------------------------------------
        !           672:  *
        !           673:  * InterpProc --
        !           674:  *
        !           675:  *     When a Tcl procedure gets invoked, this routine gets invoked
        !           676:  *     to interpret the procedure.
        !           677:  *
        !           678:  * Results:
        !           679:  *     A standard Tcl result value, usually TCL_OK.
        !           680:  *
        !           681:  * Side effects:
        !           682:  *     Depends on the commands in the procedure.
        !           683:  *
        !           684:  *----------------------------------------------------------------------
        !           685:  */
        !           686: 
        !           687: int
        !           688: InterpProc(procPtr, interp, argc, argv)
        !           689:     register Proc *procPtr;    /* Record describing procedure to be
        !           690:                                 * interpreted. */
        !           691:     Tcl_Interp *interp;                /* Interpreter in which procedure was
        !           692:                                 * invoked. */
        !           693:     int argc;                  /* Count of number of arguments to this
        !           694:                                 * procedure. */
        !           695:     char **argv;               /* Argument values. */
        !           696: {
        !           697:     char **args;
        !           698:     register Var *formalPtr, *argPtr;
        !           699:     register Interp *iPtr = (Interp *) interp;
        !           700:     CallFrame frame;
        !           701:     char *value, *end;
        !           702:     int result;
        !           703: 
        !           704:     /*
        !           705:      * Set up a call frame for the new procedure invocation.
        !           706:      */
        !           707: 
        !           708:     iPtr = procPtr->iPtr;
        !           709:     frame.varPtr = NULL;
        !           710:     if (iPtr->varFramePtr != NULL) {
        !           711:        frame.level = iPtr->varFramePtr->level + 1;
        !           712:     } else {
        !           713:        frame.level = 1;
        !           714:     }
        !           715:     frame.argc = argc;
        !           716:     frame.argv = argv;
        !           717:     frame.callerPtr = iPtr->framePtr;
        !           718:     frame.callerVarPtr = iPtr->varFramePtr;
        !           719:     iPtr->framePtr = &frame;
        !           720:     iPtr->varFramePtr = &frame;
        !           721: 
        !           722:     /*
        !           723:      * Match the actual arguments against the procedure's formal
        !           724:      * parameters to compute local variables.
        !           725:      */
        !           726: 
        !           727:     for (formalPtr = procPtr->argPtr, args = argv+1, argc -= 1;
        !           728:            formalPtr != NULL;
        !           729:            formalPtr = formalPtr->nextPtr, args++, argc--) {
        !           730: 
        !           731:        /*
        !           732:         * Handle the special case of the last formal being "args".  When
        !           733:         * it occurs, assign it a list consisting of all the remaining
        !           734:         * actual arguments.
        !           735:         */
        !           736: 
        !           737:        if ((formalPtr->nextPtr == NULL)
        !           738:                && (strcmp(formalPtr->name, "args") == 0)) {
        !           739:            if (argc < 0) {
        !           740:                argc = 0;
        !           741:            }
        !           742:            value = Tcl_Merge(argc, args);
        !           743:            argPtr = NewVar(formalPtr->name, value);
        !           744:            free(value);
        !           745:            argPtr->nextPtr = frame.varPtr;
        !           746:            frame.varPtr = argPtr;
        !           747:            argc = 0;
        !           748:            break;
        !           749:        } else if (argc > 0) {
        !           750:            value = *args;
        !           751:        } else if (formalPtr->value != NULL) {
        !           752:            value = formalPtr->value;
        !           753:        } else {
        !           754:            sprintf(iPtr->result,
        !           755:                    "no value given for parameter \"%s\" to \"%s\"",
        !           756:                    formalPtr->name, argv[0]);
        !           757:            result = TCL_ERROR;
        !           758:            goto procDone;
        !           759:        }
        !           760:        argPtr = NewVar(formalPtr->name, value);
        !           761:        argPtr->nextPtr = frame.varPtr;
        !           762:        frame.varPtr = argPtr;
        !           763:     }
        !           764:     if (argc > 0) {
        !           765:        sprintf(iPtr->result, "called \"%s\" with too many arguments",
        !           766:                argv[0]);
        !           767:        result = TCL_ERROR;
        !           768:        goto procDone;
        !           769:     }
        !           770: 
        !           771:     /*
        !           772:      * Invoke the commands in the procedure's body.
        !           773:      */
        !           774: 
        !           775:     result = Tcl_Eval(interp, procPtr->command, 0, &end);
        !           776:     if (result == TCL_RETURN) {
        !           777:        result = TCL_OK;
        !           778:     } else if (result == TCL_ERROR) {
        !           779:        char msg[100];
        !           780: 
        !           781:        /*
        !           782:         * Record information telling where the error occurred.
        !           783:         */
        !           784: 
        !           785:        sprintf(msg, " (procedure \"%.50s\" line %d)", argv[0],
        !           786:                iPtr->errorLine);
        !           787:        Tcl_AddErrorInfo(interp, msg);
        !           788:     } else if (result == TCL_BREAK) {
        !           789:        iPtr->result = "invoked \"break\" outside of a loop";
        !           790:        result = TCL_ERROR;
        !           791:     } else if (result == TCL_CONTINUE) {
        !           792:        iPtr->result = "invoked \"continue\" outside of a loop";
        !           793:        result = TCL_ERROR;
        !           794:     }
        !           795: 
        !           796:     /*
        !           797:      * Delete the call frame for this procedure invocation.
        !           798:      */
        !           799: 
        !           800:     procDone:
        !           801:     for (argPtr = frame.varPtr; argPtr != NULL; argPtr = argPtr->nextPtr) {
        !           802:        if (argPtr->flags & VAR_DYNAMIC) {
        !           803:            free(argPtr->value);
        !           804:        }
        !           805:        free((char *) argPtr);
        !           806:     }
        !           807:     iPtr->framePtr = frame.callerPtr;
        !           808:     iPtr->varFramePtr = frame.callerVarPtr;
        !           809:     return result;
        !           810: }
        !           811: 
        !           812: /*
        !           813:  *----------------------------------------------------------------------
        !           814:  *
        !           815:  * ProcDeleteProc --
        !           816:  *
        !           817:  *     This procedure is invoked just before a command procedure is
        !           818:  *     removed from an interpreter.  Its job is to release all the
        !           819:  *     resources allocated to the procedure.
        !           820:  *
        !           821:  * Results:
        !           822:  *     None.
        !           823:  *
        !           824:  * Side effects:
        !           825:  *     Memory gets freed.
        !           826:  *
        !           827:  *----------------------------------------------------------------------
        !           828:  */
        !           829: 
        !           830: void
        !           831: ProcDeleteProc(procPtr)
        !           832:     register Proc *procPtr;            /* Procedure to be deleted. */
        !           833: {
        !           834:     register Var *argPtr;
        !           835: 
        !           836:     free((char *) procPtr->command);
        !           837:     for (argPtr = procPtr->argPtr; argPtr != NULL; argPtr = argPtr->nextPtr) {
        !           838:        if (argPtr->flags & VAR_DYNAMIC) {
        !           839:            free(argPtr->value);
        !           840:        }
        !           841:        free((char *) argPtr);
        !           842:     }
        !           843:     free((char *) procPtr);
        !           844: }
        !           845: 
        !           846: /*
        !           847:  *----------------------------------------------------------------------
        !           848:  *
        !           849:  * FindVar --
        !           850:  *
        !           851:  *     Locate the Var structure corresponding to varName, if there
        !           852:  *     is one defined in a given list.
        !           853:  *
        !           854:  * Results:
        !           855:  *     The return value points to the Var structure corresponding to
        !           856:  *     the current value of varName in varListPtr, or NULL if varName
        !           857:  *     isn't currently defined in the list.
        !           858:  *
        !           859:  * Side effects:
        !           860:  *     If the variable is found, it is moved to the front of the list.
        !           861:  *
        !           862:  *----------------------------------------------------------------------
        !           863:  */
        !           864: 
        !           865: Var *
        !           866: FindVar(varListPtr, varName)
        !           867:     Var **varListPtr;          /* Pointer to head of list.  The value pointed
        !           868:                                 * to will be modified to bring the found
        !           869:                                 * variable to the front of the list. */
        !           870:     char *varName;             /* Desired variable. */
        !           871: {
        !           872:     register Var *prev, *cur;
        !           873:     register char c;
        !           874: 
        !           875:     c = *varName;
        !           876: 
        !           877:     /*
        !           878:      * Local variables take precedence over global ones.  Check the
        !           879:      * first character immediately, before wasting time calling strcmp.
        !           880:      */
        !           881: 
        !           882:     for (prev = NULL, cur = *varListPtr; cur != NULL;
        !           883:            prev = cur, cur = cur->nextPtr) {
        !           884:        if ((cur->name[0] == c) && (strcmp(cur->name, varName) == 0)) {
        !           885:            if (prev != NULL) {
        !           886:                prev->nextPtr = cur->nextPtr;
        !           887:                cur->nextPtr = *varListPtr;
        !           888:                *varListPtr = cur;
        !           889:            }
        !           890:            return cur;
        !           891:        }
        !           892:     }
        !           893:     return NULL;
        !           894: }
        !           895: 
        !           896: /*
        !           897:  *----------------------------------------------------------------------
        !           898:  *
        !           899:  * NewVar --
        !           900:  *
        !           901:  *     Create a new variable with the given name and initial value.
        !           902:  *
        !           903:  * Results:
        !           904:  *     The return value is a pointer to the new variable.  The variable
        !           905:  *     will not have been linked into any particular list, and its
        !           906:  *     nextPtr field will be NULL.
        !           907:  *
        !           908:  * Side effects:
        !           909:  *     Storage gets allocated.
        !           910:  *
        !           911:  *----------------------------------------------------------------------
        !           912:  */
        !           913: 
        !           914: Var *
        !           915: NewVar(name, value)
        !           916:     char *name;                        /* Name for variable. */
        !           917:     char *value;               /* Value for variable. */
        !           918: {
        !           919:     register Var *varPtr;
        !           920:     int nameLength, valueLength;
        !           921: 
        !           922:     nameLength = strlen(name);
        !           923:     valueLength = strlen(value);
        !           924:     if (valueLength < 20) {
        !           925:        valueLength = 20;
        !           926:     }
        !           927:     varPtr = (Var *) malloc(VAR_SIZE(nameLength, valueLength));
        !           928:     strcpy(varPtr->name, name);
        !           929:     varPtr->value = varPtr->name + nameLength + 1;
        !           930:     strcpy(varPtr->value, value);
        !           931:     varPtr->valueLength = valueLength;
        !           932:     varPtr->flags = 0;
        !           933:     varPtr->globalPtr = NULL;
        !           934:     varPtr->nextPtr = NULL;
        !           935:     return varPtr;
        !           936: }

unix.superglobalmegacorp.com

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