Tcl Source Code

Check-in [056df6f608]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Replace TclCountSpaceRuns() with TclMaxListLength() which is the function we actually want.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | dgp-switch-compile
Files: files | file ages | folders
SHA1: 056df6f608da858cf1f48d0b3634a9d632ed9dfa
User & Date: dgp 2011-05-02 15:52:52
Context
2011-05-02
17:47
Revised TclFindElement() interface. The final argument had been bracePtr, the address of a boolean v... check-in: c2ee6476c2 user: dgp tags: dgp-switch-compile
15:52
Replace TclCountSpaceRuns() with TclMaxListLength() which is the function we actually want. check-in: 056df6f608 user: dgp tags: dgp-switch-compile
15:38
Replace TclCountSpaceRuns() with TclMaxListLength() which is the function we actually want. check-in: 63ec2ace6e user: dgp tags: core-8-5-branch
12:18
Tighten up the patch. check-in: a4d8498860 user: dgp tags: dgp-switch-compile
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ChangeLog.








1
2
3
4
5
6
7







2011-04-28  Don Porter  <[email protected]>

	* generic/tclInt.h:	New utility routines:
	* generic/tclParse.c:	TclIsSpaceProc() and
	* generic/tclUtil.c:	TclCountSpaceRuns()

	* generic/tclCmdMZ.c:	Use new routines to replace calls to
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
2011-05-02  Don Porter  <[email protected]>

	* 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  <[email protected]>

	* generic/tclInt.h:	New utility routines:
	* generic/tclParse.c:	TclIsSpaceProc() and
	* generic/tclUtil.c:	TclCountSpaceRuns()

	* generic/tclCmdMZ.c:	Use new routines to replace calls to

Changes to generic/tclCompCmds.c.

4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219

	if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
	    return TCL_ERROR;
	}
	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]);
	if (maxLen < 2) {
	    return TCL_ERROR;
	}
	bodyTokenArray = (Tcl_Token *) ckalloc(sizeof(Tcl_Token) * maxLen);
	bodyToken = (Tcl_Token **) ckalloc(sizeof(Tcl_Token *) * maxLen);
	bodyLines = (int *) ckalloc(sizeof(int) * maxLen);
	bodyNext  = (int **) ckalloc(sizeof(int*) * maxLen);







<
<
<
<
|
<
<
<
<
<
<
|
<







4193
4194
4195
4196
4197
4198
4199




4200






4201

4202
4203
4204
4205
4206
4207
4208

	if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
	    return TCL_ERROR;
	}
	bytes = tokenPtr[1].start;
	numBytes = tokenPtr[1].size;





	/* Allocate enough space to work in. */






	maxLen = TclMaxListLength(bytes, numBytes, NULL);

	if (maxLen < 2) {
	    return TCL_ERROR;
	}
	bodyTokenArray = (Tcl_Token *) ckalloc(sizeof(Tcl_Token) * maxLen);
	bodyToken = (Tcl_Token **) ckalloc(sizeof(Tcl_Token *) * maxLen);
	bodyLines = (int *) ckalloc(sizeof(int) * maxLen);
	bodyNext  = (int **) ckalloc(sizeof(int*) * maxLen);

Changes to generic/tclInt.h.

2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
MODULE_SCOPE ContLineLoc* TclContinuationsEnter(Tcl_Obj *objPtr, int num,
			    int *loc);
MODULE_SCOPE void	TclContinuationsEnterDerived(Tcl_Obj *objPtr,
			    int start, int *clNext);
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,
			    int numBytes, int flags, int line,
			    int *clNextOuter, CONST char *outerScript);
MODULE_SCOPE int	TclFileAttrsCmd(Tcl_Interp *interp,
			    int objc, Tcl_Obj *const objv[]);







<
<







2569
2570
2571
2572
2573
2574
2575


2576
2577
2578
2579
2580
2581
2582
MODULE_SCOPE ContLineLoc* TclContinuationsEnter(Tcl_Obj *objPtr, int num,
			    int *loc);
MODULE_SCOPE void	TclContinuationsEnterDerived(Tcl_Obj *objPtr,
			    int start, int *clNext);
MODULE_SCOPE ContLineLoc* TclContinuationsGet(Tcl_Obj *objPtr);
MODULE_SCOPE void	TclContinuationsCopy(Tcl_Obj *objPtr,
			    Tcl_Obj *originObjPtr);


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,
			    int numBytes, int flags, int line,
			    int *clNextOuter, CONST char *outerScript);
MODULE_SCOPE int	TclFileAttrsCmd(Tcl_Interp *interp,
			    int objc, Tcl_Obj *const objv[]);
2681
2682
2683
2684
2685
2686
2687


2688
2689
2690
2691
2692
2693
2694
MODULE_SCOPE Tcl_Obj *	TclLsetList(Tcl_Interp *interp, Tcl_Obj *listPtr,
			    Tcl_Obj *indexPtr, Tcl_Obj *valuePtr);
MODULE_SCOPE Tcl_Obj *	TclLsetFlat(Tcl_Interp *interp, Tcl_Obj *listPtr,
			    int indexCount, Tcl_Obj *const indexArray[],
			    Tcl_Obj *valuePtr);
MODULE_SCOPE Tcl_Command TclMakeEnsemble(Tcl_Interp *interp, const char *name,
			    const EnsembleImplMap map[]);


MODULE_SCOPE int	TclMergeReturnOptions(Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[], Tcl_Obj **optionsPtrPtr,
			    int *codePtr, int *levelPtr);
