Tcl Source Code

Check-in [4d2d2556fc]
Login

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

Overview
Comment:merge trunk
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | novem
Files: files | file ages | folders
SHA1: 4d2d2556fca6ce9e8908b0751c470961d796a536
User & Date: jan.nijtmans 2013-02-04 22:56:43
Context
2013-02-07
10:15
merge trunk check-in: 3d2d02771d user: jan.nijtmans tags: novem
2013-02-04
22:56
merge trunk check-in: 4d2d2556fc user: jan.nijtmans tags: novem
20:48
Merge in fix for 3602706 check-in: dff3f1d1e5 user: dgp tags: trunk
14:15
merge trunk check-in: 0439b85bce user: jan.nijtmans tags: novem
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ChangeLog.








1
2
3
4
5
6
7







2013-01-30  Andreas Kupries  <[email protected]>

	* library/platform/platform.tcl (::platform::LibcVersion): See
	* library/platform/pkgIndex.tcl: [Bug 3599098]: Fixed the RE
	* unix/Makefile.in: extracting the version to avoid issues with
	* win/Makefile.in: recent changes to the glibc banner. Now
	  targeting a less variable part of the string. Bumped package to
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
2013-02-04  Donal K. Fellows  <[email protected]>

	* generic/tclCompCmds.c (TclCompileArraySetCmd): [Bug 3603163]: Stop
	crash in weird case where [eval] is used to make [array set] get
	confused about whether there is a local variable table or not. Thanks
	to Poor Yorick for identifying a reproducible crashing case.

2013-01-30  Andreas Kupries  <[email protected]>

	* library/platform/platform.tcl (::platform::LibcVersion): See
	* library/platform/pkgIndex.tcl: [Bug 3599098]: Fixed the RE
	* unix/Makefile.in: extracting the version to avoid issues with
	* win/Makefile.in: recent changes to the glibc banner. Now
	  targeting a less variable part of the string. Bumped package to

Changes to generic/tclCompCmds.c.

280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310

311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328



329






330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345



346

347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
    Tcl_Parse *parsePtr,	/* Points to a parse structure for the command
				 * created by Tcl_ParseCommand. */
    Command *cmdPtr,		/* Points to defintion of command being
				 * compiled. */
    CompileEnv *envPtr)		/* Holds resulting instructions. */
{
    DefineLineInformation;	/* TIP #280 */
    Tcl_Token *tokenPtr;
    int simpleVarName, isScalar, localIndex;
    int dataVar, iterVar, keyVar, valVar, infoIndex;
    int back, fwd, offsetBack, offsetFwd, savedStackDepth;
    ForeachInfo *infoPtr;

    if (parsePtr->numWords != 3) {
	return TCL_ERROR;
    }

    tokenPtr = TokenAfter(parsePtr->tokenPtr);
    PushVarNameWord(interp, tokenPtr, envPtr, TCL_NO_ELEMENT,
	    &localIndex, &simpleVarName, &isScalar, 1);
    tokenPtr = TokenAfter(tokenPtr);
    if (!isScalar) {
	return TCL_ERROR;
    }

    /*
     * Special case: literal empty value argument is just an "ensure array"
     * operation.
     */

    if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD && tokenPtr[1].size == 0) {

	if (localIndex >= 0) {
	    TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex,	envPtr);
	    TclEmitInstInt1(INST_JUMP_TRUE1, 7,			envPtr);
	    TclEmitInstInt4(INST_ARRAY_MAKE_IMM, localIndex,	envPtr);
	} else {
	    TclEmitOpcode(  INST_DUP,				envPtr);
	    TclEmitOpcode(  INST_ARRAY_EXISTS_STK,		envPtr);
	    TclEmitInstInt1(INST_JUMP_TRUE1, 5,			envPtr);
	    savedStackDepth = envPtr->currStackDepth;
	    TclEmitOpcode(  INST_ARRAY_MAKE_STK,		envPtr);
	    TclEmitInstInt1(INST_JUMP1, 3,			envPtr);
	    envPtr->currStackDepth = savedStackDepth;
	    TclEmitOpcode(  INST_POP,				envPtr);
	}
	PushLiteral(envPtr, "", 0);
	return TCL_OK;
    }




    if (envPtr->procPtr == NULL) {






	/*
	 * Right number of arguments, but not compilable as we can't allocate
	 * (unnamed) local variables to manage the internal iteration.
	 */

	Tcl_Obj *objPtr = Tcl_NewObj();
	char *bytes;
	int length, cmdLit;

	Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, objPtr);
	bytes = Tcl_GetStringFromObj(objPtr, &length);
	cmdLit = TclRegisterNewCmdLiteral(envPtr, bytes, length);
	TclSetCmdNameObj(interp, envPtr->literalArrayPtr[cmdLit].objPtr,
		cmdPtr);
	TclEmitPush(cmdLit, envPtr);
	TclDecrRefCount(objPtr);



	TclEmitInstInt4(INST_REVERSE, 2,			envPtr);

	CompileWord(envPtr, tokenPtr, interp, 2);
	TclEmitInstInt1(INST_INVOKE_STK1, 3,			envPtr);
	return TCL_OK;
    }

    /*
     * Prepare for the internal foreach.
     */

    dataVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
    iterVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
    keyVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
    valVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);

    infoPtr = ckalloc(sizeof(ForeachInfo) + sizeof(ForeachVarList *));
    infoPtr->numLists = 1;
    infoPtr->firstValueTemp = dataVar;
    infoPtr->loopCtTemp = iterVar;
    infoPtr->varLists[0] = ckalloc(sizeof(ForeachVarList) * 2*sizeof(int));
    infoPtr->varLists[0]->numVars = 2;
    infoPtr->varLists[0]->varIndexes[0] = keyVar;
    infoPtr->varLists[0]->varIndexes[1] = valVar;
    infoIndex = TclCreateAuxData(infoPtr, &tclForeachInfoType, envPtr);

    /*
     * Start issuing instructions to write to the array.
     */

    CompileWord(envPtr, tokenPtr, interp, 2);
    TclEmitOpcode(	INST_DUP,				envPtr);
    TclEmitOpcode(	INST_LIST_LENGTH,			envPtr);
    PushLiteral(envPtr, "1", 1);
    TclEmitOpcode(	INST_BITAND,				envPtr);
    offsetFwd = CurrentOffset(envPtr);
    TclEmitInstInt1(	INST_JUMP_FALSE1, 0,			envPtr);
    savedStackDepth = envPtr->currStackDepth;







