Tcl Source Code

Check-in [13ac6c8c7b]
Login

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

Overview
Comment:Define and use macros that test whether a Tcl list value is canonical.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | core-8-5-branch
Files: files | file ages | folders
SHA1: 13ac6c8c7b55fc9a2bdfb05efdca85459a613ef6
User & Date: dgp 2011-04-18 18:31:18
Context
2011-04-18
21:24
Use ListRepPtr(.) and other cleanup. check-in: 3dba2563a1 user: dgp tags: core-8-5-branch
18:50
Define and use macros that test whether a Tcl list value is canonical. check-in: 4b0bb72cb3 user: dgp tags: trunk
18:31
Define and use macros that test whether a Tcl list value is canonical. check-in: 13ac6c8c7b user: dgp tags: core-8-5-branch
08:22
fix for [Bug 3288345]: Wrong Tcl_StatBuf used on MinGW check-in: 4f729efe4c user: jan.nijtmans tags: core-8-5-branch
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ChangeLog.







1
2
3
4
5
6
7






2011-04-18  Jan Nijtmans  <[email protected]>

	* generic/tcl.h: fix for [Bug 3288345]: Wrong Tcl_StatBuf
	used on MinGW.

2011-04-16  Donal K. Fellows  <[email protected]>

>
>
>
>
>
>







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

	* generic/tclInt.h:	Define and use macros that test whether
	* generic/tclBasic.c:	a Tcl list value is canonical.
	* generic/tclUtil.c:

2011-04-18  Jan Nijtmans  <[email protected]>

	* generic/tcl.h: fix for [Bug 3288345]: Wrong Tcl_StatBuf
	used on MinGW.

2011-04-16  Donal K. Fellows  <[email protected]>

Changes to generic/tclBasic.c.

4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
    /*
     * An object which either has no string rep or else is a canonical list is
     * guaranteed to have been generated dynamically: bail out, this cannot
     * have a usable absolute location. _Do not touch_ the information the set
     * up by the caller. It knows better than us.
     */

    if ((!obj->bytes) || ((obj->typePtr == &tclListType) &&
	    ((List *)obj->internalRep.twoPtrValue.ptr1)->canonicalFlag)) {
	return;
    }

    /*
     * First look for location information recorded in the argument
     * stack. That is nearest.
     */







|
<







4896
4897
4898
4899
4900
4901
4902
4903