MODULE_SCOPE int	TclNokia770Doubles();
MODULE_SCOPE void	TclObjVarErrMsg(Tcl_Interp *interp, Tcl_Obj *part1Ptr,
			    Tcl_Obj *part2Ptr, const char *operation,
			    const char *reason, int index);







>
>







2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
MODULE_SCOPE Tcl_Obj *	TclLsetList(Tcl_Interp *interp, Tcl_Obj *listPtr,
			    Tcl_Obj *indexPtr, Tcl_Obj *valuePtr);
MODULE_SCOPE Tcl_Obj *	TclLsetFlat(Tcl_Interp *interp, Tcl_Obj *listPtr,
			    int indexCount, Tcl_Obj *const indexArray[],
			    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);
MODULE_SCOPE int	TclNokia770Doubles();
MODULE_SCOPE void	TclObjVarErrMsg(Tcl_Interp *interp, Tcl_Obj *part1Ptr,
			    Tcl_Obj *part2Ptr, const char *operation,
			    const char *reason, int index);

Changes to generic/tclListObj.c.

1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776


1777
1778
1779
1780
1781
1782

1783
1784
1785
1786
1787
1788
1789
     * 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. 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.
     */



    listRepPtr = AttemptNewList(interp, estCount, NULL);
    if (listRepPtr == NULL) {
	return TCL_ERROR;
    }
    elemPtrs = &listRepPtr->elements;


    for (p=string, lenRemain=length, i=0;
	    lenRemain > 0;
	    p=nextElem, lenRemain=limit-nextElem, i++) {
	result = TclFindElement(interp, p, lenRemain, &elemStart, &nextElem,
		&elemSize, &hasBrace);
	if (result != TCL_OK) {
	    for (j = 0;  j < i;  j++) {







|
<
<
<
<
|
<
|
<
<
<
<
|


>
>






>







1755
1756
1757
1758
1759
1760
1761
1762




1763

1764




1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
     * 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;

    /* Each iteration, parse and store a list element */
    for (p=string, lenRemain=length, i=0;
	    lenRemain > 0;
	    p=nextElem, lenRemain=limit-nextElem, i++) {
	result = TclFindElement(interp, p, lenRemain, &elemStart, &nextElem,
		&elemSize, &hasBrace);
	if (result != TCL_OK) {
	    for (j = 0;  j < i;  j++) {

Changes to generic/tclUtil.c.

85
86
87
88
89
90
91
92
93
94
95
96



97
98

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115









116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134





135
136
137
138
139
140
141
    UpdateStringOfEndOffset,		/* updateStringProc */
    SetEndOffsetFromAny
};

/*
 *----------------------------------------------------------------------
 *
 * TclCountSpaceRuns --
 *
 *	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'.



 *
 * Results:

 *	Returns the count.  If 'endPtr' is not NULL, writes a pointer to
 *	the end of the string scanned there.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
TclCountSpaceRuns(
    CONST char *bytes,
    int numBytes,
    CONST char **endPtr)
{
    int count = 0;










    while (numBytes) {
	if ((numBytes == -1) && (*bytes == '\0')) {
	    break;
	}
	if (TclIsSpaceProc(*bytes)) {
	    /* Space run started; bump count */
	    count++;
	    do {
		bytes++;
		numBytes -= (numBytes != -1);
	    } while (numBytes && TclIsSpaceProc(*bytes));
	    if (numBytes == 0) {
		break;
	    }
	    /* (*bytes) is non-space; return to counting state */
	}
	bytes++;
	numBytes -= (numBytes != -1);
    }





    if (endPtr) {
	*endPtr = bytes;
    }
    return count;
}

/*







|




>
>
>


>
|
|








|






>
>
>
>
>
>
>
>
>



















>
>
>
>
>







85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
    UpdateStringOfEndOffset,		/* updateStringProc */
    SetEndOffsetFromAny
};

/*
 *----------------------------------------------------------------------
 *
 * 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 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.
 *
 *----------------------------------------------------------------------
 */

int
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;
	}
	if (TclIsSpaceProc(*bytes)) {
	    /* Space run started; bump count */
	    count++;
	    do {
		bytes++;
		numBytes -= (numBytes != -1);
	    } while (numBytes && TclIsSpaceProc(*bytes));
	    if (numBytes == 0) {
		break;
	    }
	    /* (*bytes) is non-space; return to counting state */
	}
	bytes++;
	numBytes -= (numBytes != -1);
    }

    /* No list element following trailing white space */
    count -= TclIsSpaceProc(bytes[-1]); 

    done:
    if (endPtr) {
	*endPtr = bytes;
    }
    return count;
}

/*
458
459
460
461
462
463
464
465
466



467
468
469
470
471
472
473
474

475
476
477
478
479
480
481
				 * of pointers to list elements. */
{
    CONST char **argv, *end, *element;
    char *p;
    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.
     */

    size = TclCountSpaceRuns(list, -1, &end) + 2;
    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;

	result = TclFindElement(interp, list, length, &element, &list,
		&elSize, &brace);
	length -= (list - prevList);







|
|
>
>
>
|
<


|



>







476
477
478
479
480
481
482
483
484
485
486
487
488

489
490
491
492
493
494
495
496
497
498
499
500
501
502
				 * of pointers to list elements. */
{
    CONST char **argv, *end, *element;
    char *p;
    int length, size, i, result, elSize, brace;

    /*
     * 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 = 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;

	result = TclFindElement(interp, list, length, &element, &list,
		&elSize, &brace);
	length -= (list - prevList);