From 7dae77dae8c9aff0ac1739acc19c221f5398a325 Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 3 May 2011 18:53:45 +0000 Subject: Tighten SetListFromAny(). --- ChangeLog | 1 + generic/tclListObj.c | 113 ++++++++++++++++++--------------------------------- 2 files changed, 41 insertions(+), 73 deletions(-) diff --git a/ChangeLog b/ChangeLog index fea3aa0..cab340e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ 2011-05-03 Don Porter + * generic/tclListObj.c: Tighten SetListFromAny(). * generic/tclDictObj.c: Tighten SetDictFromAny(). 2011-05-02 Don Porter diff --git a/generic/tclListObj.c b/generic/tclListObj.c index 412a902..164fa4a 100644 --- a/generic/tclListObj.c +++ b/generic/tclListObj.c @@ -1691,14 +1691,8 @@ SetListFromAny( Tcl_Interp *interp, /* Used for error reporting if not NULL. */ Tcl_Obj *objPtr) /* The object to convert. */ { - char *string, *s; - const char *elemStart, *nextElem; - int lenRemain, length, estCount, elemSize, i, j, result; - const char *limit; /* Points just after string's last byte. */ - register const char *p; - register Tcl_Obj **elemPtrs; - register Tcl_Obj *elemPtr; List *listRepPtr; + Tcl_Obj **elemPtrs; /* * Dictionaries are a special case; they have a string representation such @@ -1735,96 +1729,69 @@ SetListFromAny( elemPtrs = &listRepPtr->elements; Tcl_DictObjFirst(NULL, objPtr, &search, &keyPtr, &valuePtr, &done); - i = 0; while (!done) { - elemPtrs[i++] = keyPtr; - elemPtrs[i++] = valuePtr; + *elemPtrs++ = keyPtr; + *elemPtrs++ = valuePtr; Tcl_IncrRefCount(keyPtr); Tcl_IncrRefCount(valuePtr); Tcl_DictObjNext(&search, &keyPtr, &valuePtr, &done); } + } else { + int estCount, length; + const char *limit, *nextElem = TclGetStringFromObj(objPtr, &length); /* - * Swap the representations. + * Allocate enough space to hold a (Tcl_Obj *) for each + * (possible) list element. */ - goto commitRepresentation; - } - - /* - * Get the string representation. Make it up-to-date if necessary. - */ - - string = TclGetStringFromObj(objPtr, &length); - - /* - * Parse the string into separate string objects, and create a List - * structure that points to the element string objects. - * - * First, allocate enough space to hold a (Tcl_Obj *) for each - * (possible) list element. - */ - - estCount = TclMaxListLength(string, length, &limit); - estCount += (estCount == 0); /* Smallest List struct holds 1 element. */ - listRepPtr = AttemptNewList(interp, estCount, NULL); - if (listRepPtr == NULL) { - return TCL_ERROR; - } - elemPtrs = &listRepPtr->elements; + estCount = TclMaxListLength(nextElem, length, &limit); + estCount += (estCount == 0); /* Smallest List struct holds 1 element. */ + listRepPtr = AttemptNewList(interp, estCount, NULL); + if (listRepPtr == NULL) { + return TCL_ERROR; + } + elemPtrs = &listRepPtr->elements; - /* Each iteration, parse and store a list element */ - for (p=string, lenRemain=length, i=0; - lenRemain > 0; - p=nextElem, lenRemain=limit-nextElem, i++) { - int literal; + /* Each iteration, parse and store a list element */ + while (nextElem < limit) { + const char *elemStart; + int elemSize, literal; - result = TclFindElement(interp, p, lenRemain, &elemStart, &nextElem, - &elemSize, &literal); - if (result != TCL_OK) { - for (j = 0; j < i; j++) { - elemPtr = elemPtrs[j]; - Tcl_DecrRefCount(elemPtr); + if (TCL_OK != TclFindElement(interp, nextElem, (limit - nextElem), + &elemStart, &nextElem, &elemSize, &literal)) { + while (--elemPtrs >= &listRepPtr->elements) { + Tcl_DecrRefCount(*elemPtrs); + } + ckfree((char *) listRepPtr); + return TCL_ERROR; + } + if (elemStart == limit) { + break; } - ckfree((char *) listRepPtr); - return result; - } - if (elemStart >= limit) { - break; - } - if (i > estCount) { - Tcl_Panic("SetListFromAny: bad size estimate for list"); - } - /* - * Allocate a Tcl object for the element and initialize it from the - * "elemSize" bytes starting at "elemStart". - */ + /* TODO: replace panic with error on alloc failure? */ + if (literal) { + TclNewStringObj(*elemPtrs, elemStart, elemSize); + } else { + TclNewObj(*elemPtrs); + (*elemPtrs)->bytes = ckalloc((unsigned) elemSize + 1); + (*elemPtrs)->length = TclCopyAndCollapse(elemSize, elemStart, + (*elemPtrs)->bytes); + } - s = ckalloc((unsigned) elemSize + 1); - if (literal) { - memcpy(s, elemStart, (size_t) elemSize); - s[elemSize] = 0; - } else { - elemSize = TclCopyAndCollapse(elemSize, elemStart, s); + Tcl_IncrRefCount(*elemPtrs++);/* Since list now holds ref to it. */ } - TclNewObj(elemPtr); - elemPtr->bytes = s; - elemPtr->length = elemSize; - elemPtrs[i] = elemPtr; - Tcl_IncrRefCount(elemPtr); /* Since list now holds ref to it. */ + listRepPtr->elemCount = elemPtrs - &listRepPtr->elements; } - listRepPtr->elemCount = i; - /* * Free the old internalRep before setting the new one. We do this as late * as possible to allow the conversion code, in particular * Tcl_GetStringFromObj, to use that old internalRep. */ - commitRepresentation: TclFreeIntRep(objPtr); ListSetIntRep(objPtr, listRepPtr); return TCL_OK; -- cgit v0.12