Index: tclCmdMZ.c =================================================================== RCS file: /cvsroot/tcl/tcl/generic/tclCmdMZ.c,v retrieving revision 1.39 diff -u -r1.39 tclCmdMZ.c --- tclCmdMZ.c 2001/06/12 08:07:37 1.39 +++ tclCmdMZ.c 2001/06/13 22:22:08 @@ -2240,6 +2240,11 @@ return TCL_OK; } +#define TCL_SUBST_COMMANDS 0x01 +#define TCL_SUBST_VARIABLES 0x02 +#define TCL_SUBST_BACKSLASHES 0x04 +#define TCL_SUBST_ALL 0x07 + /* *---------------------------------------------------------------------- * @@ -2273,42 +2278,34 @@ enum substOptions { SUBST_NOBACKSLASHES, SUBST_NOCOMMANDS, SUBST_NOVARS }; - Interp *iPtr = (Interp *) interp; - Tcl_DString result; - char *p, *old, *value; - int optionIndex, code, count, doVars, doCmds, doBackslashes, i; + Tcl_Obj *result; + int optionIndex, i, flags = TCL_SUBST_ALL; /* * Parse command-line options. */ - doVars = doCmds = doBackslashes = 1; for (i = 1; i < (objc-1); i++) { p = Tcl_GetString(objv[i]); if (*p != '-') { break; } if (Tcl_GetIndexFromObj(interp, objv[i], substOptions, - "switch", 0, &optionIndex) != TCL_OK) { - + "switch", 0, &optionIndex) != TCL_OK) { return TCL_ERROR; } switch (optionIndex) { - case SUBST_NOBACKSLASHES: { - doBackslashes = 0; - break; - } - case SUBST_NOCOMMANDS: { - doCmds = 0; - break; - } - case SUBST_NOVARS: { - doVars = 0; - break; - } - default: { - panic("Tcl_SubstObjCmd: bad option index to SubstOptions"); - } + case SUBST_NOBACKSLASHES: + flags &= ~TCL_SUBST_BACKSLASHES; + break; + case SUBST_NOCOMMANDS: + flags &= ~TCL_SUBST_COMMANDS; + break; + case SUBST_NOVARS: + flags &= ~TCL_SUBST_VARIABLES; + break; + default: + panic("Tcl_SubstObjCmd: bad option index to SubstOptions"); } } if (i != (objc-1)) { @@ -2317,24 +2314,60 @@ return TCL_ERROR; } - /* - * Scan through the string one character at a time, performing - * command, variable, and backslash substitutions. - */ + result = Tcl_SubstObj(interp, objv[i], flags); + if (result == NULL) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, result); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_SubstObj -- + * + * This function implements the main functionality of the "subst" + * Tcl command. It scans through the supplied string one + * character at a time, performing command, variable and backslash + * substitutions as it goes. This command is largely based on an + * implementation by Andrew Payne. + * + * Results: + * A Tcl_Obj* which contains the substituted string, or a NULL to + * indicate an error occurred (when a message will be left in the + * interpreter's result.) The reference count of the object + * returned will be zero. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +Tcl_Obj * +Tcl_SubstObj(interp, objPtr, flags) + Tcl_Interp *interp; /* Current interpreter. */ + Tcl_Obj *objPtr; /* String to substitute. */ + int flags; /* What substitutions to apply. */ +{ + Interp *iPtr = (Interp *) interp; + Tcl_Obj *result = Tcl_NewObj(); + char *old, *p; - Tcl_DStringInit(&result); - old = p = Tcl_GetString(objv[i]); + old = p = Tcl_GetString(objPtr); while (*p != 0) { switch (*p) { case '\\': - if (doBackslashes) { + if (flags & TCL_SUBST_BACKSLASHES) { char buf[TCL_UTF_MAX]; + int count; if (p != old) { - Tcl_DStringAppend(&result, old, p-old); + Tcl_AppendToObj(result, old, p-old); } - Tcl_DStringAppend(&result, buf, - Tcl_UtfBackslash(p, &count, buf)); + Tcl_AppendToObj(result, buf, + Tcl_UtfBackslash(p, &count, buf)); p += count; old = p; } else { @@ -2343,16 +2376,17 @@ break; case '$': - if (doVars) { + if (flags & TCL_SUBST_VARIABLES) { + char *value; + if (p != old) { - Tcl_DStringAppend(&result, old, p-old); + Tcl_AppendToObj(result, old, p-old); } value = Tcl_ParseVar(interp, p, &p); if (value == NULL) { - Tcl_DStringFree(&result); - return TCL_ERROR; + goto errorExit; } - Tcl_DStringAppend(&result, value, -1); + Tcl_AppendToObj(result, value, -1); old = p; } else { p++; @@ -2360,19 +2394,26 @@ break; case '[': - if (doCmds) { + if (flags & TCL_SUBST_COMMANDS) { + int code; + if (p != old) { - Tcl_DStringAppend(&result, old, p-old); + Tcl_AppendToObj(result, old, p-old); } iPtr->evalFlags = TCL_BRACKET_TERM; code = Tcl_Eval(interp, p+1); if (code == TCL_ERROR) { - Tcl_DStringFree(&result); - return code; + goto errorExit; } old = p = (p+1 + iPtr->termOffset+1); - Tcl_DStringAppend(&result, iPtr->result, -1); + Tcl_AppendObjToObj(result, Tcl_GetObjResult(interp)); Tcl_ResetResult(interp); + /* + * NOTE: NEW BEHAVIOUR! DOCUMENT... + */ + if (code == TCL_BREAK) { + return result; + } } else { p++; } @@ -2383,11 +2424,16 @@ break; } } + if (p != old) { - Tcl_DStringAppend(&result, old, p-old); + Tcl_AppendToObj(result, old, p-old); } - Tcl_DStringResult(interp, &result); - return TCL_OK; + + return result; + + errorExit: + Tcl_DecrRefCount(result); + return NULL; } /*