Tcl Source Code

Check-in [f5eea09981]
Login

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

Overview
Comment:merge trunk
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | dgp-properbytearray
Files: files | file ages | folders
SHA3-256: f5eea09981ce422a526ecf3c6e7019d7268b9ad65cbaabc1d194c439a5d6f4f8
User & Date: dgp 2018-03-11 22:27:44.471
Context
2018-03-15
15:08
merge trunk check-in: 76accc77f4 user: dgp tags: dgp-properbytearray
2018-03-11
22:27
merge trunk check-in: f5eea09981 user: dgp tags: dgp-properbytearray
21:42
merge 8.7 check-in: 3108218eee user: dgp tags: trunk
2018-03-06
13:56
merge trunk check-in: ca5a9a7e17 user: dgp tags: dgp-properbytearray
Changes
Unified Diff Ignore Whitespace Patch
Changes to generic/tclAssembly.c.
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257

2258


2259
2260


2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    Tcl_Token* tokenPtr = *tokenPtrPtr;
				/* INOUT: Pointer to the next token in the
				 * source code */
    Tcl_Obj* intObj;		/* Integer from the source code */
    int status;			/* Tcl status return */

    /*
     * Extract the next token as a string.
     */

    if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &intObj) != TCL_OK) {
	return TCL_ERROR;
    }


    /*


     * Convert to an integer, advance to the next token and return.
     */



    status = TclGetIntForIndex(interp, intObj, -2, result);
    Tcl_DecrRefCount(intObj);
    *tokenPtrPtr = TokenAfter(tokenPtr);
    return status;
}

/*
 *-----------------------------------------------------------------------------
 *







|
|

<
<
<
|
|


|
>

>
>
|

>
>

<
|







2240
2241
2242
2243
2244
2245
2246
2247
2248
2249



2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263

2264
2265
2266
2267
2268
2269
2270
2271
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    Tcl_Token* tokenPtr = *tokenPtrPtr;
				/* INOUT: Pointer to the next token in the
				 * source code */
    Tcl_Obj *value;
    int status;




    /* General operand validity check */
    if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &value) != TCL_OK) {
	return TCL_ERROR;
    }
     
    /* Convert to an integer, advance to the next token and return. */
    /*
     * NOTE: Indexing a list with an index before it yields the
     * same result as indexing after it, and might be more easily portable
     * when list size limits grow.
     */
    status = TclIndexEncode(interp, value,
	    TCL_INDEX_BEFORE,TCL_INDEX_BEFORE, result);


    Tcl_DecrRefCount(value);
    *tokenPtrPtr = TokenAfter(tokenPtr);
    return status;
}

/*
 *-----------------------------------------------------------------------------
 *
Changes to generic/tclBasic.c.
6328
6329
6330
6331
6332
6333
6334
6335
6336
6337
6338
6339
6340
6341
6342
    /*
     * If we are just starting to log an error, errorInfo is initialized from
     * the error message in the interpreter's result.
     */

    iPtr->flags |= ERR_LEGACY_COPY;
    if (iPtr->errorInfo == NULL) {
        iPtr->errorInfo = iPtr->objResultPtr;
	Tcl_IncrRefCount(iPtr->errorInfo);
	if (!iPtr->errorCode) {
	    Tcl_SetErrorCode(interp, "NONE", NULL);
	}
    }

    /*







|







6328
6329
6330
6331
6332
6333
6334
6335
6336
6337
6338
6339
6340
6341
6342
    /*
     * If we are just starting to log an error, errorInfo is initialized from
     * the error message in the interpreter's result.
     */

    iPtr->flags |= ERR_LEGACY_COPY;
    if (iPtr->errorInfo == NULL) {
	iPtr->errorInfo = iPtr->objResultPtr;
	Tcl_IncrRefCount(iPtr->errorInfo);
	if (!iPtr->errorCode) {
	    Tcl_SetErrorCode(interp, "NONE", NULL);
	}
    }

    /*
Changes to generic/tclCmdIL.c.
60
61
62
63
64
65
66
67
68

69
70
71
72
73
74
75
    int isIncreasing;		/* Nonzero means sort in increasing order. */
    int sortMode;		/* The sort mode. One of SORTMODE_* values
				 * defined below. */
    Tcl_Obj *compareCmdPtr;	/* The Tcl comparison command when sortMode is
				 * SORTMODE_COMMAND. Pre-initialized to hold
				 * base of command. */
    int *indexv;		/* If the -index option was specified, this
				 * holds the indexes contained in the list
				 * supplied as an argument to that option.

				 * NULL if no indexes supplied, and points to
				 * singleIndex field when only one
				 * supplied. */
    int indexc;			/* Number of indexes in indexv array. */
    int singleIndex;		/* Static space for common index case. */
    int unique;
    int numElements;







|
|
>







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
    int isIncreasing;		/* Nonzero means sort in increasing order. */
    int sortMode;		/* The sort mode. One of SORTMODE_* values
				 * defined below. */
    Tcl_Obj *compareCmdPtr;	/* The Tcl comparison command when sortMode is
				 * SORTMODE_COMMAND. Pre-initialized to hold
				 * base of command. */
    int *indexv;		/* If the -index option was specified, this
				 * holds an encoding of the indexes contained
				 * in the list supplied as an argument to
				 * that option.
				 * NULL if no indexes supplied, and points to
				 * singleIndex field when only one
				 * supplied. */
    int indexc;			/* Number of indexes in indexv array. */
    int singleIndex;		/* Static space for common index case. */
    int unique;
    int numElements;
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#define SORTMODE_ASCII		0
#define SORTMODE_INTEGER	1
#define SORTMODE_REAL		2
#define SORTMODE_COMMAND	3
#define SORTMODE_DICTIONARY	4
#define SORTMODE_ASCII_NC	8

/*
 * Magic values for the index field of the SortInfo structure. Note that the
 * index "end-1" will be translated to SORTIDX_END-1, etc.
 */

#define SORTIDX_NONE	-1	/* Not indexed; use whole value. */
#define SORTIDX_END	-2	/* Indexed from end. */

/*
 * Forward declarations for procedures defined in this file:
 */

static int		DictionaryCompare(const char *left, const char *right);
static Tcl_NRPostProc	IfConditionCallback;
static int		InfoArgsCmd(ClientData dummy, Tcl_Interp *interp,







<
<
<
<
<
<
<
<







89
90
91
92
93
94
95








96
97
98
99
100
101
102
#define SORTMODE_ASCII		0
#define SORTMODE_INTEGER	1
#define SORTMODE_REAL		2
#define SORTMODE_COMMAND	3
#define SORTMODE_DICTIONARY	4
#define SORTMODE_ASCII_NC	8









/*
 * Forward declarations for procedures defined in this file:
 */

static int		DictionaryCompare(const char *left, const char *right);
static Tcl_NRPostProc	IfConditionCallback;
static int		InfoArgsCmd(ClientData dummy, Tcl_Interp *interp,
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
    /*
     * Complain if the user asked for a start element that is greater than the
     * list length. This won't ever trigger for the "end-*" case as that will
     * be properly constrained by TclGetIntForIndex because we use listLen-1
     * (to allow for replacing the last elem).
     */

    if ((first > listLen) && (listLen > 0)) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"list doesn't contain element %s", TclGetString(objv[2])));
	Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LREPLACE", "BADIDX",
		NULL);
	return TCL_ERROR;
    }
    if (last >= listLen) {







|







2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
    /*
     * Complain if the user asked for a start element that is greater than the
     * list length. This won't ever trigger for the "end-*" case as that will
     * be properly constrained by TclGetIntForIndex because we use listLen-1
     * (to allow for replacing the last elem).
     */

    if ((first >= listLen) && (listLen > 0)) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"list doesn't contain element %s", TclGetString(objv[2])));
	Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LREPLACE", "BADIDX",
		NULL);
	return TCL_ERROR;
    }
    if (last >= listLen) {
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
Tcl_LsearchObjCmd(
    ClientData clientData,	/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument values. */
{
    const char *bytes, *patternBytes;
    int i, match, index, result, listc, length, elemLen, bisect;
    int allocatedIndexVector = 0;
    int dataType, isIncreasing, lower, upper, start, groupSize, groupOffset;
    Tcl_WideInt patWide, objWide;
    int allMatches, inlineReturn, negatedMatch, returnSubindices, noCase;
    double patDouble, objDouble;
    SortInfo sortInfo;
    Tcl_Obj *patObj, **listv, *listPtr, *startPtr, *itemPtr;







|







2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
Tcl_LsearchObjCmd(
    ClientData clientData,	/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument values. */
{
    const char *bytes, *patternBytes;
    int i, match, index, result=TCL_OK, listc, length, elemLen, bisect;
    int allocatedIndexVector = 0;
    int dataType, isIncreasing, lower, upper, start, groupSize, groupOffset;
    Tcl_WideInt patWide, objWide;
    int allMatches, inlineReturn, negatedMatch, returnSubindices, noCase;
    double patDouble, objDouble;
    SortInfo sortInfo;
    Tcl_Obj *patObj, **listv, *listPtr, *startPtr, *itemPtr;
3157
3158
3159
3160
3161
3162
3163

3164
3165












3166
3167
3168
3169
3170

3171
3172
3173
3174
3175
3176
3177
	    /*
	     * Fill the array by parsing each index. We don't know whether
	     * their scale is sensible yet, but we at least perform the
	     * syntactic check here.
	     */

	    for (j=0 ; j<sortInfo.indexc ; j++) {

		if (TclGetIntForIndexM(interp, indices[j], SORTIDX_END,
			&sortInfo.indexv[j]) != TCL_OK) {












		    Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
			    "\n    (-index option item number %d)", j));
		    result = TCL_ERROR;
		    goto done;
		}

	    }
	    break;
	}
	}
    }

    /*







>
|
|
>
>
>
>
>
>
>
>
>
>
>
>


<


>







3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173

3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
	    /*
	     * Fill the array by parsing each index. We don't know whether
	     * their scale is sensible yet, but we at least perform the
	     * syntactic check here.
	     */

	    for (j=0 ; j<sortInfo.indexc ; j++) {
		int encoded = 0;
		if (TclIndexEncode(interp, indices[j], TCL_INDEX_BEFORE,
			TCL_INDEX_AFTER, &encoded) != TCL_OK) {
		    result = TCL_ERROR;
		}
		if ((encoded == TCL_INDEX_BEFORE)
			|| (encoded == TCL_INDEX_AFTER)) {
		    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
			    "index \"%s\" cannot select an element "
			    "from any list", Tcl_GetString(indices[j])));
		    Tcl_SetErrorCode(interp, "TCL", "VALUE", "INDEX"
			    "OUTOFRANGE", NULL);
		    result = TCL_ERROR;
		}
		if (result == TCL_ERROR) {
		    Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
			    "\n    (-index option item number %d)", j));

		    goto done;
		}
		sortInfo.indexv[j] = encoded;
	    }
	    break;
	}
	}
    }

    /*
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
	}
	if (sortInfo.indexc > 0) {
	    /*
	     * Use the first value in the list supplied to -index as the
	     * offset of the element within each group by which to sort.
	     */

	    groupOffset = sortInfo.indexv[0];
	    if (groupOffset <= SORTIDX_END) {
		groupOffset = (groupOffset - SORTIDX_END) + groupSize - 1;
	    }
	    if (groupOffset < 0 || groupOffset >= groupSize) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"when used with \"-stride\", the leading \"-index\""
			" value must be within the group", -1));
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSEARCH",
			"BADINDEX", NULL);
		result = TCL_ERROR;







|
<
<
<







3257
3258
3259
3260
3261
3262
3263
3264



3265
3266
3267
3268
3269
3270
3271
	}
	if (sortInfo.indexc > 0) {
	    /*
	     * Use the first value in the list supplied to -index as the
	     * offset of the element within each group by which to sort.
	     */

	    groupOffset = TclIndexDecode(sortInfo.indexv[0], groupSize - 1);



	    if (groupOffset < 0 || groupOffset >= groupSize) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"when used with \"-stride\", the leading \"-index\""
			" value must be within the group", -1));
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSEARCH",
			"BADINDEX", NULL);
		result = TCL_ERROR;
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
		    Tcl_ListObjAppendElement(interp, listPtr, itemPtr);
		}
	    } else if (returnSubindices) {
		int j;

		itemPtr = Tcl_NewIntObj(i+groupOffset);
		for (j=0 ; j<sortInfo.indexc ; j++) {
		    Tcl_ListObjAppendElement(interp, itemPtr,
			    Tcl_NewIntObj(sortInfo.indexv[j]));
		}
		Tcl_ListObjAppendElement(interp, listPtr, itemPtr);
	    } else {
		Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(i));
	    }
	}
    }

    /*
     * Return everything or a single value.
     */

    if (allMatches) {
	Tcl_SetObjResult(interp, listPtr);
    } else if (!inlineReturn) {
	if (returnSubindices) {
	    int j;

	    itemPtr = Tcl_NewIntObj(index+groupOffset);
	    for (j=0 ; j<sortInfo.indexc ; j++) {
		Tcl_ListObjAppendElement(interp, itemPtr,
			Tcl_NewIntObj(sortInfo.indexv[j]));
	    }
	    Tcl_SetObjResult(interp, itemPtr);
	} else {
	    Tcl_SetObjResult(interp, Tcl_NewIntObj(index));
	}
    } else if (index < 0) {
	/*







|
|




















|
|







3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
		    Tcl_ListObjAppendElement(interp, listPtr, itemPtr);
		}
	    } else if (returnSubindices) {
		int j;

		itemPtr = Tcl_NewIntObj(i+groupOffset);
		for (j=0 ; j<sortInfo.indexc ; j++) {
		    Tcl_ListObjAppendElement(interp, itemPtr, Tcl_NewIntObj(
			    TclIndexDecode(sortInfo.indexv[j], listc)));
		}
		Tcl_ListObjAppendElement(interp, listPtr, itemPtr);
	    } else {
		Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewIntObj(i));
	    }
	}
    }

    /*
     * Return everything or a single value.
     */

    if (allMatches) {
	Tcl_SetObjResult(interp, listPtr);
    } else if (!inlineReturn) {
	if (returnSubindices) {
	    int j;

	    itemPtr = Tcl_NewIntObj(index+groupOffset);
	    for (j=0 ; j<sortInfo.indexc ; j++) {
		Tcl_ListObjAppendElement(interp, itemPtr, Tcl_NewIntObj(
			TclIndexDecode(sortInfo.indexv[j], listc)));
	    }
	    Tcl_SetObjResult(interp, itemPtr);
	} else {
	    Tcl_SetObjResult(interp, Tcl_NewIntObj(index));
	}
    } else if (index < 0) {
	/*
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
	case LSORT_DICTIONARY:
	    sortInfo.sortMode = SORTMODE_DICTIONARY;
	    break;
	case LSORT_INCREASING:
	    sortInfo.isIncreasing = 1;
	    break;
	case LSORT_INDEX: {
	    int indexc, dummy;
	    Tcl_Obj **indexv;

	    if (i == objc-2) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"\"-index\" option must be followed by list index",
			-1));
		Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL);







|







3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
	case LSORT_DICTIONARY:
	    sortInfo.sortMode = SORTMODE_DICTIONARY;
	    break;
	case LSORT_INCREASING:
	    sortInfo.isIncreasing = 1;
	    break;
	case LSORT_INDEX: {
	    int indexc;
	    Tcl_Obj **indexv;

	    if (i == objc-2) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"\"-index\" option must be followed by list index",
			-1));
		Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL);
3866
3867
3868
3869
3870
3871
3872

3873

3874










3875
3876
3877
3878
3879
3880
3881
	     * we do not store the converted values here because we do not
	     * know if this is the only -index option yet and so we can't
	     * allocate any space; that happens after the scan through all the
	     * options is done.
	     */

	    for (j=0 ; j<indexc ; j++) {

		if (TclGetIntForIndexM(interp, indexv[j], SORTIDX_END,

			&dummy) != TCL_OK) {










		    Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
			    "\n    (-index option item number %d)", j));
		    sortInfo.resultCode = TCL_ERROR;
		    goto done;
		}
	    }
	    indexPtr = objv[i+1];