|









|
|

|









|
>


















>
>
>
|
>
>
>
>
>
>
















>
>
>
|
>
|




<
<
<
<
<
<
<
<
<














|







280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365









366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
    Tcl_Parse *parsePtr,	/* Points to a parse structure for the command
				 * created by Tcl_ParseCommand. */
    Command *cmdPtr,		/* Points to defintion of command being
				 * compiled. */
    CompileEnv *envPtr)		/* Holds resulting instructions. */
{
    DefineLineInformation;	/* TIP #280 */
    Tcl_Token *varTokenPtr, *dataTokenPtr;
    int simpleVarName, isScalar, localIndex;
    int dataVar, iterVar, keyVar, valVar, infoIndex;
    int back, fwd, offsetBack, offsetFwd, savedStackDepth;
    ForeachInfo *infoPtr;

    if (parsePtr->numWords != 3) {
	return TCL_ERROR;
    }

    varTokenPtr = TokenAfter(parsePtr->tokenPtr);
    PushVarNameWord(interp, varTokenPtr, envPtr, TCL_NO_ELEMENT,
	    &localIndex, &simpleVarName, &isScalar, 1);
    dataTokenPtr = TokenAfter(varTokenPtr);
    if (!isScalar) {
	return TCL_ERROR;
    }

    /*
     * Special case: literal empty value argument is just an "ensure array"
     * operation.
     */

    if (dataTokenPtr->type == TCL_TOKEN_SIMPLE_WORD
	    && dataTokenPtr[1].size == 0) {
	if (localIndex >= 0) {
	    TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex,	envPtr);
	    TclEmitInstInt1(INST_JUMP_TRUE1, 7,			envPtr);
	    TclEmitInstInt4(INST_ARRAY_MAKE_IMM, localIndex,	envPtr);
	} else {
	    TclEmitOpcode(  INST_DUP,				envPtr);
	    TclEmitOpcode(  INST_ARRAY_EXISTS_STK,		envPtr);
	    TclEmitInstInt1(INST_JUMP_TRUE1, 5,			envPtr);
	    savedStackDepth = envPtr->currStackDepth;
	    TclEmitOpcode(  INST_ARRAY_MAKE_STK,		envPtr);
	    TclEmitInstInt1(INST_JUMP1, 3,			envPtr);
	    envPtr->currStackDepth = savedStackDepth;
	    TclEmitOpcode(  INST_POP,				envPtr);
	}
	PushLiteral(envPtr, "", 0);
	return TCL_OK;
    }

    /*
     * Prepare for the internal foreach.
     */

    dataVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
    iterVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
    keyVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);
    valVar = TclFindCompiledLocal(NULL, 0, 1, envPtr);

    if (dataVar < 0) {
	/*
	 * Right number of arguments, but not compilable as we can't allocate
	 * (unnamed) local variables to manage the internal iteration.
	 */

	Tcl_Obj *objPtr = Tcl_NewObj();
	char *bytes;
	int length, cmdLit;

	Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, objPtr);
	bytes = Tcl_GetStringFromObj(objPtr, &length);
	cmdLit = TclRegisterNewCmdLiteral(envPtr, bytes, length);
	TclSetCmdNameObj(interp, envPtr->literalArrayPtr[cmdLit].objPtr,
		cmdPtr);
	TclEmitPush(cmdLit, envPtr);
	TclDecrRefCount(objPtr);
	if (localIndex >= 0) {
	    CompileWord(envPtr, varTokenPtr, interp, 1);
	} else {
	    TclEmitInstInt4(INST_REVERSE, 2,			envPtr);
	}
	CompileWord(envPtr, dataTokenPtr, interp, 2);
	TclEmitInstInt1(INST_INVOKE_STK1, 3,			envPtr);
	return TCL_OK;
    }










    infoPtr = ckalloc(sizeof(ForeachInfo) + sizeof(ForeachVarList *));
    infoPtr->numLists = 1;
    infoPtr->firstValueTemp = dataVar;
    infoPtr->loopCtTemp = iterVar;
    infoPtr->varLists[0] = ckalloc(sizeof(ForeachVarList) * 2*sizeof(int));
    infoPtr->varLists[0]->numVars = 2;
    infoPtr->varLists[0]->varIndexes[0] = keyVar;
    infoPtr->varLists[0]->varIndexes[1] = valVar;
    infoIndex = TclCreateAuxData(infoPtr, &tclForeachInfoType, envPtr);

    /*
     * Start issuing instructions to write to the array.
     */

    CompileWord(envPtr, dataTokenPtr, interp, 2);
    TclEmitOpcode(	INST_DUP,				envPtr);
    TclEmitOpcode(	INST_LIST_LENGTH,			envPtr);
    PushLiteral(envPtr, "1", 1);
    TclEmitOpcode(	INST_BITAND,				envPtr);
    offsetFwd = CurrentOffset(envPtr);
    TclEmitInstInt1(	INST_JUMP_FALSE1, 0,			envPtr);
    savedStackDepth = envPtr->currStackDepth;

