diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | generic/tclCompCmds.c | 15 | ||||
-rw-r--r-- | generic/tclInt.h | 4 | ||||
-rw-r--r-- | generic/tclListObj.c | 20 | ||||
-rw-r--r-- | generic/tclUtil.c | 39 |
5 files changed, 48 insertions, 37 deletions
@@ -1,3 +1,10 @@ +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. + * generic/tclCompCmds.c: + 2011-04-28 Don Porter <dgp@users.sourceforge.net> * generic/tclInt.h: New utility routines: diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 8981e65..2b6f84c 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -4197,19 +4197,8 @@ TclCompileSwitchCmd( bytes = tokenPtr[1].start; numBytes = tokenPtr[1].size; - /* Smallest possible two-element list has 3 byte string rep */ - if (numBytes < 3) { - return TCL_ERROR; - } - - /* - * A list can have at most one more element than the number - * of runs of (potentially) element-separating white space. - * And one less each if whitespace leads or trails. - */ - - maxLen = TclCountSpaceRuns(bytes, numBytes, NULL) + 1 - - TclIsSpaceProc(*bytes) - TclIsSpaceProc(bytes[numBytes-1]); + /* Allocate enough space to work in. */ + maxLen = TclMaxListLength(bytes, numBytes, NULL); if (maxLen < 2) { return TCL_ERROR; } diff --git a/generic/tclInt.h b/generic/tclInt.h index a560fe8..6fb3e57 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2573,8 +2573,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, @@ -2685,6 +2683,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 d3465b0..1fabcab 100644 --- a/generic/tclListObj.c +++ b/generic/tclListObj.c @@ -1759,27 +1759,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 d542b52..76676a1 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -89,15 +89,19 @@ 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. @@ -106,13 +110,22 @@ 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; @@ -132,6 +145,11 @@ TclCountSpaceRuns( bytes++; numBytes -= (numBytes != -1); } + + /* No list element following trailing white space */ + count -= TclIsSpaceProc(bytes[-1]); + + done: if (endPtr) { *endPtr = bytes; } @@ -462,16 +480,19 @@ 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 = (CONST char **) ckalloc((unsigned) ((size * sizeof(char *)) + length + 1)); + for (i = 0, p = ((char *) argv) + size*sizeof(char *); *list != 0; i++) { CONST char *prevList = list; |