>
|
>
|
>
>
>
>
>
>
>
>
>
>







3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
	     * we do not store the converted values here because we do not
	     * know if this is the only -index option yet and so we can't
	     * allocate any space; that happens after the scan through all the
	     * options is done.
	     */

	    for (j=0 ; j<indexc ; j++) {
		int encoded = 0;
		int result = TclIndexEncode(interp, indexv[j],
			TCL_INDEX_BEFORE, TCL_INDEX_AFTER, &encoded);

		if ((result == TCL_OK) && ((encoded == TCL_INDEX_BEFORE)
			|| (encoded == TCL_INDEX_AFTER))) {
		    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
			    "index \"%s\" cannot select an element "
			    "from any list", Tcl_GetString(indexv[j])));
		    Tcl_SetErrorCode(interp, "TCL", "VALUE", "INDEX"
			    "OUTOFRANGE", NULL);
		    result = TCL_ERROR;
		}
		if (result == TCL_ERROR) {
		    Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
			    "\n    (-index option item number %d)", j));
		    sortInfo.resultCode = TCL_ERROR;
		    goto done;
		}
	    }
	    indexPtr = objv[i+1];
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
	default:
	    sortInfo.indexv =
		    TclStackAlloc(interp, sizeof(int) * sortInfo.indexc);
	    allocatedIndexVector = 1;	/* Cannot use indexc field, as it
					 * might be decreased by 1 later. */
	}
	for (j=0 ; j<sortInfo.indexc ; j++) {
	    TclGetIntForIndexM(interp, indexv[j], SORTIDX_END,
		    &sortInfo.indexv[j]);
	}
    }

    listObj = objv[objc-1];

    if (sortInfo.sortMode == SORTMODE_COMMAND) {
	Tcl_Obj *newCommandPtr, *newObjPtr;







|
|







3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
	default:
	    sortInfo.indexv =
		    TclStackAlloc(interp, sizeof(int) * sortInfo.indexc);
	    allocatedIndexVector = 1;	/* Cannot use indexc field, as it
					 * might be decreased by 1 later. */
	}
	for (j=0 ; j<sortInfo.indexc ; j++) {
	    /* Prescreened values, no errors or out of range possible */
	    TclIndexEncode(NULL, indexv[j], 0, 0, &sortInfo.indexv[j]);
	}
    }

    listObj = objv[objc-1];

    if (sortInfo.sortMode == SORTMODE_COMMAND) {
	Tcl_Obj *newCommandPtr, *newObjPtr;
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047



4048
4049
4050
4051
4052
4053
4054
	length = length / groupSize;
	if (sortInfo.indexc > 0) {
	    /*
	     * Use the first value in the list supplied to -index as the
	     * offset of the element within each group by which to sort.
	     */

	    groupOffset = sortInfo.indexv[0];
	    if (groupOffset <= SORTIDX_END) {
		groupOffset = (groupOffset - SORTIDX_END) + groupSize - 1;
	    }
	    if (groupOffset < 0 || groupOffset >= groupSize) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"when used with \"-stride\", the leading \"-index\""
			" value must be within the group", -1));
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSORT",
			"BADINDEX", NULL);
		sortInfo.resultCode = TCL_ERROR;
		goto done;
	    }
	    if (sortInfo.indexc == 1) {
		sortInfo.indexc = 0;
		sortInfo.indexv = NULL;
	    } else {
		sortInfo.indexc--;

		/*
		 * Do not shrink the actual memory block used; that doesn't
		 * work with TclStackAlloc-allocated memory. [Bug 2918962]



		 */

		for (i = 0; i < sortInfo.indexc; i++) {
		    sortInfo.indexv[i] = sortInfo.indexv[i+1];
		}
	    }
	}







|
<
<
<


















>
>
>







4034
4035
4036
4037
4038
4039
4040
4041



4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
	length = length / groupSize;
	if (sortInfo.indexc > 0) {
	    /*
	     * Use the first value in the list supplied to -index as the
	     * offset of the element within each group by which to sort.
	     */

	    groupOffset = TclIndexDecode(sortInfo.indexv[0], groupSize - 1);



	    if (groupOffset < 0 || groupOffset >= groupSize) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"when used with \"-stride\", the leading \"-index\""
			" value must be within the group", -1));
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSORT",
			"BADINDEX", NULL);
		sortInfo.resultCode = TCL_ERROR;
		goto done;
	    }
	    if (sortInfo.indexc == 1) {
		sortInfo.indexc = 0;
		sortInfo.indexv = NULL;
	    } else {
		sortInfo.indexc--;

		/*
		 * Do not shrink the actual memory block used; that doesn't
		 * work with TclStackAlloc-allocated memory. [Bug 2918962]
		 * 
		 * TODO: Consider a pointer increment to replace this
		 * array shift.
		 */

		for (i = 0; i < sortInfo.indexc; i++) {
		    sortInfo.indexv[i] = sortInfo.indexv[i+1];
		}
	    }
	}
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
	int listLen, index;
	Tcl_Obj *currentObj;

	if (TclListObjLength(infoPtr->interp, objPtr, &listLen) != TCL_OK) {
	    infoPtr->resultCode = TCL_ERROR;
	    return NULL;
	}
	index = infoPtr->indexv[i];

	/*
	 * Adjust for end-based indexing.
	 */

	if (index < SORTIDX_NONE) {
	    index += listLen + 1;
	}

	if (Tcl_ListObjIndex(infoPtr->interp, objPtr, index,
		&currentObj) != TCL_OK) {
	    infoPtr->resultCode = TCL_ERROR;
	    return NULL;
	}
	if (currentObj == NULL) {







<

<
<
<
|
<
<
<







4624
4625
4626
4627
4628
4629
4630

4631



4632



4633
4634
4635
4636
4637
4638
4639
	int listLen, index;
	Tcl_Obj *currentObj;

	if (TclListObjLength(infoPtr->interp, objPtr, &listLen) != TCL_OK) {
	    infoPtr->resultCode = TCL_ERROR;
	    return NULL;
	}





	index = TclIndexDecode(infoPtr->indexv[i], listLen - 1);




	if (Tcl_ListObjIndex(infoPtr->interp, objPtr, index,
		&currentObj) != TCL_OK) {
	    infoPtr->resultCode = TCL_ERROR;
	    return NULL;
	}
	if (currentObj == NULL) {
Changes to generic/tclCompCmdsGR.c.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

45
46
47
48
49
50
51
52


53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86


/*
 *----------------------------------------------------------------------
 *
 * TclGetIndexFromToken --
 *
 *	Parse a token and get the encoded version of the index (as understood
 *	by TEBC), assuming it is at all knowable at compile time. Only handles
 *	indices that are integers or 'end' or 'end-integer'.
 *
 * Returns:
 *	TCL_OK if parsing succeeded, and TCL_ERROR if it failed.
 *
 * Side effects:

 *	Sets *index to the index value if successful.
 *
 *----------------------------------------------------------------------
 */

int
TclGetIndexFromToken(
    Tcl_Token *tokenPtr,


    int *index)
{
    Tcl_Obj *tmpObj = Tcl_NewObj();
    int result, idx;

    if (!TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {
	Tcl_DecrRefCount(tmpObj);
	return TCL_ERROR;
    }

    result = TclGetIntFromObj(NULL, tmpObj, &idx);
    if (result == TCL_OK) {
	if (idx < 0) {
	    result = TCL_ERROR;
	}
    } else {
	result = TclGetIntForIndexM(NULL, tmpObj, TCL_INDEX_END, &idx);
	if (result == TCL_OK && idx > TCL_INDEX_END) {
	    result = TCL_ERROR;
	}
    }
    Tcl_DecrRefCount(tmpObj);

    if (result == TCL_OK) {
	*index = idx;
    }

    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * TclCompileGlobalCmd --







|
|
<





>
|







>
>
|


|

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

<
<
<
<
<







30
31
32
33
34
35
36
37
38

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60







61
62






63





64
65
66
67
68
69
70


/*
 *----------------------------------------------------------------------
 *
 * TclGetIndexFromToken --
 *
 *	Parse a token to determine if an index value is known at
 *	compile time. 

 *
 * Returns:
 *	TCL_OK if parsing succeeded, and TCL_ERROR if it failed.
 *
 * Side effects:
 *	When TCL_OK is returned, the encoded index value is written
 *	to *index.
 *
 *----------------------------------------------------------------------
 */

int
TclGetIndexFromToken(
    Tcl_Token *tokenPtr,
    int before,
    int after,
    int *indexPtr)
{
    Tcl_Obj *tmpObj = Tcl_NewObj();
    int result = TCL_ERROR;

    if (TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {







	result = TclIndexEncode(NULL, tmpObj, before, after, indexPtr);
    }






    Tcl_DecrRefCount(tmpObj);





    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * TclCompileGlobalCmd --
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
    for (i=1; i<numWords; varTokenPtr = TokenAfter(varTokenPtr),i++) {
	localIndex = IndexTailVarIfKnown(interp, varTokenPtr, envPtr);

	if (localIndex < 0) {
	    return TCL_ERROR;
	}

	/* TODO: Consider what value can pass throug the
	 * IndexTailVarIfKnown() screen.  Full CompileWord()
	 * likely does not apply here.  Push known value instead. */
	CompileWord(envPtr, varTokenPtr, interp, i);
	TclEmitInstInt4(	INST_NSUPVAR, localIndex,	envPtr);
    }

    /*







|







123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
    for (i=1; i<numWords; varTokenPtr = TokenAfter(varTokenPtr),i++) {
	localIndex = IndexTailVarIfKnown(interp, varTokenPtr, envPtr);

	if (localIndex < 0) {
	    return TCL_ERROR;
	}

	/* TODO: Consider what value can pass through the
	 * IndexTailVarIfKnown() screen.  Full CompileWord()
	 * likely does not apply here.  Push known value instead. */
	CompileWord(envPtr, varTokenPtr, interp, i);
	TclEmitInstInt4(	INST_NSUPVAR, localIndex,	envPtr);
    }

    /*
1099
1100
1101
1102
1103
1104
1105
1106

1107
1108
1109
1110

1111
1112
1113
1114
1115
1116
1117
1118
1119
1120

    valTokenPtr = TokenAfter(parsePtr->tokenPtr);
    if (numWords != 3) {
	goto emitComplexLindex;
    }

    idxTokenPtr = TokenAfter(valTokenPtr);
    if (TclGetIndexFromToken(idxTokenPtr, &idx) == TCL_OK) {

	/*
	 * All checks have been completed, and we have exactly one of these
	 * constructs:
	 *	 lindex <arbitraryValue> <posInt>

	 *	 lindex <arbitraryValue> end-<posInt>
	 * This is best compiled as a push of the arbitrary value followed by
	 * an "immediate lindex" which is the most efficient variety.
	 */

	CompileWord(envPtr, valTokenPtr, interp, 1);
	TclEmitInstInt4(	INST_LIST_INDEX_IMM, idx,	envPtr);
	return TCL_OK;
    }








|
>

<
|
|
>
|
<
|







1083
1084
1085
1086
1087
1088
1089
1090
1091
1092

1093
1094
1095
1096

1097
1098
1099
1100
1101
1102
1103
1104

    valTokenPtr = TokenAfter(parsePtr->tokenPtr);
    if (numWords != 3) {
	goto emitComplexLindex;
    }

    idxTokenPtr = TokenAfter(valTokenPtr);
    if (TclGetIndexFromToken(idxTokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_BEFORE,
	    &idx) == TCL_OK) {
	/*

	 * The idxTokenPtr parsed as a valid index value and was
	 * encoded as expected by INST_LIST_INDEX_IMM.
	 *
	 * NOTE: that we rely on indexing before a list producing the

	 * same result as indexing after a list.
	 */

	CompileWord(envPtr, valTokenPtr, interp, 1);
	TclEmitInstInt4(	INST_LIST_INDEX_IMM, idx,	envPtr);
	return TCL_OK;
    }

1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341

1342
1343




1344
1345
1346

1347
1348




1349
1350
1351
1352
1353
1354
1355
    int idx1, idx2;

    if (parsePtr->numWords != 4) {
	return TCL_ERROR;
    }
    listTokenPtr = TokenAfter(parsePtr->tokenPtr);

    /*
     * Parse the indices. Will only compile if both are constants and not an
     * _integer_ less than zero (since we reserve negative indices here for
     * end-relative indexing) or an end-based index greater than 'end' itself.
     */

    tokenPtr = TokenAfter(listTokenPtr);
    if (TclGetIndexFromToken(tokenPtr, &idx1) != TCL_OK) {

	return TCL_ERROR;
    }





    tokenPtr = TokenAfter(tokenPtr);
    if (TclGetIndexFromToken(tokenPtr, &idx2) != TCL_OK) {

	return TCL_ERROR;
    }





    /*
     * Issue instructions. It's not safe to skip doing the LIST_RANGE, as
     * we've not proved that the 'list' argument is really a list. Not that it
     * is worth trying to do that given current knowledge.
     */








<
<
<
<
<
<

|
>


>
>
>
>


|
>


>
>
>
>







1311
1312
1313
1314
1315
1316
1317






1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
    int idx1, idx2;

    if (parsePtr->numWords != 4) {
	return TCL_ERROR;
    }
    listTokenPtr = TokenAfter(parsePtr->tokenPtr);







    tokenPtr = TokenAfter(listTokenPtr);
    if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_AFTER,
	    &idx1) != TCL_OK) {
	return TCL_ERROR;
    }
    /*
     * Token was an index value, and we treat all "first" indices
     * before the list same as the start of the list.
     */

    tokenPtr = TokenAfter(tokenPtr);
    if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_END,
	    &idx2) != TCL_OK) {
	return TCL_ERROR;
    }
    /*
     * Token was an index value, and we treat all "last" indices
     * after the list same as the end of the list.
     */

    /*
     * Issue instructions. It's not safe to skip doing the LIST_RANGE, as
     * we've not proved that the 'list' argument is really a list. Not that it
     * is worth trying to do that given current knowledge.
     */