Changes to generic/tclVar.c.

471
472
473
474
475
476
477

478

479
480
481
482
483
484
485
486
487
488
489
490






491
492
493
494
495
496
497
				 * is set to NULL. */
{
    Tcl_Obj *part2Ptr = NULL;
    Var *resPtr;

    if (part2) {
	part2Ptr = Tcl_NewStringObj(part2, -1);

	Tcl_IncrRefCount(part2Ptr);

    }

    resPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr,
	    flags, msg, createPart1, createPart2, arrayPtrPtr);

    if (part2Ptr) {
	Tcl_DecrRefCount(part2Ptr);
    }

    return resPtr;
}







Var *
TclObjLookupVarEx(
    Tcl_Interp *interp,		/* Interpreter to use for lookup. */
    Tcl_Obj *part1Ptr,		/* If part2Ptr isn't NULL, this is the name of
				 * an array. Otherwise, this is a full
				 * variable name that could include a
				 * parenthesized array element. */







>
|
>












>
>
>
>
>
>







471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
				 * is set to NULL. */
{
    Tcl_Obj *part2Ptr = NULL;
    Var *resPtr;

    if (part2) {
	part2Ptr = Tcl_NewStringObj(part2, -1);
	if (createPart2) {
	    Tcl_IncrRefCount(part2Ptr);
	}
    }

    resPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr,
	    flags, msg, createPart1, createPart2, arrayPtrPtr);

    if (part2Ptr) {
	Tcl_DecrRefCount(part2Ptr);
    }

    return resPtr;
}

/*
 *	When createPart1 is 1, callers must IncrRefCount part1Ptr if they
 *	plan to DecrRefCount it.
 *	When createPart2 is 1, callers must IncrRefCount part2Ptr if they
 *	plan to DecrRefCount it.
 */
