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

1.1     ! root        1: /* 
        !             2:  * tclCmdAH.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:  *     A to H.
        !             7:  *
        !             8:  * Copyright 1987-1991 Regents of the University of California
        !             9:  * Permission to use, copy, modify, and distribute this
        !            10:  * software and its documentation for any purpose and without
        !            11:  * fee is hereby granted, provided that the above copyright
        !            12:  * notice appear in all copies.  The University of California
        !            13:  * makes no representations about the suitability of this
        !            14:  * software for any purpose.  It is provided "as is" without
        !            15:  * express or implied warranty.
        !            16:  */
        !            17: 
        !            18: #ifndef lint
        !            19: static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclCmdAH.c,v 1.76 92/07/06 09:49:41 ouster Exp $ SPRITE (Berkeley)";
        !            20: #endif
        !            21: 
        !            22: #include "tclint.h"
        !            23: 
        !            24: 
        !            25: /*
        !            26:  *----------------------------------------------------------------------
        !            27:  *
        !            28:  * Tcl_BreakCmd --
        !            29:  *
        !            30:  *     This procedure is invoked to process the "break" Tcl command.
        !            31:  *     See the user documentation for details on what it does.
        !            32:  *
        !            33:  * Results:
        !            34:  *     A standard Tcl result.
        !            35:  *
        !            36:  * Side effects:
        !            37:  *     See the user documentation.
        !            38:  *
        !            39:  *----------------------------------------------------------------------
        !            40:  */
        !            41: 
        !            42:        /* ARGSUSED */
        !            43: int
        !            44: Tcl_BreakCmd(dummy, interp, argc, argv)
        !            45:     ClientData dummy;                  /* Not used. */
        !            46:     Tcl_Interp *interp;                        /* Current interpreter. */
        !            47:     int argc;                          /* Number of arguments. */
        !            48:     char **argv;                       /* Argument strings. */
        !            49: {
        !            50:     if (argc != 1) {
        !            51:        Tcl_AppendResult(interp, "wrong # args: should be \"",
        !            52:                argv[0], "\"", (char *) NULL);
        !            53:        return TCL_ERROR;
        !            54:     }
        !            55:     return TCL_BREAK;
        !            56: }
        !            57: 
        !            58: /*
        !            59:  *----------------------------------------------------------------------
        !            60:  *
        !            61:  * Tcl_CaseCmd --
        !            62:  *
        !            63:  *     This procedure is invoked to process the "case" Tcl command.
        !            64:  *     See the user documentation for details on what it does.
        !            65:  *
        !            66:  * Results:
        !            67:  *     A standard Tcl result.
        !            68:  *
        !            69:  * Side effects:
        !            70:  *     See the user documentation.
        !            71:  *
        !            72:  *----------------------------------------------------------------------
        !            73:  */
        !            74: 
        !            75:        /* ARGSUSED */
        !            76: int
        !            77: Tcl_CaseCmd(dummy, interp, argc, argv)
        !            78:     ClientData dummy;                  /* Not used. */
        !            79:     Tcl_Interp *interp;                        /* Current interpreter. */
        !            80:     int argc;                          /* Number of arguments. */
        !            81:     char **argv;                       /* Argument strings. */
        !            82: {
        !            83:     int i, result;
        !            84:     int body;
        !            85:     char *string;
        !            86:     int caseArgc, splitArgs;
        !            87:     char **caseArgv;
        !            88: 
        !            89:     if (argc < 3) {
        !            90:        Tcl_AppendResult(interp, "wrong # args: should be \"",
        !            91:                argv[0], " string ?in? patList body ... ?default body?\"",
        !            92:                (char *) NULL);
        !            93:        return TCL_ERROR;
        !            94:     }
        !            95:     string = argv[1];
        !            96:     body = -1;
        !            97:     if (strcmp(argv[2], "in") == 0) {
        !            98:        i = 3;
        !            99:     } else {
        !           100:        i = 2;
        !           101:     }
        !           102:     caseArgc = argc - i;
        !           103:     caseArgv = argv + i;
        !           104: 
        !           105:     /*
        !           106:      * If all of the pattern/command pairs are lumped into a single
        !           107:      * argument, split them out again.
        !           108:      */
        !           109: 
        !           110:     splitArgs = 0;
        !           111:     if (caseArgc == 1) {
        !           112:        result = Tcl_SplitList(interp, caseArgv[0], &caseArgc, &caseArgv);
        !           113:        if (result != TCL_OK) {
        !           114:            return result;
        !           115:        }
        !           116:        splitArgs = 1;
        !           117:     }
        !           118: 
        !           119:     for (i = 0; i < caseArgc; i += 2) {
        !           120:        int patArgc, j;
        !           121:        char **patArgv;
        !           122:        register char *p;
        !           123: 
        !           124:        if (i == (caseArgc-1)) {
        !           125:            interp->result = "extra case pattern with no body";
        !           126:            result = TCL_ERROR;
        !           127:            goto cleanup;
        !           128:        }
        !           129: 
        !           130:        /*
        !           131:         * Check for special case of single pattern (no list) with
        !           132:         * no backslash sequences.
        !           133:         */
        !           134: 
        !           135:        for (p = caseArgv[i]; *p != 0; p++) {
        !           136:            if (isspace(*p) || (*p == '\\')) {
        !           137:                break;
        !           138:            }
        !           139:        }
        !           140:        if (*p == 0) {
        !           141:            if ((*caseArgv[i] == 'd')
        !           142:                    && (strcmp(caseArgv[i], "default") == 0)) {
        !           143:                body = i+1;
        !           144:            }
        !           145:            if (Tcl_StringMatch(string, caseArgv[i])) {
        !           146:                body = i+1;
        !           147:                goto match;
        !           148:            }
        !           149:            continue;
        !           150:        }
        !           151: 
        !           152:        /*
        !           153:         * Break up pattern lists, then check each of the patterns
        !           154:         * in the list.
        !           155:         */
        !           156: 
        !           157:        result = Tcl_SplitList(interp, caseArgv[i], &patArgc, &patArgv);
        !           158:        if (result != TCL_OK) {
        !           159:            goto cleanup;
        !           160:        }
        !           161:        for (j = 0; j < patArgc; j++) {
        !           162:            if (Tcl_StringMatch(string, patArgv[j])) {
        !           163:                body = i+1;
        !           164:                break;
        !           165:            }
        !           166:        }
        !           167:        ckfree((char *) patArgv);
        !           168:        if (j < patArgc) {
        !           169:            break;
        !           170:        }
        !           171:     }
        !           172: 
        !           173:     match:
        !           174:     if (body != -1) {
        !           175:        result = Tcl_Eval(interp, caseArgv[body], 0, (char **) NULL);
        !           176:        if (result == TCL_ERROR) {
        !           177:            char msg[100];
        !           178:            sprintf(msg, "\n    (\"%.50s\" arm line %d)", caseArgv[body-1],
        !           179:                    interp->errorLine);
        !           180:            Tcl_AddErrorInfo(interp, msg);
        !           181:        }
        !           182:        goto cleanup;
        !           183:     }
        !           184: 
        !           185:     /*
        !           186:      * Nothing matched:  return nothing.
        !           187:      */
        !           188: 
        !           189:     result = TCL_OK;
        !           190: 
        !           191:     cleanup:
        !           192:     if (splitArgs) {
        !           193:        ckfree((char *) caseArgv);
        !           194:     }
        !           195:     return result;
        !           196: }
        !           197: 
        !           198: /*
        !           199:  *----------------------------------------------------------------------
        !           200:  *
        !           201:  * Tcl_CatchCmd --
        !           202:  *
        !           203:  *     This procedure is invoked to process the "catch" Tcl command.
        !           204:  *     See the user documentation for details on what it does.
        !           205:  *
        !           206:  * Results:
        !           207:  *     A standard Tcl result.
        !           208:  *
        !           209:  * Side effects:
        !           210:  *     See the user documentation.
        !           211:  *
        !           212:  *----------------------------------------------------------------------
        !           213:  */
        !           214: 
        !           215:        /* ARGSUSED */
        !           216: int
        !           217: Tcl_CatchCmd(dummy, interp, argc, argv)
        !           218:     ClientData dummy;                  /* Not used. */
        !           219:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           220:     int argc;                          /* Number of arguments. */
        !           221:     char **argv;                       /* Argument strings. */
        !           222: {
        !           223:     int result;
        !           224: 
        !           225:     if ((argc != 2) && (argc != 3)) {
        !           226:        Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           227:                argv[0], " command ?varName?\"", (char *) NULL);
        !           228:        return TCL_ERROR;
        !           229:     }
        !           230:     result = Tcl_Eval(interp, argv[1], 0, (char **) NULL);
        !           231:     if (argc == 3) {
        !           232:        if (Tcl_SetVar(interp, argv[2], interp->result, 0) == NULL) {
        !           233:            Tcl_SetResult(interp, "couldn't save command result in variable",
        !           234:                    TCL_STATIC);
        !           235:            return TCL_ERROR;
        !           236:        }
        !           237:     }
        !           238:     Tcl_ResetResult(interp);
        !           239:     sprintf(interp->result, "%d", result);
        !           240:     return TCL_OK;
        !           241: }
        !           242: 
        !           243: /*
        !           244:  *----------------------------------------------------------------------
        !           245:  *
        !           246:  * Tcl_ConcatCmd --
        !           247:  *
        !           248:  *     This procedure is invoked to process the "concat" Tcl command.
        !           249:  *     See the user documentation for details on what it does.
        !           250:  *
        !           251:  * Results:
        !           252:  *     A standard Tcl result.
        !           253:  *
        !           254:  * Side effects:
        !           255:  *     See the user documentation.
        !           256:  *
        !           257:  *----------------------------------------------------------------------
        !           258:  */
        !           259: 
        !           260:        /* ARGSUSED */
        !           261: int
        !           262: Tcl_ConcatCmd(dummy, interp, argc, argv)
        !           263:     ClientData dummy;                  /* Not used. */
        !           264:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           265:     int argc;                          /* Number of arguments. */
        !           266:     char **argv;                       /* Argument strings. */
        !           267: {
        !           268:     if (argc == 1) {
        !           269:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           270:                " arg ?arg ...?\"", (char *) NULL);
        !           271:        return TCL_ERROR;
        !           272:     }
        !           273: 
        !           274:     interp->result = Tcl_Concat(argc-1, argv+1);
        !           275:     interp->freeProc = (Tcl_FreeProc *) free;
        !           276:     return TCL_OK;
        !           277: }
        !           278: 
        !           279: /*
        !           280:  *----------------------------------------------------------------------
        !           281:  *
        !           282:  * Tcl_ContinueCmd --
        !           283:  *
        !           284:  *     This procedure is invoked to process the "continue" Tcl command.
        !           285:  *     See the user documentation for details on what it does.
        !           286:  *
        !           287:  * Results:
        !           288:  *     A standard Tcl result.
        !           289:  *
        !           290:  * Side effects:
        !           291:  *     See the user documentation.
        !           292:  *
        !           293:  *----------------------------------------------------------------------
        !           294:  */
        !           295: 
        !           296:        /* ARGSUSED */
        !           297: int
        !           298: Tcl_ContinueCmd(dummy, interp, argc, argv)
        !           299:     ClientData dummy;                  /* Not used. */
        !           300:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           301:     int argc;                          /* Number of arguments. */
        !           302:     char **argv;                       /* Argument strings. */
        !           303: {
        !           304:     if (argc != 1) {
        !           305:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           306:                "\"", (char *) NULL);
        !           307:        return TCL_ERROR;
        !           308:     }
        !           309:     return TCL_CONTINUE;
        !           310: }
        !           311: 
        !           312: /*
        !           313:  *----------------------------------------------------------------------
        !           314:  *
        !           315:  * Tcl_ErrorCmd --
        !           316:  *
        !           317:  *     This procedure is invoked to process the "error" Tcl command.
        !           318:  *     See the user documentation for details on what it does.
        !           319:  *
        !           320:  * Results:
        !           321:  *     A standard Tcl result.
        !           322:  *
        !           323:  * Side effects:
        !           324:  *     See the user documentation.
        !           325:  *
        !           326:  *----------------------------------------------------------------------
        !           327:  */
        !           328: 
        !           329:        /* ARGSUSED */
        !           330: int
        !           331: Tcl_ErrorCmd(dummy, interp, argc, argv)
        !           332:     ClientData dummy;                  /* Not used. */
        !           333:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           334:     int argc;                          /* Number of arguments. */
        !           335:     char **argv;                       /* Argument strings. */
        !           336: {
        !           337:     Interp *iPtr = (Interp *) interp;
        !           338: 
        !           339:     if ((argc < 2) || (argc > 4)) {
        !           340:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           341:                " message ?errorInfo? ?errorCode?\"", (char *) NULL);
        !           342:        return TCL_ERROR;
        !           343:     }
        !           344:     if ((argc >= 3) && (argv[2][0] != 0)) {
        !           345:        Tcl_AddErrorInfo(interp, argv[2]);
        !           346:        iPtr->flags |= ERR_ALREADY_LOGGED;
        !           347:     }
        !           348:     if (argc == 4) {
        !           349:        Tcl_SetVar2(interp, "errorCode", (char *) NULL, argv[3],
        !           350:                TCL_GLOBAL_ONLY);
        !           351:        iPtr->flags |= ERROR_CODE_SET;
        !           352:     }
        !           353:     Tcl_SetResult(interp, argv[1], TCL_VOLATILE);
        !           354:     return TCL_ERROR;
        !           355: }
        !           356: 
        !           357: /*
        !           358:  *----------------------------------------------------------------------
        !           359:  *
        !           360:  * Tcl_EvalCmd --
        !           361:  *
        !           362:  *     This procedure is invoked to process the "eval" Tcl command.
        !           363:  *     See the user documentation for details on what it does.
        !           364:  *
        !           365:  * Results:
        !           366:  *     A standard Tcl result.
        !           367:  *
        !           368:  * Side effects:
        !           369:  *     See the user documentation.
        !           370:  *
        !           371:  *----------------------------------------------------------------------
        !           372:  */
        !           373: 
        !           374:        /* ARGSUSED */
        !           375: int
        !           376: Tcl_EvalCmd(dummy, interp, argc, argv)
        !           377:     ClientData dummy;                  /* Not used. */
        !           378:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           379:     int argc;                          /* Number of arguments. */
        !           380:     char **argv;                       /* Argument strings. */
        !           381: {
        !           382:     int result;
        !           383:     char *cmd;
        !           384: 
        !           385:     if (argc < 2) {
        !           386:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           387:                " arg ?arg ...?\"", (char *) NULL);
        !           388:        return TCL_ERROR;
        !           389:     }
        !           390:     if (argc == 2) {
        !           391:        result = Tcl_Eval(interp, argv[1], 0, (char **) NULL);
        !           392:     } else {
        !           393:     
        !           394:        /*
        !           395:         * More than one argument:  concatenate them together with spaces
        !           396:         * between, then evaluate the result.
        !           397:         */
        !           398:     
        !           399:        cmd = Tcl_Concat(argc-1, argv+1);
        !           400:        result = Tcl_Eval(interp, cmd, 0, (char **) NULL);
        !           401:        ckfree(cmd);
        !           402:     }
        !           403:     if (result == TCL_ERROR) {
        !           404:        char msg[60];
        !           405:        sprintf(msg, "\n    (\"eval\" body line %d)", interp->errorLine);
        !           406:        Tcl_AddErrorInfo(interp, msg);
        !           407:     }
        !           408:     return result;
        !           409: }
        !           410: 
        !           411: /*
        !           412:  *----------------------------------------------------------------------
        !           413:  *
        !           414:  * Tcl_ExprCmd --
        !           415:  *
        !           416:  *     This procedure is invoked to process the "expr" Tcl command.
        !           417:  *     See the user documentation for details on what it does.
        !           418:  *
        !           419:  * Results:
        !           420:  *     A standard Tcl result.
        !           421:  *
        !           422:  * Side effects:
        !           423:  *     See the user documentation.
        !           424:  *
        !           425:  *----------------------------------------------------------------------
        !           426:  */
        !           427: 
        !           428:        /* ARGSUSED */
        !           429: int
        !           430: Tcl_ExprCmd(dummy, interp, argc, argv)
        !           431:     ClientData dummy;                  /* Not used. */
        !           432:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           433:     int argc;                          /* Number of arguments. */
        !           434:     char **argv;                       /* Argument strings. */
        !           435: {
        !           436:     if (argc != 2) {
        !           437:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           438:                " expression\"", (char *) NULL);
        !           439:        return TCL_ERROR;
        !           440:     }
        !           441: 
        !           442:     return Tcl_ExprString(interp, argv[1]);
        !           443: }
        !           444: 
        !           445: /*
        !           446:  *----------------------------------------------------------------------
        !           447:  *
        !           448:  * Tcl_ForCmd --
        !           449:  *
        !           450:  *     This procedure is invoked to process the "for" Tcl command.
        !           451:  *     See the user documentation for details on what it does.
        !           452:  *
        !           453:  * Results:
        !           454:  *     A standard Tcl result.
        !           455:  *
        !           456:  * Side effects:
        !           457:  *     See the user documentation.
        !           458:  *
        !           459:  *----------------------------------------------------------------------
        !           460:  */
        !           461: 
        !           462:        /* ARGSUSED */
        !           463: int
        !           464: Tcl_ForCmd(dummy, interp, argc, argv)
        !           465:     ClientData dummy;                  /* Not used. */
        !           466:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           467:     int argc;                          /* Number of arguments. */
        !           468:     char **argv;                       /* Argument strings. */
        !           469: {
        !           470:     int result, value;
        !           471: 
        !           472:     if (argc != 5) {
        !           473:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           474:                " start test next command\"", (char *) NULL);
        !           475:        return TCL_ERROR;
        !           476:     }
        !           477: 
        !           478:     result = Tcl_Eval(interp, argv[1], 0, (char **) NULL);
        !           479:     if (result != TCL_OK) {
        !           480:        if (result == TCL_ERROR) {
        !           481:            Tcl_AddErrorInfo(interp, "\n    (\"for\" initial command)");
        !           482:        }
        !           483:        return result;
        !           484:     }
        !           485:     while (1) {
        !           486:        result = Tcl_ExprBoolean(interp, argv[2], &value);
        !           487:        if (result != TCL_OK) {
        !           488:            return result;
        !           489:        }
        !           490:        if (!value) {
        !           491:            break;
        !           492:        }
        !           493:        result = Tcl_Eval(interp, argv[4], 0, (char **) NULL);
        !           494:        if (result == TCL_CONTINUE) {
        !           495:            result = TCL_OK;
        !           496:        } else if (result != TCL_OK) {
        !           497:            if (result == TCL_ERROR) {
        !           498:                char msg[60];
        !           499:                sprintf(msg, "\n    (\"for\" body line %d)", interp->errorLine);
        !           500:                Tcl_AddErrorInfo(interp, msg);
        !           501:            }
        !           502:            break;
        !           503:        }
        !           504:        result = Tcl_Eval(interp, argv[3], 0, (char **) NULL);
        !           505:        if (result == TCL_BREAK) {
        !           506:            break;
        !           507:        } else if (result != TCL_OK) {
        !           508:            if (result == TCL_ERROR) {
        !           509:                Tcl_AddErrorInfo(interp, "\n    (\"for\" loop-end command)");
        !           510:            }
        !           511:            return result;
        !           512:        }
        !           513:     }
        !           514:     if (result == TCL_BREAK) {
        !           515:        result = TCL_OK;
        !           516:     }
        !           517:     if (result == TCL_OK) {
        !           518:        Tcl_ResetResult(interp);
        !           519:     }
        !           520:     return result;
        !           521: }
        !           522: 
        !           523: /*
        !           524:  *----------------------------------------------------------------------
        !           525:  *
        !           526:  * Tcl_ForeachCmd --
        !           527:  *
        !           528:  *     This procedure is invoked to process the "foreach" Tcl command.
        !           529:  *     See the user documentation for details on what it does.
        !           530:  *
        !           531:  * Results:
        !           532:  *     A standard Tcl result.
        !           533:  *
        !           534:  * Side effects:
        !           535:  *     See the user documentation.
        !           536:  *
        !           537:  *----------------------------------------------------------------------
        !           538:  */
        !           539: 
        !           540:        /* ARGSUSED */
        !           541: int
        !           542: Tcl_ForeachCmd(dummy, interp, argc, argv)
        !           543:     ClientData dummy;                  /* Not used. */
        !           544:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           545:     int argc;                          /* Number of arguments. */
        !           546:     char **argv;                       /* Argument strings. */
        !           547: {
        !           548:     int listArgc, i, result;
        !           549:     char **listArgv;
        !           550: 
        !           551:     if (argc != 4) {
        !           552:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           553:                " varName list command\"", (char *) NULL);
        !           554:        return TCL_ERROR;
        !           555:     }
        !           556: 
        !           557:     /*
        !           558:      * Break the list up into elements, and execute the command once
        !           559:      * for each value of the element.
        !           560:      */
        !           561: 
        !           562:     result = Tcl_SplitList(interp, argv[2], &listArgc, &listArgv);
        !           563:     if (result != TCL_OK) {
        !           564:        return result;
        !           565:     }
        !           566:     for (i = 0; i < listArgc; i++) {
        !           567:        if (Tcl_SetVar(interp, argv[1], listArgv[i], 0) == NULL) {
        !           568:            Tcl_SetResult(interp, "couldn't set loop variable", TCL_STATIC);
        !           569:            result = TCL_ERROR;
        !           570:            break;
        !           571:        }
        !           572: 
        !           573:        result = Tcl_Eval(interp, argv[3], 0, (char **) NULL);
        !           574:        if (result != TCL_OK) {
        !           575:            if (result == TCL_CONTINUE) {
        !           576:                result = TCL_OK;
        !           577:            } else if (result == TCL_BREAK) {
        !           578:                result = TCL_OK;
        !           579:                break;
        !           580:            } else if (result == TCL_ERROR) {
        !           581:                char msg[100];
        !           582:                sprintf(msg, "\n    (\"foreach\" body line %d)",
        !           583:                        interp->errorLine);
        !           584:                Tcl_AddErrorInfo(interp, msg);
        !           585:                break;
        !           586:            } else {
        !           587:                break;
        !           588:            }
        !           589:        }
        !           590:     }
        !           591:     ckfree((char *) listArgv);
        !           592:     if (result == TCL_OK) {
        !           593:        Tcl_ResetResult(interp);
        !           594:     }
        !           595:     return result;
        !           596: }
        !           597: 
        !           598: /*
        !           599:  *----------------------------------------------------------------------
        !           600:  *
        !           601:  * Tcl_FormatCmd --
        !           602:  *
        !           603:  *     This procedure is invoked to process the "format" Tcl command.
        !           604:  *     See the user documentation for details on what it does.
        !           605:  *
        !           606:  * Results:
        !           607:  *     A standard Tcl result.
        !           608:  *
        !           609:  * Side effects:
        !           610:  *     See the user documentation.
        !           611:  *
        !           612:  *----------------------------------------------------------------------
        !           613:  */
        !           614: 
        !           615:        /* ARGSUSED */
        !           616: int
        !           617: Tcl_FormatCmd(dummy, interp, argc, argv)
        !           618:     ClientData dummy;                  /* Not used. */
        !           619:     Tcl_Interp *interp;                        /* Current interpreter. */
        !           620:     int argc;                          /* Number of arguments. */
        !           621:     char **argv;                       /* Argument strings. */
        !           622: {
        !           623:     register char *format;     /* Used to read characters from the format
        !           624:                                 * string. */
        !           625:     char newFormat[40];                /* A new format specifier is generated here. */
        !           626:     int width;                 /* Field width from field specifier, or 0 if
        !           627:                                 * no width given. */
        !           628:     int precision;             /* Field precision from field specifier, or 0
        !           629:                                 * if no precision given. */
        !           630:     int size;                  /* Number of bytes needed for result of
        !           631:                                 * conversion, based on type of conversion
        !           632:                                 * ("e", "s", etc.) and width from above. */
        !           633:     char *oneWordValue = NULL; /* Used to hold value to pass to sprintf, if
        !           634:                                 * it's a one-word value. */
        !           635:     double twoWordValue;       /* Used to hold value to pass to sprintf if
        !           636:                                 * it's a two-word value. */
        !           637:     int useTwoWords;           /* 0 means use oneWordValue, 1 means use
        !           638:                                 * twoWordValue. */
        !           639:     char *dst = interp->result;        /* Where result is stored.  Starts off at
        !           640:                                 * interp->resultSpace, but may get dynamically
        !           641:                                 * re-allocated if this isn't enough. */
        !           642:     int dstSize = 0;           /* Number of non-null characters currently
        !           643:                                 * stored at dst. */
        !           644:     int dstSpace = TCL_RESULT_SIZE;
        !           645:                                /* Total amount of storage space available
        !           646:                                 * in dst (not including null terminator. */
        !           647:     int noPercent;             /* Special case for speed:  indicates there's
        !           648:                                 * no field specifier, just a string to copy. */
        !           649:     char **curArg;             /* Remainder of argv array. */
        !           650:     int useShort;              /* Value to be printed is short (half word). */
        !           651: 
        !           652:     /*
        !           653:      * This procedure is a bit nasty.  The goal is to use sprintf to
        !           654:      * do most of the dirty work.  There are several problems:
        !           655:      * 1. this procedure can't trust its arguments.
        !           656:      * 2. we must be able to provide a large enough result area to hold
        !           657:      *    whatever's generated.  This is hard to estimate.
        !           658:      * 2. there's no way to move the arguments from argv to the call
        !           659:      *    to sprintf in a reasonable way.  This is particularly nasty
        !           660:      *    because some of the arguments may be two-word values (doubles).
        !           661:      * So, what happens here is to scan the format string one % group
        !           662:      * at a time, making many individual calls to sprintf.
        !           663:      */
        !           664: 
        !           665:     if (argc < 2) {
        !           666:        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
        !           667:                " formatString ?arg arg ...?\"", (char *) NULL);
        !           668:        return TCL_ERROR;
        !           669:     }
        !           670:     curArg = argv+2;
        !           671:     argc -= 2;
        !           672:     for (format = argv[1]; *format != 0; ) {
        !           673:        register char *newPtr = newFormat;
        !           674: 
        !           675:        width = precision = useTwoWords = noPercent = useShort = 0;
        !           676: 
        !           677:        /*
        !           678:         * Get rid of any characters before the next field specifier.
        !           679:         * Collapse backslash sequences found along the way.
        !           680:         */
        !           681: 
        !           682:        if (*format != '%') {
        !           683:            register char *p;
        !           684:            int bsSize;
        !           685: 
        !           686:            oneWordValue = p = format;
        !           687:            while ((*format != '%') && (*format != 0)) {
        !           688:                if (*format == '\\') {
        !           689:                    *p = Tcl_Backslash(format, &bsSize);
        !           690:                    if (*p != 0) {
        !           691:                        p++;
        !           692:                    }
        !           693:                    format += bsSize;
        !           694:                } else {
        !           695:                    *p = *format;
        !           696:                    p++;
        !           697:                    format++;
        !           698:                }
        !           699:            }
        !           700:            size = p - oneWordValue;
        !           701:            noPercent = 1;
        !           702:            goto doField;
        !           703:        }
        !           704: 
        !           705:        if (format[1] == '%') {
        !           706:            oneWordValue = format;
        !           707:            size = 1;
        !           708:            noPercent = 1;
        !           709:            format += 2;
        !           710:            goto doField;
        !           711:        }
        !           712: 
        !           713:        /*
        !           714:         * Parse off a field specifier, compute how many characters
        !           715:         * will be needed to store the result, and substitute for
        !           716:         * "*" size specifiers.
        !           717:         */
        !           718: 
        !           719:        *newPtr = '%';
        !           720:        newPtr++;
        !           721:        format++;
        !           722:        while ((*format == '-') || (*format == '#')) {
        !           723:            *newPtr = *format;
        !           724:            newPtr++;
        !           725:            format++;
        !           726:        }
        !           727:        if (*format == '0') {
        !           728:            *newPtr = '0';
        !           729:            newPtr++;
        !           730:            format++;
        !           731:        }
        !           732:        if (isdigit(*format)) {
        !           733:            width = atoi(format);
        !           734:            do {
        !           735:                format++;
        !           736:            } while (isdigit(*format));
        !           737:        } else if (*format == '*') {
        !           738:            if (argc <= 0) {
        !           739:                goto notEnoughArgs;
        !           740:            }
        !           741:            if (Tcl_GetInt(interp, *curArg, &width) != TCL_OK) {
        !           742:                goto fmtError;
        !           743:            }
        !           744:            argc--;
        !           745:            curArg++;
        !           746:            format++;
        !           747:        }
        !           748:        if (width != 0) {
        !           749:            sprintf(newPtr, "%d", width);
        !           750:            while (*newPtr != 0) {
        !           751:                newPtr++;
        !           752:            }
        !           753:        }
        !           754:        if (*format == '.') {
        !           755:            *newPtr = '.';
        !           756:            newPtr++;
        !           757:            format++;
        !           758:        }
        !           759:        if (isdigit(*format)) {
        !           760:            precision = atoi(format);
        !           761:            do {
        !           762:                format++;
        !           763:            } while (isdigit(*format));
        !           764:        } else if (*format == '*') {
        !           765:            if (argc <= 0) {
        !           766:                goto notEnoughArgs;
        !           767:            }
        !           768:            if (Tcl_GetInt(interp, *curArg, &precision) != TCL_OK) {
        !           769:                goto fmtError;
        !           770:            }
        !           771:            argc--;
        !           772:            curArg++;
        !           773:            format++;
        !           774:        }
        !           775:        if (precision != 0) {
        !           776:            sprintf(newPtr, "%d", precision);
        !           777:            while (*newPtr != 0) {
        !           778:                newPtr++;
        !           779:            }
        !           780:        }
        !           781:        if (*format == 'l') {
        !           782:            format++;
        !           783:        } else if (*format == 'h') {
        !           784:            useShort = 1;
        !           785:            *newPtr = 'h';
        !           786:            newPtr++;
        !           787:            format++;
        !           788:        }
        !           789:        *newPtr = *format;
        !           790:        newPtr++;
        !           791:        *newPtr = 0;
        !           792:        if (argc <= 0) {
        !           793:            goto notEnoughArgs;
        !           794:        }
        !           795:        switch (*format) {
        !           796:            case 'D':
        !           797:            case 'O':
        !           798:            case 'U':
        !           799:                if (!useShort) {
        !           800:                    newPtr++;
        !           801:                } else {
        !           802:                    useShort = 0;
        !           803:                }
        !           804:                newPtr[-1] = tolower(*format);
        !           805:                newPtr[-2] = 'l';
        !           806:                *newPtr = 0;
        !           807:            case 'd':
        !           808:            case 'o':
        !           809:            case 'u':
        !           810:            case 'x':
        !           811:            case 'X':
        !           812:                if (Tcl_GetInt(interp, *curArg, (int *) &oneWordValue)
        !           813:                        != TCL_OK) {
        !           814:                    goto fmtError;
        !           815:                }
        !           816:                size = 40;
        !           817:                break;
        !           818:            case 's':
        !           819:                oneWordValue = *curArg;
        !           820:                size = strlen(*curArg);
        !           821:                break;
        !           822:            case 'c':
        !           823:                if (Tcl_GetInt(interp, *curArg, (int *) &oneWordValue)
        !           824:                        != TCL_OK) {
        !           825:                    goto fmtError;
        !           826:                }
        !           827:                size = 1;
        !           828:                break;
        !           829:            case 'F':
        !           830:                newPtr[-1] = tolower(newPtr[-1]);
        !           831:            case 'e':
        !           832:            case 'E':
        !           833:            case 'f':
        !           834:            case 'g':
        !           835:            case 'G':
        !           836:                if (Tcl_GetDouble(interp, *curArg, &twoWordValue) != TCL_OK) {
        !           837:                    goto fmtError;
        !           838:                }
        !           839:                useTwoWords = 1;
        !           840:                size = 320;
        !           841:                if (precision > 10) {
        !           842:                    size += precision;
        !           843:                }
        !           844:                break;
        !           845:            case 0:
        !           846:                interp->result =
        !           847:                        "format string ended in middle of field specifier";
        !           848:                goto fmtError;
        !           849:            default:
        !           850:                sprintf(interp->result, "bad field specifier \"%c\"", *format);
        !           851:                goto fmtError;
        !           852:        }
        !           853:        argc--;
        !           854:        curArg++;
        !           855:        format++;
        !           856: 
        !           857:        /*
        !           858:         * Make sure that there's enough space to hold the formatted
        !           859:         * result, then format it.
        !           860:         */
        !           861: 
        !           862:        doField:
        !           863:        if (width > size) {
        !           864:            size = width;
        !           865:        }
        !           866:        if ((dstSize + size) > dstSpace) {
        !           867:            char *newDst;
        !           868:            int newSpace;
        !           869: 
        !           870:            newSpace = 2*(dstSize + size);
        !           871:            newDst = (char *) ckalloc((unsigned) newSpace+1);
        !           872:            if (dstSize != 0) {
        !           873:                memcpy((VOID *) newDst, (VOID *) dst, dstSize);
        !           874:            }
        !           875:            if (dstSpace != TCL_RESULT_SIZE) {
        !           876:                ckfree(dst);
        !           877:            }
        !           878:            dst = newDst;
        !           879:            dstSpace = newSpace;
        !           880:        }
        !           881:        if (noPercent) {
        !           882:            memcpy((VOID *) (dst+dstSize), (VOID *) oneWordValue, size);
        !           883:            dstSize += size;
        !           884:            dst[dstSize] = 0;
        !           885:        } else {
        !           886:            if (useTwoWords) {
        !           887:                sprintf(dst+dstSize, newFormat, twoWordValue);
        !           888:            } else if (useShort) {
        !           889:                int tmp = (int)oneWordValue;
        !           890:                sprintf(dst+dstSize, newFormat, (short)tmp);
        !           891:            } else {
        !           892:                sprintf(dst+dstSize, newFormat, oneWordValue);
        !           893:            }
        !           894:            dstSize += strlen(dst+dstSize);
        !           895:        }
        !           896:     }
        !           897: 
        !           898:     interp->result = dst;
        !           899:     if (dstSpace != TCL_RESULT_SIZE) {
        !           900:        interp->freeProc = (Tcl_FreeProc *) free;
        !           901:     } else {
        !           902:        interp->freeProc = 0;
        !           903:     }
        !           904:     return TCL_OK;
        !           905: 
        !           906:     notEnoughArgs:
        !           907:     interp->result = "not enough arguments for all format specifiers";
        !           908:     fmtError:
        !           909:     if (dstSpace != TCL_RESULT_SIZE) {
        !           910:        ckfree(dst);
        !           911:     }
        !           912:     return TCL_ERROR;
        !           913: }

unix.superglobalmegacorp.com

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