1391
1392
1393
1394
1395
1396
1397








1398

1399
1400
1401
1402
1403
1404
1405
    /*
     * Parse the index. Will only compile if it is constant and not an
     * _integer_ less than zero (since we reserve negative indices here for
     * end-relative indexing) or an end-based index greater than 'end' itself.
     */

    tokenPtr = TokenAfter(listTokenPtr);








    if (TclGetIndexFromToken(tokenPtr, &idx) != TCL_OK) {

	return TCL_ERROR;
    }

    /*
     * There are four main cases. If there are no values to insert, this is
     * just a confirm-listiness check. If the index is '0', this is a prepend.
     * If the index is 'end' (== TCL_INDEX_END), this is an append. Otherwise,







>
>
>
>
>
>
>
>
|
>







1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
    /*
     * Parse the index. Will only compile if it is constant and not an
     * _integer_ less than zero (since we reserve negative indices here for
     * end-relative indexing) or an end-based index greater than 'end' itself.
     */

    tokenPtr = TokenAfter(listTokenPtr);

    /*
     * NOTE: This command treats all inserts at indices before the list
     * the same as inserts at the start of the list, and all inserts
     * after the list the same as inserts at the end of the list. We
     * make that transformation here so we can use the optimized bytecode
     * as much as possible.
     */
    if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_END,
	    &idx) != TCL_OK) {
	return TCL_ERROR;
    }

    /*
     * There are four main cases. If there are no values to insert, this is
     * just a confirm-listiness check. If the index is '0', this is a prepend.
     * If the index is 'end' (== TCL_INDEX_END), this is an append. Otherwise,
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432

    for (i=3 ; i<parsePtr->numWords ; i++) {
	tokenPtr = TokenAfter(tokenPtr);
	CompileWord(envPtr, tokenPtr, interp, i);
    }
    TclEmitInstInt4(		INST_LIST, i-3,			envPtr);

    if (idx == 0 /*start*/) {
	TclEmitInstInt4(	INST_REVERSE, 2,		envPtr);
	TclEmitOpcode(		INST_LIST_CONCAT,		envPtr);
    } else if (idx == TCL_INDEX_END /*end*/) {
	TclEmitOpcode(		INST_LIST_CONCAT,		envPtr);
    } else {
	/*
	 * Here we handle two ranges for idx. First when idx > 0, we
	 * want the first half of the split to end at index idx-1 and
	 * the second half to start at index idx.
	 * Second when idx < TCL_INDEX_END, indicating "end-N" indexing,







|


|







1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429

    for (i=3 ; i<parsePtr->numWords ; i++) {
	tokenPtr = TokenAfter(tokenPtr);
	CompileWord(envPtr, tokenPtr, interp, i);
    }
    TclEmitInstInt4(		INST_LIST, i-3,			envPtr);

    if (idx == TCL_INDEX_START) {
	TclEmitInstInt4(	INST_REVERSE, 2,		envPtr);
	TclEmitOpcode(		INST_LIST_CONCAT,		envPtr);
    } else if (idx == TCL_INDEX_END) {
	TclEmitOpcode(		INST_LIST_CONCAT,		envPtr);
    } else {
	/*
	 * Here we handle two ranges for idx. First when idx > 0, we
	 * want the first half of the split to end at index idx-1 and
	 * the second half to start at index idx.
	 * Second when idx < TCL_INDEX_END, indicating "end-N" indexing,
1471
1472
1473
1474
1475
1476
1477
1478
1479

1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493

1494
1495
1496
1497
1498

1499
1500
1501
1502
1503
1504
1505
1506
1507
1508



1509
1510

1511
1512
1513
1514



1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526







1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540


1541
1542
1543
1544
1545

1546
1547
1548
1549
1550
1551


1552
1553
1554





1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575

1576
1577
1578
1579
1580
1581
1582
1583
1584
1585

1586
1587


1588





1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609

1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627

1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676


1677



1678
1679



1680




1681

1682

1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701


1702
1703

1704
1705



1706
1707
1708

1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
				 * command. */
    Command *cmdPtr,		/* Points to defintion of command being
				 * compiled. */
    CompileEnv *envPtr)		/* Holds the resulting instructions. */
{
    Tcl_Token *tokenPtr, *listTokenPtr;
    DefineLineInformation;	/* TIP #280 */
    Tcl_Obj *tmpObj;
    int idx1, idx2, i, offset, offset2;


    if (parsePtr->numWords < 4) {
	return TCL_ERROR;
    }
    listTokenPtr = TokenAfter(parsePtr->tokenPtr);

    /*
     * Parse the indices. Will only compile if both are constants and not an
     * _integer_ less than zero (since we reserve negative indices here for
     * end-relative indexing) or an end-based index greater than 'end' itself.
     */

    tokenPtr = TokenAfter(listTokenPtr);
    if (TclGetIndexFromToken(tokenPtr, &idx1) != TCL_OK) {

	return TCL_ERROR;
    }

    tokenPtr = TokenAfter(tokenPtr);
    if (TclGetIndexFromToken(tokenPtr, &idx2) != TCL_OK) {

	return TCL_ERROR;
    }

    /*
     * idx1, idx2 are now in canonical form:
     *
     *  - integer:	[0,len+1]
     *  - end index:    TCL_INDEX_END
     *  - -ive offset:  TCL_INDEX_END-[len-1,0]
     *  - +ive offset:  TCL_INDEX_END+1



     */


    /*
     * Compilation fails when one index is end-based but the other isn't.
     * Fixing this will require more bytecodes, but this is a workaround for
     * now. [Bug 47ac84309b]



     */

    if ((idx1 <= TCL_INDEX_END) != (idx2 <= TCL_INDEX_END)) {
	return TCL_ERROR;
    }

    if (idx2 != TCL_INDEX_END && idx2 >= 0 && idx2 < idx1) {
	idx2 = idx1 - 1;
    }

    /*
     * Work out what this [lreplace] is actually doing.







     */

    tmpObj = NULL;
    CompileWord(envPtr, listTokenPtr, interp, 1);
    if (parsePtr->numWords == 4) {
	if (idx1 == 0) {
	    if (idx2 == TCL_INDEX_END) {
		goto dropAll;
	    }
	    idx1 = idx2 + 1;
	    idx2 = TCL_INDEX_END;
	    goto dropEnd;
	} else if (idx2 == TCL_INDEX_END) {
	    idx2 = idx1 - 1;


	    idx1 = 0;
	    goto dropEnd;
	} else {
	    if (idx2 < idx1) {
		idx2 = idx1 - 1;

	    }
	    if (idx1 > 0) {
		tmpObj = Tcl_NewIntObj(idx1);
		Tcl_IncrRefCount(tmpObj);
	    }
	    goto dropRange;


	}
    }






    tokenPtr = TokenAfter(tokenPtr);
    for (i=4 ; i<parsePtr->numWords ; i++) {
	CompileWord(envPtr, tokenPtr, interp, i);
	tokenPtr = TokenAfter(tokenPtr);
    }
    TclEmitInstInt4(		INST_LIST, i - 4,		envPtr);
    TclEmitInstInt4(		INST_REVERSE, 2,		envPtr);
    if (idx1 == 0) {
	if (idx2 == TCL_INDEX_END) {
	    goto replaceAll;
	}
	idx1 = idx2 + 1;
	idx2 = TCL_INDEX_END;
	goto replaceHead;
    } else if (idx2 == TCL_INDEX_END) {
	idx2 = idx1 - 1;
	idx1 = 0;
	goto replaceTail;
    } else {
	if (idx2 < idx1) {
	    idx2 = idx1 - 1;

	}
	if (idx1 > 0) {
	    tmpObj = Tcl_NewIntObj(idx1);
	    Tcl_IncrRefCount(tmpObj);
	}
	goto replaceRange;
    }

    /*
     * Issue instructions to perform the operations relating to configurations

     * that just drop. The only argument pushed on the stack is the list to
     * operate on.


     */






  dropAll:			/* This just ensures the arg is a list. */
    TclEmitOpcode(		INST_LIST_LENGTH,		envPtr);
    TclEmitOpcode(		INST_POP,			envPtr);
    PushStringLiteral(envPtr,	"");
    goto done;

  dropEnd:
    TclEmitInstInt4(		INST_LIST_RANGE_IMM, idx1,	envPtr);
    TclEmitInt4(			idx2,			envPtr);
    goto done;

  dropRange:
    if (tmpObj != NULL) {
	/*
	 * Emit bytecode to check the list length.
	 */

	TclEmitOpcode(		INST_DUP,			envPtr);
	TclEmitOpcode(		INST_LIST_LENGTH,		envPtr);
	TclEmitPush(TclAddLiteralObj(envPtr, tmpObj, NULL),	envPtr);

	TclEmitOpcode(		INST_GE,			envPtr);
	offset = CurrentOffset(envPtr);
	TclEmitInstInt1(	INST_JUMP_TRUE1, 0,		envPtr);

	/*
	 * Emit an error if we've been given an empty list.
	 */

	TclEmitOpcode(		INST_DUP,			envPtr);
	TclEmitOpcode(		INST_LIST_LENGTH,		envPtr);
	offset2 = CurrentOffset(envPtr);
	TclEmitInstInt1(	INST_JUMP_FALSE1, 0,		envPtr);
	TclEmitPush(TclAddLiteralObj(envPtr, Tcl_ObjPrintf(
		"list doesn't contain element %d", idx1), NULL), envPtr);
	CompileReturnInternal(envPtr, INST_RETURN_IMM, TCL_ERROR, 0,
		Tcl_ObjPrintf("-errorcode {TCL OPERATION LREPLACE BADIDX}"));
	TclStoreInt1AtPtr(CurrentOffset(envPtr) - offset,
		envPtr->codeStart + offset + 1);

	TclStoreInt1AtPtr(CurrentOffset(envPtr) - offset2,
		envPtr->codeStart + offset2 + 1);
	TclAdjustStackDepth(-1, envPtr);
    }
    TclEmitOpcode(		INST_DUP,			envPtr);
    TclEmitInstInt4(		INST_LIST_RANGE_IMM, 0,		envPtr);
    TclEmitInt4(			idx1 - 1,		envPtr);
    TclEmitInstInt4(		INST_REVERSE, 2,		envPtr);
    TclEmitInstInt4(		INST_LIST_RANGE_IMM, idx2 + 1,	envPtr);
    TclEmitInt4(			TCL_INDEX_END,		envPtr);
    TclEmitOpcode(		INST_LIST_CONCAT,		envPtr);
    goto done;

    /*
     * Issue instructions to perform the operations relating to configurations
     * that do real replacement. All arguments are pushed and assembled into a
     * pair: the list of values to replace with, and the list to do the
     * surgery on.
     */

  replaceAll:
    TclEmitOpcode(		INST_LIST_LENGTH,		envPtr);
    TclEmitOpcode(		INST_POP,			envPtr);
    goto done;

  replaceHead:
    TclEmitInstInt4(		INST_LIST_RANGE_IMM, idx1,	envPtr);
    TclEmitInt4(			idx2,			envPtr);
    TclEmitOpcode(		INST_LIST_CONCAT,		envPtr);
    goto done;

  replaceTail:
    TclEmitInstInt4(		INST_LIST_RANGE_IMM, idx1,	envPtr);
    TclEmitInt4(			idx2,			envPtr);
    TclEmitInstInt4(		INST_REVERSE, 2,		envPtr);
    TclEmitOpcode(		INST_LIST_CONCAT,		envPtr);
    goto done;

  replaceRange:
    if (tmpObj != NULL) {
	/*
	 * Emit bytecode to check the list length.
	 */

	TclEmitOpcode(		INST_DUP,			envPtr);
	TclEmitOpcode(		INST_LIST_LENGTH,		envPtr);

	/*
	 * Check the list length vs idx1.


	 */




	TclEmitPush(TclAddLiteralObj(envPtr, tmpObj, NULL),	envPtr);



	TclEmitOpcode(		INST_GE,			envPtr);




	offset = CurrentOffset(envPtr);

	TclEmitInstInt1(	INST_JUMP_TRUE1, 0,		envPtr);


	/*
	 * Emit an error if we've been given an empty list.
	 */

	TclEmitOpcode(		INST_DUP,			envPtr);
	TclEmitOpcode(		INST_LIST_LENGTH,		envPtr);
	offset2 = CurrentOffset(envPtr);
	TclEmitInstInt1(	INST_JUMP_FALSE1, 0,		envPtr);
	TclEmitPush(TclAddLiteralObj(envPtr, Tcl_ObjPrintf(
		"list doesn't contain element %d", idx1), NULL), envPtr);
	CompileReturnInternal(envPtr, INST_RETURN_IMM, TCL_ERROR, 0,
		Tcl_ObjPrintf("-errorcode {TCL OPERATION LREPLACE BADIDX}"));
	TclStoreInt1AtPtr(CurrentOffset(envPtr) - offset,
		envPtr->codeStart + offset + 1);
	TclStoreInt1AtPtr(CurrentOffset(envPtr) - offset2,
		envPtr->codeStart + offset2 + 1);
	TclAdjustStackDepth(-1, envPtr);
    }


    TclEmitOpcode(		INST_DUP,			envPtr);
    TclEmitInstInt4(		INST_LIST_RANGE_IMM, 0,		envPtr);

    TclEmitInt4(			idx1 - 1,		envPtr);
    TclEmitInstInt4(		INST_REVERSE, 2,		envPtr);



    TclEmitInstInt4(		INST_LIST_RANGE_IMM, idx2 + 1,	envPtr);
    TclEmitInt4(			TCL_INDEX_END,		envPtr);
    TclEmitInstInt4(		INST_REVERSE, 3,		envPtr);

    TclEmitOpcode(		INST_LIST_CONCAT,		envPtr);
    TclEmitInstInt4(		INST_REVERSE, 2,		envPtr);
    TclEmitOpcode(		INST_LIST_CONCAT,		envPtr);
    goto done;

    /*
     * Clean up the allocated memory.
     */

  done:
    if (tmpObj != NULL) {
	Tcl_DecrRefCount(tmpObj);
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclCompileLsetCmd --







<

>






<
<
<
<
<
<

|
>




|
>




|
<
<
|
<
<
>
>
>


>
|
<
<
<
>
>
>
|
<
<



<
<
<
<

|
>
>
>
>
>
>
>


<
<
<
<
|
<
<
|
<
<
|
|
>
>
|
<
|
<
<
>
|
<
<
<
|
<
>
>
|
<
|
>
>
>
>
>
|
|
|
|
|
<
<
<
<
<
|
<
<
<
<
<
<
<
|
<
<
>
|
|
<
<
|
<
|
<

<
>
|
<
>
>

>
>
>
>
>
|
<
|
|
<
<
|
<
|
<
<

<
<
<
<
<
|
<
<
|
>
|
|


<
<
<
|
<
<
<
<






>


<

<
<
<
<
<
<
<
<

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

|
>
>

>
>
>
|
|
>
>
>
|
>
>
>
>
|
>
|
>
|
<
|
<
|
<
<
<
<
<
<
<
<
<
<
|
|
|

>
>
|
<
>
|
<
>
>
>
|
|
<
>
|
<
<
<
|
<
<
<
|
<
<
<
|







1468
1469
1470
1471
1472
1473
1474

1475
1476
1477
1478
1479
1480
1481
1482






1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496


1497


1498
1499
1500
1501
1502
1503
1504



1505
1506
1507
1508


1509
1510
1511




1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522




1523


1524


1525
1526
1527
1528
1529

1530


1531
1532



1533

1534
1535
1536

1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547





1548







1549


1550
1551
1552


1553

1554

1555

1556
1557

1558
1559
1560
1561
1562
1563
1564
1565
1566

1567
1568


1569

1570


1571





1572


1573
1574
1575
1576
1577
1578



1579




1580
1581
1582
1583
1584
1585
1586
1587
1588

1589








1590






1591



























1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614

1615

1616










1617
1618
1619
1620
1621
1622
1623

1624
1625

1626
1627
1628
1629
1630

1631
1632



1633



1634



1635
1636
1637
1638
1639
1640
1641
1642
				 * command. */
    Command *cmdPtr,		/* Points to defintion of command being
				 * compiled. */
    CompileEnv *envPtr)		/* Holds the resulting instructions. */
{
    Tcl_Token *tokenPtr, *listTokenPtr;
    DefineLineInformation;	/* TIP #280 */

    int idx1, idx2, i, offset, offset2;
    int emptyPrefix=1, suffixStart = 0;

    if (parsePtr->numWords < 4) {
	return TCL_ERROR;
    }
    listTokenPtr = TokenAfter(parsePtr->tokenPtr);







    tokenPtr = TokenAfter(listTokenPtr);
    if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_AFTER,
	    &idx1) != TCL_OK) {
	return TCL_ERROR;
    }

    tokenPtr = TokenAfter(tokenPtr);
    if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_END,
	    &idx2) != TCL_OK) {
	return TCL_ERROR;
    }

    /*
     * idx1, idx2 are the conventional encoded forms of the tokens parsed


     * as all forms of index values.  Values of idx1 that come before the


     * list are treated the same as if they were the start of the list.
     * Values of idx2 that come after the list are treated the same as if
     * they were the end of the list.
     */

    if (idx1 == TCL_INDEX_AFTER) {
	/*



	 * [lreplace] treats idx1 value end+1 differently from end+2, etc.
	 * The operand encoding cannot distinguish them, so we must bail
	 * out to direct evaluation.
	 */


	return TCL_ERROR;
    }





    /*
     * General structure of the [lreplace] result is
     *		prefix replacement suffix
     * In a few cases we can predict various parts will be empty and
     * take advantage.
     *
     * The proper suffix begins with the greater of indices idx1 or
     * idx2 + 1. If we cannot tell at compile time which is greater,
     * we must defer to direct evaluation.
     */





    if (idx2 == TCL_INDEX_BEFORE) {


	suffixStart = idx1;


    } else if (idx2 == TCL_INDEX_END) {
	suffixStart = TCL_INDEX_AFTER;
    } else if (((idx2 < TCL_INDEX_END) && (idx1 <= TCL_INDEX_END))
	    || ((idx2 >= TCL_INDEX_START) && (idx1 >= TCL_INDEX_START))) {
	suffixStart = (idx1 > idx2 + 1) ? idx1 : idx2 + 1;

    } else {


	return TCL_ERROR;
    }





    /* All paths start with computing/pushing the original value. */
    CompileWord(envPtr, listTokenPtr, interp, 1);


    /*
     * Push all the replacement values next so any errors raised in
     * creating them get raised first.
     */
    if (parsePtr->numWords > 4) {
	/* Push the replacement arguments */
	tokenPtr = TokenAfter(tokenPtr);
	for (i=4 ; i<parsePtr->numWords ; i++) {
	    CompileWord(envPtr, tokenPtr, interp, i);
	    tokenPtr = TokenAfter(tokenPtr);
	}













	/* Make a list of them... */


	TclEmitInstInt4(	INST_LIST, i - 4,		envPtr);

	emptyPrefix = 0;


    }

     

    /*

     * [lreplace] raises an error when idx1 points after the list, but
     * only when the list is not empty. This is maximum stupidity.

     *
     * TODO: TIP this nonsense away!
     */
    if (idx1 >= TCL_INDEX_START) {
	if (emptyPrefix) {
	    TclEmitOpcode(	INST_DUP,			envPtr);
	} else {
	    TclEmitInstInt4(	INST_OVER, 1,			envPtr);
	}

	TclEmitOpcode(		INST_LIST_LENGTH,		envPtr);
	TclEmitOpcode(		INST_DUP,			envPtr);


	offset = CurrentOffset(envPtr);

	TclEmitInstInt1(	INST_JUMP_FALSE1, 0,		envPtr);








	/* List is not empty */


	TclEmitPush(TclAddLiteralObj(envPtr, Tcl_NewIntObj(idx1),
							NULL),	envPtr);
	TclEmitOpcode(		INST_GT,			envPtr);
	offset2 = CurrentOffset(envPtr);
	TclEmitInstInt1(	INST_JUMP_TRUE1, 0,		envPtr);




	/* Idx1 >= list length ===> raise an error */




	TclEmitPush(TclAddLiteralObj(envPtr, Tcl_ObjPrintf(
		"list doesn't contain element %d", idx1), NULL), envPtr);
	CompileReturnInternal(envPtr, INST_RETURN_IMM, TCL_ERROR, 0,
		Tcl_ObjPrintf("-errorcode {TCL OPERATION LREPLACE BADIDX}"));
	TclStoreInt1AtPtr(CurrentOffset(envPtr) - offset,
		envPtr->codeStart + offset + 1);
	TclEmitOpcode(		INST_POP,			envPtr);
	TclStoreInt1AtPtr(CurrentOffset(envPtr) - offset2,
		envPtr->codeStart + offset2 + 1);

    }















    if ((idx1 == suffixStart) && (parsePtr->numWords == 4)) {



























	/*
	 * This is a "no-op". Example: [lreplace {a b c} 2 0]
	 * We still do a list operation to get list-verification
	 * and canonicalization side effects.
	 */
	TclEmitInstInt4(	INST_LIST_RANGE_IMM, 0,		envPtr);
	TclEmitInt4(			TCL_INDEX_END,		envPtr);
	return TCL_OK;
    }

    if (idx1 != TCL_INDEX_START) {
	/* Prefix may not be empty; generate bytecode to push it */
	if (emptyPrefix) {
	    TclEmitOpcode(	INST_DUP,			envPtr);
	} else {
	    TclEmitInstInt4(	INST_OVER, 1,			envPtr);
	}
	TclEmitInstInt4(	INST_LIST_RANGE_IMM, 0,		envPtr);
	TclEmitInt4(			idx1 - 1,		envPtr);
	if (!emptyPrefix) {
	    TclEmitInstInt4(	INST_REVERSE, 2,		envPtr);
	    TclEmitOpcode(	INST_LIST_CONCAT,		envPtr);
	}

	emptyPrefix = 0;

    }











    if (!emptyPrefix) {
	TclEmitInstInt4(	INST_REVERSE, 2,		envPtr);
    }

    if (suffixStart == TCL_INDEX_AFTER) {
	TclEmitOpcode(		INST_POP,			envPtr);

	if (emptyPrefix) {
	    PushStringLiteral(envPtr, "");

	}
    } else {
	/* Suffix may not be empty; generate bytecode to push it */
	TclEmitInstInt4(	INST_LIST_RANGE_IMM, suffixStart, envPtr);
	TclEmitInt4(			TCL_INDEX_END,		envPtr);

	if (!emptyPrefix) {
	    TclEmitOpcode(	INST_LIST_CONCAT,		envPtr);



	}



    }




    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclCompileLsetCmd --
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954

	localIndex = IndexTailVarIfKnown(interp, varTokenPtr, envPtr);

	if (localIndex < 0) {
	    return TCL_ERROR;
	}

	/* TODO: Consider what value can pass throug the
	 * IndexTailVarIfKnown() screen.  Full CompileWord()
	 * likely does not apply here.  Push known value instead. */
	CompileWord(envPtr, varTokenPtr, interp, i);
	TclEmitInstInt4(	INST_VARIABLE, localIndex,	envPtr);

	if (i+1 < numWords) {
	    /*







|







2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868

	localIndex = IndexTailVarIfKnown(interp, varTokenPtr, envPtr);

	if (localIndex < 0) {
	    return TCL_ERROR;
	}

	/* TODO: Consider what value can pass through the
	 * IndexTailVarIfKnown() screen.  Full CompileWord()
	 * likely does not apply here.  Push known value instead. */
	CompileWord(envPtr, varTokenPtr, interp, i);
	TclEmitInstInt4(	INST_VARIABLE, localIndex,	envPtr);

	if (i+1 < numWords) {
	    /*
Changes to generic/tclCompCmdsSZ.c.
926
927
928
929
930
931
932



933
934
935
936
937

938
939












940

941










942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
    if (parsePtr->numWords != 4) {
	return TCL_ERROR;
    }
    stringTokenPtr = TokenAfter(parsePtr->tokenPtr);
    fromTokenPtr = TokenAfter(stringTokenPtr);
    toTokenPtr = TokenAfter(fromTokenPtr);




    /*
     * Parse the two indices.
     */

    if (TclGetIndexFromToken(fromTokenPtr, &idx1) != TCL_OK) {

	goto nonConstantIndices;
    }












    if (TclGetIndexFromToken(toTokenPtr, &idx2) != TCL_OK) {

	goto nonConstantIndices;










    }

    /*
     * Push the operand onto the stack and then the substring operation.
     */

    CompileWord(envPtr, stringTokenPtr,			interp, 1);
    OP44(		STR_RANGE_IMM, idx1, idx2);
    return TCL_OK;

    /*
     * Push the operands onto the stack and then the substring operation.
     */

  nonConstantIndices:
    CompileWord(envPtr, stringTokenPtr,			interp, 1);
    CompileWord(envPtr, fromTokenPtr,			interp, 2);
    CompileWord(envPtr, toTokenPtr,			interp, 3);
    OP(			STR_RANGE);
    return TCL_OK;
}

int







>
>
>




|
>


>
>
>
>
>
>
>
>
>
>
>
>
|
>

>
>
>
>
>
>
>
>
>
>






<








<







926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974

975
976
977
978
979
980
981
982

983
984
985
986
987
988
989
    if (parsePtr->numWords != 4) {
	return TCL_ERROR;
    }
    stringTokenPtr = TokenAfter(parsePtr->tokenPtr);
    fromTokenPtr = TokenAfter(stringTokenPtr);
    toTokenPtr = TokenAfter(fromTokenPtr);

    /* Every path must push the string argument */
    CompileWord(envPtr, stringTokenPtr,			interp, 1);

    /*
     * Parse the two indices.
     */

    if (TclGetIndexFromToken(fromTokenPtr, TCL_INDEX_START, TCL_INDEX_AFTER,
	    &idx1) != TCL_OK) {
	goto nonConstantIndices;
    }
    /*
     * Token parsed as an index expression. We treat all indices before
     * the string the same as the start of the string.
     */

    if (idx1 == TCL_INDEX_AFTER) {
	/* [string range $s end+1 $last] must be empty string */
	OP(		POP);
	PUSH(		"");
	return TCL_OK;
    }

    if (TclGetIndexFromToken(toTokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_END,
	    &idx2) != TCL_OK) {
	goto nonConstantIndices;
    }
    /*
     * Token parsed as an index expression. We treat all indices after
     * the string the same as the end of the string.
     */
    if (idx2 == TCL_INDEX_BEFORE) {
	/* [string range $s $first -1] must be empty string */
	OP(		POP);
	PUSH(		"");
	return TCL_OK;
    }

    /*
     * Push the operand onto the stack and then the substring operation.
     */


    OP44(		STR_RANGE_IMM, idx1, idx2);
    return TCL_OK;

    /*
     * Push the operands onto the stack and then the substring operation.
     */

  nonConstantIndices:

    CompileWord(envPtr, fromTokenPtr,			interp, 2);
    CompileWord(envPtr, toTokenPtr,			interp, 3);
    OP(			STR_RANGE);
    return TCL_OK;
}

