Annotation of micropolis/src/tcl/tclcmdmz.c, revision 1.1.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.