Var *
TclObjLookupVarEx(
    Tcl_Interp *interp,		/* Interpreter to use for lookup. */
    Tcl_Obj *part1Ptr,		/* If part2Ptr isn't NULL, this is the name of
				 * an array. Otherwise, this is a full
				 * variable name that could include a
				 * parenthesized array element. */
624
625
626
627
628
629
630

631

632
633
634
635
636
637
638
		    Tcl_SetErrorCode(interp, "TCL", "VALUE", "VARNAME", NULL);
		}
		return NULL;
	    }
	    part2 = newPart2 = part1Ptr->internalRep.twoPtrValue.ptr2;
	    if (newPart2) {
		part2Ptr = Tcl_NewStringObj(newPart2, -1);

		Tcl_IncrRefCount(part2Ptr);

	    }
	    part1Ptr = part1Ptr->internalRep.twoPtrValue.ptr1;
	    typePtr = part1Ptr->typePtr;
	    if (typePtr == &localVarNameType) {
		goto localVarNameTypeHandling;
	    }
	}







>
|
>







632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
		    Tcl_SetErrorCode(interp, "TCL", "VALUE", "VARNAME", NULL);
		}
		return NULL;
	    }
	    part2 = newPart2 = part1Ptr->internalRep.twoPtrValue.ptr2;
	    if (newPart2) {
		part2Ptr = Tcl_NewStringObj(newPart2, -1);
		if (createPart2) {
		    Tcl_IncrRefCount(part2Ptr);
		}
	    }
	    part1Ptr = part1Ptr->internalRep.twoPtrValue.ptr1;
	    typePtr = part1Ptr->typePtr;
	    if (typePtr == &localVarNameType) {
		goto localVarNameTypeHandling;
	    }
	}
670
671
672
673
674
675
676

677

678
679
680
681
682
683
684
		len1 = i;

		newPart2 = ckalloc(len2 + 1);
		memcpy(newPart2, part2, (unsigned) len2);
		*(newPart2+len2) = '\0';
		part2 = newPart2;
		part2Ptr = Tcl_NewStringObj(newPart2, -1);

		Tcl_IncrRefCount(part2Ptr);


		/*
		 * Free the internal rep of the original part1Ptr, now renamed
		 * objPtr, and set it to tclParsedVarNameType.
		 */

		objPtr = part1Ptr;







>
|
>







680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
		len1 = i;

		newPart2 = ckalloc(len2 + 1);
		memcpy(newPart2, part2, (unsigned) len2);
		*(newPart2+len2) = '\0';
		part2 = newPart2;
		part2Ptr = Tcl_NewStringObj(newPart2, -1);
		if (createPart2) {
		    Tcl_IncrRefCount(part2Ptr);
		}

		/*
		 * Free the internal rep of the original part1Ptr, now renamed
		 * objPtr, and set it to tclParsedVarNameType.
		 */

		objPtr = part1Ptr;
1077
1078
1079
1080
1081
1082
1083


1084
1085
1086
1087
1088
1089
1090
 *	a variable that has been unset but it only being kept in existence (if
 *	VAR_UNDEFINED) by a trace.
 *
 * Side effects:
 *	The variable at arrayPtr may be converted to be an array if
 *	createPart1 is 1. A new hashtable entry may be created if createPart2
 *	is 1.


 *
 *----------------------------------------------------------------------
 */

