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