From b98b08c0bcc1ff54563b161a36885df1bfba2a18 Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 3 May 2011 17:34:51 +0000 Subject: Tighten SetDictFromAny(). --- ChangeLog | 4 ++ generic/tclDictObj.c | 185 ++++++++++++++++++--------------------------------- generic/tclUtil.c | 2 +- 3 files changed, 69 insertions(+), 122 deletions(-) diff --git a/ChangeLog b/ChangeLog index f821704..fea3aa0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2011-05-03 Don Porter + + * generic/tclDictObj.c: Tighten SetDictFromAny(). + 2011-05-02 Don Porter * generic/tclCmdMZ.c: Revised TclFindElement() interface. The diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c index 8b44137..33fec57 100644 --- a/generic/tclDictObj.c +++ b/generic/tclDictObj.c @@ -556,14 +556,11 @@ SetDictFromAny( Tcl_Interp *interp, Tcl_Obj *objPtr) { - char *string, *s; - const char *elemStart, *nextElem; - int lenRemain, length, elemSize, result, isNew; - char *limit; /* Points just after string's last byte. */ - register const char *p; - register Tcl_Obj *keyPtr, *valuePtr; - Dict *dict; Tcl_HashEntry *hPtr; + int isNew, result; + Dict *dict = (Dict *) ckalloc(sizeof(Dict)); + + InitChainTable(dict); /* * Since lists and dictionaries have very closely-related string @@ -575,28 +572,15 @@ SetDictFromAny( int objc, i; Tcl_Obj **objv; - if (TclListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { - return TCL_ERROR; - } + /* Cannot fail, we already know the Tcl_ObjType is "list". */ + TclListObjGetElements(NULL, objPtr, &objc, &objv); if (objc & 1) { - if (interp != NULL) { - Tcl_SetResult(interp, "missing value to go with key", - TCL_STATIC); - } - return TCL_ERROR; + goto missingValue; } - /* - * Build the hash of key/value pairs. - */ - - dict = (Dict *) ckalloc(sizeof(Dict)); - InitChainTable(dict); for (i=0 ; i 0; - p = nextElem, lenRemain = (limit - nextElem)) { - int literal; - - result = TclFindElement(interp, p, lenRemain, - &elemStart, &nextElem, &elemSize, &literal); - if (result != TCL_OK) { - goto errorExit; - } - if (elemStart >= limit) { - break; - } - - /* - * Allocate a Tcl object for the element and initialize it from the - * "elemSize" bytes starting at "elemStart". - */ - - s = ckalloc((unsigned) elemSize + 1); - if (literal) { - memcpy(s, elemStart, (size_t) elemSize); - s[elemSize] = 0; - } else { - elemSize = TclCopyAndCollapse(elemSize, elemStart, s); - } - - TclNewObj(keyPtr); - keyPtr->bytes = s; - keyPtr->length = elemSize; - - p = nextElem; - lenRemain = (limit - nextElem); - if (lenRemain <= 0) { - goto missingKey; - } - - result = TclFindElement(interp, p, lenRemain, - &elemStart, &nextElem, &elemSize, &literal); - if (result != TCL_OK) { - TclDecrRefCount(keyPtr); - goto errorExit; - } - if (elemStart >= limit) { - goto missingKey; - } - - /* - * Allocate a Tcl object for the element and initialize it from the - * "elemSize" bytes starting at "elemStart". - */ - - s = ckalloc((unsigned) elemSize + 1); - if (literal) { - memcpy((void *) s, (void *) elemStart, (size_t) elemSize); - s[elemSize] = 0; - } else { - elemSize = TclCopyAndCollapse(elemSize, elemStart, s); - } + if (literal) { + TclNewStringObj(keyPtr, elemStart, elemSize); + } else { + /* Avoid double copy */ + TclNewObj(keyPtr); + keyPtr->bytes = ckalloc((unsigned) elemSize + 1); + keyPtr->length = TclCopyAndCollapse(elemSize, elemStart, + keyPtr->bytes); + } - TclNewObj(valuePtr); - valuePtr->bytes = s; - valuePtr->length = elemSize; + result = TclFindElement(interp, nextElem, (limit - nextElem), + &elemStart, &nextElem, &elemSize, &literal); + if (result != TCL_OK) { + TclDecrRefCount(keyPtr); + goto errorExit; + } - /* - * Store key and value in the hash table we're building. - */ + if (literal) { + TclNewStringObj(valuePtr, elemStart, elemSize); + } else { + /* Avoid double copy */ + TclNewObj(valuePtr); + valuePtr->bytes = ckalloc((unsigned) elemSize + 1); + valuePtr->length = TclCopyAndCollapse(elemSize, elemStart, + valuePtr->bytes); + } - hPtr = CreateChainEntry(dict, keyPtr, &isNew); - if (!isNew) { - Tcl_Obj *discardedValue = Tcl_GetHashValue(hPtr); + /* Store key and value in the hash table we're building. */ + hPtr = CreateChainEntry(dict, keyPtr, &isNew); + if (!isNew) { + Tcl_Obj *discardedValue = Tcl_GetHashValue(hPtr); - TclDecrRefCount(keyPtr); - TclDecrRefCount(discardedValue); + TclDecrRefCount(keyPtr); + TclDecrRefCount(discardedValue); + } + Tcl_SetHashValue(hPtr, valuePtr); + Tcl_IncrRefCount(valuePtr); /* since hash now holds ref to it */ } - Tcl_SetHashValue(hPtr, valuePtr); - Tcl_IncrRefCount(valuePtr); /* since hash now holds ref to it */ } - installHash: /* * Free the old internalRep before setting the new one. We do this as late * as possible to allow the conversion code, in particular @@ -730,11 +674,10 @@ SetDictFromAny( objPtr->typePtr = &tclDictType; return TCL_OK; - missingKey: + missingValue: if (interp != NULL) { Tcl_SetResult(interp, "missing value to go with key", TCL_STATIC); } - TclDecrRefCount(keyPtr); result = TCL_ERROR; errorExit: diff --git a/generic/tclUtil.c b/generic/tclUtil.c index fd3d935..1e10465 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -180,7 +180,7 @@ TclMaxListLength( * the element is in braces, then *elementPtr will point to the character * after the opening brace and *sizePtr will not include either of the * braces. If there isn't an element in the list, *sizePtr will be zero, - * and both *elementPtr and *termPtr will point just after the last + * and both *elementPtr and *nextPtr will point just after the last * character in the list. If literalPtr is non-NULL, *literalPtr is set * to a boolean value indicating whether the substring returned as * the values of **elementPtr and *sizePtr is the literal value of -- cgit v0.12