4904
4905
4906
4907
4908
4909
4910
    /*
     * An object which either has no string rep or else is a canonical list is
     * guaranteed to have been generated dynamically: bail out, this cannot
     * have a usable absolute location. _Do not touch_ the information the set
     * up by the caller. It knows better than us.
     */

    if ((obj->bytes == NULL) || TclListObjIsCanonical(obj)) {

	return;
    }

    /*
     * First look for location information recorded in the argument
     * stack. That is nearest.
     */
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
     *
     * This restriction has been relaxed a bit by storing in lists whether
     * they are "canonical" or not (a canonical list being one that is either
     * pure or that has its string rep derived by UpdateStringOfList from the
     * internal rep).
     */

    if (objPtr->typePtr == &tclListType) {	/* is a list... */
	List *listRepPtr = objPtr->internalRep.twoPtrValue.ptr1;

	if (objPtr->bytes == NULL ||	/* ...without a string rep */
	    listRepPtr->canonicalFlag) {/* ...or that is canonical */
	    /*
	     * TIP #280 Structures for tracking lines. As we know that this is
	     * dynamic execution we ignore the invoker, even if known.
	     */

	    int nelements;
	    Tcl_Obj **elements, *copyPtr = TclListObjCopy(NULL, objPtr);
	    CmdFrame *eoFramePtr = (CmdFrame *)
		TclStackAlloc(interp, sizeof(CmdFrame));

	    eoFramePtr->type = TCL_LOCATION_EVAL_LIST;
	    eoFramePtr->level = (iPtr->cmdFramePtr == NULL?
				 1 : iPtr->cmdFramePtr->level + 1);
	    eoFramePtr->framePtr = iPtr->framePtr;
	    eoFramePtr->nextPtr = iPtr->cmdFramePtr;

	    eoFramePtr->nline = 0;
	    eoFramePtr->line = NULL;

	    eoFramePtr->cmd.listPtr  = objPtr;
	    Tcl_IncrRefCount(eoFramePtr->cmd.listPtr);
	    eoFramePtr->data.eval.path = NULL;

	    /*
	     * TIP #280 We do _not_ compute all the line numbers for the words
	     * in the command. For the eval of a pure list the most sensible
	     * choice is to put all words on line 1. Given that we neither
	     * need memory for them nor compute anything.  'line' is left
	     * NULL. The two places using this information (TclInfoFrame, and
	     * TclInitCompileEnv), are special-cased to use the proper line
	     * number directly instead of accessing the 'line' array.
	     */

	    Tcl_ListObjGetElements(NULL, copyPtr,
				   &nelements, &elements);

	    iPtr->cmdFramePtr = eoFramePtr;
	    result = Tcl_EvalObjv(interp, nelements, elements,
				  flags);

	    Tcl_DecrRefCount(copyPtr);
	    iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr;
	    Tcl_DecrRefCount(eoFramePtr->cmd.listPtr);
	    TclStackFree(interp, eoFramePtr);

	    goto done;
	}
    }

    if (flags & TCL_EVAL_DIRECT) {
	/*
	 * We're not supposed to use the compiler or byte-code interpreter.
	 * Let Tcl_EvalEx evaluate the command directly (and probably more
	 * slowly).
	 */

	/*







<
<
|
<
<
|
|
|
|

|
|
|


|
|
|
|
|

|
|

|
|
|

|
|
|
|
|
|
|
|
|

|
<

|
|
<

|
|
|
|
<
<
<
<
<
|







5078
5079
5080
5081
5082
5083
5084


5085


5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119

5120
5121
5122

5123
5124
5125
5126
5127





5128
5129
5130
5131
5132
5133
5134
5135
     *
     * This restriction has been relaxed a bit by storing in lists whether
     * they are "canonical" or not (a canonical list being one that is either
     * pure or that has its string rep derived by UpdateStringOfList from the
     * internal rep).
     */



    if (TclListObjIsCanonical(objPtr)) {


	/*
	 * TIP #280 Structures for tracking lines. As we know that this is
	 * dynamic execution we ignore the invoker, even if known.
	 */

	int nelements;
	Tcl_Obj **elements, *copyPtr = TclListObjCopy(NULL, objPtr);
	CmdFrame *eoFramePtr = (CmdFrame *)
		TclStackAlloc(interp, sizeof(CmdFrame));

	eoFramePtr->type = TCL_LOCATION_EVAL_LIST;
	eoFramePtr->level = (iPtr->cmdFramePtr == NULL?  1 
		: iPtr->cmdFramePtr->level + 1);
	eoFramePtr->framePtr = iPtr->framePtr;
	eoFramePtr->nextPtr = iPtr->cmdFramePtr;

	eoFramePtr->nline = 0;
	eoFramePtr->line = NULL;

	eoFramePtr->cmd.listPtr  = objPtr;
	Tcl_IncrRefCount(eoFramePtr->cmd.listPtr);
	eoFramePtr->data.eval.path = NULL;

	/*
	 * TIP #280 We do _not_ compute all the line numbers for the words
	 * in the command. For the eval of a pure list the most sensible
	 * choice is to put all words on line 1. Given that we neither
	 * need memory for them nor compute anything.  'line' is left
	 * NULL. The two places using this information (TclInfoFrame, and
	 * TclInitCompileEnv), are special-cased to use the proper line
	 * number directly instead of accessing the 'line' array.
	 */

	Tcl_ListObjGetElements(NULL, copyPtr, &nelements, &elements);


	iPtr->cmdFramePtr = eoFramePtr;
	result = Tcl_EvalObjv(interp, nelements, elements, flags);


	Tcl_DecrRefCount(copyPtr);
	iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr;
	Tcl_DecrRefCount(eoFramePtr->cmd.listPtr);
	TclStackFree(interp, eoFramePtr);





    } else if (flags & TCL_EVAL_DIRECT) {
	/*
	 * We're not supposed to use the compiler or byte-code interpreter.
	 * Let Tcl_EvalEx evaluate the command directly (and probably more
	 * slowly).
	 */

	/*
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
		Tcl_LogCommandInfo(interp, script, script, numSrcBytes);
	    }
	}
	iPtr->evalFlags = 0;
	iPtr->varFramePtr = savedVarFramePtr;
    }

  done:
    TclDecrRefCount(objPtr);
    return result;
}

/*
 *----------------------------------------------------------------------
 *







<







5281
5282
5283
5284
5285
5286
5287

5288
5289
5290
5291
5292
5293
5294
		Tcl_LogCommandInfo(interp, script, script, numSrcBytes);
	    }
	}
	iPtr->evalFlags = 0;
	iPtr->varFramePtr = savedVarFramePtr;
    }


    TclDecrRefCount(objPtr);
    return result;
}

/*
 *----------------------------------------------------------------------
 *

Changes to generic/tclInt.h.

2203
2204
2205
2206
2207
2208
2209



2210
2211
2212
2213
2214
2215
2216
2217
2218
2219



2220
2221
2222
2223
2224
2225
2226
#define ListObjGetElements(listPtr, objc, objv) \
    ((objv) = &(ListRepPtr(listPtr)->elements), \
     (objc) = ListRepPtr(listPtr)->elemCount)

#define ListObjLength(listPtr, len) \
    ((len) = ListRepPtr(listPtr)->elemCount)




#define TclListObjGetElements(interp, listPtr, objcPtr, objvPtr) \
    (((listPtr)->typePtr == &tclListType) \
	    ? ((ListObjGetElements((listPtr), *(objcPtr), *(objvPtr))), TCL_OK)\
	    : Tcl_ListObjGetElements((interp), (listPtr), (objcPtr), (objvPtr)))

#define TclListObjLength(interp, listPtr, lenPtr) \
    (((listPtr)->typePtr == &tclListType) \
	    ? ((ListObjLength((listPtr), *(lenPtr))), TCL_OK)\
	    : Tcl_ListObjLength((interp), (listPtr), (lenPtr)))




/*
 * Macros providing a faster path to integers: Tcl_GetLongFromObj everywhere,
 * Tcl_GetIntFromObj and TclGetIntForIndex on platforms where longs are ints.
 *
 * WARNING: these macros eval their args more than once.
 */








>
>
>










>
>
>







2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
#define ListObjGetElements(listPtr, objc, objv) \
    ((objv) = &(ListRepPtr(listPtr)->elements), \
     (objc) = ListRepPtr(listPtr)->elemCount)

#define ListObjLength(listPtr, len) \
    ((len) = ListRepPtr(listPtr)->elemCount)

#define ListObjIsCanonical(listPtr) \
    (((listPtr)->bytes == NULL) || ListRepPtr(listPtr)->canonicalFlag)

#define TclListObjGetElements(interp, listPtr, objcPtr, objvPtr) \
    (((listPtr)->typePtr == &tclListType) \
	    ? ((ListObjGetElements((listPtr), *(objcPtr), *(objvPtr))), TCL_OK)\
	    : Tcl_ListObjGetElements((interp), (listPtr), (objcPtr), (objvPtr)))

#define TclListObjLength(interp, listPtr, lenPtr) \
    (((listPtr)->typePtr == &tclListType) \
	    ? ((ListObjLength((listPtr), *(lenPtr))), TCL_OK)\
	    : Tcl_ListObjLength((interp), (listPtr), (lenPtr)))

#define TclListObjIsCanonical(listPtr) \
    (((listPtr)->typePtr == &tclListType) ? ListObjIsCanonical((listPtr)) : 0)

/*
 * Macros providing a faster path to integers: Tcl_GetLongFromObj everywhere,
 * Tcl_GetIntFromObj and TclGetIntForIndex on platforms where longs are ints.
 *
 * WARNING: these macros eval their args more than once.
 */

Changes to generic/tclUtil.c.

1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211

1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
    /*
     * Check first to see if all the items are of list type or empty. If so,
     * we will concat them together as lists, and return a list object. This
     * is only valid when the lists are in canonical form.
     */

    for (i = 0;  i < objc;  i++) {
	List *listRepPtr;

	objPtr = objv[i];
	if (objPtr->typePtr != &tclListType) {
	    TclGetString(objPtr);
	    if (objPtr->length) {
		break;
	    } else {
		continue;
	    }
	}
	listRepPtr = (List *) objPtr->internalRep.twoPtrValue.ptr1;
	if (objPtr->bytes != NULL && !listRepPtr->canonicalFlag) {

	    break;
	}
    }
    if (i == objc) {
	Tcl_Obj **listv;
	int listc;

	resPtr = NULL;
	for (i = 0;  i < objc;  i++) {
	    /*
	     * Tcl_ListObjAppendList could be used here, but this saves us a
	     * bit of type checking (since we've already done it). Use of
	     * INT_MAX tells us to always put the new stuff on the end. It
	     * will be set right in Tcl_ListObjReplace.
	     * Note that all objs at this point are either lists or have an
	     * empty string rep.
	     */

	    objPtr = objv[i];
	    if (objPtr->bytes && !objPtr->length) {
		continue;
	    }
	    TclListObjGetElements(NULL, objPtr, &listc, &listv);
	    if (listc) {
		if (resPtr) {
		    Tcl_ListObjReplace(NULL, resPtr, INT_MAX, 0, listc, listv);
		} else {







|


|
<
<
<
<
|
|
<
<
|
>



















|







1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202




1203
1204


1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
    /*
     * Check first to see if all the items are of list type or empty. If so,
     * we will concat them together as lists, and return a list object. This
     * is only valid when the lists are in canonical form.
     */

    for (i = 0;  i < objc;  i++) {
	int length;

	objPtr = objv[i];
	if (TclListObjIsCanonical(objPtr)) {




	    continue;
	}


	Tcl_GetStringFromObj(objPtr, &length);
	if (length > 0) {
	    break;
	}
    }
    if (i == objc) {
	Tcl_Obj **listv;
	int listc;

	resPtr = NULL;
	for (i = 0;  i < objc;  i++) {
	    /*
	     * Tcl_ListObjAppendList could be used here, but this saves us a
	     * bit of type checking (since we've already done it). Use of
	     * INT_MAX tells us to always put the new stuff on the end. It
	     * will be set right in Tcl_ListObjReplace.
	     * Note that all objs at this point are either lists or have an
	     * empty string rep.
	     */

	    objPtr = objv[i];
	    if (objPtr->bytes && objPtr->length == 0) {
		continue;
	    }
	    TclListObjGetElements(NULL, objPtr, &listc, &listv);
	    if (listc) {
		if (resPtr) {
		    Tcl_ListObjReplace(NULL, resPtr, INT_MAX, 0, listc, listv);
		} else {