summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
Diffstat (limited to 'generic')
-rw-r--r--generic/tclInt.h4
-rw-r--r--generic/tclListObj.c20
-rw-r--r--generic/tclUtil.c39
3 files changed, 39 insertions, 24 deletions
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;