diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | generic/tclInt.h | 4 | ||||
-rw-r--r-- | generic/tclListObj.c | 20 | ||||
-rw-r--r-- | generic/tclUtil.c | 39 |
4 files changed, 45 insertions, 24 deletions
@@ -1,3 +1,9 @@ +2011-05-02 Don Porter <dgp@users.sourceforge.net> + + * generic/tclInt.h: Replace TclCountSpaceRuns() with + * generic/tclListObj.c: TclMaxListLength() which is the function we + * generic/tclUtil.c: actually want. + 2011-04-28 Don Porter <dgp@users.sourceforge.net> * generic/tclInt.h: New utility routines: diff --git a/generic/tclInt.h b/generic/tclInt.h index 7d9f066..e3aaccb 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2900,8 +2900,6 @@ MODULE_SCOPE void TclContinuationsEnterDerived(Tcl_Obj *objPtr, MODULE_SCOPE ContLineLoc *TclContinuationsGet(Tcl_Obj *objPtr); MODULE_SCOPE void TclContinuationsCopy(Tcl_Obj *objPtr, Tcl_Obj *originObjPtr); -MODULE_SCOPE int TclCountSpaceRuns(CONST char *bytes, int numBytes, - CONST char **endPtr); MODULE_SCOPE void TclDeleteNamespaceVars(Namespace *nsPtr); /* TIP #280 - Modified token based evulation, with line information. */ MODULE_SCOPE int TclEvalEx(Tcl_Interp *interp, const char *script, @@ -3011,6 +3009,8 @@ MODULE_SCOPE Tcl_Obj * TclLsetFlat(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *valuePtr); MODULE_SCOPE Tcl_Command TclMakeEnsemble(Tcl_Interp *interp, const char *name, const EnsembleImplMap map[]); +MODULE_SCOPE int TclMaxListLength(CONST char *bytes, int numBytes, + CONST char **endPtr); MODULE_SCOPE int TclMergeReturnOptions(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Tcl_Obj **optionsPtrPtr, int *codePtr, int *levelPtr); diff --git a/generic/tclListObj.c b/generic/tclListObj.c index 9437f7e..03843b8 100644 --- a/generic/tclListObj.c +++ b/generic/tclListObj.c @@ -1783,27 +1783,21 @@ SetListFromAny( /* * Parse the string into separate string objects, and create a List - * structure that points to the element string objects. We use a modified - * version of Tcl_SplitList's implementation to avoid one malloc and a - * string copy for each list element. First, estimate the number of - * elements by counting the number of space characters in the list. - */ - - estCount = TclCountSpaceRuns(string, length, &limit) + 1; - - /* - * Allocate a new List structure with enough room for "estCount" elements. - * Each element is a pointer to a Tcl_Obj with the appropriate string rep. - * The initial "estCount" elements are set using the corresponding "argv" - * strings. + * 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; + /* Each iteration, parse and store a list element */ for (p=string, lenRemain=length, i=0; lenRemain > 0; p=nextElem, lenRemain=limit-nextElem, i++) { diff --git a/generic/tclUtil.c b/generic/tclUtil.c index fdfb190..d4630af 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -88,15 +88,19 @@ const Tcl_ObjType tclEndOffsetType = { /* *---------------------------------------------------------------------- * - * TclCountSpaceRuns -- + * TclMaxListLength -- * * Given 'bytes' pointing to 'numBytes' bytes, scan through them and * count the number of whitespace runs that could be list element * separators. If 'numBytes' is -1, scan to the terminating '\0'. + * Not a full list parser. Typically used to get a quick and dirty + * overestimate of length size in order to allocate space for an + * actual list parser to operate with. * * Results: - * Returns the count. If 'endPtr' is not NULL, writes a pointer to - * the end of the string scanned there. + * Returns the largest number of list elements that could possibly + * be in this string, interpreted as a Tcl list. If 'endPtr' is not + * NULL, writes a pointer to the end of the string scanned there. * * Side effects: * None. @@ -105,13 +109,22 @@ const Tcl_ObjType tclEndOffsetType = { */ int -TclCountSpaceRuns( +TclMaxListLength( CONST char *bytes, int numBytes, CONST char **endPtr) { int count = 0; + if ((numBytes == 0) || ((numBytes == -1) && (*bytes == '\0'))) { + /* Empty string case - quick exit */ + goto done; + } + + /* No list element before leading white space */ + count += 1 - TclIsSpaceProc(*bytes); + + /* Count white space runs as potential element separators */ while (numBytes) { if ((numBytes == -1) && (*bytes == '\0')) { break; @@ -131,6 +144,11 @@ TclCountSpaceRuns( bytes++; numBytes -= (numBytes != -1); } + + /* No list element following trailing white space */ + count -= TclIsSpaceProc(bytes[-1]); + + done: if (endPtr) { *endPtr = bytes; } @@ -469,15 +487,18 @@ Tcl_SplitList( int length, size, i, result, elSize, brace; /* - * Figure out how much space to allocate. There must be enough space for - * both the array of pointers and also for a copy of the list. To estimate - * the number of pointers needed, count the number of space characters in - * the list. + * Allocate enough space to work in. A (CONST char *) for each + * (possible) list element plus one more for terminating NULL, + * plus as many bytes as in the original string value, plus one + * more for a terminating '\0'. Space used to hold element separating + * white space in the original string gets re-purposed to hold '\0' + * characters in the argv array. */ - size = TclCountSpaceRuns(list, -1, &end) + 2; + size = TclMaxListLength(list, -1, &end) + 1; length = end - list; argv = ckalloc((size * sizeof(char *)) + length + 1); + for (i = 0, p = ((char *) argv) + size*sizeof(char *); *list != 0; i++) { const char *prevList = list; |