Annotation of micropolis/src/tcl/tclcmdmz.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * tclCmdMZ.c --
        !             3:  *
        !             4:  *     This file contains the top-level command routines for most of
        !             5:  *     the Tcl built-in commands whose names begin with the letters
        !             6:  *     M to Z.  It contains only commands in the generic core (i.e.
        !             7:  *     those that don't depend much upon UNIX facilities).
        !             8:  *
        !             9:  * Copyright 1987-1991 Regents of the University of California
        !            10:  * Permission to use, copy, modify, and distribute this
        !            11:  * software and its documentation for any purpose and without
        !            12:  * fee is hereby granted, provided that the above copyright
        !            13:  * notice appear in all copies.  The University of California
        !            14:  * makes no representations about the suitability of this
        !            15:  * software for any purpose.  It is provided "as is" without
        !            16:  * express or implied warranty.
        !            17:  */
        !            18: 
        !            19: #ifndef lint
        !            20: static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclCmdMZ.c,v 1.13 92/04/23 11:07:54 ouster Exp $ SPRITE (Berkeley)";
        !            21: #endif
        !            22: 
        !            23: #include "tclint.h"
        !            24: 
        !            25: /*
        !            26:  * Structure used to hold information about variable traces:
        !            27:  */
        !            28: 
        !            29: typedef struct {
        !            30:     int flags;                 /* Operations for which Tcl command is
        !            31:                                 * to be invoked. */
        !            32:     int length;                        /* Number of non-NULL chars. in command. */
        !            33:     char command[4];           /* Space for Tcl command to invoke.  Actual
        !            34:                                 * size will be as large as necessary to
        !            35:                                 * hold command.  This field must be the
        !            36:                                 * last in the structure, so that it can
        !            37:                                 * be larger than 4 bytes. */
        !            38: } TraceVarInfo;
        !            39: 
        !            40: /*
        !            41:  * Forward declarations for procedures defined in this file:
        !            42:  */
        !            43: 
        !            44: static char *          TraceVarProc _ANSI_ARGS_((ClientData clientData,
        !            45:                            Tcl_Interp *interp, char *name1, char *name2,
        !            46:                            int flags));
        !            47: 
        !            48: /*
        !            49:  *----------------------------------------------------------------------
        !            50:  *
        !            51:  * Tcl_RegexpCmd --
        !            52:  *
        !            53:  *     This procedure is invoked to process the "regexp" Tcl command.
        !            54:  *     See the user documentation for details on what it does.
        !            55:  *
        !            56:  * Results:
        !            57:  *     A standard Tcl result.
        !            58:  *
        !            59:  * Side effects:
        !            60:  *     See the user documentation.
        !            61:  *
        !            62:  *----------------------------------------------------------------------
        !            63:  */
        !            64: 
        !            65:        /* ARGSUSED */
        !            66: int
        !            67: Tcl_RegexpCmd(dummy, interp, argc, argv)
        !            68:     ClientData dummy;                  /* Not used. */
        !            69:     Tcl_Interp *interp;                        /* Current interpreter. */
        !            70:     int argc;                          /* Number of arguments. */
        !            71:     char **argv;                       /* Argument strings. */
        !            72: {
        !            73:     int noCase = 0;
        !            74:     int indices = 0;
        !            75:     regexp *regexpPtr;
        !            76:     char **argPtr, *string;
        !            77:     int match, i;
        !            78: 
        !            79:     if (argc < 3) {
        !            80:        wrongNumArgs:
        !            81:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !            82:                " ?-nocase? exp string ?matchVar? ?subMatchVar ",
        !            83:                "subMatchVar ...?\"", (char *) NULL);
        !            84:        return TCL_ERROR;
        !            85:     }
        !            86:     argPtr = argv+1;
        !            87:     argc--;
        !            88:     while ((argc > 0) && (argPtr[0][0] == '-')) {
        !            89:        if (strcmp(argPtr[0], "-indices") == 0) {
        !            90:            argPtr++;
        !            91:            argc--;
        !            92:            indices = 1;
        !            93:        } else if (strcmp(argPtr[0], "-nocase") == 0) {
        !            94:            argPtr++;
        !            95:            argc--;
        !            96:            noCase = 1;
        !            97:        } else {
        !            98:            break;
        !            99:        }
        !           100:     }
        !           101:     if (argc < 2) {
        !           102:        goto wrongNumArgs;
        !           103:     }
        !           104:     regexpPtr = TclCompileRegexp(interp, argPtr[0]);
        !           105:     if (regexpPtr == NULL) {
        !           106:        return TCL_ERROR;
        !           107:     }
        !           108: 
        !           109:     /*
        !           110:      * Convert the string to lower case, if desired, and perform
        !           111:      * the match.
        !           112:      */
        !           113: 
        !           114:     if (noCase) {
        !           115:        register char *dst, *src;
        !           116: 
        !           117:        string = (char *) ckalloc((unsigned) (strlen(argPtr[1]) + 1));
        !           118:        for (src = argPtr[1], dst = string; *src != 0; src++, dst++) {
        !           119:            if (isupper(*src)) {
        !           120:                *dst = tolower(*src);
        !           121:            } else {
        !           122:                *dst = *src;
        !           123:            }
        !           124:        }
        !           125:        *dst = 0;
        !           126:     } else {
        !           127:        string = argPtr[1];
        !           128:     }
        !           129:     tclRegexpError = NULL;
        !           130:     match = regexec(regexpPtr, string);
        !           131:     if (string != argPtr[1]) {
        !           132:        ckfree(string);
        !           133:     }
        !           134:     if (tclRegexpError != NULL) {
        !           135:        Tcl_AppendResult(interp, "error while matching pattern: ",
        !           136:                tclRegexpError, (char *) NULL);
        !           137:        return TCL_ERROR;
        !           138:     }
        !           139:     if (!match) {
        !           140:        interp->result = "0";
        !           141:        return TCL_OK;
        !           142:     }
        !           143: 
        !           144:     /*
        !           145:      * If additional variable names have been specified, return
        !           146:      * index information in those variables.
        !           147:      */
        !           148: 
        !           149:     argc -= 2;
        !           150:     if (argc > NSUBEXP) {
        !           151:        interp->result = "too many substring variables";
        !           152:        return TCL_ERROR;
        !           153:     }
        !           154:     for (i = 0; i < argc; i++) {
        !           155:        char *result, info[50];
        !           156: 
        !           157:        if (regexpPtr->startp[i] == NULL) {
        !           158:            if (indices) {
        !           159:                result = Tcl_SetVar(interp, argPtr[i+2], "-1 -1", 0);
        !           160:            } else {
        !           161:                result = Tcl_SetVar(interp, argPtr[i+2], "", 0);
        !           162:            }
        !           163:        } else {
        !           164:            if (indices) {
        !           165:                sprintf(info, "%d %d", regexpPtr->startp[i] - string,
        !           166:                        regexpPtr->endp[i] - string - 1);
        !           167:                result = Tcl_SetVar(interp, argPtr[i+2], info, 0);
        !           168:            } else {
        !           169:                char savedChar, *first, *last;
        !           170: 
        !           171:                first = argPtr[1] + (regexpPtr->startp[i] - string);
        !           172:                last = argPtr[1] + (regexpPtr->endp[i] - string);
        !           173:                savedChar = *last;
        !           174:                *last = 0;
        !           175:                result = Tcl_SetVar(interp, argPtr[i+2], first, 0);
        !           176:                *last = savedChar;
        !           177:            }
        !           178:        }
        !           179:        if (result == NULL) {
        !           180:            Tcl_AppendResult(interp, "couldn't set variable \"",
        !           181:                    argPtr[i+2], "\"", (char *) NULL);
        !           182:            return TCL_ERROR;
        !           183:        }
        !           184:     }
        !           185:     interp->result = "1";
        !           186:     return TCL_OK;
        !           187: }
        !           188: 
        !           189: /*
        !           190:  *----------------------------------------------------------------------
        !           191:  *
        !           192:  * Tcl_RegsubCmd --
        !           193:  *
        !           194:  *     This procedure is invoked to process the "regsub" Tcl command.
        !           195:  *     See the user documentation for details on what it does.
        !           196:  *
        !           197:  * Results:
        !           198:  *     A standard Tcl result.
        !           199:  *
        !           200:  * Side effects:
        !           201:  *     See the user documentation.
        !           202:  *
        !           203:  *----------------------------------------------------------------------
        !           204:  */
        !           205: 
        !           206:        /* ARGSUSED */
        !           207: int
        !           208: Tcl_RegsubCmd(dummy, interp, argc, argv)
        !           209:     ClientData dummy;                  /* Not used. */
        !           210:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           211:     int argc;                          /* Number of arguments. */
        !           212:     char **argv;                       /* Argument strings. */
        !           213: {
        !           214:     int noCase = 0, all = 0;
        !           215:     regexp *regexpPtr;
        !           216:     char *string, *p, *firstChar, *newValue, **argPtr;
        !           217:     int match, result, flags;
        !           218:     register char *src, c;
        !           219: 
        !           220:     if (argc < 5) {
        !           221:        wrongNumArgs:
        !           222:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           223:                " ?-nocase? ?-all? exp string subSpec varName\"", (char *) NULL);
        !           224:        return TCL_ERROR;
        !           225:     }
        !           226:     argPtr = argv+1;
        !           227:     argc--;
        !           228:     while (argPtr[0][0] == '-') {
        !           229:        if (strcmp(argPtr[0], "-nocase") == 0) {
        !           230:            argPtr++;
        !           231:            argc--;
        !           232:            noCase = 1;
        !           233:        } else if (strcmp(argPtr[0], "-all") == 0) {
        !           234:            argPtr++;
        !           235:            argc--;
        !           236:            all = 1;
        !           237:        } else {
        !           238:            break;
        !           239:        }
        !           240:     }
        !           241:     if (argc != 4) {
        !           242:        goto wrongNumArgs;
        !           243:     }
        !           244:     regexpPtr = TclCompileRegexp(interp, argPtr[0]);
        !           245:     if (regexpPtr == NULL) {
        !           246:        return TCL_ERROR;
        !           247:     }
        !           248: 
        !           249:     /*
        !           250:      * Convert the string to lower case, if desired.
        !           251:      */
        !           252: 
        !           253:     if (noCase) {
        !           254:        register char *dst;
        !           255: 
        !           256:        string = (char *) ckalloc((unsigned) (strlen(argPtr[1]) + 1));
        !           257:        for (src = argPtr[1], dst = string; *src != 0; src++, dst++) {
        !           258:            if (isupper(*src)) {
        !           259:                *dst = tolower(*src);
        !           260:            } else {
        !           261:                *dst = *src;
        !           262:            }
        !           263:        }
        !           264:        *dst = 0;
        !           265:     } else {
        !           266:        string = argPtr[1];
        !           267:     }
        !           268: 
        !           269:     /*
        !           270:      * The following loop is to handle multiple matches within the
        !           271:      * same source string;  each iteration handles one match and its
        !           272:      * corresponding substitution.  If "-all" hasn't been specified
        !           273:      * then the loop body only gets executed once.
        !           274:      */
        !           275: 
        !           276:     flags = 0;
        !           277:     for (p = string; *p != 0; ) {
        !           278:        tclRegexpError = NULL;
        !           279:        match = regexec(regexpPtr, p);
        !           280:        if (tclRegexpError != NULL) {
        !           281:            Tcl_AppendResult(interp, "error while matching pattern: ",
        !           282:                    tclRegexpError, (char *) NULL);
        !           283:            result = TCL_ERROR;
        !           284:            goto done;
        !           285:        }
        !           286:        if (!match) {
        !           287:            break;
        !           288:        }
        !           289: 
        !           290:        /*
        !           291:         * Copy the portion of the source string before the match to the
        !           292:         * result variable.
        !           293:         */
        !           294:     
        !           295:        src = argPtr[1] + (regexpPtr->startp[0] - string);
        !           296:        c = *src;
        !           297:        *src = 0;
        !           298:        newValue = Tcl_SetVar(interp, argPtr[3], argPtr[1] + (p - string),
        !           299:                flags);
        !           300:        *src = c;
        !           301:        flags = TCL_APPEND_VALUE;
        !           302:        if (newValue == NULL) {
        !           303:            cantSet:
        !           304:            Tcl_AppendResult(interp, "couldn't set variable \"",
        !           305:                    argPtr[3], "\"", (char *) NULL);
        !           306:            result = TCL_ERROR;
        !           307:            goto done;
        !           308:        }
        !           309:     
        !           310:        /*
        !           311:         * Append the subSpec argument to the variable, making appropriate
        !           312:         * substitutions.  This code is a bit hairy because of the backslash
        !           313:         * conventions and because the code saves up ranges of characters in
        !           314:         * subSpec to reduce the number of calls to Tcl_SetVar.
        !           315:         */
        !           316:     
        !           317:        for (src = firstChar = argPtr[2], c = *src; c != 0; src++, c = *src) {
        !           318:            int index;
        !           319:     
        !           320:            if (c == '&') {
        !           321:                index = 0;
        !           322:            } else if (c == '\\') {
        !           323:                c = src[1];
        !           324:                if ((c >= '0') && (c <= '9')) {
        !           325:                    index = c - '0';
        !           326:                } else if ((c == '\\') || (c == '&')) {
        !           327:                    *src = c;
        !           328:                    src[1] = 0;
        !           329:                    newValue = Tcl_SetVar(interp, argPtr[3], firstChar,
        !           330:                            TCL_APPEND_VALUE);
        !           331:                    *src = '\\';
        !           332:                    src[1] = c;
        !           333:                    if (newValue == NULL) {
        !           334:                        goto cantSet;
        !           335:                    }
        !           336:                    firstChar = src+2;
        !           337:                    src++;
        !           338:                    continue;
        !           339:                } else {
        !           340:                    continue;
        !           341:                }
        !           342:            } else {
        !           343:                continue;
        !           344:            }
        !           345:            if (firstChar != src) {
        !           346:                c = *src;
        !           347:                *src = 0;
        !           348:                newValue = Tcl_SetVar(interp, argPtr[3], firstChar,
        !           349:                        TCL_APPEND_VALUE);
        !           350:                *src = c;
        !           351:                if (newValue == NULL) {
        !           352:                    goto cantSet;
        !           353:                }
        !           354:            }
        !           355:            if ((index < NSUBEXP) && (regexpPtr->startp[index] != NULL)
        !           356:                    && (regexpPtr->endp[index] != NULL)) {
        !           357:                char *first, *last, saved;
        !           358:     
        !           359:                first = argPtr[1] + (regexpPtr->startp[index] - string);
        !           360:                last = argPtr[1] + (regexpPtr->endp[index] - string);
        !           361:                saved = *last;
        !           362:                *last = 0;
        !           363:                newValue = Tcl_SetVar(interp, argPtr[3], first,
        !           364:                        TCL_APPEND_VALUE);
        !           365:                *last = saved;
        !           366:                if (newValue == NULL) {
        !           367:                    goto cantSet;
        !           368:                }
        !           369:            }
        !           370:            if (*src == '\\') {
        !           371:                src++;
        !           372:            }
        !           373:            firstChar = src+1;
        !           374:        }
        !           375:        if (firstChar != src) {
        !           376:            if (Tcl_SetVar(interp, argPtr[3], firstChar,
        !           377:                    TCL_APPEND_VALUE) == NULL) {
        !           378:                goto cantSet;
        !           379:            }
        !           380:        }
        !           381:        p = regexpPtr->endp[0];
        !           382:        if (!all) {
        !           383:            break;
        !           384:        }
        !           385:     }
        !           386: 
        !           387:     /*
        !           388:      * If there were no matches at all, then return a "0" result.
        !           389:      */
        !           390: 
        !           391:     if (p == string) {
        !           392:        interp->result = "0";
        !           393:        result = TCL_OK;
        !           394:        goto done;
        !           395:     }
        !           396: 
        !           397:     /*
        !           398:      * Copy the portion of the source string after the last match to the
        !           399:      * result variable.
        !           400:      */
        !           401: 
        !           402:     if (*p != 0) {
        !           403:        if (Tcl_SetVar(interp, argPtr[3], p, TCL_APPEND_VALUE) == NULL) {
        !           404:            goto cantSet;
        !           405:        }
        !           406:     }
        !           407:     interp->result = "1";
        !           408:     result = TCL_OK;
        !           409: 
        !           410:     done:
        !           411:     if (string != argPtr[1]) {
        !           412:        ckfree(string);
        !           413:     }
        !           414:     return result;
        !           415: }
        !           416: 
        !           417: /*
        !           418:  *----------------------------------------------------------------------
        !           419:  *
        !           420:  * Tcl_RenameCmd --
        !           421:  *
        !           422:  *     This procedure is invoked to process the "rename" Tcl command.
        !           423:  *     See the user documentation for details on what it does.
        !           424:  *
        !           425:  * Results:
        !           426:  *     A standard Tcl result.
        !           427:  *
        !           428:  * Side effects:
        !           429:  *     See the user documentation.
        !           430:  *
        !           431:  *----------------------------------------------------------------------
        !           432:  */
        !           433: 
        !           434:        /* ARGSUSED */
        !           435: int
        !           436: Tcl_RenameCmd(dummy, interp, argc, argv)
        !           437:     ClientData dummy;                  /* Not used. */
        !           438:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           439:     int argc;                          /* Number of arguments. */
        !           440:     char **argv;                       /* Argument strings. */
        !           441: {
        !           442:     register Command *cmdPtr;
        !           443:     Interp *iPtr = (Interp *) interp;
        !           444:     Tcl_HashEntry *hPtr;
        !           445:     int new;
        !           446: 
        !           447:     if (argc != 3) {
        !           448:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           449:                " oldName newName\"", (char *) NULL);
        !           450:        return TCL_ERROR;
        !           451:     }
        !           452:     if (argv[2][0] == '\0') {
        !           453:        if (Tcl_DeleteCommand(interp, argv[1]) != 0) {
        !           454:            Tcl_AppendResult(interp, "can't delete \"", argv[1],
        !           455:                    "\": command doesn't exist", (char *) NULL);
        !           456:            return TCL_ERROR;
        !           457:        }
        !           458:        return TCL_OK;
        !           459:     }
        !           460:     hPtr = Tcl_FindHashEntry(&iPtr->commandTable, argv[2]);
        !           461:     if (hPtr != NULL) {
        !           462:        Tcl_AppendResult(interp, "can't rename to \"", argv[2],
        !           463:                "\": command already exists", (char *) NULL);
        !           464:        return TCL_ERROR;
        !           465:     }
        !           466:     hPtr = Tcl_FindHashEntry(&iPtr->commandTable, argv[1]);
        !           467:     if (hPtr == NULL) {
        !           468:        Tcl_AppendResult(interp, "can't rename \"", argv[1],
        !           469:                "\":  command doesn't exist", (char *) NULL);
        !           470:        return TCL_ERROR;
        !           471:     }
        !           472:     cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
        !           473:     Tcl_DeleteHashEntry(hPtr);
        !           474:     hPtr = Tcl_CreateHashEntry(&iPtr->commandTable, argv[2], &new);
        !           475:     Tcl_SetHashValue(hPtr, cmdPtr);
        !           476:     return TCL_OK;
        !           477: }
        !           478: 
        !           479: /*
        !           480:  *----------------------------------------------------------------------
        !           481:  *
        !           482:  * Tcl_ReturnCmd --
        !           483:  *
        !           484:  *     This procedure is invoked to process the "return" Tcl command.
        !           485:  *     See the user documentation for details on what it does.
        !           486:  *
        !           487:  * Results:
        !           488:  *     A standard Tcl result.
        !           489:  *
        !           490:  * Side effects:
        !           491:  *     See the user documentation.
        !           492:  *
        !           493:  *----------------------------------------------------------------------
        !           494:  */
        !           495: 
        !           496:        /* ARGSUSED */
        !           497: int
        !           498: Tcl_ReturnCmd(dummy, interp, argc, argv)
        !           499:     ClientData dummy;                  /* Not used. */
        !           500:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           501:     int argc;                          /* Number of arguments. */
        !           502:     char **argv;                       /* Argument strings. */
        !           503: {
        !           504:     if (argc > 2) {
        !           505:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           506:                " ?value?\"", (char *) NULL);
        !           507:        return TCL_ERROR;
        !           508:     }
        !           509:     if (argc == 2) {
        !           510:        Tcl_SetResult(interp, argv[1], TCL_VOLATILE);
        !           511:     }
        !           512:     return TCL_RETURN;
        !           513: }
        !           514: 
        !           515: /*
        !           516:  *----------------------------------------------------------------------
        !           517:  *
        !           518:  * Tcl_ScanCmd --
        !           519:  *
        !           520:  *     This procedure is invoked to process the "scan" Tcl command.
        !           521:  *     See the user documentation for details on what it does.
        !           522:  *
        !           523:  * Results:
        !           524:  *     A standard Tcl result.
        !           525:  *
        !           526:  * Side effects:
        !           527:  *     See the user documentation.
        !           528:  *
        !           529:  *----------------------------------------------------------------------
        !           530:  */
        !           531: 
        !           532:        /* ARGSUSED */
        !           533: int
        !           534: Tcl_ScanCmd(dummy, interp, argc, argv)
        !           535:     ClientData dummy;                  /* Not used. */
        !           536:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           537:     int argc;                          /* Number of arguments. */
        !           538:     char **argv;                       /* Argument strings. */
        !           539: {
        !           540:     int arg1Length;                    /* Number of bytes in argument to be
        !           541:                                         * scanned.  This gives an upper limit
        !           542:                                         * on string field sizes. */
        !           543: #   define MAX_FIELDS 20
        !           544:     typedef struct {
        !           545:        char fmt;                       /* Format for field. */
        !           546:        int size;                       /* How many bytes to allow for
        !           547:                                         * field. */
        !           548:        char *location;                 /* Where field will be stored. */
        !           549:     } Field;
        !           550:     Field fields[MAX_FIELDS];          /* Info about all the fields in the
        !           551:                                         * format string. */
        !           552:     register Field *curField;
        !           553:     int numFields = 0;                 /* Number of fields actually
        !           554:                                         * specified. */
        !           555:     int suppress;                      /* Current field is assignment-
        !           556:                                         * suppressed. */
        !           557:     int totalSize = 0;                 /* Number of bytes needed to store
        !           558:                                         * all results combined. */
        !           559:     char *results;                     /* Where scanned output goes.  */
        !           560:     int numScanned;                    /* sscanf's result. */
        !           561:     register char *fmt;
        !           562:     int i, widthSpecified;
        !           563: 
        !           564:     if (argc < 3) {
        !           565:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           566:                " string format ?varName varName ...?\"", (char *) NULL);
        !           567:        return TCL_ERROR;
        !           568:     }
        !           569: 
        !           570:     /*
        !           571:      * This procedure operates in four stages:
        !           572:      * 1. Scan the format string, collecting information about each field.
        !           573:      * 2. Allocate an array to hold all of the scanned fields.
        !           574:      * 3. Call sscanf to do all the dirty work, and have it store the
        !           575:      *    parsed fields in the array.
        !           576:      * 4. Pick off the fields from the array and assign them to variables.
        !           577:      */
        !           578: 
        !           579:     arg1Length = (strlen(argv[1]) + 4) & ~03;
        !           580:     for (fmt = argv[2]; *fmt != 0; fmt++) {
        !           581:        if (*fmt != '%') {
        !           582:            continue;
        !           583:        }
        !           584:        fmt++;
        !           585:        if (*fmt == '*') {
        !           586:            suppress = 1;
        !           587:            fmt++;
        !           588:        } else {
        !           589:            suppress = 0;
        !           590:        }
        !           591:        widthSpecified = 0;
        !           592:        while (isdigit(*fmt)) {
        !           593:            widthSpecified = 1;
        !           594:            fmt++;
        !           595:        }
        !           596:        if (suppress) {
        !           597:            continue;
        !           598:        }
        !           599:        if (numFields == MAX_FIELDS) {
        !           600:            interp->result = "too many fields to scan";
        !           601:            return TCL_ERROR;
        !           602:        }
        !           603:        curField = &fields[numFields];
        !           604:        numFields++;
        !           605:        switch (*fmt) {
        !           606:            case 'D':
        !           607:            case 'O':
        !           608:            case 'X':
        !           609:            case 'd':
        !           610:            case 'o':
        !           611:            case 'x':
        !           612:                curField->fmt = 'd';
        !           613:                curField->size = sizeof(int);
        !           614:                break;
        !           615: 
        !           616:            case 's':
        !           617:                curField->fmt = 's';
        !           618:                curField->size = arg1Length;
        !           619:                break;
        !           620: 
        !           621:            case 'c':
        !           622:                 if (widthSpecified) {
        !           623:                     interp->result = 
        !           624:                          "field width may not be specified in %c conversion";
        !           625:                     return TCL_ERROR;
        !           626:                 }
        !           627:                curField->fmt = 'c';
        !           628:                curField->size = sizeof(int);
        !           629:                break;
        !           630: 
        !           631:            case 'E':
        !           632:            case 'F':
        !           633:                curField->fmt = 'F';
        !           634:                curField->size = sizeof(double);
        !           635:                break;
        !           636: 
        !           637:            case 'e':
        !           638:            case 'f':
        !           639:                curField->fmt = 'f';
        !           640:                curField->size = sizeof(float);
        !           641:                break;
        !           642: 
        !           643:            case '[':
        !           644:                curField->fmt = 's';
        !           645:                curField->size = arg1Length;
        !           646:                do {
        !           647:                    fmt++;
        !           648:                } while (*fmt != ']');
        !           649:                break;
        !           650: 
        !           651:            default:
        !           652:                sprintf(interp->result, "bad scan conversion character \"%c\"",
        !           653:                        *fmt);
        !           654:                return TCL_ERROR;
        !           655:        }
        !           656:        totalSize += curField->size;
        !           657:     }
        !           658: 
        !           659:     if (numFields != (argc-3)) {
        !           660:        interp->result =
        !           661:                "different numbers of variable names and field specifiers";
        !           662:        return TCL_ERROR;
        !           663:     }
        !           664: 
        !           665:     /*
        !           666:      * Step 2:
        !           667:      */
        !           668: 
        !           669:     results = (char *) ckalloc((unsigned) totalSize);
        !           670:     for (i = 0, totalSize = 0, curField = fields;
        !           671:            i < numFields; i++, curField++) {
        !           672:        curField->location = results + totalSize;
        !           673:        totalSize += curField->size;
        !           674:     }
        !           675: 
        !           676:     /*
        !           677:      * Step 3:
        !           678:      */
        !           679: 
        !           680:     numScanned = sscanf(argv[1], argv[2],
        !           681:            fields[0].location, fields[1].location, fields[2].location,
        !           682:            fields[3].location, fields[4].location, fields[5].location,
        !           683:            fields[6].location, fields[7].location, fields[8].location,
        !           684:            fields[9].location, fields[10].location, fields[11].location,
        !           685:            fields[12].location, fields[13].location, fields[14].location,
        !           686:            fields[15].location, fields[16].location, fields[17].location,
        !           687:            fields[18].location, fields[19].location);
        !           688: 
        !           689:     /*
        !           690:      * Step 4:
        !           691:      */
        !           692: 
        !           693:     if (numScanned < numFields) {
        !           694:        numFields = numScanned;
        !           695:     }
        !           696:     for (i = 0, curField = fields; i < numFields; i++, curField++) {
        !           697:        switch (curField->fmt) {
        !           698:            char string[120];
        !           699: 
        !           700:            case 'd':
        !           701:                sprintf(string, "%d", *((int *) curField->location));
        !           702:                if (Tcl_SetVar(interp, argv[i+3], string, 0) == NULL) {
        !           703:                    storeError:
        !           704:                    Tcl_AppendResult(interp,
        !           705:                            "couldn't set variable \"", argv[i+3], "\"",
        !           706:                            (char *) NULL);
        !           707:                    ckfree((char *) results);
        !           708:                    return TCL_ERROR;
        !           709:                }
        !           710:                break;
        !           711: 
        !           712:            case 'c':
        !           713:                sprintf(string, "%d", *((char *) curField->location) & 0xff);
        !           714:                if (Tcl_SetVar(interp, argv[i+3], string, 0) == NULL) {
        !           715:                    goto storeError;
        !           716:                }
        !           717:                break;
        !           718: 
        !           719:            case 's':
        !           720:                if (Tcl_SetVar(interp, argv[i+3], curField->location, 0)
        !           721:                        == NULL) {
        !           722:                    goto storeError;
        !           723:                }
        !           724:                break;
        !           725: 
        !           726:            case 'F':
        !           727:                sprintf(string, "%g", *((double *) curField->location));
        !           728:                if (Tcl_SetVar(interp, argv[i+3], string, 0) == NULL) {
        !           729:                    goto storeError;
        !           730:                }
        !           731:                break;
        !           732: 
        !           733:            case 'f':
        !           734:                sprintf(string, "%g", *((float *) curField->location));
        !           735:                if (Tcl_SetVar(interp, argv[i+3], string, 0) == NULL) {
        !           736:                    goto storeError;
        !           737:                }
        !           738:                break;
        !           739:        }
        !           740:     }
        !           741:     ckfree(results);
        !           742:     sprintf(interp->result, "%d", numScanned);
        !           743:     return TCL_OK;
        !           744: }
        !           745: 
        !           746: /*
        !           747:  *----------------------------------------------------------------------
        !           748:  *
        !           749:  * Tcl_SplitCmd --
        !           750:  *
        !           751:  *     This procedure is invoked to process the "split" Tcl command.
        !           752:  *     See the user documentation for details on what it does.
        !           753:  *
        !           754:  * Results:
        !           755:  *     A standard Tcl result.
        !           756:  *
        !           757:  * Side effects:
        !           758:  *     See the user documentation.
        !           759:  *
        !           760:  *----------------------------------------------------------------------
        !           761:  */
        !           762: 
        !           763:        /* ARGSUSED */
        !           764: int
        !           765: Tcl_SplitCmd(dummy, interp, argc, argv)
        !           766:     ClientData dummy;                  /* Not used. */
        !           767:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           768:     int argc;                          /* Number of arguments. */
        !           769:     char **argv;                       /* Argument strings. */
        !           770: {
        !           771:     char *splitChars;
        !           772:     register char *p, *p2;
        !           773:     char *elementStart;
        !           774: 
        !           775:     if (argc == 2) {
        !           776:        splitChars = " \n\t\r";
        !           777:     } else if (argc == 3) {
        !           778:        splitChars = argv[2];
        !           779:     } else {
        !           780:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           781:                " string ?splitChars?\"", (char *) NULL);
        !           782:        return TCL_ERROR;
        !           783:     }
        !           784: 
        !           785:     /*
        !           786:      * Handle the special case of splitting on every character.
        !           787:      */
        !           788: 
        !           789:     if (*splitChars == 0) {
        !           790:        char string[2];
        !           791:        string[1] = 0;
        !           792:        for (p = argv[1]; *p != 0; p++) {
        !           793:            string[0] = *p;
        !           794:            Tcl_AppendElement(interp, string, 0);
        !           795:        }
        !           796:        return TCL_OK;
        !           797:     }
        !           798: 
        !           799:     /*
        !           800:      * Normal case: split on any of a given set of characters.
        !           801:      * Discard instances of the split characters.
        !           802:      */
        !           803: 
        !           804:     for (p = elementStart = argv[1]; *p != 0; p++) {
        !           805:        char c = *p;
        !           806:        for (p2 = splitChars; *p2 != 0; p2++) {
        !           807:            if (*p2 == c) {
        !           808:                *p = 0;
        !           809:                Tcl_AppendElement(interp, elementStart, 0);
        !           810:                *p = c;
        !           811:                elementStart = p+1;
        !           812:                break;
        !           813:            }
        !           814:        }
        !           815:     }
        !           816:     if (p != argv[1]) {
        !           817:        Tcl_AppendElement(interp, elementStart, 0);
        !           818:     }
        !           819:     return TCL_OK;
        !           820: }
        !           821: 
        !           822: /*
        !           823:  *----------------------------------------------------------------------
        !           824:  *
        !           825:  * Tcl_StringCmd --
        !           826:  *
        !           827:  *     This procedure is invoked to process the "string" Tcl command.
        !           828:  *     See the user documentation for details on what it does.
        !           829:  *
        !           830:  * Results:
        !           831:  *     A standard Tcl result.
        !           832:  *
        !           833:  * Side effects:
        !           834:  *     See the user documentation.
        !           835:  *
        !           836:  *----------------------------------------------------------------------
        !           837:  */
        !           838: 
        !           839:        /* ARGSUSED */
        !           840: int
        !           841: Tcl_StringCmd(dummy, interp, argc, argv)
        !           842:     ClientData dummy;                  /* Not used. */
        !           843:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           844:     int argc;                          /* Number of arguments. */
        !           845:     char **argv;                       /* Argument strings. */
        !           846: {
        !           847:     int length;
        !           848:     register char *p, c;
        !           849:     int match;
        !           850:     int first;
        !           851:     int left = 0, right = 0;
        !           852: 
        !           853:     if (argc < 2) {
        !           854:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           855:                " option arg ?arg ...?\"", (char *) NULL);
        !           856:        return TCL_ERROR;
        !           857:     }
        !           858:     c = argv[1][0];
        !           859:     length = strlen(argv[1]);
        !           860:     if ((c == 'c') && (strncmp(argv[1], "compare", length) == 0)) {
        !           861:        if (argc != 4) {
        !           862:            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           863:                    " compare string1 string2\"", (char *) NULL);
        !           864:            return TCL_ERROR;
        !           865:        }
        !           866:        match = strcmp(argv[2], argv[3]);
        !           867:        if (match > 0) {
        !           868:            interp->result = "1";
        !           869:        } else if (match < 0) {
        !           870:            interp->result = "-1";
        !           871:        } else {
        !           872:            interp->result = "0";
        !           873:        }
        !           874:        return TCL_OK;
        !           875:     } else if ((c == 'f') && (strncmp(argv[1], "first", length) == 0)) {
        !           876:        if (argc != 4) {
        !           877:            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           878:                    " first string1 string2\"", (char *) NULL);
        !           879:            return TCL_ERROR;
        !           880:        }
        !           881:        first = 1;
        !           882: 
        !           883:        firstLast:
        !           884:        match = -1;
        !           885:        c = *argv[2];
        !           886:        length = strlen(argv[2]);
        !           887:        for (p = argv[3]; *p != 0; p++) {
        !           888:            if (*p != c) {
        !           889:                continue;
        !           890:            }
        !           891:            if (strncmp(argv[2], p, length) == 0) {
        !           892:                match = p-argv[3];
        !           893:                if (first) {
        !           894:                    break;
        !           895:                }
        !           896:            }
        !           897:        }
        !           898:        sprintf(interp->result, "%d", match);
        !           899:        return TCL_OK;
        !           900:     } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0)) {
        !           901:        int index;
        !           902: 
        !           903:        if (argc != 4) {
        !           904:            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           905:                    " index string charIndex\"", (char *) NULL);
        !           906:            return TCL_ERROR;
        !           907:        }
        !           908:        if (Tcl_GetInt(interp, argv[3], &index) != TCL_OK) {
        !           909:            return TCL_ERROR;
        !           910:        }
        !           911:        if ((index >= 0) && (index < strlen(argv[2]))) {
        !           912:            interp->result[0] = argv[2][index];
        !           913:            interp->result[1] = 0;
        !           914:        }
        !           915:        return TCL_OK;
        !           916:     } else if ((c == 'l') && (strncmp(argv[1], "last", length) == 0)
        !           917:            && (length >= 2)) {
        !           918:        if (argc != 4) {
        !           919:            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           920:                    " last string1 string2\"", (char *) NULL);
        !           921:            return TCL_ERROR;
        !           922:        }
        !           923:        first = 0;
        !           924:        goto firstLast;
        !           925:     } else if ((c == 'l') && (strncmp(argv[1], "length", length) == 0)
        !           926:            && (length >= 2)) {
        !           927:        if (argc != 3) {
        !           928:            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           929:                    " length string\"", (char *) NULL);
        !           930:            return TCL_ERROR;
        !           931:        }
        !           932:        sprintf(interp->result, "%d", strlen(argv[2]));
        !           933:        return TCL_OK;
        !           934:     } else if ((c == 'm') && (strncmp(argv[1], "match", length) == 0)) {
        !           935:        if (argc != 4) {
        !           936:            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           937:                    " match pattern string\"", (char *) NULL);
        !           938:            return TCL_ERROR;
        !           939:        }
        !           940:        if (Tcl_StringMatch(argv[3], argv[2]) != 0) {
        !           941:            interp->result = "1";
        !           942:        } else {
        !           943:            interp->result = "0";
        !           944:        }
        !           945:        return TCL_OK;
        !           946:     } else if ((c == 'r') && (strncmp(argv[1], "range", length) == 0)) {
        !           947:        int first, last, stringLength;
        !           948: 
        !           949:        if (argc != 5) {
        !           950:            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           951:                    " range string first last\"", (char *) NULL);
        !           952:            return TCL_ERROR;
        !           953:        }
        !           954:        stringLength = strlen(argv[2]);
        !           955:        if (Tcl_GetInt(interp, argv[3], &first) != TCL_OK) {
        !           956:            return TCL_ERROR;
        !           957:        }
        !           958:        if ((*argv[4] == 'e')
        !           959:                && (strncmp(argv[4], "end", strlen(argv[4])) == 0)) {
        !           960:            last = stringLength-1;
        !           961:        } else {
        !           962:            if (Tcl_GetInt(interp, argv[4], &last) != TCL_OK) {
        !           963:                Tcl_ResetResult(interp);
        !           964:                Tcl_AppendResult(interp,
        !           965:                        "expected integer or \"end\" but got \"",
        !           966:                        argv[4], "\"", (char *) NULL);
        !           967:                return TCL_ERROR;
        !           968:            }
        !           969:        }
        !           970:        if (first < 0) {
        !           971:            first = 0;
        !           972:        }
        !           973:        if (last >= stringLength) {
        !           974:            last = stringLength-1;
        !           975:        }
        !           976:        if (last >= first) {
        !           977:            char saved, *p;
        !           978: 
        !           979:            p = argv[2] + last + 1;
        !           980:            saved = *p;
        !           981:            *p = 0;
        !           982:            Tcl_SetResult(interp, argv[2] + first, TCL_VOLATILE);
        !           983:            *p = saved;
        !           984:        }
        !           985:        return TCL_OK;
        !           986:     } else if ((c == 't') && (strncmp(argv[1], "tolower", length) == 0)
        !           987:            && (length >= 3)) {
        !           988:        register char *p;
        !           989: 
        !           990:        if (argc != 3) {
        !           991:            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           992:                    " tolower string\"", (char *) NULL);
        !           993:            return TCL_ERROR;
        !           994:        }
        !           995:        Tcl_SetResult(interp, argv[2], TCL_VOLATILE);
        !           996:        for (p = interp->result; *p != 0; p++) {
        !           997:            if (isupper(*p)) {
        !           998:                *p = tolower(*p);
        !           999:            }
        !          1000:        }
        !          1001:        return TCL_OK;
        !          1002:     } else if ((c == 't') && (strncmp(argv[1], "toupper", length) == 0)
        !          1003:            && (length >= 3)) {
        !          1004:        register char *p;
        !          1005: 
        !          1006:        if (argc != 3) {
        !          1007:            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !          1008:                    " toupper string\"", (char *) NULL);
        !          1009:            return TCL_ERROR;
        !          1010:        }
        !          1011:        Tcl_SetResult(interp, argv[2], TCL_VOLATILE);
        !          1012:        for (p = interp->result; *p != 0; p++) {
        !          1013:            if (islower(*p)) {
        !          1014:                *p = toupper(*p);
        !          1015:            }
        !          1016:        }
        !          1017:        return TCL_OK;
        !          1018:     } else if ((c == 't') && (strncmp(argv[1], "trim", length) == 0)
        !          1019:            && (length == 4)) {
        !          1020:        char *trimChars;
        !          1021:        register char *p, *checkPtr;
        !          1022: 
        !          1023:        left = right = 1;
        !          1024: 
        !          1025:        trim:
        !          1026:        if (argc == 4) {
        !          1027:            trimChars = argv[3];
        !          1028:        } else if (argc == 3) {
        !          1029:            trimChars = " \t\n\r";
        !          1030:        } else {
        !          1031:            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !          1032:                    " ", argv[1], " string ?chars?\"", (char *) NULL);
        !          1033:            return TCL_ERROR;
        !          1034:        }
        !          1035:        p = argv[2];
        !          1036:        if (left) {
        !          1037:            for (c = *p; c != 0; p++, c = *p) {
        !          1038:                for (checkPtr = trimChars; *checkPtr != c; checkPtr++) {
        !          1039:                    if (*checkPtr == 0) {
        !          1040:                        goto doneLeft;
        !          1041:                    }
        !          1042:                }
        !          1043:            }
        !          1044:        }
        !          1045:        doneLeft:
        !          1046:        Tcl_SetResult(interp, p, TCL_VOLATILE);
        !          1047:        if (right) {
        !          1048:            char *donePtr;
        !          1049: 
        !          1050:            p = interp->result + strlen(interp->result) - 1;
        !          1051:            donePtr = &interp->result[-1];
        !          1052:            for (c = *p; p != donePtr; p--, c = *p) {
        !          1053:                for (checkPtr = trimChars; *checkPtr != c; checkPtr++) {
        !          1054:                    if (*checkPtr == 0) {
        !          1055:                        goto doneRight;
        !          1056:                    }
        !          1057:                }
        !          1058:            }
        !          1059:            doneRight:
        !          1060:            p[1] = 0;
        !          1061:        }
        !          1062:        return TCL_OK;
        !          1063:     } else if ((c == 't') && (strncmp(argv[1], "trimleft", length) == 0)
        !          1064:            && (length > 4)) {
        !          1065:        left = 1;
        !          1066:        argv[1] = "trimleft";
        !          1067:        goto trim;
        !          1068:     } else if ((c == 't') && (strncmp(argv[1], "trimright", length) == 0)
        !          1069:            && (length > 4)) {
        !          1070:        right = 1;
        !          1071:        argv[1] = "trimright";
        !          1072:        goto trim;
        !          1073:     } else {
        !          1074:        Tcl_AppendResult(interp, "bad option \"", argv[1],
        !          1075:                "\": should be compare, first, index, last, length, match, ",
        !          1076:                "range, tolower, toupper, trim, trimleft, or trimright",
        !          1077:                (char *) NULL);
        !          1078:        return TCL_ERROR;
        !          1079:     }
        !          1080: }
        !          1081: 
        !          1082: /*
        !          1083:  *----------------------------------------------------------------------
        !          1084:  *
        !          1085:  * Tcl_TraceCmd --
        !          1086:  *
        !          1087:  *     This procedure is invoked to process the "trace" Tcl command.
        !          1088:  *     See the user documentation for details on what it does.
        !          1089:  *
        !          1090:  * Results:
        !          1091:  *     A standard Tcl result.
        !          1092:  *
        !          1093:  * Side effects:
        !          1094:  *     See the user documentation.
        !          1095:  *
        !          1096:  *----------------------------------------------------------------------
        !          1097:  */
        !          1098: 
        !          1099:        /* ARGSUSED */
        !          1100: int
        !          1101: Tcl_TraceCmd(dummy, interp, argc, argv)
        !          1102:     ClientData dummy;                  /* Not used. */
        !          1103:     Tcl_Interp *interp;                        /* Current interpreter. */
        !          1104:     int argc;                          /* Number of arguments. */
        !          1105:     char **argv;                       /* Argument strings. */
        !          1106: {
        !          1107:     char c;
        !          1108:     int length;
        !          1109: 
        !          1110:     if (argc < 2) {
        !          1111:        Tcl_AppendResult(interp, "too few args: should be \"",
        !          1112:                argv[0], " option [arg arg ...]\"", (char *) NULL);
        !          1113:        return TCL_ERROR;
        !          1114:     }
        !          1115:     c = argv[1][1];
        !          1116:     length = strlen(argv[1]);
        !          1117:     if ((c == 'a') && (strncmp(argv[1], "variable", length) == 0)
        !          1118:            && (length >= 2)) {
        !          1119:        char *p;
        !          1120:        int flags, length;
        !          1121:        TraceVarInfo *tvarPtr;
        !          1122: 
        !          1123:        if (argc != 5) {
        !          1124:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1125:                    argv[0], " variable name ops command\"", (char *) NULL);
        !          1126:            return TCL_ERROR;
        !          1127:        }
        !          1128: 
        !          1129:        flags = 0;
        !          1130:        for (p = argv[3] ; *p != 0; p++) {
        !          1131:            if (*p == 'r') {
        !          1132:                flags |= TCL_TRACE_READS;
        !          1133:            } else if (*p == 'w') {
        !          1134:                flags |= TCL_TRACE_WRITES;
        !          1135:            } else if (*p == 'u') {
        !          1136:                flags |= TCL_TRACE_UNSETS;
        !          1137:            } else {
        !          1138:                goto badOps;
        !          1139:            }
        !          1140:        }
        !          1141:        if (flags == 0) {
        !          1142:            goto badOps;
        !          1143:        }
        !          1144: 
        !          1145:        length = strlen(argv[4]);
        !          1146:        tvarPtr = (TraceVarInfo *) ckalloc((unsigned)
        !          1147:                (sizeof(TraceVarInfo) - sizeof(tvarPtr->command) + length + 1));
        !          1148:        tvarPtr->flags = flags;
        !          1149:        tvarPtr->length = length;
        !          1150:        flags |= TCL_TRACE_UNSETS;
        !          1151:        strcpy(tvarPtr->command, argv[4]);
        !          1152:        if (Tcl_TraceVar(interp, argv[2], flags, TraceVarProc,
        !          1153:                (ClientData) tvarPtr) != TCL_OK) {
        !          1154:            ckfree((char *) tvarPtr);
        !          1155:            return TCL_ERROR;
        !          1156:        }
        !          1157:     } else if ((c == 'd') && (strncmp(argv[1], "vdelete", length)
        !          1158:            && (length >= 2)) == 0) {
        !          1159:        char *p;
        !          1160:        int flags, length;
        !          1161:        TraceVarInfo *tvarPtr;
        !          1162:        ClientData clientData;
        !          1163: 
        !          1164:        if (argc != 5) {
        !          1165:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1166:                    argv[0], " vdelete name ops command\"", (char *) NULL);
        !          1167:            return TCL_ERROR;
        !          1168:        }
        !          1169: 
        !          1170:        flags = 0;
        !          1171:        for (p = argv[3] ; *p != 0; p++) {
        !          1172:            if (*p == 'r') {
        !          1173:                flags |= TCL_TRACE_READS;
        !          1174:            } else if (*p == 'w') {
        !          1175:                flags |= TCL_TRACE_WRITES;
        !          1176:            } else if (*p == 'u') {
        !          1177:                flags |= TCL_TRACE_UNSETS;
        !          1178:            } else {
        !          1179:                goto badOps;
        !          1180:            }
        !          1181:        }
        !          1182:        if (flags == 0) {
        !          1183:            goto badOps;
        !          1184:        }
        !          1185: 
        !          1186:        /*
        !          1187:         * Search through all of our traces on this variable to
        !          1188:         * see if there's one with the given command.  If so, then
        !          1189:         * delete the first one that matches.
        !          1190:         */
        !          1191: 
        !          1192:        length = strlen(argv[4]);
        !          1193:        clientData = 0;
        !          1194:        while ((clientData = Tcl_VarTraceInfo(interp, argv[2], 0,
        !          1195:                TraceVarProc, clientData)) != 0) {
        !          1196:            tvarPtr = (TraceVarInfo *) clientData;
        !          1197:            if ((tvarPtr->length == length) && (tvarPtr->flags == flags)
        !          1198:                    && (strncmp(argv[4], tvarPtr->command, length) == 0)) {
        !          1199:                Tcl_UntraceVar(interp, argv[2], flags | TCL_TRACE_UNSETS,
        !          1200:                        TraceVarProc, clientData);
        !          1201:                ckfree((char *) tvarPtr);
        !          1202:                break;
        !          1203:            }
        !          1204:        }
        !          1205:     } else if ((c == 'i') && (strncmp(argv[1], "vinfo", length) == 0)
        !          1206:            && (length >= 2)) {
        !          1207:        ClientData clientData;
        !          1208:        char ops[4], *p;
        !          1209:        char *prefix = "{";
        !          1210: 
        !          1211:        if (argc != 3) {
        !          1212:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1213:                    argv[0], " vinfo name\"", (char *) NULL);
        !          1214:            return TCL_ERROR;
        !          1215:        }
        !          1216:        clientData = 0;
        !          1217:        while ((clientData = Tcl_VarTraceInfo(interp, argv[2], 0,
        !          1218:                TraceVarProc, clientData)) != 0) {
        !          1219:            TraceVarInfo *tvarPtr = (TraceVarInfo *) clientData;
        !          1220:            p = ops;
        !          1221:            if (tvarPtr->flags & TCL_TRACE_READS) {
        !          1222:                *p = 'r';
        !          1223:                p++;
        !          1224:            }
        !          1225:            if (tvarPtr->flags & TCL_TRACE_WRITES) {
        !          1226:                *p = 'w';
        !          1227:                p++;
        !          1228:            }
        !          1229:            if (tvarPtr->flags & TCL_TRACE_UNSETS) {
        !          1230:                *p = 'u';
        !          1231:                p++;
        !          1232:            }
        !          1233:            *p = '\0';
        !          1234:            Tcl_AppendResult(interp, prefix, (char *) NULL);
        !          1235:            Tcl_AppendElement(interp, ops, 1);
        !          1236:            Tcl_AppendElement(interp, tvarPtr->command, 0);
        !          1237:            Tcl_AppendResult(interp, "}", (char *) NULL);
        !          1238:            prefix = " {";
        !          1239:        }
        !          1240:     } else {
        !          1241:        Tcl_AppendResult(interp, "bad option \"", argv[1],
        !          1242:                "\": should be variable, vdelete, or vinfo",
        !          1243:                (char *) NULL);
        !          1244:        return TCL_ERROR;
        !          1245:     }
        !          1246:     return TCL_OK;
        !          1247: 
        !          1248:     badOps:
        !          1249:     Tcl_AppendResult(interp, "bad operations \"", argv[3],
        !          1250:            "\": should be one or more of rwu", (char *) NULL);
        !          1251:     return TCL_ERROR;
        !          1252: }
        !          1253: 
        !          1254: /*
        !          1255:  *----------------------------------------------------------------------
        !          1256:  *
        !          1257:  * TraceVarProc --
        !          1258:  *
        !          1259:  *     This procedure is called to handle variable accesses that have
        !          1260:  *     been traced using the "trace" command.
        !          1261:  *
        !          1262:  * Results:
        !          1263:  *     Normally returns NULL.  If the trace command returns an error,
        !          1264:  *     then this procedure returns an error string.
        !          1265:  *
        !          1266:  * Side effects:
        !          1267:  *     Depends on the command associated with the trace.
        !          1268:  *
        !          1269:  *----------------------------------------------------------------------
        !          1270:  */
        !          1271: 
        !          1272:        /* ARGSUSED */
        !          1273: static char *
        !          1274: TraceVarProc(clientData, interp, name1, name2, flags)
        !          1275:     ClientData clientData;     /* Information about the variable trace. */
        !          1276:     Tcl_Interp *interp;                /* Interpreter containing variable. */
        !          1277:     char *name1;               /* Name of variable or array. */
        !          1278:     char *name2;               /* Name of element within array;  NULL means
        !          1279:                                 * scalar variable is being referenced. */
        !          1280:     int flags;                 /* OR-ed bits giving operation and other
        !          1281:                                 * information. */
        !          1282: {
        !          1283:     TraceVarInfo *tvarPtr = (TraceVarInfo *) clientData;
        !          1284:     char *result;
        !          1285:     int code, cmdLength, flags1, flags2;
        !          1286:     Interp dummy;
        !          1287: #define STATIC_SIZE 199
        !          1288:     char staticSpace[STATIC_SIZE+1];
        !          1289:     char *cmdPtr, *p;
        !          1290: 
        !          1291:     result = NULL;
        !          1292:     if ((tvarPtr->flags & flags) && !(flags & TCL_INTERP_DESTROYED)) {
        !          1293: 
        !          1294:        /*
        !          1295:         * Generate a command to execute by appending list elements
        !          1296:         * for the two variable names and the operation.  The five
        !          1297:         * extra characters are for three space, the opcode character,
        !          1298:         * and the terminating null.
        !          1299:         */
        !          1300: 
        !          1301:        if (name2 == NULL) {
        !          1302:            name2 = "";
        !          1303:        }
        !          1304:        cmdLength = tvarPtr->length + Tcl_ScanElement(name1, &flags1) +
        !          1305:                Tcl_ScanElement(name2, &flags2) + 5;
        !          1306:        if (cmdLength < STATIC_SIZE) {
        !          1307:            cmdPtr = staticSpace;
        !          1308:        } else {
        !          1309:            cmdPtr = (char *) ckalloc((unsigned) cmdLength);
        !          1310:        }
        !          1311:        p = cmdPtr;
        !          1312:        strcpy(p, tvarPtr->command);
        !          1313:        p += tvarPtr->length;
        !          1314:        *p = ' ';
        !          1315:        p++;
        !          1316:        p += Tcl_ConvertElement(name1, p, flags1);
        !          1317:        *p = ' ';
        !          1318:        p++;
        !          1319:        p += Tcl_ConvertElement(name2, p, flags2);
        !          1320:        *p = ' ';
        !          1321:        if (flags & TCL_TRACE_READS) {
        !          1322:            p[1] = 'r';
        !          1323:        } else if (flags & TCL_TRACE_WRITES) {
        !          1324:            p[1] = 'w';
        !          1325:        } else if (flags & TCL_TRACE_UNSETS) {
        !          1326:            p[1] = 'u';
        !          1327:        }
        !          1328:        p[2] = '\0';
        !          1329: 
        !          1330:        /*
        !          1331:         * Execute the command.  Be careful to save and restore the
        !          1332:         * result from the interpreter used for the command.
        !          1333:         */
        !          1334: 
        !          1335:        dummy.freeProc = interp->freeProc;
        !          1336:        if (interp->freeProc == 0) {
        !          1337:            Tcl_SetResult((Tcl_Interp *) &dummy, interp->result, TCL_VOLATILE);
        !          1338:        } else {
        !          1339:            dummy.result = interp->result;
        !          1340:        }
        !          1341:        code = Tcl_Eval(interp, cmdPtr, 0, (char **) NULL);
        !          1342:        if (cmdPtr != staticSpace) {
        !          1343:            ckfree(cmdPtr);
        !          1344:        }
        !          1345:        if (code != TCL_OK) {
        !          1346:            result = "access disallowed by trace command";
        !          1347:            Tcl_ResetResult(interp);            /* Must clear error state. */
        !          1348:        }
        !          1349:        Tcl_FreeResult(interp);
        !          1350:        interp->result = dummy.result;
        !          1351:        interp->freeProc = dummy.freeProc;
        !          1352:     }
        !          1353:     if (flags & TCL_TRACE_DESTROYED) {
        !          1354:        ckfree((char *) tvarPtr);
        !          1355:     }
        !          1356:     return result;
        !          1357: }
        !          1358: 
        !          1359: /*
        !          1360:  *----------------------------------------------------------------------
        !          1361:  *
        !          1362:  * Tcl_WhileCmd --
        !          1363:  *
        !          1364:  *     This procedure is invoked to process the "while" Tcl command.
        !          1365:  *     See the user documentation for details on what it does.
        !          1366:  *
        !          1367:  * Results:
        !          1368:  *     A standard Tcl result.
        !          1369:  *
        !          1370:  * Side effects:
        !          1371:  *     See the user documentation.
        !          1372:  *
        !          1373:  *----------------------------------------------------------------------
        !          1374:  */
        !          1375: 
        !          1376:        /* ARGSUSED */
        !          1377: int
        !          1378: Tcl_WhileCmd(dummy, interp, argc, argv)
        !          1379:     ClientData dummy;                  /* Not used. */
        !          1380:     Tcl_Interp *interp;                        /* Current interpreter. */
        !          1381:     int argc;                          /* Number of arguments. */
        !          1382:     char **argv;                       /* Argument strings. */
        !          1383: {
        !          1384:     int result, value;
        !          1385: 
        !          1386:     if (argc != 3) {
        !          1387:        Tcl_AppendResult(interp, "wrong # args: should be \"",
        !          1388:                argv[0], " test command\"", (char *) NULL);
        !          1389:        return TCL_ERROR;
        !          1390:     }
        !          1391: 
        !          1392:     while (1) {
        !          1393:        result = Tcl_ExprBoolean(interp, argv[1], &value);
        !          1394:        if (result != TCL_OK) {
        !          1395:            return result;
        !          1396:        }
        !          1397:        if (!value) {
        !          1398:            break;
        !          1399:        }
        !          1400:        result = Tcl_Eval(interp, argv[2], 0, (char **) NULL);
        !          1401:        if (result == TCL_CONTINUE) {
        !          1402:            result = TCL_OK;
        !          1403:        } else if (result != TCL_OK) {
        !          1404:            if (result == TCL_ERROR) {
        !          1405:                char msg[60];
        !          1406:                sprintf(msg, "\n    (\"while\" body line %d)",
        !          1407:                        interp->errorLine);
        !          1408:                Tcl_AddErrorInfo(interp, msg);
        !          1409:            }
        !          1410:            break;
        !          1411:        }
        !          1412:     }
        !          1413:     if (result == TCL_BREAK) {
        !          1414:        result = TCL_OK;
        !          1415:     }
        !          1416:     if (result == TCL_OK) {
        !          1417:        Tcl_ResetResult(interp);
        !          1418:     }
        !          1419:     return result;
        !          1420: }

unix.superglobalmegacorp.com

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