Var *
TclLookupArrayElement(
    Tcl_Interp *interp,		/* Interpreter to use for lookup. */







>
>







1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
 *	a variable that has been unset but it only being kept in existence (if
 *	VAR_UNDEFINED) by a trace.
 *
 * Side effects:
 *	The variable at arrayPtr may be converted to be an array if
 *	createPart1 is 1. A new hashtable entry may be created if createPart2
 *	is 1.
 *	When createElem is 1, callers must incr elNamePtr if they plan
 *	to decr it.
 *
 *----------------------------------------------------------------------
 */

Var *
TclLookupArrayElement(
    Tcl_Interp *interp,		/* Interpreter to use for lookup. */
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222

1223
1224
1225
1226
1227
1228
1229
    Tcl_Interp *interp,		/* Command interpreter in which varName is to
				 * be looked up. */
    const char *varName,	/* Name of a variable in interp. */
    int flags)			/* OR-ed combination of TCL_GLOBAL_ONLY,
				 * TCL_NAMESPACE_ONLY or TCL_LEAVE_ERR_MSG
				 * bits. */
{
    Tcl_Obj *varNamePtr, *resultPtr;

    varNamePtr = Tcl_NewStringObj(varName, -1);
    Tcl_IncrRefCount(varNamePtr);
    resultPtr = Tcl_ObjGetVar2(interp, varNamePtr, NULL, flags);

    TclDecrRefCount(varNamePtr);

    if (resultPtr == NULL) {
	return NULL;
    }
    return TclGetString(resultPtr);
}







<
<
|
<
|
>







1225
1226
1227
1228
1229
1230
1231


1232

1233
1234
1235
1236
1237
1238
1239
1240
1241
    Tcl_Interp *interp,		/* Command interpreter in which varName is to
				 * be looked up. */
    const char *varName,	/* Name of a variable in interp. */
    int flags)			/* OR-ed combination of TCL_GLOBAL_ONLY,
				 * TCL_NAMESPACE_ONLY or TCL_LEAVE_ERR_MSG
				 * bits. */
{


    Tcl_Obj *varNamePtr = Tcl_NewStringObj(varName, -1);

    Tcl_Obj *resultPtr = Tcl_ObjGetVar2(interp, varNamePtr, NULL, flags);

    TclDecrRefCount(varNamePtr);

    if (resultPtr == NULL) {
	return NULL;
    }
    return TclGetString(resultPtr);
}
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
				 * the name of a variable. */
    const char *part2,		/* If non-NULL, gives the name of an element
				 * in the array part1. */
    int flags)			/* OR-ed combination of TCL_GLOBAL_ONLY,
				 * TCL_NAMESPACE_ONLY and TCL_LEAVE_ERR_MSG *
				 * bits. */
{
    Tcl_Obj *resultPtr, *part1Ptr, *part2Ptr;

    part1Ptr = Tcl_NewStringObj(part1, -1);
    Tcl_IncrRefCount(part1Ptr);
    if (part2) {
	part2Ptr = Tcl_NewStringObj(part2, -1);
	Tcl_IncrRefCount(part2Ptr);
    } else {
	part2Ptr = NULL;
    }

    resultPtr = Tcl_ObjGetVar2(interp, part1Ptr, part2Ptr, flags);

    Tcl_DecrRefCount(part1Ptr);
    if (part2Ptr) {
	Tcl_DecrRefCount(part2Ptr);







|
<
|
|



<
<







1271
1272
1273
1274
1275
1276
1277
1278

1279
1280
1281
1282
1283


1284
1285
1286
1287
1288
1289
1290
				 * the name of a variable. */
    const char *part2,		/* If non-NULL, gives the name of an element
				 * in the array part1. */
    int flags)			/* OR-ed combination of TCL_GLOBAL_ONLY,
				 * TCL_NAMESPACE_ONLY and TCL_LEAVE_ERR_MSG *
				 * bits. */
{
    Tcl_Obj *resultPtr;

    Tcl_Obj *part2Ptr = NULL, *part1Ptr = Tcl_NewStringObj(part1, -1);

    if (part2) {
	part2Ptr = Tcl_NewStringObj(part2, -1);
	Tcl_IncrRefCount(part2Ptr);


    }

    resultPtr = Tcl_ObjGetVar2(interp, part1Ptr, part2Ptr, flags);

    Tcl_DecrRefCount(part1Ptr);
    if (part2Ptr) {
	Tcl_DecrRefCount(part2Ptr);
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
    const char *part2,		/* If non-NULL, gives the name of an element
				 * in the array part1. */
    int flags)			/* OR-ed combination of TCL_GLOBAL_ONLY, and
				 * TCL_LEAVE_ERR_MSG bits. */
{
    Tcl_Obj *resPtr, *part2Ptr = NULL, *part1Ptr = Tcl_NewStringObj(part1, -1);

    Tcl_IncrRefCount(part1Ptr);
    if (part2) {
	part2Ptr = Tcl_NewStringObj(part2, -1);
	Tcl_IncrRefCount(part2Ptr);
    }

    resPtr = Tcl_ObjGetVar2(interp, part1Ptr, part2Ptr, flags);








<







1327
1328
1329
1330
1331
1332
1333

1334
1335
1336
1337
1338
1339
1340
    const char *part2,		/* If non-NULL, gives the name of an element
				 * in the array part1. */
    int flags)			/* OR-ed combination of TCL_GLOBAL_ONLY, and
				 * TCL_LEAVE_ERR_MSG bits. */
{
    Tcl_Obj *resPtr, *part2Ptr = NULL, *part1Ptr = Tcl_NewStringObj(part1, -1);


    if (part2) {
	part2Ptr = Tcl_NewStringObj(part2, -1);
	Tcl_IncrRefCount(part2Ptr);
    }

    resPtr = Tcl_ObjGetVar2(interp, part1Ptr, part2Ptr, flags);

1353
1354
1355
1356
1357
1358
1359


1360
1361
1362
1363
1364
1365
1366
 *	and a message will be left in the interpreter's result if the
 *	TCL_LEAVE_ERR_MSG flag is set.
 *
 * Side effects:
 *	The ref count for the returned object is _not_ incremented to reflect
 *	the returned reference; if you want to keep a reference to the object
 *	you must increment its ref count yourself.


 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
Tcl_ObjGetVar2(
    Tcl_Interp *interp,		/* Command interpreter in which variable is to







>
>







1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
 *	and a message will be left in the interpreter's result if the
 *	TCL_LEAVE_ERR_MSG flag is set.
 *
 * Side effects:
 *	The ref count for the returned object is _not_ incremented to reflect
 *	the returned reference; if you want to keep a reference to the object
 *	you must increment its ref count yourself.
 *
 *	Callers must incr part2Ptr if they plan to decr it.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
Tcl_ObjGetVar2(
    Tcl_Interp *interp,		/* Command interpreter in which variable is to
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
    const char *varName,	/* Name of a variable in interp. */
    const char *newValue,	/* New value for varName. */
    int flags)			/* Various flags that tell how to set value:
				 * any of TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
				 * TCL_APPEND_VALUE, TCL_LIST_ELEMENT,
				 * TCL_LEAVE_ERR_MSG. */
{
    Tcl_Obj *valuePtr, *varNamePtr, *varValuePtr;

    varNamePtr = Tcl_NewStringObj(varName, -1);
    Tcl_IncrRefCount(varNamePtr);
    valuePtr = Tcl_NewStringObj(newValue, -1);
    Tcl_IncrRefCount(valuePtr);

    varValuePtr = Tcl_ObjSetVar2(interp, varNamePtr, NULL, valuePtr, flags);

    Tcl_DecrRefCount(varNamePtr);
    Tcl_DecrRefCount(valuePtr);
    if (varValuePtr == NULL) {
	return NULL;
    }
    return TclGetString(varValuePtr);
}

/*







|

<

<
<
<
|
|

|







1569
1570
1571
1572
1573
1574
1575
1576
1577

1578



1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
    const char *varName,	/* Name of a variable in interp. */
    const char *newValue,	/* New value for varName. */
    int flags)			/* Various flags that tell how to set value:
				 * any of TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
				 * TCL_APPEND_VALUE, TCL_LIST_ELEMENT,
				 * TCL_LEAVE_ERR_MSG. */
{
    Tcl_Obj *varValuePtr, *varNamePtr = Tcl_NewStringObj(varName, -1);


    Tcl_IncrRefCount(varNamePtr);



    varValuePtr = Tcl_ObjSetVar2(interp, varNamePtr, NULL, 
	    Tcl_NewStringObj(newValue, -1), flags);
    Tcl_DecrRefCount(varNamePtr);

    if (varValuePtr == NULL) {
	return NULL;
    }
    return TclGetString(varValuePtr);
}

/*
1717
1718
1719
1720
1721
1722
1723

1724
1725
1726
1727
1728
1729
1730
 *	not be the same one referenced by newValuePtr; this is because
 *	variable traces may modify the variable's value.
 *
 * Side effects:
 *	The value of the given variable is set. If either the array or the
 *	entry didn't exist then a new variable is created.
 *	Callers must Incr part1Ptr if they plan to Decr it.

 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
Tcl_ObjSetVar2(
    Tcl_Interp *interp,		/* Command interpreter in which variable is to







>







1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
 *	not be the same one referenced by newValuePtr; this is because
 *	variable traces may modify the variable's value.
 *
 * Side effects:
 *	The value of the given variable is set. If either the array or the
 *	entry didn't exist then a new variable is created.
 *	Callers must Incr part1Ptr if they plan to Decr it.
 *	Callers must Incr part2Ptr if they plan to Decr it.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
Tcl_ObjSetVar2(
    Tcl_Interp *interp,		/* Command interpreter in which variable is to
2007
2008
2009
2010
2011
2012
2013

2014
2015
2016
2017
2018
2019
2020
 * Side effects:
 *	The value of the given variable is incremented by the specified
 *	amount. If either the array or the entry didn't exist then a new
 *	variable is created. The ref count for the returned object is _not_
 *	incremented to reflect the returned reference; if you want to keep a
 *	reference to the object you must increment its ref count yourself.
 *	Callers must Incr part1Ptr if they plan to Decr it.

 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
TclIncrObjVar2(
    Tcl_Interp *interp,		/* Command interpreter in which variable is to







>







2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
 * Side effects:
 *	The value of the given variable is incremented by the specified
 *	amount. If either the array or the entry didn't exist then a new
 *	variable is created. The ref count for the returned object is _not_
 *	incremented to reflect the returned reference; if you want to keep a
 *	reference to the object you must increment its ref count yourself.
 *	Callers must Incr part1Ptr if they plan to Decr it.
 *	Callers must Incr part2Ptr if they plan to Decr it.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
TclIncrObjVar2(
    Tcl_Interp *interp,		/* Command interpreter in which variable is to
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
    int flags)			/* OR-ed combination of any of
				 * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
				 * TCL_LEAVE_ERR_MSG. */
{
    int result;
    Tcl_Obj *part2Ptr = NULL, *part1Ptr = Tcl_NewStringObj(part1, -1);

    Tcl_IncrRefCount(part1Ptr);
    if (part2) {
	part2Ptr = Tcl_NewStringObj(part2, -1);
	Tcl_IncrRefCount(part2Ptr);
    }

    /*
     * Filter to pass through only the flags this interface supports.
     */

    flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG);







<


<







2222
2223
2224
2225
2226
2227
2228

2229
2230

2231
2232
2233
2234
2235
2236
2237
    int flags)			/* OR-ed combination of any of
				 * TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
				 * TCL_LEAVE_ERR_MSG. */
{
    int result;
    Tcl_Obj *part2Ptr = NULL, *part1Ptr = Tcl_NewStringObj(part1, -1);


    if (part2) {
	part2Ptr = Tcl_NewStringObj(part2, -1);

    }

    /*
     * Filter to pass through only the flags this interface supports.
     */

    flags &= (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG);
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
    searchPtr->nextEntry = VarHashFirstEntry(varPtr->value.tablePtr,
	    &searchPtr->search);
    Tcl_SetHashValue(hPtr, searchPtr);
    Tcl_SetObjResult(interp,
	    Tcl_ObjPrintf("s-%d-%s", searchPtr->id, varName));
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * ArrayAnyMoreCmd --
 *
 *	This object-based function is invoked to process the "array anymore"
 *	Tcl command. See the user documentation for details on what it does.







|







3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
    searchPtr->nextEntry = VarHashFirstEntry(varPtr->value.tablePtr,
	    &searchPtr->search);
    Tcl_SetHashValue(hPtr, searchPtr);
    Tcl_SetObjResult(interp,
	    Tcl_ObjPrintf("s-%d-%s", searchPtr->id, varName));
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * ArrayAnyMoreCmd --
 *
 *	This object-based function is invoked to process the "array anymore"
 *	Tcl command. See the user documentation for details on what it does.
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
	    gotValue = 0;
	    break;
	}
    }
    Tcl_SetObjResult(interp, iPtr->execEnvPtr->constants[gotValue]);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * ArrayNextElementCmd --
 *
 *	This object-based function is invoked to process the "array
 *	nextelement" Tcl command. See the user documentation for details on







