|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.