diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2003-07-04 10:30:27 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2003-07-04 10:30:27 (GMT) |
commit | 81b15600f5cee6d721bd157eef9347bfab1521fe (patch) | |
tree | a0d2ff8e14d59d5e8552430f44e0ceee0837acaa /generic | |
parent | 9ef344f3f4c962cb0710eabd4bdbca23381e8088 (diff) | |
download | tcl-81b15600f5cee6d721bd157eef9347bfab1521fe.zip tcl-81b15600f5cee6d721bd157eef9347bfab1521fe.tar.gz tcl-81b15600f5cee6d721bd157eef9347bfab1521fe.tar.bz2 |
[string map] now can take dictionaries for maps but the condition for doing so
is deeply tricky. [Bug 759936]
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tclCmdMZ.c | 78 |
1 files changed, 60 insertions, 18 deletions
diff --git a/generic/tclCmdMZ.c b/generic/tclCmdMZ.c index 9c212ab..33fc59f 100644 --- a/generic/tclCmdMZ.c +++ b/generic/tclCmdMZ.c @@ -14,7 +14,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCmdMZ.c,v 1.92 2003/06/25 23:02:11 dkf Exp $ + * RCS: @(#) $Id: tclCmdMZ.c,v 1.93 2003/07/04 10:30:27 dkf Exp $ */ #include "tclInt.h" @@ -1811,11 +1811,11 @@ Tcl_StringObjCmd(dummy, interp, objc, objv) break; } case STR_MAP: { - int mapElemc, nocase = 0; + int mapElemc, nocase = 0, mapWithDict = 0; Tcl_Obj **mapElemv; Tcl_UniChar *ustring1, *ustring2, *p, *end; int (*strCmpFn)_ANSI_ARGS_((CONST Tcl_UniChar*, - CONST Tcl_UniChar*, unsigned long)); + CONST Tcl_UniChar*, unsigned long)); if (objc < 4 || objc > 5) { Tcl_WrongNumArgs(interp, 2, objv, "?-nocase? charMap string"); @@ -1829,28 +1829,64 @@ Tcl_StringObjCmd(dummy, interp, objc, objv) nocase = 1; } else { Tcl_AppendStringsToObj(resultPtr, "bad option \"", - string2, "\": must be -nocase", - (char *) NULL); + string2, "\": must be -nocase", (char *) NULL); return TCL_ERROR; } } - if (Tcl_ListObjGetElements(interp, objv[objc-2], &mapElemc, - &mapElemv) != TCL_OK) { - return TCL_ERROR; - } - if (mapElemc == 0) { + /* + * This test is tricky, but has to be that way or you get + * other strange inconsistencies (see test string-10.20 + * for illustration why!) + */ + if (objv[objc-2]->typePtr == &tclDictType && + objv[objc-2]->bytes == NULL) { + int i, done; + Tcl_DictSearch search; + /* - * empty charMap, just return whatever string was given + * We know the type exactly, so all dict operations + * will succeed for sure. This shortens this code + * quite a bit. */ - Tcl_SetObjResult(interp, objv[objc-1]); - return TCL_OK; - } else if (mapElemc & 1) { + Tcl_DictObjSize(interp, objv[objc-2], &mapElemc); + if (mapElemc == 0) { + /* + * empty charMap, just return whatever string was given + */ + Tcl_SetObjResult(interp, objv[objc-1]); + return TCL_OK; + } + mapElemc *= 2; + mapWithDict = 1; /* - * The charMap must be an even number of key/value items + * Copy the dictionary out into an array; that's the + * easiest way to adapt this code... */ - Tcl_SetStringObj(resultPtr, "char map list unbalanced", -1); - return TCL_ERROR; + mapElemv = (Tcl_Obj **) ckalloc(sizeof(Tcl_Obj *) * mapElemc); + Tcl_DictObjFirst(interp, objv[objc-2], &search, + mapElemv+0, mapElemv+1, &done); + for (i=2 ; i<mapElemc ; i+=2) { + Tcl_DictObjNext(&search, mapElemv+i, mapElemv+i+1, &done); + } + } else { + if (Tcl_ListObjGetElements(interp, objv[objc-2], + &mapElemc, &mapElemv) != TCL_OK) { + return TCL_ERROR; + } + if (mapElemc == 0) { + /* + * empty charMap, just return whatever string was given + */ + Tcl_SetObjResult(interp, objv[objc-1]); + return TCL_OK; + } else if (mapElemc & 1) { + /* + * The charMap must be an even number of key/value items + */ + Tcl_SetStringObj(resultPtr, "char map list unbalanced", -1); + return TCL_ERROR; + } } objc--; @@ -1859,6 +1895,9 @@ Tcl_StringObjCmd(dummy, interp, objc, objv) /* * Empty input string, just stop now */ + if (mapWithDict) { + ckfree((char *) mapElemv); + } break; } end = ustring1 + length1; @@ -1921,7 +1960,7 @@ Tcl_StringObjCmd(dummy, interp, objc, objv) mapLens = (int *) ckalloc((mapElemc * 2) * sizeof(int)); if (nocase) { u2lc = (Tcl_UniChar *) - ckalloc((mapElemc) * sizeof(Tcl_UniChar)); + ckalloc((mapElemc) * sizeof(Tcl_UniChar)); } for (index = 0; index < mapElemc; index++) { mapStrings[index] = Tcl_GetUnicodeFromObj(mapElemv[index], @@ -1978,6 +2017,9 @@ Tcl_StringObjCmd(dummy, interp, objc, objv) */ Tcl_AppendUnicodeToObj(resultPtr, p, ustring1 - p); } + if (mapWithDict) { + ckfree((char *) mapElemv); + } break; } case STR_MATCH: { |