|
|
1.1 ! root 1: /* ! 2: * tclCmdIZ.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: * I to Z. ! 7: * ! 8: * Copyright 1987 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: /sprite/src/lib/tcl/RCS/tclCmdIZ.c,v 1.36 90/04/18 17:09:07 ouster Exp $ SPRITE (Berkeley)"; ! 20: #pragma ref rcsid ! 21: #endif not lint ! 22: ! 23: #define _POSIX_SOURCE ! 24: ! 25: #include <ctype.h> ! 26: #include <errno.h> ! 27: #include <stdio.h> ! 28: #include <stdlib.h> ! 29: #include <string.h> ! 30: #include <sys/types.h> ! 31: #include <fcntl.h> ! 32: #include <sys/stat.h> ! 33: #include <sys/times.h> ! 34: #include "tclInt.h" ! 35: ! 36: /* ! 37: *---------------------------------------------------------------------- ! 38: * ! 39: * Tcl_IfCmd -- ! 40: * ! 41: * This procedure is invoked to process the "if" Tcl command. ! 42: * See the user documentation for details on what it does. ! 43: * ! 44: * Results: ! 45: * A standard Tcl result. ! 46: * ! 47: * Side effects: ! 48: * See the user documentation. ! 49: * ! 50: *---------------------------------------------------------------------- ! 51: */ ! 52: ! 53: /* ARGSUSED */ ! 54: int ! 55: Tcl_IfCmd(dummy, interp, argc, argv) ! 56: ClientData dummy; /* Not used. */ ! 57: Tcl_Interp *interp; /* Current interpreter. */ ! 58: int argc; /* Number of arguments. */ ! 59: char **argv; /* Argument strings. */ ! 60: { ! 61: #pragma ref dummy ! 62: char *condition, *ifPart, *elsePart, *cmd, *name; ! 63: int result, value; ! 64: ! 65: name = argv[0]; ! 66: if (argc < 3) { ! 67: ifSyntax: ! 68: sprintf(interp->result, "wrong # args: should be \"%.50s bool [then] command [[else] command]\"", ! 69: name); ! 70: return TCL_ERROR; ! 71: } ! 72: condition = argv[1]; ! 73: argc -= 2; ! 74: argv += 2; ! 75: if ((**argv == 't') && (strncmp(*argv, "then", strlen(*argv)) == 0)) { ! 76: argc--; ! 77: argv++; ! 78: } ! 79: if (argc < 1) { ! 80: goto ifSyntax; ! 81: } ! 82: ifPart = *argv; ! 83: argv++; ! 84: argc--; ! 85: if (argc == 0) { ! 86: elsePart = ""; ! 87: } else { ! 88: if ((**argv == 'e') && (strncmp(*argv, "else", strlen(*argv)) == 0)) { ! 89: argc--; ! 90: argv++; ! 91: } ! 92: if (argc != 1) { ! 93: goto ifSyntax; ! 94: } ! 95: elsePart = *argv; ! 96: } ! 97: ! 98: cmd = ifPart; ! 99: result = Tcl_Expr(interp, condition, &value); ! 100: if (result != TCL_OK) { ! 101: return result; ! 102: } ! 103: if (value == 0) { ! 104: cmd = elsePart; ! 105: } ! 106: result = Tcl_Eval(interp, cmd, 0, (char **) NULL); ! 107: if (result == TCL_ERROR) { ! 108: char msg[60]; ! 109: sprintf(msg, " (\"if\" body line %d)", interp->errorLine); ! 110: Tcl_AddErrorInfo(interp, msg); ! 111: } ! 112: return result; ! 113: } ! 114: ! 115: /* ! 116: *---------------------------------------------------------------------- ! 117: * ! 118: * Tcl_IndexCmd -- ! 119: * ! 120: * This procedure is invoked to process the "index" Tcl command. ! 121: * See the user documentation for details on what it does. ! 122: * ! 123: * Results: ! 124: * A standard Tcl result. ! 125: * ! 126: * Side effects: ! 127: * See the user documentation. ! 128: * ! 129: *---------------------------------------------------------------------- ! 130: */ ! 131: ! 132: /* ARGSUSED */ ! 133: int ! 134: Tcl_IndexCmd(dummy, interp, argc, argv) ! 135: ClientData dummy; /* Not used. */ ! 136: Tcl_Interp *interp; /* Current interpreter. */ ! 137: int argc; /* Number of arguments. */ ! 138: char **argv; /* Argument strings. */ ! 139: { ! 140: #pragma ref dummy ! 141: char *p, *element; ! 142: int index, size, parenthesized, result; ! 143: ! 144: if (argc < 3) { ! 145: indexSyntax: ! 146: sprintf(interp->result, ! 147: "wrong # args: should be \"%.50s value index [chars]\"", ! 148: argv[0]); ! 149: return TCL_ERROR; ! 150: } ! 151: p = argv[1]; ! 152: index = atoi(argv[2]); ! 153: if (!isdigit(*argv[2]) || (index < 0)) { ! 154: sprintf(interp->result, "bad index \"%.50s\"", argv[2]); ! 155: return TCL_ERROR; ! 156: } ! 157: if (argc == 3) { ! 158: for ( ; index >= 0; index--) { ! 159: result = TclFindElement(interp, p, &element, &p, &size, ! 160: &parenthesized); ! 161: if (result != TCL_OK) { ! 162: return result; ! 163: } ! 164: } ! 165: if (size >= TCL_RESULT_SIZE) { ! 166: interp->result = (char *) malloc((unsigned) size+1); ! 167: interp->dynamic = 1; ! 168: } ! 169: if (parenthesized) { ! 170: bcopy(element, interp->result, size); ! 171: interp->result[size] = 0; ! 172: } else { ! 173: TclCopyAndCollapse(size, element, interp->result); ! 174: } ! 175: } else if (argc == 4) { ! 176: if (strncmp(argv[3], "chars", strlen(argv[3])) != 0) { ! 177: sprintf(interp->result, "bad argument \"%s\": must be \"chars\"", ! 178: argv[3]); ! 179: return TCL_ERROR; ! 180: } ! 181: size = strlen(p); ! 182: if (index < size) { ! 183: interp->result[0] = p[index]; ! 184: interp->result[1] = 0; ! 185: } ! 186: } else { ! 187: goto indexSyntax; ! 188: } ! 189: return TCL_OK; ! 190: } ! 191: ! 192: /* ! 193: *---------------------------------------------------------------------- ! 194: * ! 195: * Tcl_InfoCmd -- ! 196: * ! 197: * This procedure is invoked to process the "info" Tcl command. ! 198: * See the user documentation for details on what it does. ! 199: * ! 200: * Results: ! 201: * A standard Tcl result. ! 202: * ! 203: * Side effects: ! 204: * See the user documentation. ! 205: * ! 206: *---------------------------------------------------------------------- ! 207: */ ! 208: ! 209: /* ARGSUSED */ ! 210: int ! 211: Tcl_InfoCmd(dummy, interp, argc, argv) ! 212: ClientData dummy; /* Not used. */ ! 213: Tcl_Interp *interp; /* Current interpreter. */ ! 214: int argc; /* Number of arguments. */ ! 215: char **argv; /* Argument strings. */ ! 216: { ! 217: #pragma ref dummy ! 218: register Interp *iPtr = (Interp *) interp; ! 219: Proc *procPtr; ! 220: Var *varPtr; ! 221: Command *cmdPtr; ! 222: int length; ! 223: char c; ! 224: ! 225: /* ! 226: * When collecting a list of things (e.g. args or vars) "flag" tells ! 227: * what kind of thing is being collected, according to the definitions ! 228: * below. ! 229: */ ! 230: ! 231: int flag; ! 232: # define VARS 0 ! 233: # define LOCALS 1 ! 234: # define PROCS 2 ! 235: # define CMDS 3 ! 236: ! 237: # define ARG_SIZE 20 ! 238: char *argSpace[ARG_SIZE]; ! 239: int argSize; ! 240: char *pattern; ! 241: ! 242: if (argc < 2) { ! 243: sprintf(iPtr->result, ! 244: "too few args: should be \"%.50s option [arg arg ...]\"", ! 245: argv[0]); ! 246: return TCL_ERROR; ! 247: } ! 248: c = argv[1][0]; ! 249: length = strlen(argv[1]); ! 250: if ((c == 'a') && (strncmp(argv[1], "args", length)) == 0) { ! 251: if (argc != 3) { ! 252: sprintf(iPtr->result, ! 253: "wrong # args: should be \"%.50s args procname\"", ! 254: argv[0]); ! 255: return TCL_ERROR; ! 256: } ! 257: procPtr = TclFindProc(iPtr, argv[2]); ! 258: if (procPtr == NULL) { ! 259: infoNoSuchProc: ! 260: sprintf(iPtr->result, ! 261: "info requested on \"%s\", which isn't a procedure", ! 262: argv[2]); ! 263: return TCL_ERROR; ! 264: } ! 265: flag = VARS; ! 266: varPtr = procPtr->argPtr; ! 267: argc = 0; /* Prevent pattern matching. */ ! 268: } else if ((c == 'b') && (strncmp(argv[1], "body", length)) == 0) { ! 269: if (argc != 3) { ! 270: sprintf(iPtr->result, ! 271: "wrong # args: should be \"%.50s body procname\"", ! 272: argv[0]); ! 273: return TCL_ERROR; ! 274: } ! 275: procPtr = TclFindProc(iPtr, argv[2]); ! 276: if (procPtr == NULL) { ! 277: goto infoNoSuchProc; ! 278: } ! 279: iPtr->result = procPtr->command; ! 280: return TCL_OK; ! 281: } else if ((c == 'c') && (strncmp(argv[1], "cmdcount", length) == 0) ! 282: && (length >= 2)) { ! 283: if (argc != 2) { ! 284: sprintf(iPtr->result, ! 285: "wrong # args: should be \"%.50s cmdcount\"", ! 286: argv[0]); ! 287: return TCL_ERROR; ! 288: } ! 289: sprintf(iPtr->result, "%d", iPtr->cmdCount); ! 290: return TCL_OK; ! 291: } else if ((c == 'c') && (strncmp(argv[1], "commands", length) == 0) ! 292: && (length >= 2)){ ! 293: if (argc > 3) { ! 294: sprintf(iPtr->result, ! 295: "wrong # args: should be \"%.50s commands [pattern]\"", ! 296: argv[0]); ! 297: return TCL_ERROR; ! 298: } ! 299: flag = CMDS; ! 300: cmdPtr = iPtr->commandPtr; ! 301: } else if ((c == 'd') && (strncmp(argv[1], "default", length)) == 0) { ! 302: if (argc != 5) { ! 303: sprintf(iPtr->result, "wrong # args: should be \"%.50s default procname arg varname\"", ! 304: argv[0]); ! 305: return TCL_ERROR; ! 306: } ! 307: procPtr = TclFindProc(iPtr, argv[2]); ! 308: if (procPtr == NULL) { ! 309: goto infoNoSuchProc; ! 310: } ! 311: for (varPtr = procPtr->argPtr; ; varPtr = varPtr->nextPtr) { ! 312: if (varPtr == NULL) { ! 313: sprintf(iPtr->result, ! 314: "procedure \"%s\" doesn't have an argument \"%s\"", ! 315: argv[2], argv[3]); ! 316: return TCL_ERROR; ! 317: } ! 318: if (strcmp(argv[3], varPtr->name) == 0) { ! 319: if (varPtr->value != NULL) { ! 320: Tcl_SetVar((Tcl_Interp *) iPtr, argv[4], varPtr->value, 0); ! 321: iPtr->result = "1"; ! 322: } else { ! 323: Tcl_SetVar((Tcl_Interp *) iPtr, argv[4], "", 0); ! 324: iPtr->result = "0"; ! 325: } ! 326: return TCL_OK; ! 327: } ! 328: } ! 329: } else if ((c == 'e') && (strncmp(argv[1], "exists", length) == 0)) { ! 330: char *p; ! 331: if (argc != 3) { ! 332: sprintf(iPtr->result, ! 333: "wrong # args: should be \"%.50s exists varName\"", ! 334: argv[0]); ! 335: return TCL_ERROR; ! 336: } ! 337: p = Tcl_GetVar((Tcl_Interp *) iPtr, argv[2], 0); ! 338: if (p != NULL) { ! 339: iPtr->result[0] = '1'; ! 340: } else { ! 341: iPtr->result[0] = '0'; ! 342: } ! 343: iPtr->result[1] = 0; ! 344: return TCL_OK; ! 345: } else if ((c == 'g') && (strncmp(argv[1], "globals", length) == 0)) { ! 346: if (argc > 3) { ! 347: sprintf(iPtr->result, ! 348: "wrong # args: should be \"%.50s globals [pattern]\"", ! 349: argv[0]); ! 350: return TCL_ERROR; ! 351: } ! 352: flag = VARS; ! 353: varPtr = iPtr->globalPtr; ! 354: } else if ((c == 'l') && (strncmp(argv[1], "locals", length) == 0) ! 355: && (length >= 2)) { ! 356: if (argc > 3) { ! 357: sprintf(iPtr->result, ! 358: "wrong # args: should be \"%.50s locals [pattern]\"", ! 359: argv[0]); ! 360: return TCL_ERROR; ! 361: } ! 362: flag = LOCALS; ! 363: if (iPtr->varFramePtr == NULL) { ! 364: varPtr = NULL; ! 365: } else { ! 366: varPtr = iPtr->varFramePtr->varPtr; ! 367: } ! 368: } else if ((c == 'l') && (strncmp(argv[1], "level", length) == 0) ! 369: && (length >= 2)) { ! 370: if (argc == 2) { ! 371: if (iPtr->varFramePtr == NULL) { ! 372: iPtr->result = "0"; ! 373: } else { ! 374: sprintf(iPtr->result, "%d", iPtr->varFramePtr->level); ! 375: } ! 376: return TCL_OK; ! 377: } else if (argc == 3) { ! 378: int level; ! 379: char *end; ! 380: CallFrame *framePtr; ! 381: ! 382: level = strtol(argv[2], &end, 10); ! 383: if ((end == argv[2]) || (*end != '\0')) { ! 384: levelError: ! 385: sprintf(iPtr->result, "bad level \"%.50s\"", argv[1]); ! 386: return TCL_ERROR; ! 387: } ! 388: if (level <= 0) { ! 389: if (iPtr->varFramePtr == NULL) { ! 390: goto levelError; ! 391: } ! 392: level += iPtr->varFramePtr->level; ! 393: } ! 394: if (level == 0) { ! 395: return TCL_OK; ! 396: } ! 397: for (framePtr = iPtr->varFramePtr; framePtr != NULL; ! 398: framePtr = framePtr->callerVarPtr) { ! 399: if (framePtr->level == level) { ! 400: break; ! 401: } ! 402: } ! 403: if (framePtr == NULL) { ! 404: goto levelError; ! 405: } ! 406: iPtr->result = Tcl_Merge(framePtr->argc, framePtr->argv); ! 407: iPtr->dynamic = 1; ! 408: return TCL_OK; ! 409: } ! 410: sprintf(iPtr->result, ! 411: "wrong # args: should be \"%.50s level [number]\"", ! 412: argv[0]); ! 413: return TCL_ERROR; ! 414: } else if ((c == 'p') && (strncmp(argv[1], "procs", length)) == 0) { ! 415: if (argc > 3) { ! 416: sprintf(iPtr->result, ! 417: "wrong # args: should be \"%.50s procs [pattern]\"", ! 418: argv[0]); ! 419: return TCL_ERROR; ! 420: } ! 421: flag = PROCS; ! 422: cmdPtr = iPtr->commandPtr; ! 423: } else if ((c == 't') && (strncmp(argv[1], "tclversion", length) == 0)) { ! 424: ! 425: /* ! 426: * Note: TCL_VERSION below is expected to be set with a "-D" ! 427: * switch in the Makefile. ! 428: */ ! 429: ! 430: strcpy(iPtr->result, TCL_VERSION); ! 431: return TCL_OK; ! 432: } else if ((c == 'v') && (strncmp(argv[1], "vars", length)) == 0) { ! 433: if (argc > 3) { ! 434: sprintf(iPtr->result, ! 435: "wrong # args: should be \"%.50s vars [pattern]\"", ! 436: argv[0]); ! 437: return TCL_ERROR; ! 438: } ! 439: flag = VARS; ! 440: if (iPtr->varFramePtr == NULL) { ! 441: varPtr = iPtr->globalPtr; ! 442: } else { ! 443: varPtr = iPtr->varFramePtr->varPtr; ! 444: } ! 445: } else { ! 446: sprintf(iPtr->result, "bad \"%.50s\" option \"%.50s\": must be args, body, commands, cmdcount, default, exists, globals, level, locals, procs, tclversion, or vars", ! 447: argv[0], argv[1]); ! 448: return TCL_ERROR; ! 449: } ! 450: ! 451: /* ! 452: * At this point we have to assemble a list of something or other. ! 453: * Collect them in an expandable argv-argc array. ! 454: */ ! 455: ! 456: if (argc == 3) { ! 457: pattern = argv[2]; ! 458: } else { ! 459: pattern = NULL; ! 460: } ! 461: argv = argSpace; ! 462: argSize = ARG_SIZE; ! 463: argc = 0; ! 464: while (1) { ! 465: /* ! 466: * Increase the size of the argument array if necessary to ! 467: * accommodate another string. ! 468: */ ! 469: ! 470: if (argc == argSize) { ! 471: char **newArgs; ! 472: ! 473: argSize *= 2; ! 474: newArgs = (char **) malloc((unsigned) argSize*sizeof(char *)); ! 475: bcopy((char *) argv, (char *) newArgs, argc*sizeof(char *)); ! 476: if (argv != argSpace) { ! 477: free((char *) argv); ! 478: } ! 479: argv = newArgs; ! 480: } ! 481: ! 482: if ((flag == PROCS) || (flag == CMDS)) { ! 483: if (flag == PROCS) { ! 484: for ( ; cmdPtr != NULL; cmdPtr = cmdPtr->nextPtr) { ! 485: if (TclIsProc(cmdPtr)) { ! 486: break; ! 487: } ! 488: } ! 489: } ! 490: if (cmdPtr == NULL) { ! 491: break; ! 492: } ! 493: argv[argc] = cmdPtr->name; ! 494: cmdPtr = cmdPtr->nextPtr; ! 495: } else { ! 496: if (flag == LOCALS) { ! 497: for ( ; varPtr != NULL; varPtr = varPtr->nextPtr) { ! 498: if (!(varPtr->flags & VAR_GLOBAL)) { ! 499: break; ! 500: } ! 501: } ! 502: } ! 503: if (varPtr == NULL) { ! 504: break; ! 505: } ! 506: argv[argc] = varPtr->name; ! 507: varPtr = varPtr->nextPtr; ! 508: } ! 509: if ((pattern == NULL) || Tcl_StringMatch(argv[argc], pattern)) { ! 510: argc++; ! 511: } ! 512: } ! 513: ! 514: iPtr->result = Tcl_Merge(argc, argv); ! 515: iPtr->dynamic = 1; ! 516: if (argv != argSpace) { ! 517: free((char *) argv); ! 518: } ! 519: return TCL_OK; ! 520: } ! 521: ! 522: /* ! 523: *---------------------------------------------------------------------- ! 524: * ! 525: * Tcl_LengthCmd -- ! 526: * ! 527: * This procedure is invoked to process the "length" Tcl command. ! 528: * See the user documentation for details on what it does. ! 529: * ! 530: * Results: ! 531: * A standard Tcl result. ! 532: * ! 533: * Side effects: ! 534: * See the user documentation. ! 535: * ! 536: *---------------------------------------------------------------------- ! 537: */ ! 538: ! 539: /* ARGSUSED */ ! 540: int ! 541: Tcl_LengthCmd(dummy, interp, argc, argv) ! 542: ClientData dummy; /* Not used. */ ! 543: Tcl_Interp *interp; /* Current interpreter. */ ! 544: int argc; /* Number of arguments. */ ! 545: char **argv; /* Argument strings. */ ! 546: { ! 547: #pragma ref dummy ! 548: int count; ! 549: char *p; ! 550: ! 551: if (argc < 2) { ! 552: lengthSyntax: ! 553: sprintf(interp->result, ! 554: "wrong # args: should be \"%.50s value [chars]\"", argv[0]); ! 555: return TCL_ERROR; ! 556: } ! 557: p = argv[1]; ! 558: if (argc == 2) { ! 559: char *element; ! 560: int result; ! 561: ! 562: for (count = 0; *p != 0 ; count++) { ! 563: result = TclFindElement(interp, p, &element, &p, (int *) NULL, ! 564: (int *) NULL); ! 565: if (result != TCL_OK) { ! 566: return result; ! 567: } ! 568: if (*element == 0) { ! 569: break; ! 570: } ! 571: } ! 572: } else if ((argc == 3) ! 573: && (strncmp(argv[2], "chars", strlen(argv[2])) == 0)) { ! 574: count = strlen(p); ! 575: } else { ! 576: goto lengthSyntax; ! 577: } ! 578: sprintf(interp->result, "%d", count); ! 579: return TCL_OK; ! 580: } ! 581: ! 582: /* ! 583: *---------------------------------------------------------------------- ! 584: * ! 585: * Tcl_ListCmd -- ! 586: * ! 587: * This procedure is invoked to process the "list" Tcl command. ! 588: * See the user documentation for details on what it does. ! 589: * ! 590: * Results: ! 591: * A standard Tcl result. ! 592: * ! 593: * Side effects: ! 594: * See the user documentation. ! 595: * ! 596: *---------------------------------------------------------------------- ! 597: */ ! 598: ! 599: /* ARGSUSED */ ! 600: int ! 601: Tcl_ListCmd(dummy, interp, argc, argv) ! 602: ClientData dummy; /* Not used. */ ! 603: Tcl_Interp *interp; /* Current interpreter. */ ! 604: int argc; /* Number of arguments. */ ! 605: char **argv; /* Argument strings. */ ! 606: { ! 607: #pragma ref dummy ! 608: if (argc < 2) { ! 609: sprintf(interp->result, ! 610: "not enough args: should be \"%.50s arg [arg ...]\"", ! 611: argv[0]); ! 612: return TCL_ERROR; ! 613: } ! 614: interp->result = Tcl_Merge(argc-1, argv+1); ! 615: interp->dynamic = 1; ! 616: return TCL_OK; ! 617: } ! 618: ! 619: /* ! 620: *---------------------------------------------------------------------- ! 621: * ! 622: * Tcl_PrintCmd -- ! 623: * ! 624: * This procedure is invoked to process the "print" Tcl command. ! 625: * See the user documentation for details on what it does. ! 626: * ! 627: * Results: ! 628: * A standard Tcl result. ! 629: * ! 630: * Side effects: ! 631: * See the user documentation. ! 632: * ! 633: *---------------------------------------------------------------------- ! 634: */ ! 635: ! 636: /* ARGSUSED */ ! 637: int ! 638: Tcl_PrintCmd(notUsed, interp, argc, argv) ! 639: ClientData notUsed; /* Not used. */ ! 640: Tcl_Interp *interp; /* Current interpreter. */ ! 641: int argc; /* Number of arguments. */ ! 642: char **argv; /* Argument strings. */ ! 643: { ! 644: #pragma ref notUsed ! 645: FILE *f; ! 646: int result; ! 647: ! 648: if ((argc < 2) || (argc > 4)) { ! 649: sprintf(interp->result, ! 650: "wrong # args: should be \"%.50s string [file [append]]\"", ! 651: argv[0]); ! 652: return TCL_ERROR; ! 653: } ! 654: ! 655: if (argc == 2) { ! 656: f = stdout; ! 657: } else { ! 658: if (argc == 4) { ! 659: if (strncmp(argv[3], "append", strlen(argv[3])) != 0) { ! 660: sprintf(interp->result, ! 661: "bad option \"%.50s\": must be \"append\"", ! 662: argv[3]); ! 663: return TCL_ERROR; ! 664: } ! 665: f = fopen(argv[2], "a"); ! 666: } else { ! 667: f = fopen(argv[2], "w"); ! 668: } ! 669: if (f == NULL) { ! 670: sprintf(interp->result, "couldn't open \"%.50s\": %.80s", ! 671: argv[2], strerror(errno)); ! 672: return TCL_ERROR; ! 673: } ! 674: } ! 675: fputs(argv[1], f); ! 676: if (argc == 2) { ! 677: result = fflush(stdout); ! 678: } else { ! 679: result = fclose(f); ! 680: } ! 681: if (result == EOF) { ! 682: sprintf(interp->result, "I/O error while writing: %.50s", ! 683: strerror(errno)); ! 684: return TCL_ERROR; ! 685: } ! 686: return TCL_OK; ! 687: } ! 688: ! 689: /* ! 690: *---------------------------------------------------------------------- ! 691: * ! 692: * Tcl_RangeCmd -- ! 693: * ! 694: * This procedure is invoked to process the "range" Tcl command. ! 695: * See the user documentation for details on what it does. ! 696: * ! 697: * Results: ! 698: * A standard Tcl result. ! 699: * ! 700: * Side effects: ! 701: * See the user documentation. ! 702: * ! 703: *---------------------------------------------------------------------- ! 704: */ ! 705: ! 706: /* ARGSUSED */ ! 707: int ! 708: Tcl_RangeCmd(notUsed, interp, argc, argv) ! 709: ClientData notUsed; /* Not used. */ ! 710: Tcl_Interp *interp; /* Current interpreter. */ ! 711: int argc; /* Number of arguments. */ ! 712: char **argv; /* Argument strings. */ ! 713: { ! 714: #pragma ref notUsed ! 715: int first, last, result; ! 716: char *begin, *end, c, *dummy; ! 717: int count; ! 718: ! 719: if (argc < 4) { ! 720: rangeSyntax: ! 721: sprintf(interp->result, "wrong #/type of args: should be \"%.50s value first last [chars]\"", ! 722: argv[0]); ! 723: return TCL_ERROR; ! 724: } ! 725: first = atoi(argv[2]); ! 726: if (!isdigit(*argv[2]) || (first < 0)) { ! 727: sprintf(interp->result, "bad range specifier \"%.50s\"", argv[2]); ! 728: return TCL_ERROR; ! 729: } ! 730: if ((*argv[3] == 'e') && (strncmp(argv[3], "end", strlen(argv[3])) == 0)) { ! 731: last = -1; ! 732: } else { ! 733: last = atoi(argv[3]); ! 734: if (!isdigit(*argv[3]) || (last < 0)) { ! 735: sprintf(interp->result, "bad range specifier \"%.50s\"", argv[3]); ! 736: return TCL_ERROR; ! 737: } ! 738: } ! 739: ! 740: if (argc == 5) { ! 741: count = strlen(argv[4]); ! 742: if ((count == 0) || (strncmp(argv[4], "chars", count) != 0)) { ! 743: goto rangeSyntax; ! 744: } ! 745: ! 746: /* ! 747: * Extract a range of characters. ! 748: */ ! 749: ! 750: count = strlen(argv[1]); ! 751: if (first >= count) { ! 752: interp->result = ""; ! 753: return TCL_OK; ! 754: } ! 755: begin = argv[1] + first; ! 756: if ((last == -1) || (last >= count)) { ! 757: last = count; ! 758: } else if (last < first) { ! 759: interp->result = ""; ! 760: return TCL_OK; ! 761: } ! 762: end = argv[1] + last + 1; ! 763: } else { ! 764: if (argc != 4) { ! 765: goto rangeSyntax; ! 766: } ! 767: ! 768: /* ! 769: * Extract a range of fields. ! 770: */ ! 771: ! 772: for (count = 0, begin = argv[1]; count < first; count++) { ! 773: result = TclFindElement(interp, begin, &dummy, &begin, (int *) NULL, ! 774: (int *) NULL); ! 775: if (result != TCL_OK) { ! 776: return result; ! 777: } ! 778: if (*begin == 0) { ! 779: break; ! 780: } ! 781: } ! 782: if (last == -1) { ! 783: Tcl_Return(interp, begin, TCL_VOLATILE); ! 784: return TCL_OK; ! 785: } ! 786: if (last < first) { ! 787: interp->result = ""; ! 788: return TCL_OK; ! 789: } ! 790: for (count = first, end = begin; (count <= last) && (*end != 0); ! 791: count++) { ! 792: result = TclFindElement(interp, end, &dummy, &end, (int *) NULL, ! 793: (int *) NULL); ! 794: if (result != TCL_OK) { ! 795: return result; ! 796: } ! 797: } ! 798: ! 799: /* ! 800: * Chop off trailing spaces. ! 801: */ ! 802: ! 803: while (isspace(end[-1])) { ! 804: end--; ! 805: } ! 806: } ! 807: c = *end; ! 808: *end = 0; ! 809: Tcl_Return(interp, begin, TCL_VOLATILE); ! 810: *end = c; ! 811: return TCL_OK; ! 812: } ! 813: ! 814: /* ! 815: *---------------------------------------------------------------------- ! 816: * ! 817: * Tcl_RenameCmd -- ! 818: * ! 819: * This procedure is invoked to process the "rename" Tcl command. ! 820: * See the user documentation for details on what it does. ! 821: * ! 822: * Results: ! 823: * A standard Tcl result. ! 824: * ! 825: * Side effects: ! 826: * See the user documentation. ! 827: * ! 828: *---------------------------------------------------------------------- ! 829: */ ! 830: ! 831: /* ARGSUSED */ ! 832: int ! 833: Tcl_RenameCmd(dummy, interp, argc, argv) ! 834: ClientData dummy; /* Not used. */ ! 835: Tcl_Interp *interp; /* Current interpreter. */ ! 836: int argc; /* Number of arguments. */ ! 837: char **argv; /* Argument strings. */ ! 838: { ! 839: #pragma ref dummy ! 840: register Command *oldPtr, *newPtr; ! 841: Interp *iPtr = (Interp *) interp; ! 842: ! 843: if (argc != 3) { ! 844: sprintf(interp->result, ! 845: "wrong # args: should be \"%.50s oldName newName\"", ! 846: argv[0]); ! 847: return TCL_ERROR; ! 848: } ! 849: if (argv[2][0] == '\0') { ! 850: Tcl_DeleteCommand(interp, argv[1]); ! 851: return TCL_OK; ! 852: } ! 853: newPtr = TclFindCmd(iPtr, argv[2], 0); ! 854: if (newPtr != NULL) { ! 855: sprintf(interp->result, "can't rename to \"%.50s\": already exists", ! 856: argv[2]); ! 857: return TCL_ERROR; ! 858: } ! 859: oldPtr = TclFindCmd(iPtr, argv[1], 0); ! 860: if (oldPtr == NULL) { ! 861: sprintf(interp->result, ! 862: "can't rename \"%.50s\": command doesn't exist", ! 863: argv[1]); ! 864: return TCL_ERROR; ! 865: } ! 866: iPtr->commandPtr = oldPtr->nextPtr; ! 867: newPtr = (Command *) malloc(CMD_SIZE(strlen(argv[2]))); ! 868: newPtr->proc = oldPtr->proc; ! 869: newPtr->clientData = oldPtr->clientData; ! 870: newPtr->deleteProc = oldPtr->deleteProc; ! 871: newPtr->nextPtr = iPtr->commandPtr; ! 872: iPtr->commandPtr = newPtr; ! 873: strcpy(newPtr->name, argv[2]); ! 874: free((char *) oldPtr); ! 875: return TCL_OK; ! 876: } ! 877: ! 878: /* ! 879: *---------------------------------------------------------------------- ! 880: * ! 881: * Tcl_ReturnCmd -- ! 882: * ! 883: * This procedure is invoked to process the "return" Tcl command. ! 884: * See the user documentation for details on what it does. ! 885: * ! 886: * Results: ! 887: * A standard Tcl result. ! 888: * ! 889: * Side effects: ! 890: * See the user documentation. ! 891: * ! 892: *---------------------------------------------------------------------- ! 893: */ ! 894: ! 895: /* ARGSUSED */ ! 896: int ! 897: Tcl_ReturnCmd(dummy, interp, argc, argv) ! 898: ClientData dummy; /* Not used. */ ! 899: Tcl_Interp *interp; /* Current interpreter. */ ! 900: int argc; /* Number of arguments. */ ! 901: char **argv; /* Argument strings. */ ! 902: { ! 903: #pragma ref dummy ! 904: if (argc > 2) { ! 905: sprintf(interp->result, "too many args: should be \"%.50s [value]\"", ! 906: argv[0]); ! 907: return TCL_ERROR; ! 908: } ! 909: if (argc == 2) { ! 910: Tcl_Return(interp, argv[1], TCL_VOLATILE); ! 911: } ! 912: return TCL_RETURN; ! 913: } ! 914: ! 915: /* ! 916: *---------------------------------------------------------------------- ! 917: * ! 918: * Tcl_ScanCmd -- ! 919: * ! 920: * This procedure is invoked to process the "scan" Tcl command. ! 921: * See the user documentation for details on what it does. ! 922: * ! 923: * Results: ! 924: * A standard Tcl result. ! 925: * ! 926: * Side effects: ! 927: * See the user documentation. ! 928: * ! 929: *---------------------------------------------------------------------- ! 930: */ ! 931: ! 932: /* ARGSUSED */ ! 933: int ! 934: Tcl_ScanCmd(dummy, interp, argc, argv) ! 935: ClientData dummy; /* Not used. */ ! 936: Tcl_Interp *interp; /* Current interpreter. */ ! 937: int argc; /* Number of arguments. */ ! 938: char **argv; /* Argument strings. */ ! 939: { ! 940: #pragma ref dummy ! 941: int arg1Length; /* Number of bytes in argument to be ! 942: * scanned. This gives an upper limit ! 943: * on string field sizes. */ ! 944: # define MAX_FIELDS 20 ! 945: typedef struct { ! 946: char fmt; /* Format for field. */ ! 947: int size; /* How many bytes to allow for ! 948: * field. */ ! 949: char *location; /* Where field will be stored. */ ! 950: } Field; ! 951: Field fields[MAX_FIELDS]; /* Info about all the fields in the ! 952: * format string. */ ! 953: register Field *curField; ! 954: int numFields = 0; /* Number of fields actually ! 955: * specified. */ ! 956: int suppress; /* Current field is assignment- ! 957: * suppressed. */ ! 958: int totalSize = 0; /* Number of bytes needed to store ! 959: * all results combined. */ ! 960: char *results; /* Where scanned output goes. */ ! 961: int numScanned; /* sscanf's result. */ ! 962: register char *fmt; ! 963: int i; ! 964: ! 965: if (argc < 3) { ! 966: sprintf(interp->result, ! 967: "too few args: should be \"%.50s string format varName ...\"", ! 968: argv[0]); ! 969: return TCL_ERROR; ! 970: } ! 971: ! 972: /* ! 973: * This procedure operates in four stages: ! 974: * 1. Scan the format string, collecting information about each field. ! 975: * 2. Allocate an array to hold all of the scanned fields. ! 976: * 3. Call sscanf to do all the dirty work, and have it store the ! 977: * parsed fields in the array. ! 978: * 4. Pick off the fields from the array and assign them to variables. ! 979: */ ! 980: ! 981: arg1Length = (strlen(argv[1]) + 4) & ~03; ! 982: for (fmt = argv[2]; *fmt != 0; fmt++) { ! 983: if (*fmt != '%') { ! 984: continue; ! 985: } ! 986: fmt++; ! 987: if (*fmt == '*') { ! 988: suppress = 1; ! 989: fmt++; ! 990: } else { ! 991: suppress = 0; ! 992: } ! 993: while (isdigit(*fmt)) { ! 994: fmt++; ! 995: } ! 996: if (suppress) { ! 997: continue; ! 998: } ! 999: if (numFields == MAX_FIELDS) { ! 1000: sprintf(interp->result, ! 1001: "can't have more than %d fields in \"%.50s\"", MAX_FIELDS, ! 1002: argv[0]); ! 1003: return TCL_ERROR; ! 1004: } ! 1005: curField = &fields[numFields]; ! 1006: numFields++; ! 1007: switch (*fmt) { ! 1008: case 'D': ! 1009: case 'O': ! 1010: case 'X': ! 1011: case 'd': ! 1012: case 'o': ! 1013: case 'x': ! 1014: curField->fmt = 'd'; ! 1015: curField->size = sizeof(int); ! 1016: break; ! 1017: ! 1018: case 's': ! 1019: curField->fmt = 's'; ! 1020: curField->size = arg1Length; ! 1021: break; ! 1022: ! 1023: case 'c': ! 1024: curField->fmt = 'c'; ! 1025: curField->size = sizeof(int); ! 1026: break; ! 1027: ! 1028: case 'E': ! 1029: case 'F': ! 1030: curField->fmt = 'F'; ! 1031: curField->size = 8; ! 1032: break; ! 1033: ! 1034: case 'e': ! 1035: case 'f': ! 1036: curField->fmt = 'f'; ! 1037: curField->size = 4; ! 1038: break; ! 1039: ! 1040: case '[': ! 1041: curField->fmt = 's'; ! 1042: curField->size = arg1Length; ! 1043: do { ! 1044: fmt++; ! 1045: } while (*fmt != ']'); ! 1046: break; ! 1047: ! 1048: default: ! 1049: sprintf(interp->result, "bad scan conversion character \"%c\"", ! 1050: *fmt); ! 1051: return TCL_ERROR; ! 1052: } ! 1053: totalSize += curField->size; ! 1054: } ! 1055: ! 1056: if (numFields != (argc-3)) { ! 1057: interp->result = ! 1058: "different numbers of variable names and field specifiers"; ! 1059: return TCL_ERROR; ! 1060: } ! 1061: ! 1062: /* ! 1063: * Step 2: ! 1064: */ ! 1065: ! 1066: results = (char *) malloc((unsigned) totalSize); ! 1067: for (i = 0, totalSize = 0, curField = fields; ! 1068: i < numFields; i++, curField++) { ! 1069: curField->location = results + totalSize; ! 1070: totalSize += curField->size; ! 1071: } ! 1072: ! 1073: /* ! 1074: * Step 3: ! 1075: */ ! 1076: ! 1077: numScanned = sscanf(argv[1], argv[2], ! 1078: fields[0].location, fields[1].location, fields[2].location, ! 1079: fields[3].location, fields[4].location); ! 1080: ! 1081: /* ! 1082: * Step 4: ! 1083: */ ! 1084: ! 1085: if (numScanned < numFields) { ! 1086: numFields = numScanned; ! 1087: } ! 1088: for (i = 0, curField = fields; i < numFields; i++, curField++) { ! 1089: switch (curField->fmt) { ! 1090: char string[30]; ! 1091: ! 1092: case 'd': ! 1093: sprintf(string, "%d", *((int *) curField->location)); ! 1094: Tcl_SetVar(interp, argv[i+3], string, 0); ! 1095: break; ! 1096: ! 1097: case 'c': ! 1098: sprintf(string, "%d", *((char *) curField->location) & 0xff); ! 1099: Tcl_SetVar(interp, argv[i+3], string, 0); ! 1100: break; ! 1101: ! 1102: case 's': ! 1103: Tcl_SetVar(interp, argv[i+3], curField->location, 0); ! 1104: break; ! 1105: ! 1106: case 'F': ! 1107: sprintf(string, "%g", *((double *) curField->location)); ! 1108: Tcl_SetVar(interp, argv[i+3], string, 0); ! 1109: break; ! 1110: ! 1111: case 'f': ! 1112: sprintf(string, "%g", *((float *) curField->location)); ! 1113: Tcl_SetVar(interp, argv[i+3], string, 0); ! 1114: break; ! 1115: } ! 1116: } ! 1117: free(results); ! 1118: sprintf(interp->result, "%d", numScanned); ! 1119: return TCL_OK; ! 1120: } ! 1121: ! 1122: /* ! 1123: *---------------------------------------------------------------------- ! 1124: * ! 1125: * Tcl_SourceCmd -- ! 1126: * ! 1127: * This procedure is invoked to process the "source" Tcl command. ! 1128: * See the user documentation for details on what it does. ! 1129: * ! 1130: * Results: ! 1131: * A standard Tcl result. ! 1132: * ! 1133: * Side effects: ! 1134: * See the user documentation. ! 1135: * ! 1136: *---------------------------------------------------------------------- ! 1137: */ ! 1138: ! 1139: /* ARGSUSED */ ! 1140: int ! 1141: Tcl_SourceCmd(dummy, interp, argc, argv) ! 1142: ClientData dummy; /* Not used. */ ! 1143: Tcl_Interp *interp; /* Current interpreter. */ ! 1144: int argc; /* Number of arguments. */ ! 1145: char **argv; /* Argument strings. */ ! 1146: { ! 1147: #pragma ref dummy ! 1148: int fileId, result; ! 1149: struct stat statBuf; ! 1150: char *cmdBuffer, *end; ! 1151: char *fileName; ! 1152: ! 1153: if (argc != 2) { ! 1154: sprintf(interp->result, "wrong # args: should be \"%.50s fileName\"", ! 1155: argv[0]); ! 1156: return TCL_ERROR; ! 1157: } ! 1158: fileName = Tcl_TildeSubst(interp, argv[1]); ! 1159: if (fileName == NULL) { ! 1160: return TCL_ERROR; ! 1161: } ! 1162: fileId = open(fileName, O_RDONLY, 0); ! 1163: if (fileId < 0) { ! 1164: sprintf(interp->result, "couldn't read file \"%.50s\"", argv[1]); ! 1165: return TCL_ERROR; ! 1166: } ! 1167: if (fstat(fileId, &statBuf) == -1) { ! 1168: sprintf(interp->result, "couldn't stat file \"%.50s\"", argv[1]); ! 1169: close(fileId); ! 1170: return TCL_ERROR; ! 1171: } ! 1172: cmdBuffer = (char *) malloc((unsigned) statBuf.st_size+1); ! 1173: if (read(fileId, cmdBuffer, (int) statBuf.st_size) != statBuf.st_size) { ! 1174: sprintf(interp->result, "error in reading file \"%.50s\"", argv[1]); ! 1175: close(fileId); ! 1176: return TCL_ERROR; ! 1177: } ! 1178: close(fileId); ! 1179: cmdBuffer[statBuf.st_size] = 0; ! 1180: result = Tcl_Eval(interp, cmdBuffer, 0, &end); ! 1181: if (result == TCL_RETURN) { ! 1182: result = TCL_OK; ! 1183: } ! 1184: if (result == TCL_ERROR) { ! 1185: char msg[100]; ! 1186: ! 1187: /* ! 1188: * Record information telling where the error occurred. ! 1189: */ ! 1190: ! 1191: sprintf(msg, " (file \"%.50s\" line %d)", argv[1], interp->errorLine); ! 1192: Tcl_AddErrorInfo(interp, msg); ! 1193: } ! 1194: free(cmdBuffer); ! 1195: return result; ! 1196: } ! 1197: ! 1198: /* ! 1199: *---------------------------------------------------------------------- ! 1200: * ! 1201: * Tcl_StringCmd -- ! 1202: * ! 1203: * This procedure is invoked to process the "string" Tcl command. ! 1204: * See the user documentation for details on what it does. ! 1205: * ! 1206: * Results: ! 1207: * A standard Tcl result. ! 1208: * ! 1209: * Side effects: ! 1210: * See the user documentation. ! 1211: * ! 1212: *---------------------------------------------------------------------- ! 1213: */ ! 1214: ! 1215: /* ARGSUSED */ ! 1216: int ! 1217: Tcl_StringCmd(dummy, interp, argc, argv) ! 1218: ClientData dummy; /* Not used. */ ! 1219: Tcl_Interp *interp; /* Current interpreter. */ ! 1220: int argc; /* Number of arguments. */ ! 1221: char **argv; /* Argument strings. */ ! 1222: { ! 1223: #pragma ref dummy ! 1224: int length; ! 1225: register char *p, c; ! 1226: int match; ! 1227: int first; ! 1228: ! 1229: if (argc != 4) { ! 1230: sprintf(interp->result, ! 1231: "wrong # args: should be \"%.50s option a b\"", ! 1232: argv[0]); ! 1233: return TCL_ERROR; ! 1234: } ! 1235: length = strlen(argv[1]); ! 1236: if (strncmp(argv[1], "compare", length) == 0) { ! 1237: match = strcmp(argv[2], argv[3]); ! 1238: if (match > 0) { ! 1239: interp->result = "1"; ! 1240: } else if (match < 0) { ! 1241: interp->result = "-1"; ! 1242: } else { ! 1243: interp->result = "0"; ! 1244: } ! 1245: return TCL_OK; ! 1246: } ! 1247: if (strncmp(argv[1], "first", length) == 0) { ! 1248: first = 1; ! 1249: } else if (strncmp(argv[1], "last", length) == 0) { ! 1250: first = 0; ! 1251: } else if (strncmp(argv[1], "match", length) == 0) { ! 1252: if (Tcl_StringMatch(argv[3], argv[2]) != 0) { ! 1253: interp->result = "1"; ! 1254: } else { ! 1255: interp->result = "0"; ! 1256: } ! 1257: return TCL_OK; ! 1258: } else { ! 1259: sprintf(interp->result, ! 1260: "bad \"%.50s\" option \"%.50s\": must be compare, first, or last", ! 1261: argv[0], argv[1]); ! 1262: return TCL_ERROR; ! 1263: } ! 1264: match = -1; ! 1265: c = *argv[2]; ! 1266: length = strlen(argv[2]); ! 1267: for (p = argv[3]; *p != 0; p++) { ! 1268: if (*p != c) { ! 1269: continue; ! 1270: } ! 1271: if (strncmp(argv[2], p, length) == 0) { ! 1272: match = p-argv[3]; ! 1273: if (first) { ! 1274: break; ! 1275: } ! 1276: } ! 1277: } ! 1278: sprintf(interp->result, "%d", match); ! 1279: return TCL_OK; ! 1280: } ! 1281: ! 1282: /* ! 1283: *---------------------------------------------------------------------- ! 1284: * ! 1285: * Tcl_TimeCmd -- ! 1286: * ! 1287: * This procedure is invoked to process the "time" Tcl command. ! 1288: * See the user documentation for details on what it does. ! 1289: * ! 1290: * Results: ! 1291: * A standard Tcl result. ! 1292: * ! 1293: * Side effects: ! 1294: * See the user documentation. ! 1295: * ! 1296: *---------------------------------------------------------------------- ! 1297: */ ! 1298: ! 1299: /* ARGSUSED */ ! 1300: int ! 1301: Tcl_TimeCmd(dummy, interp, argc, argv) ! 1302: ClientData dummy; /* Not used. */ ! 1303: Tcl_Interp *interp; /* Current interpreter. */ ! 1304: int argc; /* Number of arguments. */ ! 1305: char **argv; /* Argument strings. */ ! 1306: { ! 1307: #pragma ref dummy ! 1308: int count, i, result; ! 1309: struct tms start, stop; ! 1310: int micros; ! 1311: double timePer; ! 1312: ! 1313: if (argc == 2) { ! 1314: count = 1; ! 1315: } else if (argc == 3) { ! 1316: if (sscanf(argv[2], "%d", &count) != 1) { ! 1317: sprintf(interp->result, "bad count \"%.50s\" given to \"%.50s\"", ! 1318: argv[2], argv[0]); ! 1319: return TCL_ERROR; ! 1320: } ! 1321: } else { ! 1322: sprintf(interp->result, ! 1323: "wrong # args: should be \"%.50s command [count]\"", ! 1324: argv[0]); ! 1325: return TCL_ERROR; ! 1326: } ! 1327: times(&start); ! 1328: for (i = count ; i > 0; i--) { ! 1329: result = Tcl_Eval(interp, argv[1], 0, (char **) NULL); ! 1330: if (result != TCL_OK) { ! 1331: if (result == TCL_ERROR) { ! 1332: char msg[60]; ! 1333: sprintf(msg, " (\"time\" body line %d)", interp->errorLine); ! 1334: Tcl_AddErrorInfo(interp, msg); ! 1335: } ! 1336: return result; ! 1337: } ! 1338: } ! 1339: times(&stop); ! 1340: micros = (stop.tms_utime - start.tms_utime)*1000000; ! 1341: timePer = micros; ! 1342: Tcl_Return(interp, (char *) NULL, TCL_STATIC); ! 1343: sprintf(interp->result, "%.0f microseconds per iteration", timePer/count); ! 1344: return TCL_OK; ! 1345: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.