diff options
Diffstat (limited to 'contrib/tcl/generic/tclCmdMZ.c')
-rw-r--r-- | contrib/tcl/generic/tclCmdMZ.c | 1280 |
1 files changed, 661 insertions, 619 deletions
diff --git a/contrib/tcl/generic/tclCmdMZ.c b/contrib/tcl/generic/tclCmdMZ.c index 5158ddeea77e9..ec1f737dce4ae 100644 --- a/contrib/tcl/generic/tclCmdMZ.c +++ b/contrib/tcl/generic/tclCmdMZ.c @@ -7,16 +7,17 @@ * those that don't depend much upon UNIX facilities). * * Copyright (c) 1987-1993 The Regents of the University of California. - * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * SCCS: @(#) tclCmdMZ.c 1.66 96/07/23 16:15:55 + * SCCS: @(#) tclCmdMZ.c 1.99 97/05/19 17:37:17 */ #include "tclInt.h" #include "tclPort.h" +#include "tclCompile.h" /* * Structure used to hold information about variable traces: @@ -80,7 +81,7 @@ Tcl_PwdCmd(dummy, interp, argc, argv) if (dirName == NULL) { return TCL_ERROR; } - interp->result = dirName; + Tcl_SetResult(interp, dirName, TCL_VOLATILE); return TCL_OK; } @@ -191,7 +192,7 @@ Tcl_RegexpCmd(dummy, interp, argc, argv) return TCL_ERROR; } if (!match) { - interp->result = "0"; + Tcl_SetResult(interp, "0", TCL_STATIC); return TCL_OK; } @@ -221,10 +222,14 @@ Tcl_RegexpCmd(dummy, interp, argc, argv) first = argPtr[1] + (start - string); last = argPtr[1] + (end - string); - savedChar = *last; - *last = 0; - result = Tcl_SetVar(interp, argPtr[i+2], first, 0); - *last = savedChar; + if (first == last) { /* don't modify argument */ + result = Tcl_SetVar(interp, argPtr[i+2], "", 0); + } else { + savedChar = *last; + *last = 0; + result = Tcl_SetVar(interp, argPtr[i+2], first, 0); + *last = savedChar; + } } } if (result == NULL) { @@ -233,7 +238,7 @@ Tcl_RegexpCmd(dummy, interp, argc, argv) return TCL_ERROR; } } - interp->result = "1"; + Tcl_SetResult(interp, "1", TCL_STATIC); return TCL_OK; } @@ -264,11 +269,11 @@ Tcl_RegsubCmd(dummy, interp, argc, argv) { int noCase = 0, all = 0; Tcl_RegExp regExpr; - char *string, *pattern, *p, *firstChar, *newValue, **argPtr; - int match, flags, code, numMatches; + char *string, *pattern, *p, *firstChar, **argPtr; + int match, code, numMatches; char *start, *end, *subStart, *subEnd; register char *src, c; - Tcl_DString stringDString, patternDString; + Tcl_DString stringDString, patternDString, resultDString; if (argc < 5) { wrongNumArgs: @@ -324,6 +329,7 @@ Tcl_RegsubCmd(dummy, interp, argc, argv) pattern = argPtr[0]; string = argPtr[1]; } + Tcl_DStringInit(&resultDString); regExpr = Tcl_RegExpCompile(interp, pattern); if (regExpr == NULL) { code = TCL_ERROR; @@ -337,7 +343,6 @@ Tcl_RegsubCmd(dummy, interp, argc, argv) * then the loop body only gets executed once. */ - flags = 0; numMatches = 0; for (p = string; *p != 0; ) { match = Tcl_RegExpExec(interp, regExpr, p, string); @@ -356,20 +361,7 @@ Tcl_RegsubCmd(dummy, interp, argc, argv) */ Tcl_RegExpRange(regExpr, 0, &start, &end); - src = argPtr[1] + (start - string); - c = *src; - *src = 0; - newValue = Tcl_SetVar(interp, argPtr[3], argPtr[1] + (p - string), - flags); - *src = c; - flags = TCL_APPEND_VALUE; - if (newValue == NULL) { - cantSet: - Tcl_AppendResult(interp, "couldn't set variable \"", - argPtr[3], "\"", (char *) NULL); - code = TCL_ERROR; - goto done; - } + Tcl_DStringAppend(&resultDString, argPtr[1] + (p - string), start - p); /* * Append the subSpec argument to the variable, making appropriate @@ -390,13 +382,9 @@ Tcl_RegsubCmd(dummy, interp, argc, argv) } else if ((c == '\\') || (c == '&')) { *src = c; src[1] = 0; - newValue = Tcl_SetVar(interp, argPtr[3], firstChar, - TCL_APPEND_VALUE); + Tcl_DStringAppend(&resultDString, firstChar, -1); *src = '\\'; src[1] = c; - if (newValue == NULL) { - goto cantSet; - } firstChar = src+2; src++; continue; @@ -409,12 +397,8 @@ Tcl_RegsubCmd(dummy, interp, argc, argv) if (firstChar != src) { c = *src; *src = 0; - newValue = Tcl_SetVar(interp, argPtr[3], firstChar, - TCL_APPEND_VALUE); + Tcl_DStringAppend(&resultDString, firstChar, -1); *src = c; - if (newValue == NULL) { - goto cantSet; - } } Tcl_RegExpRange(regExpr, index, &subStart, &subEnd); if ((subStart != NULL) && (subEnd != NULL)) { @@ -424,12 +408,8 @@ Tcl_RegsubCmd(dummy, interp, argc, argv) last = argPtr[1] + (subEnd - string); saved = *last; *last = 0; - newValue = Tcl_SetVar(interp, argPtr[3], first, - TCL_APPEND_VALUE); + Tcl_DStringAppend(&resultDString, first, -1); *last = saved; - if (newValue == NULL) { - goto cantSet; - } } if (*src == '\\') { src++; @@ -437,25 +417,16 @@ Tcl_RegsubCmd(dummy, interp, argc, argv) firstChar = src+1; } if (firstChar != src) { - if (Tcl_SetVar(interp, argPtr[3], firstChar, - TCL_APPEND_VALUE) == NULL) { - goto cantSet; - } + Tcl_DStringAppend(&resultDString, firstChar, -1); } if (end == p) { - char tmp[2]; /* * Always consume at least one character of the input string * in order to prevent infinite loops. */ - tmp[0] = argPtr[1][p - string]; - tmp[1] = 0; - newValue = Tcl_SetVar(interp, argPtr[3], tmp, flags); - if (newValue == NULL) { - goto cantSet; - } + Tcl_DStringAppend(&resultDString, argPtr[1] + (p - string), 1); p = end + 1; } else { p = end; @@ -471,32 +442,41 @@ Tcl_RegsubCmd(dummy, interp, argc, argv) */ if ((*p != 0) || (numMatches == 0)) { - if (Tcl_SetVar(interp, argPtr[3], argPtr[1] + (p - string), - flags) == NULL) { - goto cantSet; - } + Tcl_DStringAppend(&resultDString, argPtr[1] + (p - string), -1); + } + if (Tcl_SetVar(interp, argPtr[3], Tcl_DStringValue(&resultDString), 0) + == NULL) { + Tcl_AppendResult(interp, + "couldn't set variable \"", argPtr[3], "\"", + (char *) NULL); + code = TCL_ERROR; + } else { + char buf[40]; + + TclFormatInt(buf, numMatches); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + code = TCL_OK; } - sprintf(interp->result, "%d", numMatches); - code = TCL_OK; done: if (noCase) { Tcl_DStringFree(&stringDString); Tcl_DStringFree(&patternDString); } + Tcl_DStringFree(&resultDString); return code; } /* *---------------------------------------------------------------------- * - * Tcl_RenameCmd -- + * Tcl_RenameObjCmd -- * * This procedure is invoked to process the "rename" Tcl command. * See the user documentation for details on what it does. * * Results: - * A standard Tcl result. + * A standard Tcl object result. * * Side effects: * See the user documentation. @@ -506,114 +486,34 @@ Tcl_RegsubCmd(dummy, interp, argc, argv) /* ARGSUSED */ int -Tcl_RenameCmd(dummy, interp, argc, argv) - ClientData dummy; /* Not used. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ +Tcl_RenameObjCmd(dummy, interp, objc, objv) + ClientData dummy; /* Arbitrary value passed to the command. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { - register Command *cmdPtr; - Interp *iPtr = (Interp *) interp; - Tcl_HashEntry *hPtr; - int new; - char *srcName, *dstName; - - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " oldName newName\"", (char *) NULL); - return TCL_ERROR; - } - if (argv[2][0] == '\0') { - if (Tcl_DeleteCommand(interp, argv[1]) != 0) { - Tcl_AppendResult(interp, "can't delete \"", argv[1], - "\": command doesn't exist", (char *) NULL); - return TCL_ERROR; - } - return TCL_OK; - } - - srcName = argv[1]; - dstName = argv[2]; - hPtr = Tcl_FindHashEntry(&iPtr->commandTable, dstName); - if (hPtr != NULL) { - Tcl_AppendResult(interp, "can't rename to \"", argv[2], - "\": command already exists", (char *) NULL); - return TCL_ERROR; - } - - /* - * The code below was added in 11/95 to preserve backwards compatibility - * when "tkerror" was renamed "bgerror": we guarantee that the hash - * table entries for both commands refer to a single shared Command - * structure. This code should eventually become unnecessary. - */ - - if ((srcName[0] == 't') && (strcmp(srcName, "tkerror") == 0)) { - srcName = "bgerror"; - } - dstName = argv[2]; - if ((dstName[0] == 't') && (strcmp(dstName, "tkerror") == 0)) { - dstName = "bgerror"; - } - - hPtr = Tcl_FindHashEntry(&iPtr->commandTable, srcName); - if (hPtr == NULL) { - Tcl_AppendResult(interp, "can't rename \"", argv[1], - "\": command doesn't exist", (char *) NULL); - return TCL_ERROR; - } - cmdPtr = (Command *) Tcl_GetHashValue(hPtr); - - /* - * Prevent formation of alias loops through renaming. - */ + char *oldName, *newName; - if (TclPreventAliasLoop(interp, interp, dstName, cmdPtr->proc, - cmdPtr->clientData) != TCL_OK) { - return TCL_ERROR; - } - - Tcl_DeleteHashEntry(hPtr); - hPtr = Tcl_CreateHashEntry(&iPtr->commandTable, dstName, &new); - Tcl_SetHashValue(hPtr, cmdPtr); - cmdPtr->hPtr = hPtr; - - /* - * The code below provides more backwards compatibility for the - * "tkerror" => "bgerror" renaming. As with the other compatibility - * code above, it should eventually be removed. - */ - - if ((dstName[0] == 'b') && (strcmp(dstName, "bgerror") == 0)) { - /* - * The destination command is "bgerror"; create a "tkerror" - * command that shares the same Command structure. - */ - - hPtr = Tcl_CreateHashEntry(&iPtr->commandTable, "tkerror", &new); - Tcl_SetHashValue(hPtr, cmdPtr); + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "oldName newName"); + return TCL_ERROR; } - if ((srcName[0] == 'b') && (strcmp(srcName, "bgerror") == 0)) { - /* - * The source command is "bgerror": delete the hash table - * entry for "tkerror" if it exists. - */ - Tcl_DeleteHashEntry(Tcl_FindHashEntry(&iPtr->commandTable, "tkerror")); - } - return TCL_OK; + oldName = Tcl_GetStringFromObj(objv[1], (int *) NULL); + newName = Tcl_GetStringFromObj(objv[2], (int *) NULL); + return TclRenameCommand(interp, oldName, newName); } /* *---------------------------------------------------------------------- * - * Tcl_ReturnCmd -- + * Tcl_ReturnObjCmd -- * - * This procedure is invoked to process the "return" Tcl command. - * See the user documentation for details on what it does. + * This object-based procedure is invoked to process the "return" Tcl + * command. See the user documentation for details on what it does. * * Results: - * A standard Tcl result. + * A standard Tcl object result. * * Side effects: * See the user documentation. @@ -623,14 +523,14 @@ Tcl_RenameCmd(dummy, interp, argc, argv) /* ARGSUSED */ int -Tcl_ReturnCmd(dummy, interp, argc, argv) - ClientData dummy; /* Not used. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ +Tcl_ReturnObjCmd(dummy, interp, objc, objv) + ClientData dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { Interp *iPtr = (Interp *) interp; - int c, code; + int optionLen, argLen, code, result; if (iPtr->errorInfo != NULL) { ckfree(iPtr->errorInfo); @@ -641,41 +541,64 @@ Tcl_ReturnCmd(dummy, interp, argc, argv) iPtr->errorCode = NULL; } code = TCL_OK; - for (argv++, argc--; argc > 1; argv += 2, argc -= 2) { - if (strcmp(argv[0], "-code") == 0) { - c = argv[1][0]; - if ((c == 'o') && (strcmp(argv[1], "ok") == 0)) { + + /* + * THIS FAILS IF AN OBJECT CONTAINS AN EMBEDDED NULL. + */ + + for (objv++, objc--; objc > 1; objv += 2, objc -= 2) { + char *option = Tcl_GetStringFromObj(objv[0], &optionLen); + char *arg = Tcl_GetStringFromObj(objv[1], &argLen); + + if (strcmp(option, "-code") == 0) { + register int c = arg[0]; + if ((c == 'o') && (strcmp(arg, "ok") == 0)) { code = TCL_OK; - } else if ((c == 'e') && (strcmp(argv[1], "error") == 0)) { + } else if ((c == 'e') && (strcmp(arg, "error") == 0)) { code = TCL_ERROR; - } else if ((c == 'r') && (strcmp(argv[1], "return") == 0)) { + } else if ((c == 'r') && (strcmp(arg, "return") == 0)) { code = TCL_RETURN; - } else if ((c == 'b') && (strcmp(argv[1], "break") == 0)) { + } else if ((c == 'b') && (strcmp(arg, "break") == 0)) { code = TCL_BREAK; - } else if ((c == 'c') && (strcmp(argv[1], "continue") == 0)) { + } else if ((c == 'c') && (strcmp(arg, "continue") == 0)) { code = TCL_CONTINUE; - } else if (Tcl_GetInt(interp, argv[1], &code) != TCL_OK) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad completion code \"", - argv[1], "\": must be ok, error, return, break, ", - "continue, or an integer", (char *) NULL); - return TCL_ERROR; + } else { + result = Tcl_GetIntFromObj((Tcl_Interp *) NULL, objv[1], + &code); + if (result != TCL_OK) { + Tcl_ResetResult(interp); + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "bad completion code \"", + Tcl_GetStringFromObj(objv[1], (int *) NULL), + "\": must be ok, error, return, break, ", + "continue, or an integer", (char *) NULL); + return result; + } } - } else if (strcmp(argv[0], "-errorinfo") == 0) { - iPtr->errorInfo = (char *) ckalloc((unsigned) (strlen(argv[1]) + 1)); - strcpy(iPtr->errorInfo, argv[1]); - } else if (strcmp(argv[0], "-errorcode") == 0) { - iPtr->errorCode = (char *) ckalloc((unsigned) (strlen(argv[1]) + 1)); - strcpy(iPtr->errorCode, argv[1]); + } else if (strcmp(option, "-errorinfo") == 0) { + iPtr->errorInfo = + (char *) ckalloc((unsigned) (strlen(arg) + 1)); + strcpy(iPtr->errorInfo, arg); + } else if (strcmp(option, "-errorcode") == 0) { + iPtr->errorCode = + (char *) ckalloc((unsigned) (strlen(arg) + 1)); + strcpy(iPtr->errorCode, arg); } else { - Tcl_AppendResult(interp, "bad option \"", argv[0], - ": must be -code, -errorcode, or -errorinfo", + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "bad option \"", option, + "\": must be -code, -errorcode, or -errorinfo", (char *) NULL); return TCL_ERROR; } } - if (argc == 1) { - Tcl_SetResult(interp, argv[0], TCL_VOLATILE); + + if (objc == 1) { + /* + * Set the interpreter's object result. An inline version of + * Tcl_SetObjResult. + */ + + Tcl_SetObjResult(interp, objv[0]); } iPtr->returnCode = code; return TCL_RETURN; @@ -728,6 +651,7 @@ Tcl_ScanCmd(dummy, interp, argc, argv) int numScanned; /* sscanf's result. */ register char *fmt; int i, widthSpecified, length, code; + char buf[40]; /* * The variables below are used to hold a copy of the format @@ -799,7 +723,7 @@ Tcl_ScanCmd(dummy, interp, argc, argv) continue; } if (numFields == MAX_FIELDS) { - interp->result = "too many fields to scan"; + Tcl_SetResult(interp, "too many fields to scan", TCL_STATIC); code = TCL_ERROR; goto done; } @@ -826,8 +750,9 @@ Tcl_ScanCmd(dummy, interp, argc, argv) case 'c': if (widthSpecified) { - interp->result = - "field width may not be specified in %c conversion"; + Tcl_SetResult(interp, + "field width may not be specified in %c conversion", + TCL_STATIC); code = TCL_ERROR; goto done; } @@ -851,7 +776,8 @@ Tcl_ScanCmd(dummy, interp, argc, argv) do { fmt++; if (*fmt == 0) { - interp->result = "unmatched [ in format string"; + Tcl_SetResult(interp, + "unmatched [ in format string", TCL_STATIC); code = TCL_ERROR; goto done; } @@ -861,10 +787,14 @@ Tcl_ScanCmd(dummy, interp, argc, argv) break; default: - sprintf(interp->result, "bad scan conversion character \"%c\"", - *fmt); - code = TCL_ERROR; - goto done; + { + char buf[50]; + + sprintf(buf, "bad scan conversion character \"%c\"", *fmt); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + code = TCL_ERROR; + goto done; + } } curField->size = TCL_ALIGN(curField->size); totalSize += curField->size; @@ -872,8 +802,9 @@ Tcl_ScanCmd(dummy, interp, argc, argv) *dst = 0; if (numFields != (argc-3)) { - interp->result = - "different numbers of variable names and field specifiers"; + Tcl_SetResult(interp, + "different numbers of variable names and field specifiers", + TCL_STATIC); code = TCL_ERROR; goto done; } @@ -924,7 +855,7 @@ Tcl_ScanCmd(dummy, interp, argc, argv) char string[TCL_DOUBLE_SPACE]; case 'd': - sprintf(string, "%d", *((int *) curField->location)); + TclFormatInt(string, *((int *) curField->location)); if (Tcl_SetVar(interp, argv[i+3], string, 0) == NULL) { storeError: Tcl_AppendResult(interp, @@ -943,7 +874,7 @@ Tcl_ScanCmd(dummy, interp, argc, argv) break; case 'c': - sprintf(string, "%d", *((char *) curField->location) & 0xff); + TclFormatInt(string, *((char *) curField->location) & 0xff); if (Tcl_SetVar(interp, argv[i+3], string, 0) == NULL) { goto storeError; } @@ -957,15 +888,16 @@ Tcl_ScanCmd(dummy, interp, argc, argv) break; case 'f': - Tcl_PrintDouble(interp, *((double *) curField->location), - string); + Tcl_PrintDouble((Tcl_Interp *) NULL, + *((double *) curField->location), string); if (Tcl_SetVar(interp, argv[i+3], string, 0) == NULL) { goto storeError; } break; } } - sprintf(interp->result, "%d", numScanned); + TclFormatInt(buf, numScanned); + Tcl_SetResult(interp, buf, TCL_VOLATILE); done: if (results != NULL) { ckfree(results); @@ -979,13 +911,13 @@ Tcl_ScanCmd(dummy, interp, argc, argv) /* *---------------------------------------------------------------------- * - * Tcl_SourceCmd -- + * Tcl_SourceObjCmd -- * * This procedure is invoked to process the "source" Tcl command. * See the user documentation for details on what it does. * * Results: - * A standard Tcl result. + * A standard Tcl object result. * * Side effects: * See the user documentation. @@ -995,18 +927,27 @@ Tcl_ScanCmd(dummy, interp, argc, argv) /* ARGSUSED */ int -Tcl_SourceCmd(dummy, interp, argc, argv) - ClientData dummy; /* Not used. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ +Tcl_SourceObjCmd(dummy, interp, objc, objv) + ClientData dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { - if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " fileName\"", (char *) NULL); + char *bytes; + int result; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "fileName"); return TCL_ERROR; } - return Tcl_EvalFile(interp, argv[1]); + + /* + * THIS FAILS IF THE OBJECT'S STRING REP CONTAINS A NULL. + */ + + bytes = Tcl_GetStringFromObj(objv[1], (int *) NULL); + result = Tcl_EvalFile(interp, bytes); + return result; } /* @@ -1088,7 +1029,7 @@ Tcl_SplitCmd(dummy, interp, argc, argv) /* *---------------------------------------------------------------------- * - * Tcl_StringCmd -- + * Tcl_StringObjCmd -- * * This procedure is invoked to process the "string" Tcl command. * See the user documentation for details on what it does. @@ -1104,312 +1045,338 @@ Tcl_SplitCmd(dummy, interp, argc, argv) /* ARGSUSED */ int -Tcl_StringCmd(dummy, interp, argc, argv) - ClientData dummy; /* Not used. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ +Tcl_StringObjCmd(dummy, interp, objc, objv) + ClientData dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { - size_t length; - register char *p; - int match, c, first; - int left = 0, right = 0; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " option arg ?arg ...?\"", (char *) NULL); + int index, first, left, right; + Tcl_Obj *resultPtr; + char *string1, *string2; + int length1, length2; + static char *options[] = { + "compare", "first", "index", "last", + "length", "match", "range", "tolower", + "toupper", "trim", "trimleft", "trimright", + "wordend", "wordstart", NULL + }; + enum options { + STR_COMPARE, STR_FIRST, STR_INDEX, STR_LAST, + STR_LENGTH, STR_MATCH, STR_RANGE, STR_TOLOWER, + STR_TOUPPER, STR_TRIM, STR_TRIMLEFT, STR_TRIMRIGHT, + STR_WORDEND, STR_WORDSTART + }; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?"); return TCL_ERROR; } - c = argv[1][0]; - length = strlen(argv[1]); - if ((c == 'c') && (strncmp(argv[1], "compare", length) == 0)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " compare string1 string2\"", (char *) NULL); - return TCL_ERROR; + + if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + + resultPtr = Tcl_GetObjResult(interp); + switch ((enum options) index) { + case STR_COMPARE: { + int match, length; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "string1 string2"); + return TCL_ERROR; + } + + string1 = Tcl_GetStringFromObj(objv[2], &length1); + string2 = Tcl_GetStringFromObj(objv[3], &length2); + + length = (length1 < length2) ? length1 : length2; + match = memcmp(string1, string2, (unsigned) length); + if (match == 0) { + match = length1 - length2; + } + Tcl_SetIntObj(resultPtr, (match > 0) ? 1 : (match < 0) ? -1 : 0); + break; } - match = strcmp(argv[2], argv[3]); - if (match > 0) { - interp->result = "1"; - } else if (match < 0) { - interp->result = "-1"; - } else { - interp->result = "0"; + case STR_FIRST: { + first = 1; + goto firstlast; } - return TCL_OK; - } else if ((c == 'f') && (strncmp(argv[1], "first", length) == 0)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " first string1 string2\"", (char *) NULL); - return TCL_ERROR; + case STR_INDEX: { + int index; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "string charIndex"); + return TCL_ERROR; + } + + string1 = Tcl_GetStringFromObj(objv[2], &length1); + if (Tcl_GetIntFromObj(interp, objv[3], &index) != TCL_OK) { + return TCL_ERROR; + } + if ((index >= 0) && (index < length1)) { + Tcl_SetStringObj(resultPtr, string1 + index, 1); + } + break; } - first = 1; + case STR_LAST: { + char *p, *end; + int match; - firstLast: - match = -1; - c = *argv[2]; - length = strlen(argv[2]); - for (p = argv[3]; *p != 0; p++) { - if (*p != c) { - continue; + first = 0; + + firstlast: + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "string1 string2"); + return TCL_ERROR; } - if (strncmp(argv[2], p, length) == 0) { - match = p-argv[3]; - if (first) { - break; + + string1 = Tcl_GetStringFromObj(objv[2], &length1); + string2 = Tcl_GetStringFromObj(objv[3], &length2); + match = -1; + end = string2 + length2 - length1 + 1; + for (p = string2; p < end; p++) { + if (memcmp(string1, p, (unsigned) length1) == 0) { + match = p - string2; + if (first) { + break; + } } } + Tcl_SetIntObj(resultPtr, match); + break; } - sprintf(interp->result, "%d", match); - return TCL_OK; - } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0)) { - int index; + case STR_LENGTH: { + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "string"); + return TCL_ERROR; + } - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " index string charIndex\"", (char *) NULL); - return TCL_ERROR; - } - if (Tcl_GetInt(interp, argv[3], &index) != TCL_OK) { - return TCL_ERROR; - } - if ((index >= 0) && (index < (int) strlen(argv[2]))) { - interp->result[0] = argv[2][index]; - interp->result[1] = 0; - } - return TCL_OK; - } else if ((c == 'l') && (strncmp(argv[1], "last", length) == 0) - && (length >= 2)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " last string1 string2\"", (char *) NULL); - return TCL_ERROR; - } - first = 0; - goto firstLast; - } else if ((c == 'l') && (strncmp(argv[1], "length", length) == 0) - && (length >= 2)) { - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " length string\"", (char *) NULL); - return TCL_ERROR; - } - sprintf(interp->result, "%d", strlen(argv[2])); - return TCL_OK; - } else if ((c == 'm') && (strncmp(argv[1], "match", length) == 0)) { - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " match pattern string\"", (char *) NULL); - return TCL_ERROR; - } - if (Tcl_StringMatch(argv[3], argv[2]) != 0) { - interp->result = "1"; - } else { - interp->result = "0"; + (void) Tcl_GetStringFromObj(objv[2], &length1); + Tcl_SetIntObj(resultPtr, length1); + break; } - return TCL_OK; - } else if ((c == 'r') && (strncmp(argv[1], "range", length) == 0)) { - int first, last, stringLength; + case STR_MATCH: { + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "pattern string"); + return TCL_ERROR; + } - if (argc != 5) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " range string first last\"", (char *) NULL); - return TCL_ERROR; - } - stringLength = strlen(argv[2]); - if (Tcl_GetInt(interp, argv[3], &first) != TCL_OK) { - return TCL_ERROR; + string1 = Tcl_GetStringFromObj(objv[2], &length1); + string2 = Tcl_GetStringFromObj(objv[3], &length2); + Tcl_SetBooleanObj(resultPtr, Tcl_StringMatch(string2, string1)); + break; } - if ((*argv[4] == 'e') - && (strncmp(argv[4], "end", strlen(argv[4])) == 0)) { - last = stringLength-1; - } else { - if (Tcl_GetInt(interp, argv[4], &last) != TCL_OK) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, - "expected integer or \"end\" but got \"", - argv[4], "\"", (char *) NULL); + case STR_RANGE: { + int first, last; + + if (objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "string first last"); return TCL_ERROR; } - } - if (first < 0) { - first = 0; - } - if (last >= stringLength) { - last = stringLength-1; - } - if (last >= first) { - char saved, *p; - p = argv[2] + last + 1; - saved = *p; - *p = 0; - Tcl_SetResult(interp, argv[2] + first, TCL_VOLATILE); - *p = saved; + string1 = Tcl_GetStringFromObj(objv[2], &length1); + if (TclGetIntForIndex(interp, objv[3], length1 - 1, + &first) != TCL_OK) { + return TCL_ERROR; + } + if (TclGetIntForIndex(interp, objv[4], length1 - 1, + &last) != TCL_OK) { + return TCL_ERROR; + } + if (first < 0) { + first = 0; + } + if (last >= length1 - 1) { + last = length1 - 1; + } + if (last >= first) { + Tcl_SetStringObj(resultPtr, string1 + first, last - first + 1); + } + break; } - return TCL_OK; - } else if ((c == 't') && (strncmp(argv[1], "tolower", length) == 0) - && (length >= 3)) { - register char *p; + case STR_TOLOWER: { + char *p, *end; - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " tolower string\"", (char *) NULL); - return TCL_ERROR; - } - Tcl_SetResult(interp, argv[2], TCL_VOLATILE); - for (p = interp->result; *p != 0; p++) { - if (isupper(UCHAR(*p))) { - *p = (char)tolower(UCHAR(*p)); + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "string"); + return TCL_ERROR; } - } - return TCL_OK; - } else if ((c == 't') && (strncmp(argv[1], "toupper", length) == 0) - && (length >= 3)) { - register char *p; - if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " toupper string\"", (char *) NULL); - return TCL_ERROR; - } - Tcl_SetResult(interp, argv[2], TCL_VOLATILE); - for (p = interp->result; *p != 0; p++) { - if (islower(UCHAR(*p))) { - *p = (char) toupper(UCHAR(*p)); + string1 = Tcl_GetStringFromObj(objv[2], &length1); + + /* + * Since I know resultPtr is not a shared object, I can reach + * in and diddle the bytes in its string rep to convert them in + * place to lower case. + */ + + Tcl_SetStringObj(resultPtr, string1, length1); + string1 = Tcl_GetStringFromObj(resultPtr, &length1); + end = string1 + length1; + for (p = string1; p < end; p++) { + if (isupper(UCHAR(*p))) { + *p = (char) tolower(UCHAR(*p)); + } } + break; } - return TCL_OK; - } else if ((c == 't') && (strncmp(argv[1], "trim", length) == 0) - && (length == 4)) { - char *trimChars; - register char *p, *checkPtr; - - left = right = 1; - - trim: - if (argc == 4) { - trimChars = argv[3]; - } else if (argc == 3) { - trimChars = " \t\n\r"; - } else { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " ", argv[1], " string ?chars?\"", (char *) NULL); - return TCL_ERROR; + case STR_TOUPPER: { + char *p, *end; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "string"); + return TCL_ERROR; + } + + string1 = Tcl_GetStringFromObj(objv[2], &length1); + + /* + * Since I know resultPtr is not a shared object, I can reach + * in and diddle the bytes in its string rep to convert them in + * place to upper case. + */ + + Tcl_SetStringObj(resultPtr, string1, length1); + string1 = Tcl_GetStringFromObj(resultPtr, &length1); + end = string1 + length1; + for (p = string1; p < end; p++) { + if (islower(UCHAR(*p))) { + *p = (char) toupper(UCHAR(*p)); + } + } + break; } - p = argv[2]; - if (left) { - for (c = *p; c != 0; p++, c = *p) { - for (checkPtr = trimChars; *checkPtr != c; checkPtr++) { - if (*checkPtr == 0) { - goto doneLeft; + case STR_TRIM: { + char ch; + char *p, *end, *check, *checkEnd; + + left = 1; + right = 1; + + trim: + if (objc == 4) { + string2 = Tcl_GetStringFromObj(objv[3], &length2); + } else if (objc == 3) { + string2 = " \t\n\r"; + length2 = strlen(string2); + } else { + Tcl_WrongNumArgs(interp, 2, objv, "string ?chars?"); + return TCL_ERROR; + } + string1 = Tcl_GetStringFromObj(objv[2], &length1); + checkEnd = string2 + length2; + + if (left) { + end = string1 + length1; + for (p = string1; p < end; p++) { + ch = *p; + for (check = string2; ; check++) { + if (check >= checkEnd) { + p = end; + break; + } + if (ch == *check) { + length1--; + string1++; + break; + } } } } - } - doneLeft: - Tcl_SetResult(interp, p, TCL_VOLATILE); - if (right) { - char *donePtr; - - p = interp->result + strlen(interp->result) - 1; - donePtr = &interp->result[-1]; - for (c = *p; p != donePtr; p--, c = *p) { - for (checkPtr = trimChars; *checkPtr != c; checkPtr++) { - if (*checkPtr == 0) { - goto doneRight; + if (right) { + end = string1; + for (p = string1 + length1; p > end; ) { + p--; + ch = *p; + for (check = string2; ; check++) { + if (check >= checkEnd) { + p = end; + break; + } + if (ch == *check) { + length1--; + break; + } } } } - doneRight: - p[1] = 0; - } - return TCL_OK; - } else if ((c == 't') && (strncmp(argv[1], "trimleft", length) == 0) - && (length > 4)) { - left = 1; - argv[1] = "trimleft"; - goto trim; - } else if ((c == 't') && (strncmp(argv[1], "trimright", length) == 0) - && (length > 4)) { - right = 1; - argv[1] = "trimright"; - goto trim; - } else if ((c == 'w') && (strncmp(argv[1], "wordend", length) == 0) - && (length > 4)) { - int length, index, cur; - char *string; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " ", argv[1], " string index\"", (char *) NULL); - return TCL_ERROR; - } - string = argv[2]; - if (Tcl_GetInt(interp, argv[3], &index) != TCL_OK) { - return TCL_ERROR; - } - length = strlen(argv[2]); - if (index < 0) { - index = 0; - } - if (index >= length) { - cur = length; - goto wordendDone; + Tcl_SetStringObj(resultPtr, string1, length1); + break; } - for (cur = index ; cur < length; cur++) { - c = UCHAR(string[cur]); - if (!isalnum(c) && (c != '_')) { - break; + case STR_TRIMLEFT: { + left = 1; + right = 0; + goto trim; + } + case STR_TRIMRIGHT: { + left = 0; + right = 1; + goto trim; + } + case STR_WORDEND: { + int cur, c; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "string index"); + return TCL_ERROR; } + + string1 = Tcl_GetStringFromObj(objv[2], &length1); + if (Tcl_GetIntFromObj(interp, objv[3], &index) != TCL_OK) { + return TCL_ERROR; + } + if (index < 0) { + index = 0; + } + cur = length1; + if (index < length1) { + for (cur = index; cur < length1; cur++) { + c = UCHAR(string1[cur]); + if (!isalnum(c) && (c != '_')) { + break; + } + } + if (cur == index) { + cur = index + 1; + } + } + Tcl_SetIntObj(resultPtr, cur); + break; } - if (cur == index) { - cur = index+1; - } - wordendDone: - sprintf(interp->result, "%d", cur); - return TCL_OK; - } else if ((c == 'w') && (strncmp(argv[1], "wordstart", length) == 0) - && (length > 4)) { - int length, index, cur; - char *string; - - if (argc != 4) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " ", argv[1], " string index\"", (char *) NULL); - return TCL_ERROR; - } - string = argv[2]; - if (Tcl_GetInt(interp, argv[3], &index) != TCL_OK) { - return TCL_ERROR; - } - length = strlen(argv[2]); - if (index >= length) { - index = length-1; - } - if (index <= 0) { + case STR_WORDSTART: { + int cur, c; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "string index"); + return TCL_ERROR; + } + + string1 = Tcl_GetStringFromObj(objv[2], &length1); + if (Tcl_GetIntFromObj(interp, objv[3], &index) != TCL_OK) { + return TCL_ERROR; + } + if (index >= length1) { + index = length1 - 1; + } cur = 0; - goto wordstartDone; - } - for (cur = index ; cur >= 0; cur--) { - c = UCHAR(string[cur]); - if (!isalnum(c) && (c != '_')) { - break; + if (index > 0) { + for (cur = index; cur >= 0; cur--) { + c = UCHAR(string1[cur]); + if (!isalnum(c) && (c != '_')) { + break; + } + } + if (cur != index) { + cur += 1; + } } + Tcl_SetIntObj(resultPtr, cur); + break; } - if (cur != index) { - cur += 1; - } - wordstartDone: - sprintf(interp->result, "%d", cur); - return TCL_OK; - } else { - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": should be compare, first, index, last, length, match, ", - "range, tolower, toupper, trim, trimleft, trimright, ", - "wordend, or wordstart", (char *) NULL); - return TCL_ERROR; } + return TCL_OK; } /* @@ -1532,7 +1499,7 @@ Tcl_SubstCmd(dummy, interp, argc, argv) Tcl_DStringFree(&result); return code; } - old = p = iPtr->termPtr+1; + old = p = (p+1 + iPtr->termOffset+1); Tcl_DStringAppend(&result, iPtr->result, -1); Tcl_ResetResult(interp); } else { @@ -1555,13 +1522,13 @@ Tcl_SubstCmd(dummy, interp, argc, argv) /* *---------------------------------------------------------------------- * - * Tcl_SwitchCmd -- + * Tcl_SwitchObjCmd -- * - * This procedure is invoked to process the "switch" Tcl command. - * See the user documentation for details on what it does. + * This object-based procedure is invoked to process the "switch" Tcl + * command. See the user documentation for details on what it does. * * Results: - * A standard Tcl result. + * A standard Tcl object result. * * Side effects: * See the user documentation. @@ -1571,96 +1538,121 @@ Tcl_SubstCmd(dummy, interp, argc, argv) /* ARGSUSED */ int -Tcl_SwitchCmd(dummy, interp, argc, argv) - ClientData dummy; /* Not used. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ +Tcl_SwitchObjCmd(dummy, interp, objc, objv) + ClientData dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { #define EXACT 0 #define GLOB 1 #define REGEXP 2 - int i, code, mode, matched; - int body; - char *string; - int switchArgc, splitArgs; - char **switchArgv; - - switchArgc = argc-1; - switchArgv = argv+1; + int switchObjc, index; + Tcl_Obj *CONST *switchObjv; + Tcl_Obj *patternObj, *bodyObj; + char *string, *pattern, *body; + int splitObjs, length, patternLen, i, code, mode, matched, bodyIdx; + static char *switches[] = + {"-exact", "-glob", "-regexp", "--", (char *) NULL}; + + switchObjc = objc-1; + switchObjv = objv+1; mode = EXACT; - while ((switchArgc > 0) && (*switchArgv[0] == '-')) { - if (strcmp(*switchArgv, "-exact") == 0) { - mode = EXACT; - } else if (strcmp(*switchArgv, "-glob") == 0) { - mode = GLOB; - } else if (strcmp(*switchArgv, "-regexp") == 0) { - mode = REGEXP; - } else if (strcmp(*switchArgv, "--") == 0) { - switchArgc--; - switchArgv++; - break; - } else { - Tcl_AppendResult(interp, "bad option \"", switchArgv[0], - "\": should be -exact, -glob, -regexp, or --", - (char *) NULL); + + string = Tcl_GetStringFromObj(switchObjv[0], &length); + while ((switchObjc > 0) && (*string == '-')) { + if (Tcl_GetIndexFromObj(interp, switchObjv[0], switches, + "option", 0, &index) != TCL_OK) { return TCL_ERROR; } - switchArgc--; - switchArgv++; + switch (index) { + case 0: /* -exact */ + mode = EXACT; + break; + case 1: /* -glob */ + mode = GLOB; + break; + case 2: /* -regexp */ + mode = REGEXP; + break; + case 3: /* -- */ + switchObjc--; + switchObjv++; + goto doneWithSwitches; + } + switchObjc--; + switchObjv++; + string = Tcl_GetStringFromObj(switchObjv[0], &length); } - if (switchArgc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " ?switches? string pattern body ... ?default body?\"", - (char *) NULL); + + doneWithSwitches: + if (switchObjc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, + "?switches? string pattern body ... ?default body?"); return TCL_ERROR; } - string = *switchArgv; - switchArgc--; - switchArgv++; + + string = Tcl_GetStringFromObj(switchObjv[0], &length); + switchObjc--; + switchObjv++; /* * If all of the pattern/command pairs are lumped into a single * argument, split them out again. */ - splitArgs = 0; - if (switchArgc == 1) { - code = Tcl_SplitList(interp, switchArgv[0], &switchArgc, &switchArgv); + splitObjs = 0; + if (switchObjc == 1) { + code = Tcl_ListObjLength(interp, switchObjv[0], &switchObjc); if (code != TCL_OK) { return code; } - splitArgs = 1; + splitObjs = 1; } - for (i = 0; i < switchArgc; i += 2) { - if (i == (switchArgc-1)) { - interp->result = "extra switch pattern with no body"; + for (i = 0; i < switchObjc; i += 2) { + if (i == (switchObjc-1)) { + Tcl_ResetResult(interp); + Tcl_AppendToObj(Tcl_GetObjResult(interp), + "extra switch pattern with no body", -1); code = TCL_ERROR; - goto cleanup; + goto done; } /* * See if the pattern matches the string. */ + if (splitObjs) { + code = Tcl_ListObjIndex(interp, switchObjv[0], i, &patternObj); + if (code != TCL_OK) { + return code; + } + pattern = Tcl_GetStringFromObj(patternObj, &patternLen); + } else { + pattern = Tcl_GetStringFromObj(switchObjv[i], &patternLen); + } + matched = 0; - if ((*switchArgv[i] == 'd') && (i == switchArgc-2) - && (strcmp(switchArgv[i], "default") == 0)) { + if ((*pattern == 'd') && (i == switchObjc-2) + && (strcmp(pattern, "default") == 0)) { matched = 1; } else { + /* + * THIS FAILS IF AN OBJECT'S STRING REP HAS A NULL. + */ switch (mode) { case EXACT: - matched = (strcmp(string, switchArgv[i]) == 0); + matched = (strcmp(string, pattern) == 0); break; case GLOB: - matched = Tcl_StringMatch(string, switchArgv[i]); + matched = Tcl_StringMatch(string, pattern); break; case REGEXP: - matched = Tcl_RegExpMatch(interp, string, switchArgv[i]); + matched = Tcl_RegExpMatch(interp, string, pattern); if (matched < 0) { code = TCL_ERROR; - goto cleanup; + goto done; } break; } @@ -1670,29 +1662,44 @@ Tcl_SwitchCmd(dummy, interp, argc, argv) } /* - * We've got a match. Find a body to execute, skipping bodies + * We've got a match. Find a body to execute, skipping bodies * that are "-". */ - for (body = i+1; ; body += 2) { - if (body >= switchArgc) { - Tcl_AppendResult(interp, "no body specified for pattern \"", - switchArgv[i], "\"", (char *) NULL); + for (bodyIdx = i+1; ; bodyIdx += 2) { + if (bodyIdx >= switchObjc) { + Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), + "no body specified for pattern \"", pattern, + "\"", (char *) NULL); code = TCL_ERROR; - goto cleanup; + goto done; + } + + if (splitObjs) { + code = Tcl_ListObjIndex(interp, switchObjv[0], bodyIdx, + &bodyObj); + if (code != TCL_OK) { + return code; + } + } else { + bodyObj = switchObjv[bodyIdx]; } - if ((switchArgv[body][0] != '-') || (switchArgv[body][1] != 0)) { + /* + * THIS FAILS IF AN OBJECT'S STRING REP HAS A NULL. + */ + body = Tcl_GetStringFromObj(bodyObj, &length); + if ((length != 1) || (body[0] != '-')) { break; } } - code = Tcl_Eval(interp, switchArgv[body]); + code = Tcl_EvalObj(interp, bodyObj); if (code == TCL_ERROR) { char msg[100]; - sprintf(msg, "\n (\"%.50s\" arm line %d)", switchArgv[i], + sprintf(msg, "\n (\"%.50s\" arm line %d)", pattern, interp->errorLine); - Tcl_AddErrorInfo(interp, msg); + Tcl_AddObjErrorInfo(interp, msg, -1); } - goto cleanup; + goto done; } /* @@ -1701,23 +1708,23 @@ Tcl_SwitchCmd(dummy, interp, argc, argv) code = TCL_OK; - cleanup: - if (splitArgs) { - ckfree((char *) switchArgv); - } + done: return code; +#undef EXACT +#undef GLOB +#undef REGEXP } /* *---------------------------------------------------------------------- * - * Tcl_TimeCmd -- + * Tcl_TimeObjCmd -- * - * This procedure is invoked to process the "time" Tcl command. - * See the user documentation for details on what it does. + * This object-based procedure is invoked to process the "time" Tcl + * command. See the user documentation for details on what it does. * * Results: - * A standard Tcl result. + * A standard Tcl object result. * * Side effects: * See the user documentation. @@ -1727,45 +1734,48 @@ Tcl_SwitchCmd(dummy, interp, argc, argv) /* ARGSUSED */ int -Tcl_TimeCmd(dummy, interp, argc, argv) - ClientData dummy; /* Not used. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ +Tcl_TimeObjCmd(dummy, interp, objc, objv) + ClientData dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of arguments. */ + Tcl_Obj *CONST objv[]; /* Argument objects. */ { - int count, i, result; - double timePer; + register Tcl_Obj *objPtr; + register int i, result; + int count; + double totalMicroSec; Tcl_Time start, stop; + char buf[100]; - if (argc == 2) { + if (objc == 2) { count = 1; - } else if (argc == 3) { - if (Tcl_GetInt(interp, argv[2], &count) != TCL_OK) { - return TCL_ERROR; + } else if (objc == 3) { + result = Tcl_GetIntFromObj(interp, objv[2], &count); + if (result != TCL_OK) { + return result; } } else { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " command ?count?\"", (char *) NULL); + Tcl_WrongNumArgs(interp, 1, objv, "command ?count?"); return TCL_ERROR; } + + objPtr = objv[1]; + i = count; TclpGetTime(&start); - for (i = count ; i > 0; i--) { - result = Tcl_Eval(interp, argv[1]); + while (i-- > 0) { + result = Tcl_EvalObj(interp, objPtr); if (result != TCL_OK) { - if (result == TCL_ERROR) { - char msg[60]; - sprintf(msg, "\n (\"time\" body line %d)", - interp->errorLine); - Tcl_AddErrorInfo(interp, msg); - } return result; } } TclpGetTime(&stop); - timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec); + + totalMicroSec = + (stop.sec - start.sec)*1000000 + (stop.usec - start.usec); + sprintf(buf, "%.0f microseconds per iteration", + ((count <= 0) ? 0 : totalMicroSec/count)); Tcl_ResetResult(interp); - sprintf(interp->result, "%.0f microseconds per iteration", - (count <= 0) ? 0 : timePer/count); + Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1); return TCL_OK; } @@ -1975,11 +1985,13 @@ TraceVarProc(clientData, interp, name1, name2, flags) int flags; /* OR-ed bits giving operation and other * information. */ { + Interp *iPtr = (Interp *) interp; TraceVarInfo *tvarPtr = (TraceVarInfo *) clientData; char *result; int code; Interp dummy; Tcl_DString cmd; + Tcl_Obj *saveObjPtr, *oldObjResultPtr; result = NULL; if (tvarPtr->errMsg != NULL) { @@ -2011,29 +2023,54 @@ TraceVarProc(clientData, interp, name1, name2, flags) } /* - * Execute the command. Be careful to save and restore the - * result from the interpreter used for the command. + * Execute the command. Be careful to save and restore both the + * string and object results from the interpreter used for + * the command. We discard any object result the command returns. */ + dummy.objResultPtr = Tcl_NewObj(); + Tcl_IncrRefCount(dummy.objResultPtr); if (interp->freeProc == 0) { dummy.freeProc = (Tcl_FreeProc *) 0; dummy.result = ""; - Tcl_SetResult((Tcl_Interp *) &dummy, interp->result, TCL_VOLATILE); + Tcl_SetResult((Tcl_Interp *) &dummy, interp->result, + TCL_VOLATILE); } else { dummy.freeProc = interp->freeProc; dummy.result = interp->result; interp->freeProc = (Tcl_FreeProc *) 0; } + + saveObjPtr = Tcl_GetObjResult(interp); + Tcl_IncrRefCount(saveObjPtr); + code = Tcl_Eval(interp, Tcl_DStringValue(&cmd)); - Tcl_DStringFree(&cmd); - if (code != TCL_OK) { - tvarPtr->errMsg = (char *) ckalloc((unsigned) (strlen(interp->result) + 1)); + if (code != TCL_OK) { /* copy error msg to result */ + tvarPtr->errMsg = (char *) + ckalloc((unsigned) (strlen(interp->result) + 1)); strcpy(tvarPtr->errMsg, interp->result); result = tvarPtr->errMsg; - Tcl_ResetResult(interp); /* Must clear error state. */ + Tcl_ResetResult(interp); /* must clear error state. */ } + + /* + * Restore the interpreter's string result. + */ + Tcl_SetResult(interp, dummy.result, (dummy.freeProc == 0) ? TCL_VOLATILE : dummy.freeProc); + + /* + * Restore the interpreter's object result from saveObjPtr. + */ + + oldObjResultPtr = iPtr->objResultPtr; + iPtr->objResultPtr = saveObjPtr; /* was incremented above */ + TclDecrRefCount(oldObjResultPtr); + + Tcl_DecrRefCount(dummy.objResultPtr); + dummy.objResultPtr = NULL; + Tcl_DStringFree(&cmd); } if (flags & TCL_TRACE_DESTROYED) { result = NULL; @@ -2050,58 +2087,63 @@ TraceVarProc(clientData, interp, name1, name2, flags) * * Tcl_WhileCmd -- * - * This procedure is invoked to process the "while" Tcl command. - * See the user documentation for details on what it does. + * This procedure is invoked to process the "while" Tcl command. + * See the user documentation for details on what it does. + * + * With the bytecode compiler, this procedure is only called when + * a command name is computed at runtime, and is "while" or the name + * to which "while" was renamed: e.g., "set z while; $z {$i<100} {}" * * Results: - * A standard Tcl result. + * A standard Tcl result. * * Side effects: - * See the user documentation. + * See the user documentation. * *---------------------------------------------------------------------- */ - /* ARGSUSED */ + /* ARGSUSED */ int Tcl_WhileCmd(dummy, interp, argc, argv) - ClientData dummy; /* Not used. */ - Tcl_Interp *interp; /* Current interpreter. */ - int argc; /* Number of arguments. */ - char **argv; /* Argument strings. */ + ClientData dummy; /* Not used. */ + Tcl_Interp *interp; /* Current interpreter. */ + int argc; /* Number of arguments. */ + char **argv; /* Argument strings. */ { int result, value; if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " test command\"", (char *) NULL); - return TCL_ERROR; + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " test command\"", (char *) NULL); + return TCL_ERROR; } while (1) { - result = Tcl_ExprBoolean(interp, argv[1], &value); - if (result != TCL_OK) { - return result; - } - if (!value) { - break; - } - result = Tcl_Eval(interp, argv[2]); - if ((result != TCL_OK) && (result != TCL_CONTINUE)) { - if (result == TCL_ERROR) { - char msg[60]; - sprintf(msg, "\n (\"while\" body line %d)", - interp->errorLine); - Tcl_AddErrorInfo(interp, msg); - } - break; - } + result = Tcl_ExprBoolean(interp, argv[1], &value); + if (result != TCL_OK) { + return result; + } + if (!value) { + break; + } + result = Tcl_Eval(interp, argv[2]); + if ((result != TCL_OK) && (result != TCL_CONTINUE)) { + if (result == TCL_ERROR) { + char msg[60]; + sprintf(msg, "\n (\"while\" body line %d)", + interp->errorLine); + Tcl_AddErrorInfo(interp, msg); + } + break; + } } if (result == TCL_BREAK) { - result = TCL_OK; + result = TCL_OK; } if (result == TCL_OK) { - Tcl_ResetResult(interp); + Tcl_ResetResult(interp); } return result; } + |