|







3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
	    gotValue = 0;
	    break;
	}
    }
    Tcl_SetObjResult(interp, iPtr->execEnvPtr->constants[gotValue]);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * ArrayNextElementCmd --
 *
 *	This object-based function is invoked to process the "array
 *	nextelement" Tcl command. See the user documentation for details on
5777
5778
5779
5780
5781
5782
5783
5784
5785
5786
5787
5788
5789
5790
5791
				 * TCL_LEAVE_ERR_MSG. If both TCL_GLOBAL_ONLY
				 * and TCL_NAMESPACE_ONLY are given,
				 * TCL_GLOBAL_ONLY is ignored. */
{
    Tcl_Obj *namePtr = Tcl_NewStringObj(name, -1);
    Tcl_Var var;

    Tcl_IncrRefCount(namePtr);
    var = ObjFindNamespaceVar(interp, namePtr, contextNsPtr, flags);
    Tcl_DecrRefCount(namePtr);
    return var;
}

static Tcl_Var
ObjFindNamespaceVar(







<







5783
5784
5785
5786
5787
5788
5789

5790
5791
5792
5793
5794
5795
5796
				 * TCL_LEAVE_ERR_MSG. If both TCL_GLOBAL_ONLY
				 * and TCL_NAMESPACE_ONLY are given,
				 * TCL_GLOBAL_ONLY is ignored. */
{
    Tcl_Obj *namePtr = Tcl_NewStringObj(name, -1);
    Tcl_Var var;


    var = ObjFindNamespaceVar(interp, namePtr, contextNsPtr, flags);
    Tcl_DecrRefCount(namePtr);
    return var;
}

static Tcl_Var
ObjFindNamespaceVar(
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
     * to check both possible search paths: from the specified namespace
     * context and from the global namespace.
     */

    varPtr = NULL;
    if (simpleName != name) {
	simpleNamePtr = Tcl_NewStringObj(simpleName, -1);
	Tcl_IncrRefCount(simpleNamePtr);
    } else {
	simpleNamePtr = namePtr;
    }

    for (search = 0;  (search < 2) && (varPtr == NULL);  search++) {
	if ((nsPtr[search] != NULL) && (simpleName != NULL)) {
	    varPtr = VarHashFindVar(&nsPtr[search]->varTable, simpleNamePtr);







<







5877
5878
5879
5880
5881
5882
5883

5884
5885
5886
5887
5888
5889
5890
     * to check both possible search paths: from the specified namespace
     * context and from the global namespace.
     */

    varPtr = NULL;
    if (simpleName != name) {
	simpleNamePtr = Tcl_NewStringObj(simpleName, -1);

    } else {
	simpleNamePtr = namePtr;
    }

    for (search = 0;  (search < 2) && (varPtr == NULL);  search++) {
	if ((nsPtr[search] != NULL) && (simpleName != NULL)) {
	    varPtr = VarHashFindVar(&nsPtr[search]->varTable, simpleNamePtr);

Changes to tests/set.test.

519
520
521
522
523
524
525





526
527
528
529
530
531
532

test set-5.1 {error on malformed array name} testset2 {
    unset -nocomplain z
    catch {testset2 z(a) b} msg
    catch {testset2 z(b) a} msg1
    list $msg $msg1
} {{can't read "z(a)(b)": variable isn't array} {can't read "z(b)(a)": variable isn't array}}






# cleanup
catch {unset a}
catch {unset b}
catch {unset i}
catch {unset x}
catch {unset z}







>
>
>
>
>







519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537

test set-5.1 {error on malformed array name} testset2 {
    unset -nocomplain z
    catch {testset2 z(a) b} msg
    catch {testset2 z(b) a} msg1
    list $msg $msg1
} {{can't read "z(a)(b)": variable isn't array} {can't read "z(b)(a)": variable isn't array}}

# In a mem-debug build, this test will crash unless Bug 3602706 is fixed.
test set-5.2 {Bug 3602706} -body {
    testset2 ::tcl_platform not-in-there
} -returnCodes error -result * -match glob

# cleanup
catch {unset a}
catch {unset b}
catch {unset i}
catch {unset x}
catch {unset z}

Changes to tests/var.test.

789
790
791
792
793
794
795





































































796
797
798
799
800
801
802
} -result 0

test var-19.1 {crash when freeing locals hashtable: Bug 3037525} {
    proc foo {} { catch {upvar 0 dummy \$index} }
    foo ; # This crashes without the fix for the bug
    rename foo {}
} {}






































































catch {namespace delete ns}
catch {unset arr}
catch {unset v}

catch {rename p ""}
catch {namespace delete test_ns_var}







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







789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
} -result 0

test var-19.1 {crash when freeing locals hashtable: Bug 3037525} {
    proc foo {} { catch {upvar 0 dummy \$index} }
    foo ; # This crashes without the fix for the bug
    rename foo {}
} {}

test var-20.1 {array set compilation correctness: Bug 3603163} -setup {
    unset -nocomplain x
} -body {
    apply {{} {
	global x
	array set x {a 1}
    }}
    array size x
} -result 1
test var-20.2 {array set compilation correctness: Bug 3603163} -setup {
    unset -nocomplain x
} -body {
    apply {{} {
	global x
	array set x {}
    }}
    array size x
} -result 0
test var-20.3 {array set compilation correctness: Bug 3603163} -setup {
    unset -nocomplain x
} -body {
    apply {{} {
	array set ::x {a 1}
    }}
    array size x
} -result 1
test var-20.4 {array set compilation correctness: Bug 3603163} -setup {
    unset -nocomplain x
} -body {
    apply {{} {
	array set ::x {}
    }}
    array size x
} -result 0
test var-20.5 {array set compilation correctness: Bug 3603163} -setup {
    unset -nocomplain x
} -body {
    apply {{} {
	global x
	eval {array set x {a 1}}
    }}
    array size x
} -result 1
test var-20.6 {array set compilation correctness: Bug 3603163} -setup {
    unset -nocomplain x
} -body {
    apply {{} {
	global x
	eval {array set x {}}
    }}
    array size x
} -result 0
test var-20.7 {array set compilation correctness: Bug 3603163} -setup {
    unset -nocomplain x
} -body {
    apply {{} {
	eval {array set ::x {a 1}}
    }}
    array size x
} -result 1
test var-20.8 {array set compilation correctness: Bug 3603163} -setup {
    unset -nocomplain x
} -body {
    apply {{} {
	eval {array set ::x {}}
    }}
    array size x
} -result 0

catch {namespace delete ns}
catch {unset arr}
catch {unset v}

catch {rename p ""}
catch {namespace delete test_ns_var}