int
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995

996
997




998
999
1000

1001
1002




1003

1004
1005
1006
1007








1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024








1025
1026
1027
1028
1029
1030
1031
    valueTokenPtr = TokenAfter(parsePtr->tokenPtr);
    if (parsePtr->numWords == 5) {
	tokenPtr = TokenAfter(valueTokenPtr);
	tokenPtr = TokenAfter(tokenPtr);
	replacementTokenPtr = TokenAfter(tokenPtr);
    }

    /*
     * Parse the indices. Will only compile special cases if both are
     * constants and not an _integer_ less than zero (since we reserve
     * negative indices here for end-relative indexing) or an end-based index
     * greater than 'end' itself.
     */

    tokenPtr = TokenAfter(valueTokenPtr);
    if (TclGetIndexFromToken(tokenPtr, &idx1) != TCL_OK) {

	goto genericReplace;
    }





    tokenPtr = TokenAfter(tokenPtr);
    if (TclGetIndexFromToken(tokenPtr, &idx2) != TCL_OK) {

	goto genericReplace;
    }






    /*
     * We handle these replacements specially: first character (where
     * idx1=idx2=0) and last character (where idx1=idx2=TCL_INDEX_END). Anything
     * else and the semantics get rather screwy.








     */

    if (idx1 == 0 && idx2 == 0) {
	int notEq, end;

	/*
	 * Just working with the first character.
	 */

	CompileWord(envPtr, valueTokenPtr, interp, 1);
	if (replacementTokenPtr == NULL) {
	    /* Drop first */
	    OP44(	STR_RANGE_IMM, 1, TCL_INDEX_END);
	    return TCL_OK;
	}
	/* Replace first */
	CompileWord(envPtr, replacementTokenPtr, interp, 4);








	OP4(		OVER, 1);
	PUSH(		"");
	OP(		STR_EQ);
	JUMP1(		JUMP_FALSE, notEq);
	OP(		POP);
	JUMP1(		JUMP, end);
	FIXJUMP1(notEq);







<
<
<
<
<
<
<

|
>


>
>
>
>


|
>


>
>
>
>

>




>
>
>
>
>
>
>
>

















>
>
>
>
>
>
>
>







1005
1006
1007
1008
1009
1010
1011







1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
    valueTokenPtr = TokenAfter(parsePtr->tokenPtr);
    if (parsePtr->numWords == 5) {
	tokenPtr = TokenAfter(valueTokenPtr);
	tokenPtr = TokenAfter(tokenPtr);
	replacementTokenPtr = TokenAfter(tokenPtr);
    }








    tokenPtr = TokenAfter(valueTokenPtr);
    if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_AFTER,
	    &idx1) != TCL_OK) {
	goto genericReplace;
    }
    /*
     * Token parsed as an index value. Indices before the string are
     * treated as index of start of string.
     */

    tokenPtr = TokenAfter(tokenPtr);
    if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_END,
	    &idx2) != TCL_OK) {
	goto genericReplace;
    }
    /*
     * Token parsed as an index value. Indices after the string are
     * treated as index of end of string.
     */

/* TODO...... */
    /*
     * We handle these replacements specially: first character (where
     * idx1=idx2=0) and last character (where idx1=idx2=TCL_INDEX_END). Anything
     * else and the semantics get rather screwy.
     *
     * TODO: These seem to be very narrow cases.  They are not even
     * covered by the test suite, and any programming that ends up
     * here could have been coded by the programmer using [string range]
     * and [string cat]. [*]  Not clear at all to me that the bytecode
     * generated here is worthwhile.
     *
     *  [*] Except for the empty string exceptions.  UGGGGHHHH.
     */

    if (idx1 == 0 && idx2 == 0) {
	int notEq, end;

	/*
	 * Just working with the first character.
	 */

	CompileWord(envPtr, valueTokenPtr, interp, 1);
	if (replacementTokenPtr == NULL) {
	    /* Drop first */
	    OP44(	STR_RANGE_IMM, 1, TCL_INDEX_END);
	    return TCL_OK;
	}
	/* Replace first */
	CompileWord(envPtr, replacementTokenPtr, interp, 4);

	/*
	 * NOTE: The following tower of bullshit is present because
	 * [string replace] was boneheadedly defined not to replace
	 * empty strings, so we actually have to detect the empty
	 * string case and treat it differently.
	 */

	OP4(		OVER, 1);
	PUSH(		"");
	OP(		STR_EQ);
	JUMP1(		JUMP_FALSE, notEq);
	OP(		POP);
	JUMP1(		JUMP, end);
	FIXJUMP1(notEq);
1047
1048
1049
1050
1051
1052
1053



1054
1055
1056
1057
1058
1059
1060
	if (replacementTokenPtr == NULL) {
	    /* Drop last */
	    OP44(	STR_RANGE_IMM, 0, TCL_INDEX_END-1);
	    return TCL_OK;
	}
	/* Replace last */
	CompileWord(envPtr, replacementTokenPtr, interp, 4);



	OP4(		OVER, 1);
	PUSH(		"");
	OP(		STR_EQ);
	JUMP1(		JUMP_FALSE, notEq);
	OP(		POP);
	JUMP1(		JUMP, end);
	FIXJUMP1(notEq);







>
>
>







1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
	if (replacementTokenPtr == NULL) {
	    /* Drop last */
	    OP44(	STR_RANGE_IMM, 0, TCL_INDEX_END-1);
	    return TCL_OK;
	}
	/* Replace last */
	CompileWord(envPtr, replacementTokenPtr, interp, 4);

	/* More bullshit; see NOTE above. */

	OP4(		OVER, 1);
	PUSH(		"");
	OP(		STR_EQ);
	JUMP1(		JUMP_FALSE, notEq);
	OP(		POP);
	JUMP1(		JUMP, end);
	FIXJUMP1(notEq);
Changes to generic/tclCompile.h.
1096
1097
1098
1099
1100
1101
1102
1103

1104
1105
1106
1107
1108
1109
1110
MODULE_SCOPE int	TclFindCompiledLocal(const char *name, int nameChars,
			    int create, CompileEnv *envPtr);
MODULE_SCOPE int	TclFixupForwardJump(CompileEnv *envPtr,
			    JumpFixup *jumpFixupPtr, int jumpDist,
			    int distThreshold);
MODULE_SCOPE void	TclFreeCompileEnv(CompileEnv *envPtr);
MODULE_SCOPE void	TclFreeJumpFixupArray(JumpFixupArray *fixupArrayPtr);
MODULE_SCOPE int	TclGetIndexFromToken(Tcl_Token *tokenPtr, int *index);

MODULE_SCOPE ByteCode *	TclInitByteCode(CompileEnv *envPtr);
MODULE_SCOPE ByteCode *	TclInitByteCodeObj(Tcl_Obj *objPtr,
			    const Tcl_ObjType *typePtr, CompileEnv *envPtr);
MODULE_SCOPE void	TclInitCompileEnv(Tcl_Interp *interp,
			    CompileEnv *envPtr, const char *string,
			    int numBytes, const CmdFrame *invoker, int word);
MODULE_SCOPE void	TclInitJumpFixupArray(JumpFixupArray *fixupArrayPtr);







|
>







1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
MODULE_SCOPE int	TclFindCompiledLocal(const char *name, int nameChars,
			    int create, CompileEnv *envPtr);
MODULE_SCOPE int	TclFixupForwardJump(CompileEnv *envPtr,
			    JumpFixup *jumpFixupPtr, int jumpDist,
			    int distThreshold);
MODULE_SCOPE void	TclFreeCompileEnv(CompileEnv *envPtr);
MODULE_SCOPE void	TclFreeJumpFixupArray(JumpFixupArray *fixupArrayPtr);
MODULE_SCOPE int	TclGetIndexFromToken(Tcl_Token *tokenPtr,
			    int before, int after, int *indexPtr);
MODULE_SCOPE ByteCode *	TclInitByteCode(CompileEnv *envPtr);
MODULE_SCOPE ByteCode *	TclInitByteCodeObj(Tcl_Obj *objPtr,
			    const Tcl_ObjType *typePtr, CompileEnv *envPtr);
MODULE_SCOPE void	TclInitCompileEnv(Tcl_Interp *interp,
			    CompileEnv *envPtr, const char *string,
			    int numBytes, const CmdFrame *invoker, int word);
MODULE_SCOPE void	TclInitJumpFixupArray(JumpFixupArray *fixupArrayPtr);
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
/*
 * Flags bits used by TclPushVarName.
 */

#define TCL_NO_LARGE_INDEX 1	/* Do not return localIndex value > 255 */
#define TCL_NO_ELEMENT 2	/* Do not push the array element. */

/*
 * Special value used by TclGetIndexFromToken to encoding the "end" index.
 */

#define TCL_INDEX_END	(-2)

/*
 * DTrace probe macros (NOPs if DTrace support is not enabled).
 */

/*
 * Define the following macros to enable debug logging of the DTrace proc,
 * cmd, and inst probes. Note that this does _not_ require a platform with







<
<
<
<
<
<







1640
1641
1642
1643
1644
1645
1646






1647
1648
1649
1650
1651
1652
1653
/*
 * Flags bits used by TclPushVarName.
 */

#define TCL_NO_LARGE_INDEX 1	/* Do not return localIndex value > 255 */
#define TCL_NO_ELEMENT 2	/* Do not push the array element. */







/*
 * DTrace probe macros (NOPs if DTrace support is not enabled).
 */

/*
 * Define the following macros to enable debug logging of the DTrace proc,
 * cmd, and inst probes. Note that this does _not_ require a platform with
Changes to generic/tclExecute.c.
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
	 */

	if (TclListObjGetElements(interp, valuePtr, &objc, &objv) != TCL_OK) {
	    TRACE_ERROR(interp);
	    goto gotError;
	}

	/*
	 * Select the list item based on the index. Negative operand means
	 * end-based indexing.
	 */

	if (opnd < -1) {
	    index = opnd+1 + objc;
	} else {
	    index = opnd;
	}
	pcAdjustment = 5;

    lindexFastPath:
	if (index >= 0 && index < objc) {
	    objResultPtr = objv[index];
	} else {
	    TclNewObj(objResultPtr);







<
<
|
<

<
<
<
|
<







4596
4597
4598
4599
4600
4601
4602


4603

4604



4605

4606
4607
4608
4609
4610
4611
4612
	 */

	if (TclListObjGetElements(interp, valuePtr, &objc, &objv) != TCL_OK) {
	    TRACE_ERROR(interp);
	    goto gotError;
	}



	/* Decode end-offset index values. */





	index = TclIndexDecode(opnd, objc - 1);

	pcAdjustment = 5;

    lindexFastPath:
	if (index >= 0 && index < objc) {
	    objResultPtr = objv[index];
	} else {
	    TclNewObj(objResultPtr);
4753
4754
4755
4756
4757
4758
4759








4760
4761



4762


4763
4764
4765
4766
4767
4768
4769
4770

4771

4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783


4784


4785
4786

4787
4788
4789
4790
4791
4792



4793



4794
4795


4796
4797
4798
4799
4800

4801
4802
4803
4804
4805
4806
4807

#ifndef TCL_COMPILE_DEBUG
	if (*(pc+9) == INST_POP) {
	    NEXT_INST_F(10, 1, 0);
	}
#endif









	/*
	 * Adjust the indices for end-based handling.



	 */



	if (fromIdx < -1) {
	    fromIdx += 1+objc;
	    if (fromIdx < -1) {
		fromIdx = -1;
	    }
	} else if (fromIdx > objc) {
	    fromIdx = objc;

	}

	if (toIdx < -1) {
	    toIdx += 1 + objc;
	    if (toIdx < -1) {
		toIdx = -1;
	    }
	} else if (toIdx > objc) {
	    toIdx = objc;
	}

	/*
	 * Check if we are referring to a valid, non-empty list range, and if
	 * so, build the list of elements in that range.


	 */



	if (fromIdx<=toIdx && fromIdx<objc && toIdx>=0) {

	    if (fromIdx < 0) {
		fromIdx = 0;
	    }
	    if (toIdx >= objc) {
		toIdx = objc-1;
	    }



	    if (fromIdx == 0 && toIdx != objc-1 && !Tcl_IsShared(valuePtr)) {



		Tcl_ListObjReplace(interp, valuePtr,
			toIdx + 1, LIST_MAX, 0, NULL);


		TRACE_APPEND(("%.30s\n", O2S(valuePtr)));
		NEXT_INST_F(9, 0, 0);
	    }
	    objResultPtr = Tcl_NewListObj(toIdx-fromIdx+1, objv+fromIdx);
	} else {

	    TclNewObj(objResultPtr);
	}

	TRACE_APPEND(("\"%.30s\"", O2S(objResultPtr)));
	NEXT_INST_F(9, 1, 1);

    case INST_LIST_IN:







>
>
>
>
>
>
>
>
|
<
>
>
>

>
>
|
<
<
<
<
|
<
|
>

>
|
|
|
|
|
<
<
|
|

|
<
>
>

>
>
|
|
>
|
|
|
<
<
|
>
>
>
|
>
>
>
|
|
>
>



<

>







4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761

4762
4763
4764
4765
4766
4767
4768




4769

4770
4771
4772
4773
4774
4775
4776
4777
4778


4779
4780
4781
4782

4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793


4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808

4809
4810
4811
4812
4813
4814
4815
4816
4817

#ifndef TCL_COMPILE_DEBUG
	if (*(pc+9) == INST_POP) {
	    NEXT_INST_F(10, 1, 0);
	}
#endif

	/* Every range of an empty list is an empty list */
	if (objc == 0) {
	    TRACE_APPEND(("\n"));
	    NEXT_INST_F(9, 0, 0);
	}

	/* Decode index value operands. */

	/* 

	assert ( toIdx != TCL_INDEX_AFTER);
	 *
	 * Extra safety for legacy bytecodes:
	 */
	if (toIdx == TCL_INDEX_AFTER) {
	    toIdx = TCL_INDEX_END;
	}






	if ((toIdx == TCL_INDEX_BEFORE) || (fromIdx == TCL_INDEX_AFTER)) {
	    goto emptyList;
	}
	toIdx = TclIndexDecode(toIdx, objc - 1);
	if (toIdx < 0) {
	    goto emptyList;
	} else if (toIdx >= objc) {
	    toIdx = objc - 1;
	}



	assert ( toIdx >= 0 && toIdx < objc);
	/*
	assert ( fromIdx != TCL_INDEX_BEFORE );

	 *
	 * Extra safety for legacy bytecodes:
	 */
	if (fromIdx == TCL_INDEX_BEFORE) {
	    fromIdx = TCL_INDEX_START;
	}

	fromIdx = TclIndexDecode(fromIdx, objc - 1);
	if (fromIdx < 0) {
	    fromIdx = 0;
	}



	if (fromIdx <= toIdx) {
	    /* Construct the subsquence list */
	    /* unshared optimization */
	    if (Tcl_IsShared(valuePtr)) {
		objResultPtr = Tcl_NewListObj(toIdx-fromIdx+1, objv+fromIdx);
	    } else {
		if (toIdx != objc - 1) {
		    Tcl_ListObjReplace(NULL, valuePtr, toIdx + 1, LIST_MAX,
			    0, NULL);
		}
		Tcl_ListObjReplace(NULL, valuePtr, 0, fromIdx, 0, NULL);
		TRACE_APPEND(("%.30s\n", O2S(valuePtr)));
		NEXT_INST_F(9, 0, 0);
	    }

	} else {
	emptyList:
	    TclNewObj(objResultPtr);
	}

	TRACE_APPEND(("\"%.30s\"", O2S(objResultPtr)));
	NEXT_INST_F(9, 1, 1);

    case INST_LIST_IN:
5139
5140
5141
5142
5143
5144
5145








5146
5147




5148


5149
5150
5151
5152
5153
5154
5155
5156
5157

5158
5159
5160
5161
5162
5163


5164



5165
5166











5167
5168
5169
5170

5171
5172
5173
5174
5175
5176
5177
    case INST_STR_RANGE_IMM:
	valuePtr = OBJ_AT_TOS;
	fromIdx = TclGetInt4AtPtr(pc+1);
	toIdx = TclGetInt4AtPtr(pc+5);
	length = Tcl_GetCharLength(valuePtr);
	TRACE(("\"%.20s\" %d %d => ", O2S(valuePtr), fromIdx, toIdx));









	/*
	 * Adjust indices for end-based indexing.




	 */



	if (fromIdx < -1) {
	    fromIdx += 1 + length;
	    if (fromIdx < 0) {
		fromIdx = 0;
	    }
	} else if (fromIdx >= length) {
	    fromIdx = length;
	}

	if (toIdx < -1) {
	    toIdx += 1 + length;
	} else if (toIdx >= length) {
	    toIdx = length - 1;
	}



	/*



	 * Check if we can do a sane substring.
	 */












	if (fromIdx <= toIdx) {
	    objResultPtr = Tcl_GetRange(valuePtr, fromIdx, toIdx);
	} else {

	    TclNewObj(objResultPtr);
	}
	TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
	NEXT_INST_F(9, 1, 1);

    {
	Tcl_UniChar *ustring1, *ustring2, *ustring3, *end, *p;







>
>
>
>
>
>
>
>

<
>
>
>
>

>
>
|
|
<
<
|
|
<
<
|
>
|
|




>
>

>
>
>
|

>
>
>
>
>
>
>
>
>
>
>




>







5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164

5165
5166
5167
5168
5169
5170
5171
5172
5173


5174
5175


5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
    case INST_STR_RANGE_IMM:
	valuePtr = OBJ_AT_TOS;
	fromIdx = TclGetInt4AtPtr(pc+1);
	toIdx = TclGetInt4AtPtr(pc+5);
	length = Tcl_GetCharLength(valuePtr);
	TRACE(("\"%.20s\" %d %d => ", O2S(valuePtr), fromIdx, toIdx));

	/* Every range of an empty value is an empty value */
	if (length == 0) {
	    TRACE_APPEND(("\n"));
	    NEXT_INST_F(9, 0, 0);
	}

	/* Decode index operands. */

	/*

	assert ( toIdx != TCL_INDEX_BEFORE );
	assert ( toIdx != TCL_INDEX_AFTER);
	 *
	 * Extra safety for legacy bytecodes:
	 */
	if (toIdx == TCL_INDEX_BEFORE) {
	    goto emptyRange;
	}
	if (toIdx == TCL_INDEX_AFTER) {


	    toIdx = TCL_INDEX_END;
	}



	toIdx = TclIndexDecode(toIdx, length - 1);
	if (toIdx < 0) {
	    goto emptyRange;
	} else if (toIdx >= length) {
	    toIdx = length - 1;
	}

	assert ( toIdx >= 0 && toIdx < length );

	/*
	assert ( fromIdx != TCL_INDEX_BEFORE );
	assert ( fromIdx != TCL_INDEX_AFTER);
	 *
	 * Extra safety for legacy bytecodes:
	 */
	if (fromIdx == TCL_INDEX_BEFORE) {
	    fromIdx = TCL_INDEX_START;
	}
	if (fromIdx == TCL_INDEX_AFTER) {
	    goto emptyRange;
	}

	fromIdx = TclIndexDecode(fromIdx, length - 1);
	if (fromIdx < 0) {
	    fromIdx = 0;
	}

	if (fromIdx <= toIdx) {
	    objResultPtr = Tcl_GetRange(valuePtr, fromIdx, toIdx);
	} else {
	emptyRange:
	    TclNewObj(objResultPtr);
	}
	TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
	NEXT_INST_F(9, 1, 1);

    {
	Tcl_UniChar *ustring1, *ustring2, *ustring3, *end, *p;
Changes to generic/tclInt.h.
3993
3994
3995
3996
3997
3998
3999















4000
4001
4002
4003
4004
4005
4006

MODULE_SCOPE int	TclCompareObjKeys(void *keyPtr, Tcl_HashEntry *hPtr);
MODULE_SCOPE void	TclFreeObjEntry(Tcl_HashEntry *hPtr);
MODULE_SCOPE TCL_HASH_TYPE TclHashObjKey(Tcl_HashTable *tablePtr, void *keyPtr);

MODULE_SCOPE int	TclFullFinalizationRequested(void);
















/*
 *----------------------------------------------------------------
 * Macros used by the Tcl core to create and release Tcl objects.
 * TclNewObj(objPtr) creates a new object denoting an empty string.
 * TclDecrRefCount(objPtr) decrements the object's reference count, and frees
 * the object if its reference count is zero. These macros are inline versions
 * of Tcl_NewObj() and Tcl_DecrRefCount(). Notice that the names differ in not







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021

MODULE_SCOPE int	TclCompareObjKeys(void *keyPtr, Tcl_HashEntry *hPtr);
MODULE_SCOPE void	TclFreeObjEntry(Tcl_HashEntry *hPtr);
MODULE_SCOPE TCL_HASH_TYPE TclHashObjKey(Tcl_HashTable *tablePtr, void *keyPtr);

MODULE_SCOPE int	TclFullFinalizationRequested(void);

/*
 * Utility routines for encoding index values as integers. Used by both
 * some of the command compilers and by [lsort] and [lsearch].
 */

MODULE_SCOPE int	TclIndexEncode(Tcl_Interp *interp, Tcl_Obj *objPtr,
			    int before, int after, int *indexPtr);
MODULE_SCOPE int	TclIndexDecode(int encoded, int endValue);

/* Constants used in index value encoding routines. */
#define TCL_INDEX_END           (-2)
#define TCL_INDEX_BEFORE        (-1)
#define TCL_INDEX_START         (0)
#define TCL_INDEX_AFTER         (INT_MAX)

/*
 *----------------------------------------------------------------
 * Macros used by the Tcl core to create and release Tcl objects.
 * TclNewObj(objPtr) creates a new object denoting an empty string.
 * TclDecrRefCount(objPtr) decrements the object's reference count, and frees
 * the object if its reference count is zero. These macros are inline versions
 * of Tcl_NewObj() and Tcl_DecrRefCount(). Notice that the names differ in not
Changes to generic/tclListObj.c.
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
	 * argPtr designates something that is neither an index nor a
	 * well-formed list. Report the error via TclLindexFlat.
	 */

	return TclLindexFlat(interp, listPtr, 1, &argPtr);
    }

    if (indexListCopy->typePtr == &tclListType) {
	List *listRepPtr = ListRepPtr(indexListCopy);

	listPtr = TclLindexFlat(interp, listPtr, listRepPtr->elemCount,
		&listRepPtr->elements);
    } else {
	int indexCount = -1;	/* Size of the array of list indices. */
	Tcl_Obj **indices = NULL;
				/* Array of list indices. */

	Tcl_ListObjGetElements(NULL, indexListCopy, &indexCount, &indices);
	listPtr = TclLindexFlat(interp, listPtr, indexCount, indices);
    }
    Tcl_DecrRefCount(indexListCopy);
    return listPtr;
}

/*







<
<
|
<
<
<
|
|
<

|







1137
1138
1139
1140
1141
1142
1143


1144



1145
1146

1147
1148
1149
1150
1151
1152
1153
1154
1155
	 * argPtr designates something that is neither an index nor a
	 * well-formed list. Report the error via TclLindexFlat.
	 */

	return TclLindexFlat(interp, listPtr, 1, &argPtr);
    }



    {



	int indexCount = -1;		/* Size of the array of list indices. */
	Tcl_Obj **indices = NULL; 	/* Array of list indices. */


	TclListObjGetElements(NULL, indexListCopy, &indexCount, &indices);
	listPtr = TclLindexFlat(interp, listPtr, indexCount, indices);
    }
    Tcl_DecrRefCount(indexListCopy);
    return listPtr;
}

/*
Changes to generic/tclLoad.c.
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
    /*
     * Test for whether the initialization failed. If so, transfer the error
     * from the target interpreter to the originating one.
     */

    if (code != TCL_OK) {
	Interp *iPtr = (Interp *) target;
	if (iPtr->legacyResult && !iPtr->legacyFreeProc) {
	    /*
	     * A call to Tcl_InitStubs() determined the caller extension and
	     * this interp are incompatible in their stubs mechanisms, and
	     * recorded the error in the oldest legacy place we have to do so.
	     */
	    Tcl_SetObjResult(target, Tcl_NewStringObj(iPtr->legacyResult, -1));
	    iPtr->legacyResult = NULL;







|







467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
    /*
     * Test for whether the initialization failed. If so, transfer the error
     * from the target interpreter to the originating one.
     */

    if (code != TCL_OK) {
	Interp *iPtr = (Interp *) target;
	if (iPtr->legacyResult && *(iPtr->legacyResult) && !iPtr->legacyFreeProc) {
	    /*
	     * A call to Tcl_InitStubs() determined the caller extension and
	     * this interp are incompatible in their stubs mechanisms, and
	     * recorded the error in the oldest legacy place we have to do so.
	     */
	    Tcl_SetObjResult(target, Tcl_NewStringObj(iPtr->legacyResult, -1));
	    iPtr->legacyResult = NULL;
Changes to generic/tclOO.c.
628
629
630
631
632
633
634









635
636
637
638
639
640
641
    ClientData clientData,	/* Pointer to the OO system foundation
				 * structure. */
    Tcl_Interp *interp)		/* The interpreter containing the OO system
				 * foundation. */
{
    Foundation *fPtr = GetFoundation(interp);










    TclDecrRefCount(fPtr->unknownMethodNameObj);
    TclDecrRefCount(fPtr->constructorName);
    TclDecrRefCount(fPtr->destructorName);
    TclDecrRefCount(fPtr->clonedName);
    TclDecrRefCount(fPtr->defineName);
    ckfree(fPtr);
}







>
>
>
>
>
>
>
>
>







628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
    ClientData clientData,	/* Pointer to the OO system foundation
				 * structure. */
    Tcl_Interp *interp)		/* The interpreter containing the OO system
				 * foundation. */
{
    Foundation *fPtr = GetFoundation(interp);

    /*
     * Crude mechanism to avoid leaking the Object struct of the
     * foundation components oo::object and oo::class
     *
     * Should probably be replaced with something more elegantly designed.
     */
    while (TclOODecrRefCount(fPtr->objectCls->thisPtr) == 0) {};
    while (TclOODecrRefCount(fPtr->classCls->thisPtr) == 0) {};

    TclDecrRefCount(fPtr->unknownMethodNameObj);
    TclDecrRefCount(fPtr->constructorName);
    TclDecrRefCount(fPtr->destructorName);
    TclDecrRefCount(fPtr->clonedName);
    TclDecrRefCount(fPtr->defineName);
    ckfree(fPtr);
}
1016
1017
1018
1019
1020
1021
1022

1023
1024















1025
1026
1027
1028
1029
1030
1031
    if (clsPtr->filters.num) {
	Tcl_Obj *filterObj;

	FOREACH(filterObj, clsPtr->filters) {
	    TclDecrRefCount(filterObj);
	}
	ckfree(clsPtr->filters.list);

	clsPtr->filters.num = 0;
    }
















    /*
     * Squelch our metadata.
     */

    if (clsPtr->metadataPtr != NULL) {
	Tcl_ObjectMetadataType *metadataTypePtr;







>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
    if (clsPtr->filters.num) {
	Tcl_Obj *filterObj;

	FOREACH(filterObj, clsPtr->filters) {
	    TclDecrRefCount(filterObj);
	}
	ckfree(clsPtr->filters.list);
	clsPtr->filters.list = NULL;
	clsPtr->filters.num = 0;
    }

    /*
     * Squelch our instances.
     */

    if (clsPtr->instances.num) {
	Object *oPtr;

	FOREACH(oPtr, clsPtr->instances) {
	    TclOODecrRefCount(oPtr);
	}
	ckfree(clsPtr->instances.list);
	clsPtr->instances.list = NULL;
	clsPtr->instances.num = 0;
    }

    /*
     * Squelch our metadata.
     */

    if (clsPtr->metadataPtr != NULL) {
	Tcl_ObjectMetadataType *metadataTypePtr;
Changes to generic/tclPkg.c.
724
725
726
727
728
729
730



731
732







733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750

751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
	 * We found an ifneeded script for the package. Be careful while
	 * executing it: this could cause reentrancy, so (a) protect the
	 * script itself from deletion and (b) don't assume that bestPtr
	 * will still exist when the script completes.
	 */

	char *versionToProvide = bestPtr->version;



	Tcl_Preserve(versionToProvide);
	pkgPtr->clientData = versionToProvide;







	if (bestPtr->pkgIndex) {
	    TclPkgFileSeen(interp, bestPtr->pkgIndex);
	}
	reqPtr->versionToProvide = versionToProvide;
	Tcl_NRAddCallback(interp, SelectPackageFinal, reqPtr, INT2PTR(reqc), (void *)reqv, data[3]);
	Tcl_NREvalObj(interp, Tcl_NewStringObj(bestPtr->script, -1), TCL_EVAL_GLOBAL);
    }
    return TCL_OK;
}

static int
SelectPackageFinal(ClientData data[], Tcl_Interp *interp, int result) {
    Require *reqPtr = data[0];
    int reqc = PTR2INT(data[1]);
    Tcl_Obj **const reqv = data[2];
    const char *name = reqPtr->name;
    char *versionToProvide = reqPtr->versionToProvide;


    PkgFiles *pkgFiles;
    PkgName *pkgName;

    pkgFiles = TclInitPkgFiles(interp);
    /* Push "ifneeded" package name in "tclPkgFiles" assocdata. */
    pkgName = ckalloc(sizeof(PkgName) + strlen(name));
    pkgName->nextPtr = pkgFiles->names;
    strcpy(pkgName->name, name);
    pkgFiles->names = pkgName;

    /* Pop the "ifneeded" package name from "tclPkgFiles" assocdata*/
    pkgFiles->names = pkgName->nextPtr;
    ckfree(pkgName);

    reqPtr->pkgPtr = FindPackage(interp, name);
    if (result == TCL_OK) {
	Tcl_ResetResult(interp);
	if (reqPtr->pkgPtr->version == NULL) {







>
>
>


>
>
>
>
>
>
>


















>
|
|
<
<
<
<
<
<
<
<
<







724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763









764
765
766
767
768
769
770
	 * We found an ifneeded script for the package. Be careful while
	 * executing it: this could cause reentrancy, so (a) protect the
	 * script itself from deletion and (b) don't assume that bestPtr
	 * will still exist when the script completes.
	 */

	char *versionToProvide = bestPtr->version;
	PkgFiles *pkgFiles;
	PkgName *pkgName;

	Tcl_Preserve(versionToProvide);
	pkgPtr->clientData = versionToProvide;

	pkgFiles = TclInitPkgFiles(interp);
	/* Push "ifneeded" package name in "tclPkgFiles" assocdata. */
	pkgName = ckalloc(sizeof(PkgName) + strlen(name));
	pkgName->nextPtr = pkgFiles->names;
	strcpy(pkgName->name, name);
	pkgFiles->names = pkgName;
	if (bestPtr->pkgIndex) {
	    TclPkgFileSeen(interp, bestPtr->pkgIndex);
	}
	reqPtr->versionToProvide = versionToProvide;
	Tcl_NRAddCallback(interp, SelectPackageFinal, reqPtr, INT2PTR(reqc), (void *)reqv, data[3]);
	Tcl_NREvalObj(interp, Tcl_NewStringObj(bestPtr->script, -1), TCL_EVAL_GLOBAL);
    }
    return TCL_OK;
}

static int
SelectPackageFinal(ClientData data[], Tcl_Interp *interp, int result) {
    Require *reqPtr = data[0];
    int reqc = PTR2INT(data[1]);
    Tcl_Obj **const reqv = data[2];
    const char *name = reqPtr->name;
    char *versionToProvide = reqPtr->versionToProvide;

    /* Pop the "ifneeded" package name from "tclPkgFiles" assocdata*/
    PkgFiles *pkgFiles = Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
    PkgName *pkgName = pkgFiles->names;









    pkgFiles->names = pkgName->nextPtr;
    ckfree(pkgName);

    reqPtr->pkgPtr = FindPackage(interp, name);
    if (result == TCL_OK) {
	Tcl_ResetResult(interp);
	if (reqPtr->pkgPtr->version == NULL) {
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
	    }

	    /*
	     * Create a new-style requirement for the exact version.
	     */

	    ov = Tcl_NewStringObj(version, -1);
	    Tcl_IncrRefCount(ov);
	    Tcl_AppendStringsToObj(ov, "-", version, NULL);
	    version = NULL;
	    argv3 = TclGetString(objv[3]);
	    Tcl_IncrRefCount(objv[3]);

	    objvListPtr = Tcl_NewListObj(0, NULL);
	    Tcl_IncrRefCount(objvListPtr);







<







1244
1245
1246
1247
1248
1249
1250

1251
1252
1253
1254
1255
1256
1257
	    }

	    /*
	     * Create a new-style requirement for the exact version.
	     */

	    ov = Tcl_NewStringObj(version, -1);

	    Tcl_AppendStringsToObj(ov, "-", version, NULL);
	    version = NULL;
	    argv3 = TclGetString(objv[3]);
	    Tcl_IncrRefCount(objv[3]);

	    objvListPtr = Tcl_NewListObj(0, NULL);
	    Tcl_IncrRefCount(objvListPtr);
Changes to generic/tclUtil.c.
96
97
98
99
100
101
102


103
104
105
106
107
108
109
/*
 * Prototypes for functions defined later in this file.
 */

static void		ClearHash(Tcl_HashTable *tablePtr);
static void		FreeProcessGlobalValue(ClientData clientData);
static void		FreeThreadHash(ClientData clientData);


static Tcl_HashTable *	GetThreadHash(Tcl_ThreadDataKey *keyPtr);
static int		SetEndOffsetFromAny(Tcl_Interp *interp,
			    Tcl_Obj *objPtr);
static int		FindElement(Tcl_Interp *interp, const char *string,
			    int stringLength, const char *typeStr,
			    const char *typeCode, const char **elementPtr,
			    const char **nextPtr, int *sizePtr,







>
>







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/*
 * Prototypes for functions defined later in this file.
 */

static void		ClearHash(Tcl_HashTable *tablePtr);
static void		FreeProcessGlobalValue(ClientData clientData);
static void		FreeThreadHash(ClientData clientData);
static int		GetEndOffsetFromObj(Tcl_Obj *objPtr, int endValue,
			    int *indexPtr);
static Tcl_HashTable *	GetThreadHash(Tcl_ThreadDataKey *keyPtr);
static int		SetEndOffsetFromAny(Tcl_Interp *interp,
			    Tcl_Obj *objPtr);
static int		FindElement(Tcl_Interp *interp, const char *string,
			    int stringLength, const char *typeStr,
			    const char *typeCode, const char **elementPtr,
			    const char **nextPtr, int *sizePtr,
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
    char *opPtr;
    const char *bytes;

    if (TclGetIntFromObj(NULL, objPtr, indexPtr) == TCL_OK) {
	return TCL_OK;
    }

    if (SetEndOffsetFromAny(NULL, objPtr) == TCL_OK) {
	/*
	 * If the object is already an offset from the end of the list, or can
	 * be converted to one, use it.
	 */

	*indexPtr = endValue + (int)objPtr->internalRep.wideValue;
	return TCL_OK;
    }

    bytes = TclGetString(objPtr);
    length = objPtr->length;

    /*







<
<
<
<
<
|
<







3330
3331
3332
3333
3334
3335
3336





3337

3338
3339
3340
3341
3342
3343
3344
    char *opPtr;
    const char *bytes;

    if (TclGetIntFromObj(NULL, objPtr, indexPtr) == TCL_OK) {
	return TCL_OK;
    }






    if (GetEndOffsetFromObj(objPtr, endValue, indexPtr) == TCL_OK) {

	return TCL_OK;
    }

    bytes = TclGetString(objPtr);
    length = objPtr->length;

    /*
3397
3398
3399
3400
3401
3402
3403



































3404
3405
3406
3407
3408
3409
3410
	}
	Tcl_SetErrorCode(interp, "TCL", "VALUE", "INDEX", NULL);
    }

    return TCL_ERROR;
}




































/*
 *----------------------------------------------------------------------
 *
 * SetEndOffsetFromAny --
 *
 *	Look for a string of the form "end[+-]offset" and convert it to an
 *	internal representation holding the offset.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
	}
	Tcl_SetErrorCode(interp, "TCL", "VALUE", "INDEX", NULL);
    }

    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
 *
 * GetEndOffsetFromObj --
 *
 *      Look for a string of the form "end[+-]offset" and convert it to an
 *      internal representation holding the offset.
 *
 * Results:
 *      Tcl return code.
 *
 * Side effects:
 *      May store a Tcl_ObjType.
 *
 *----------------------------------------------------------------------
 */

static int
GetEndOffsetFromObj(
    Tcl_Obj *objPtr,            /* Pointer to the object to parse */
    int endValue,               /* The value to be stored at "indexPtr" if
                                 * "objPtr" holds "end". */
    int *indexPtr)              /* Location filled in with an integer
                                 * representing an index. */
{
    if (SetEndOffsetFromAny(NULL, objPtr) != TCL_OK) {
	return TCL_ERROR;
    }

    /* TODO: Handle overflow cases sensibly */
    *indexPtr = endValue + (int)objPtr->internalRep.wideValue;
    return TCL_OK;
}

    
/*
 *----------------------------------------------------------------------
 *
 * SetEndOffsetFromAny --
 *
 *	Look for a string of the form "end[+-]offset" and convert it to an
 *	internal representation holding the offset.
3471
3472
3473
3474
3475
3476
3477


3478
3479
3480
3481
3482
3483
3484
	    return TCL_ERROR;
	}
	if (objPtr->typePtr != &tclIntType) {
		goto badIndexFormat;
	}
	offset = objPtr->internalRep.wideValue;
	if (bytes[3] == '-') {


	    offset = -offset;
	}
    } else {
	/*
	 * Conversion failed. Report the error.
	 */








>
>







3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
	    return TCL_ERROR;
	}
	if (objPtr->typePtr != &tclIntType) {
		goto badIndexFormat;
	}
	offset = objPtr->internalRep.wideValue;
	if (bytes[3] == '-') {

	    /* TODO: Review overflow concerns here! */
	    offset = -offset;
	}
    } else {
	/*
	 * Conversion failed. Report the error.
	 */

3498
3499
3500
3501
3502
3503
3504









































































































































3505
3506
3507
3508
3509
3510
3511

    TclFreeIntRep(objPtr);
    objPtr->internalRep.wideValue = offset;
    objPtr->typePtr = &endOffsetType;

    return TCL_OK;
}










































































































































/*
 *----------------------------------------------------------------------
 *
 * ClearHash --
 *
 *	Remove all the entries in the hash table *tablePtr.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681

    TclFreeIntRep(objPtr);
    objPtr->internalRep.wideValue = offset;
    objPtr->typePtr = &endOffsetType;

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclIndexEncode --
 *
 *      Parse objPtr to determine if it is an index value. Two cases
 *	are possible.  The value objPtr might be parsed as an absolute
 *	index value in the C signed int range.  Note that this includes
 *	index values that are integers as presented and it includes index
 *      arithmetic expressions. The absolute index values that can be
 *	directly meaningful as an index into either a list or a string are
 *	those integer values >= TCL_INDEX_START (0)
 *	and < TCL_INDEX_AFTER (INT_MAX).
 *      The largest string supported in Tcl 8 has bytelength INT_MAX.
 *      This means the largest supported character length is also INT_MAX,
 *      and the index of the last character in a string of length INT_MAX
 *      is INT_MAX-1.
 *
 *      Any absolute index value parsed outside that range is encoded
 *      using the before and after values passed in by the
 *      caller as the encoding to use for indices that are either
 *      less than or greater than the usable index range. TCL_INDEX_AFTER
 *      is available as a good choice for most callers to use for
 *      after. Likewise, the value TCL_INDEX_BEFORE is good for
 *      most callers to use for before.  Other values are possible
 *      when the caller knows it is helpful in producing its own behavior
 *      for indices before and after the indexed item.
 *
 *      A token can also be parsed as an end-relative index expression.
 *      All end-relative expressions that indicate an index larger
 *      than end (end+2, end--5) point beyond the end of the indexed
 *      collection, and can be encoded as after.  The end-relative
 *      expressions that indicate an index less than or equal to end
 *      are encoded relative to the value TCL_INDEX_END (-2).  The
 *      index "end" is encoded as -2, down to the index "end-0x7ffffffe"
 *      which is encoded as INT_MIN. Since the largest index into a
 *      string possible in Tcl 8 is 0x7ffffffe, the interpretation of
 *      "end-0x7ffffffe" for that largest string would be 0.  Thus,
 *      if the tokens "end-0x7fffffff" or "end+-0x80000000" are parsed,
 *      they can be encoded with the before value.
 *
 *      These details will require re-examination whenever string and
 *      list length limits are increased, but that will likely also
 *      mean a revised routine capable of returning Tcl_WideInt values.
 *
 * Returns:
 *      TCL_OK if parsing succeeded, and TCL_ERROR if it failed.
 *
 * Side effects:
 *      When TCL_OK is returned, the encoded index value is written
 *      to *indexPtr.
 *
 *----------------------------------------------------------------------
 */

int
TclIndexEncode(
    Tcl_Interp *interp,	/* For error reporting, may be NULL */
    Tcl_Obj *objPtr,	/* Index value to parse */
    int before,		/* Value to return for index before beginning */
    int after,		/* Value to return for index after end */
    int *indexPtr)	/* Where to write the encoded answer, not NULL */
{
    int idx;

    if (TCL_OK == TclGetIntFromObj(NULL, objPtr, &idx)) {
        /* We parsed a value in the range INT_MIN...INT_MAX */
    integerEncode:
        if (idx < TCL_INDEX_START) {
            /* All negative absolute indices are "before the beginning" */
            idx = before;
        } else if (idx == INT_MAX) {
            /* This index value is always "after the end" */
            idx = after;
        }
        /* usual case, the absolute index value encodes itself */
    } else if (TCL_OK == GetEndOffsetFromObj(objPtr, 0, &idx)) {
        /*
         * We parsed an end+offset index value. 
         * idx holds the offset value in the range INT_MIN...INT_MAX.
         */
        if (idx > 0) {
            /*
             * All end+postive or end-negative expressions 
             * always indicate "after the end".
             */
            idx = after;
        } else if (idx < INT_MIN - TCL_INDEX_END) {
            /* These indices always indicate "before the beginning */
            idx = before;
        } else {
            /* Encoded end-positive (or end+negative) are offset */
            idx += TCL_INDEX_END;
        }

    /* TODO: Consider flag to suppress repeated end-offset parse. */
    } else if (TCL_OK == TclGetIntForIndexM(interp, objPtr, 0, &idx)) {
        /*
         * Only reach this case when the index value is a
         * constant index arithmetic expression, and idx
         * holds the result. Treat it the same as if it were
         * parsed as an absolute integer value.
         */
        goto integerEncode;
    } else {
	return TCL_ERROR;
    }
    *indexPtr = idx;
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclIndexDecode --
 *
 *	Decodes a value previously encoded by TclIndexEncode.  The argument
 *	endValue indicates what value of "end" should be used in the
 *	decoding.
 *
 * Results:
 *	The decoded index value.
 *
 *----------------------------------------------------------------------
 */

int
TclIndexDecode(
    int encoded,	/* Value to decode */
    int endValue)	/* Meaning of "end" to use, > TCL_INDEX_END */
{
    if (encoded <= TCL_INDEX_END) {
	return (encoded - TCL_INDEX_END) + endValue;
    }
    return encoded;
}

/*
 *----------------------------------------------------------------------
 *
 * ClearHash --
 *
 *	Remove all the entries in the hash table *tablePtr.
Changes to tests/assemble.test.
1568
1569
1570
1571
1572
1573
1574






1575
1576
1577
1578
1579
1580
1581
}
test assemble-15.7 {listIndexImm} {
    -body {
	assemble {push {a b c}; listIndexImm end}
    }
    -result c
}







# assemble-16 - invokeStk

test assemble-16.1 {invokeStk - wrong # args} {
    -body {
	assemble {invokeStk}
    }







>
>
>
>
>
>







1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
}
test assemble-15.7 {listIndexImm} {
    -body {
	assemble {push {a b c}; listIndexImm end}
    }
    -result c
}
test assemble-15.8 {listIndexImm} {
    assemble {push {a b c}; listIndexImm end+2}
} {}
test assemble-15.9 {listIndexImm} {
    assemble {push {a b c}; listIndexImm -1-1}
} {}

# assemble-16 - invokeStk

test assemble-16.1 {invokeStk - wrong # args} {
    -body {
	assemble {invokeStk}
    }
Changes to tests/cmdIL.test.
156
157
158
159
160
161
162






163
164
165
166
167
168
169
} [list \0 \x7f \x80 \uffff]
test cmdIL-1.39 {Tcl_LsortObjCmd procedure, Bug 8e1e31eac0fd6b6c} fullutf {
    lsort -ascii [list \0 \x7f \x80 \U01ffff \uffff]
} [list \0 \x7f \x80 \uffff \U01ffff]
test cmdIL-1.40 {Tcl_LsortObjCmd procedure, Bug 8e1e31eac0fd6b6c} fullutf {
    lsort -ascii -nocase [list \0 \x7f \x80 \U01ffff \uffff]
} [list \0 \x7f \x80 \uffff \U01ffff]







# Can't think of any good tests for the MergeSort and MergeLists procedures,
# except a bunch of random lists to sort.

test cmdIL-2.1 {MergeSort and MergeLists procedures} -setup {
    set result {}
    set r 1435753299







>
>
>
>
>
>







156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
} [list \0 \x7f \x80 \uffff]
test cmdIL-1.39 {Tcl_LsortObjCmd procedure, Bug 8e1e31eac0fd6b6c} fullutf {
    lsort -ascii [list \0 \x7f \x80 \U01ffff \uffff]
} [list \0 \x7f \x80 \uffff \U01ffff]
test cmdIL-1.40 {Tcl_LsortObjCmd procedure, Bug 8e1e31eac0fd6b6c} fullutf {
    lsort -ascii -nocase [list \0 \x7f \x80 \U01ffff \uffff]
} [list \0 \x7f \x80 \uffff \U01ffff]
test cmdIL-1.41 {lsort -stride and -index} -body {
    lsort -stride 2 -index -2 {a 2 b 1}
} -returnCodes error -result {index "-2" cannot select an element from any list}
test cmdIL-1.42 {lsort -stride and-index} -body {
    lsort -stride 2 -index -1-1 {a 2 b 1}
} -returnCodes error -result {index "-1-1" cannot select an element from any list}

# Can't think of any good tests for the MergeSort and MergeLists procedures,
# except a bunch of random lists to sort.

test cmdIL-2.1 {MergeSort and MergeLists procedures} -setup {
    set result {}
    set r 1435753299
212
213
214
215
216
217
218



























219
220
221
222
223
224
225
} -returnCodes error -result {expected integer but got "c"}
test cmdIL-3.4.1 {SortCompare procedure, -index option} -body {
    lsort -integer -index 2 "{1 2 3} \\\{"
} -returnCodes error -result {unmatched open brace in list}
test cmdIL-3.5 {SortCompare procedure, -index option} -body {
    lsort -integer -index 2 {{20 10 13} {15}}
} -returnCodes error -result {element 2 missing from sublist "15"}



























test cmdIL-3.6 {SortCompare procedure, -index option} {
    lsort -integer -index 2 {{1 15 30} {2 5 25} {3 25 20}}
} {{3 25 20} {2 5 25} {1 15 30}}
test cmdIL-3.7 {SortCompare procedure, -ascii option} {
    lsort -ascii {d e c b a d35 d300 100 20}
} {100 20 a b c d d300 d35 e}
test cmdIL-3.8 {SortCompare procedure, -dictionary option} {







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
} -returnCodes error -result {expected integer but got "c"}
test cmdIL-3.4.1 {SortCompare procedure, -index option} -body {
    lsort -integer -index 2 "{1 2 3} \\\{"
} -returnCodes error -result {unmatched open brace in list}
test cmdIL-3.5 {SortCompare procedure, -index option} -body {
    lsort -integer -index 2 {{20 10 13} {15}}
} -returnCodes error -result {element 2 missing from sublist "15"}
test cmdIL-3.5.1 {SortCompare procedure, -index option (out of range, calculated index)} -body {
    lsort -index 1+3 {{1 . c} {2 . b} {3 . a}}
} -returnCodes error -result {element 4 missing from sublist "1 . c"}
test cmdIL-3.5.2 {SortCompare procedure, -index option (out of range, calculated index)} -body {
    lsort -index -1-1 {{1 . c} {2 . b} {3 . a}}
} -returnCodes error -result {index "-1-1" cannot select an element from any list}
test cmdIL-3.5.3 {SortCompare procedure, -index option (out of range, calculated index)} -body {
    lsort -index -2 {{1 . c} {2 . b} {3 . a}}
} -returnCodes error -result {index "-2" cannot select an element from any list}
test cmdIL-3.5.4 {SortCompare procedure, -index option (out of range, calculated index)} -body {
    lsort -index end-4 {{1 . c} {2 . b} {3 . a}}
} -returnCodes error -result {element -2 missing from sublist "1 . c"}
test cmdIL-3.5.5 {SortCompare procedure, -index option} {
    lsort -index {} {a b}
} {a b}
test cmdIL-3.5.6 {SortCompare procedure, -index option} {
    lsort -index {} [list a \{]
} {a \{}
test cmdIL-3.5.7 {SortCompare procedure, -index option (out of range, calculated index)} -body {
    lsort -index end--1 {{1 . c} {2 . b} {3 . a}}
} -returnCodes error -result {index "end--1" cannot select an element from any list}
test cmdIL-3.5.8 {SortCompare procedure, -index option (out of range, calculated index)} -body {
    lsort -index end+1 {{1 . c} {2 . b} {3 . a}}
} -returnCodes error -result {index "end+1" cannot select an element from any list}
test cmdIL-3.5.9 {SortCompare procedure, -index option (out of range, calculated index)} -body {
    lsort -index end+2 {{1 . c} {2 . b} {3 . a}}
} -returnCodes error -result {index "end+2" cannot select an element from any list}
test cmdIL-3.6 {SortCompare procedure, -index option} {
    lsort -integer -index 2 {{1 15 30} {2 5 25} {3 25 20}}
} {{3 25 20} {2 5 25} {1 15 30}}
test cmdIL-3.7 {SortCompare procedure, -ascii option} {
    lsort -ascii {d e c b a d35 d300 100 20}
} {100 20 a b c d d300 d35 e}
test cmdIL-3.8 {SortCompare procedure, -dictionary option} {
Changes to tests/lindex.test.
75
76
77
78
79
80
81









82
83
84
85
86
87
88
    set x -0o9
    list [catch { testevalex {lindex {a b c} $x} } result] $result
} -match glob -result {1 {*}}
test lindex-3.7 {indexes don't shimmer wide ints} {
    set x [expr {(wide(1)<<31) - 2}]
    list $x [lindex {1 2 3} $x] [incr x] [incr x]
} {2147483646 {} 2147483647 2147483648}










# Indices relative to end

test lindex-4.1 {index = end} testevalex {
    set x end
    list [testevalex {lindex {a b c} $x}] [testevalex {lindex {a b c} $x}]
} {c c}







>
>
>
>
>
>
>
>
>







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
    set x -0o9
    list [catch { testevalex {lindex {a b c} $x} } result] $result
} -match glob -result {1 {*}}
test lindex-3.7 {indexes don't shimmer wide ints} {
    set x [expr {(wide(1)<<31) - 2}]
    list $x [lindex {1 2 3} $x] [incr x] [incr x]
} {2147483646 {} 2147483647 2147483648}
test lindex-3.8 {compiled with static indices out of range, negative} {
    list [lindex {a b c} -1] [lindex {a b c} -2] [lindex {a b c} -3]
} [lrepeat 3 {}]
test lindex-3.9 {compiled with calculated indices out of range, negative constant} {
    list [lindex {a b c} -1-1] [lindex {a b c} -2+0] [lindex {a b c} -2+1]
} [lrepeat 3 {}]
test lindex-3.10 {compiled with calculated indices out of range, after end} {
    list [lindex {a b c} end+1] [lindex {a b c} end+2] [lindex {a b c} end+3]
} [lrepeat 3 {}]

# Indices relative to end

test lindex-4.1 {index = end} testevalex {
    set x end
    list [testevalex {lindex {a b c} $x}] [testevalex {lindex {a b c} $x}]
} {c c}
Changes to tests/lrange.test.
86
87
88
89
90
91
92


















93
94
95
96
97
98
99
} {1 {unmatched open brace in list}}

test lrange-3.1 {Bug 3588366: end-offsets before start} {
    apply {l {
	lrange $l 0 end-5
    }} {1 2 3 4 5}
} {}



















# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
} {1 {unmatched open brace in list}}

test lrange-3.1 {Bug 3588366: end-offsets before start} {
    apply {l {
	lrange $l 0 end-5
    }} {1 2 3 4 5}
} {}

test lrange-3.2 {compiled with static indices out of range, negative} {
    list [lrange {a b c} -1 -2] [lrange {a b c} -2 -1] [lrange {a b c} -3 -2] [lrange {a b c} -2 -3]
} [lrepeat 4 {}]
test lrange-3.3 {compiled with calculated indices out of range, negative constant} {
    list [lrange {a b c} 0-1 -1-1] [lrange {a b c} -2+0 0-1] [lrange {a b c} -2-1 -2+1] [lrange {a b c} -2+1 -2-1]
} [lrepeat 4 {}]
test lrange-3.4 {compiled with calculated indices out of range, after end} {
    list [lrange {a b c} end+1 end+2] [lrange {a b c} end+2 end+1] [lrange {a b c} end+2 end+3] [lrange {a b c} end+3 end+2]
} [lrepeat 4 {}]

test lrange-3.5 {compiled with calculated indices, start out of range (negative)} {
    list [lrange {a b c} -1 1] [lrange {a b c} -1+0 end-1] [lrange {a b c} -2 1] [lrange {a b c} -2+0 0+1]
} [lrepeat 4 {a b}]
test lrange-3.6 {compiled with calculated indices, end out of range (after end)} {
    list [lrange {a b c} 1 end+1] [lrange {a b c} 1+0 2+1] [lrange {a b c} 1 end+1] [lrange {a b c} end-1 3+1]
} [lrepeat 4 {b c}]


# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
Changes to tests/lreplace.test.
94
95
96
97
98
99
100
101
102
103
104
105


106




107
108
109
110
111
112
113
test lreplace-1.26 {lreplace command} {
    catch {unset foo}
    set foo {a b}
    list [set foo [lreplace $foo end end]] \
        [set foo [lreplace $foo end end]] \
        [set foo [lreplace $foo end end]]
} {a {} {}}
test lreplace-1.27 {lreplace command} {
    lreplace x 1 1
} x
test lreplace-1.28 {lreplace command} {
    lreplace x 1 1 y


} {x y}





test lreplace-2.1 {lreplace errors} {
    list [catch lreplace msg] $msg
} {1 {wrong # args: should be "lreplace list first last ?element ...?"}}
test lreplace-2.2 {lreplace errors} {
    list [catch {lreplace a b} msg] $msg
} {1 {wrong # args: should be "lreplace list first last ?element ...?"}}







|

|
|

>
>
|
>
>
>
>







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
test lreplace-1.26 {lreplace command} {
    catch {unset foo}
    set foo {a b}
    list [set foo [lreplace $foo end end]] \
        [set foo [lreplace $foo end end]] \
        [set foo [lreplace $foo end end]]
} {a {} {}}
test lreplace-1.27 {lreplace command} -body {
    lreplace x 1 1
} -returnCodes 1 -result {list doesn't contain element 1}
test lreplace-1.28 {lreplace command} -body {
    lreplace x 1 1 y
} -returnCodes 1 -result {list doesn't contain element 1}
test lreplace-1.29 {lreplace command} -body {
    lreplace x 1 1 [error foo]
} -returnCodes 1 -result {foo}
test lreplace-1.30 {lreplace command} -body {
    lreplace {not {}alist} 0 0 [error foo]
} -returnCodes 1 -result {foo}

test lreplace-2.1 {lreplace errors} {
    list [catch lreplace msg] $msg
} {1 {wrong # args: should be "lreplace list first last ?element ...?"}}
test lreplace-2.2 {lreplace errors} {
    list [catch {lreplace a b} msg] $msg
} {1 {wrong # args: should be "lreplace list first last ?element ...?"}}
Changes to tests/lsearch.test.
414
415
416
417
418
419
420




























421
422
423
424
425
426
427
} {0 1}
test lsearch-17.6 {lsearch -index option, basic functionality} {
    lsearch -all -index 1 -glob {{ab cb} {ab bb} {db bx}} b*
} {1 2}
test lsearch-17.7 {lsearch -index option, basic functionality} {
    lsearch -all -index 1 -regexp {{ab cb} {ab bb} {ab ab}} {[cb]b}
} {0 1}





























test lsearch-18.1 {lsearch -index option, list as index basic functionality} {
    lsearch -index {0 0} {{{x x} {x b} {a d}} {{a c} {a b} {a a}}} a
} 1
test lsearch-18.2 {lsearch -index option, list as index basic functionality} {
    lsearch -index {2 0} -exact {{{x x} {x b} {a d}} {{a c} {a b} {a a}}} a
} 0







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
} {0 1}
test lsearch-17.6 {lsearch -index option, basic functionality} {
    lsearch -all -index 1 -glob {{ab cb} {ab bb} {db bx}} b*
} {1 2}
test lsearch-17.7 {lsearch -index option, basic functionality} {
    lsearch -all -index 1 -regexp {{ab cb} {ab bb} {ab ab}} {[cb]b}
} {0 1}
test lsearch-17.8 {lsearch -index option, empty argument} {
    lsearch -index {} a a
} 0
test lsearch-17.9 {lsearch -index option, empty argument} {
    lsearch -index {} a a
} [lsearch a a]
test lsearch-17.10 {lsearch -index option, empty argument} {
    lsearch -index {} [list \{] \{
} 0
test lsearch-17.11 {lsearch -index option, empty argument} {
    lsearch -index {} [list \{] \{
} [lsearch [list \{] \{]
test lsearch-17.12 {lsearch -index option, encoding aliasing} -body {
    lsearch -index -2 a a
} -returnCodes error -result {index "-2" cannot select an element from any list}
test lsearch-17.13 {lsearch -index option, encoding aliasing} -body {
    lsearch -index -1-1 a a
} -returnCodes error -result {index "-1-1" cannot select an element from any list}
test lsearch-17.14 {lsearch -index option, encoding aliasing} -body {
    lsearch -index end--1 a a
} -returnCodes error -result {index "end--1" cannot select an element from any list}
test lsearch-17.15 {lsearch -index option, encoding aliasing} -body {
    lsearch -index end+1 a a
} -returnCodes error -result {index "end+1" cannot select an element from any list}
test lsearch-17.16 {lsearch -index option, encoding aliasing} -body {
    lsearch -index end+2 a a
} -returnCodes error -result {index "end+2" cannot select an element from any list}


test lsearch-18.1 {lsearch -index option, list as index basic functionality} {
    lsearch -index {0 0} {{{x x} {x b} {a d}} {{a c} {a b} {a a}}} a
} 1
test lsearch-18.2 {lsearch -index option, list as index basic functionality} {
    lsearch -index {2 0} -exact {{{x x} {x b} {a d}} {{a c} {a b} {a a}}} a
} 0
449
450
451
452
453
454
455






456
457
458
459
460
461
462
} {0 0 1}
test lsearch-19.5 {lsearch -subindices option} {
    lsearch -subindices -all -index {0 0} -exact {{{a c} {a b} {d a}} {{a c} {a b} {d a}}} a
} {{0 0 0} {1 0 0}}
test lsearch-19.6 {lsearch -subindices option} {
    lsearch -subindices -all -index {1 0} -exact {{{a c} {a b} {d a}} {{a c} {a b} {d a}}} a
} {{0 1 0} {1 1 0}}







test lsearch-20.1 {lsearch -index option, index larger than sublists} -body {
    lsearch -index 2 {{a c} {a b} {a a}} a
} -returnCodes error -result {element 2 missing from sublist "a c"}
test lsearch-20.2 {lsearch -index option, malformed index} -body {
    lsearch -index foo {{a c} {a b} {a a}} a
} -returnCodes error -result {bad index "foo": must be integer?[+-]integer? or end?[+-]integer?}







>
>
>
>
>
>







477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
} {0 0 1}
test lsearch-19.5 {lsearch -subindices option} {
    lsearch -subindices -all -index {0 0} -exact {{{a c} {a b} {d a}} {{a c} {a b} {d a}}} a
} {{0 0 0} {1 0 0}}
test lsearch-19.6 {lsearch -subindices option} {
    lsearch -subindices -all -index {1 0} -exact {{{a c} {a b} {d a}} {{a c} {a b} {d a}}} a
} {{0 1 0} {1 1 0}}
test lsearch-19.7 {lsearch -subindices option} {
    lsearch -subindices -index end {{1 a}} a
} {0 1}
test lsearch-19.8 {lsearch -subindices option} {
    lsearch -subindices -all -index end {{1 a}} a
} {{0 1}}

test lsearch-20.1 {lsearch -index option, index larger than sublists} -body {
    lsearch -index 2 {{a c} {a b} {a a}} a
} -returnCodes error -result {element 2 missing from sublist "a c"}
test lsearch-20.2 {lsearch -index option, malformed index} -body {
    lsearch -index foo {{a c} {a b} {a a}} a
} -returnCodes error -result {bad index "foo": must be integer?[+-]integer? or end?[+-]integer?}