Tk Source Code

Check-in [aaf11bdc]
Login

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

Overview
Comment:Bug [069c9e43c4]: FreeOptionInternalRep() breaks Tk_CreateOptionTable()
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: aaf11bdce2085809d8fe033855f4cac5ef21f852
User & Date: jan.nijtmans 2013-08-14 13:16:07
References
2013-10-31
10:04 Ticket [f214b8ad] shutdown woes status still Open with 3 other changes artifact: 0c6cd482 user: jan.nijtmans
2013-08-14
13:16 Closed ticket [069c9e43]: FreeOptionInternalRep() breaks Tk_CreateOptionTable() plus 6 other changes artifact: 5736cf7b user: jan.nijtmans
Context
2013-08-15
03:56
Bug [c597acdab3]: Call [$pb step] in tail position in ttk::progressbar::Autoincrement, so that the widget is in a consistent state when any write traces on the linked -variable are fired. check-in: 8ea3ccb4 user: jenglish tags: trunk
2013-08-14
13:16
Bug [069c9e43c4]: FreeOptionInternalRep() breaks Tk_CreateOptionTable() check-in: aaf11bdc user: jan.nijtmans tags: trunk
10:53
Fix reference counting for "option" objects, when being duplicated. Closed-Leaf check-in: bc21cf92 user: jan.nijtmans tags: bug-069c9e43c4
2013-08-11
14:51
Sync with Tcl version of tcl.m4 check-in: f2303527 user: jan.nijtmans tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ChangeLog.






1
2
3
4
5
6
7





2013-07-02  Jan Nijtmans  <[email protected]>

	* unix/tcl.m4:  Bug [32afa6e256]: dirent64 check is incorrect in tcl.m4
	* unix/configure: (thanks to Brian Griffin)

2012-06-28  Jan Nijtmans  <[email protected]>

>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
2013-08-14  Jan Nijtmans  <[email protected]>

	* generic/tkConfig.c:  Bug [069c9e43c4]: FreeOptionInternalRep() breaks
	* tests/config.test:   Tk_CreateOptionTable()

2013-07-02  Jan Nijtmans  <[email protected]>

	* unix/tcl.m4:  Bug [32afa6e256]: dirent64 check is incorrect in tcl.m4
	* unix/configure: (thanks to Brian Griffin)

2012-06-28  Jan Nijtmans  <[email protected]>

Changes to generic/tkConfig.c.

23
24
25
26
27
28
29
30
31
32
33





34
35
36
37
38
39
40
41
#define __NO_OLD_CONFIG
#endif

#include "tkInt.h"
#include "tkFont.h"

/*
 * The following definition is an AssocData key used to keep track of all of
 * the option tables that have been created for an interpreter.
 */






#define OPTION_HASH_KEY "TkOptionTable"

/*
 * The following two structures are used along with Tk_OptionSpec structures
 * to manage configuration options. Tk_OptionSpec is static templates that are
 * compiled into the code of a widget or other object manager. However, to
 * look up options efficiently we need to supplement the static information
 * with additional dynamic information, and this dynamic information may be







|
|


>
>
>
>
>
|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#define __NO_OLD_CONFIG
#endif

#include "tkInt.h"
#include "tkFont.h"

/*
 * The following definition keeps track of all of
 * the option tables that have been created for a thread.
 */

typedef struct ThreadSpecificData {
    int initialized;		/* 0 means table below needs initializing. */
    Tcl_HashTable hashTable;
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;


/*
 * The following two structures are used along with Tk_OptionSpec structures
 * to manage configuration options. Tk_OptionSpec is static templates that are
 * compiled into the code of a widget or other object manager. However, to
 * look up options efficiently we need to supplement the static information
 * with additional dynamic information, and this dynamic information may be
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130

131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
				 * used to delete the entry. */
    struct OptionTable *nextPtr;/* If templatePtr was part of a chain of
				 * templates, this points to the table
				 * corresponding to the next template in the
				 * chain. */
    int numOptions;		/* The number of items in the options array
				 * below. */
    int refCount2; /* Reference counter for controlling the freeing
                    * of the memory occupied by this OptionTable */
    Option options[1];		/* Information about the individual options in
				 * the table. This must be the last field in
				 * the structure: the actual size of the array
				 * will be numOptions, not 1. */
} OptionTable;

/*
 * Forward declarations for functions defined later in this file:
 */

static int		DoObjConfig(Tcl_Interp *interp, char *recordPtr,
			    Option *optionPtr, Tcl_Obj *valuePtr,
			    Tk_Window tkwin, Tk_SavedOption *savePtr);
static void		DestroyOptionHashTable(ClientData clientData,
			    Tcl_Interp *interp);
static void		FreeResources(Option *optionPtr, Tcl_Obj *objPtr,
			    char *internalPtr, Tk_Window tkwin);
static Tcl_Obj *	GetConfigList(char *recordPtr,
			    Option *optionPtr, Tk_Window tkwin);
static Tcl_Obj *	GetObjectForOption(char *recordPtr,
			    Option *optionPtr, Tk_Window tkwin);
static Option *		GetOption(const char *name, OptionTable *tablePtr);
static Option *		GetOptionFromObj(Tcl_Interp *interp,
			    Tcl_Obj *objPtr, OptionTable *tablePtr);
static int		ObjectIsEmpty(Tcl_Obj *objPtr);
static void		FreeOptionInternalRep(Tcl_Obj *objPtr);


/*
 * The structure below defines an object type that is used to cache the result
 * of looking up an option name. If an object has this type, then its
 * internalPtr1 field points to the OptionTable in which it was looked up, and
 * the internalPtr2 field points to the entry that matched.
 */

static const Tcl_ObjType optionObjType = {
    "option",			/* name */
    FreeOptionInternalRep,	/* freeIntRepProc */
    NULL,			/* dupIntRepProc */
    NULL,			/* updateStringProc */
    NULL			/* setFromAnyProc */
};

/*
 *--------------------------------------------------------------
 *







<
<













<
<











>











|







101
102
103
104
105
106
107


108
109
110
111
112
113
114
115
116
117
118
119
120


121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
				 * used to delete the entry. */
    struct OptionTable *nextPtr;/* If templatePtr was part of a chain of
				 * templates, this points to the table
				 * corresponding to the next template in the
				 * chain. */
    int numOptions;		/* The number of items in the options array
				 * below. */


    Option options[1];		/* Information about the individual options in
				 * the table. This must be the last field in
				 * the structure: the actual size of the array
				 * will be numOptions, not 1. */
} OptionTable;

/*
 * Forward declarations for functions defined later in this file:
 */

static int		DoObjConfig(Tcl_Interp *interp, char *recordPtr,
			    Option *optionPtr, Tcl_Obj *valuePtr,
			    Tk_Window tkwin, Tk_SavedOption *savePtr);


static void		FreeResources(Option *optionPtr, Tcl_Obj *objPtr,
			    char *internalPtr, Tk_Window tkwin);
static Tcl_Obj *	GetConfigList(char *recordPtr,
			    Option *optionPtr, Tk_Window tkwin);
static Tcl_Obj *	GetObjectForOption(char *recordPtr,
			    Option *optionPtr, Tk_Window tkwin);
static Option *		GetOption(const char *name, OptionTable *tablePtr);
static Option *		GetOptionFromObj(Tcl_Interp *interp,
			    Tcl_Obj *objPtr, OptionTable *tablePtr);
static int		ObjectIsEmpty(Tcl_Obj *objPtr);
static void		FreeOptionInternalRep(Tcl_Obj *objPtr);
static void		DupOptionInternalRep(Tcl_Obj *, Tcl_Obj *);

/*
 * The structure below defines an object type that is used to cache the result
 * of looking up an option name. If an object has this type, then its
 * internalPtr1 field points to the OptionTable in which it was looked up, and
 * the internalPtr2 field points to the entry that matched.
 */

static const Tcl_ObjType optionObjType = {
    "option",			/* name */
    FreeOptionInternalRep,	/* freeIntRepProc */
    DupOptionInternalRep,	/* dupIntRepProc */
    NULL,			/* updateStringProc */
    NULL			/* setFromAnyProc */
};

/*
 *--------------------------------------------------------------
 *
166
167
168
169
170
171
172
173
174
175
176
177
178
179


180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
Tk_CreateOptionTable(
    Tcl_Interp *interp,		/* Interpreter associated with the application
				 * in which this table will be used. */
    const Tk_OptionSpec *templatePtr)
				/* Static information about the configuration
				 * options. */
{
    Tcl_HashTable *hashTablePtr;
    Tcl_HashEntry *hashEntryPtr;
    int newEntry;
    OptionTable *tablePtr;
    const Tk_OptionSpec *specPtr, *specPtr2;
    Option *optionPtr;
    int numOptions, i;



    /*
     * We use an AssocData value in the interpreter to keep a hash table of
     * all the option tables we've created for this application. This is used
     * for two purposes. First, it allows us to share the tables (e.g. in
     * several chains) and second, we use the deletion callback for the
     * AssocData to delete all the option tables when the interpreter is
     * deleted. The code below finds the hash table or creates a new one if it
     * doesn't already exist.
     */

    hashTablePtr = Tcl_GetAssocData(interp, OPTION_HASH_KEY, NULL);
    if (hashTablePtr == NULL) {
	hashTablePtr = ckalloc(sizeof(Tcl_HashTable));
	Tcl_InitHashTable(hashTablePtr, TCL_ONE_WORD_KEYS);
	Tcl_SetAssocData(interp, OPTION_HASH_KEY, DestroyOptionHashTable,
		hashTablePtr);
    }

    /*
     * See if a table has already been created for this template. If so, just
     * reuse the existing table.
     */

    hashEntryPtr = Tcl_CreateHashEntry(hashTablePtr, (char *) templatePtr,
	    &newEntry);
    if (!newEntry) {
	tablePtr = Tcl_GetHashValue(hashEntryPtr);
	tablePtr->refCount++;
	return (Tk_OptionTable) tablePtr;
    }

    /*
     * Count the number of options in the template, then create the table
     * structure.
     */

    numOptions = 0;
    for (specPtr = templatePtr; specPtr->type != TK_OPTION_END; specPtr++) {
	numOptions++;
    }
    tablePtr = ckalloc(sizeof(OptionTable) + (numOptions * sizeof(Option)));
    tablePtr->refCount = 1;
    tablePtr->refCount2 = 1;
    tablePtr->hashEntryPtr = hashEntryPtr;
    tablePtr->nextPtr = NULL;
    tablePtr->numOptions = numOptions;

    /*
     * Initialize all of the Option structures in the table.
     */







<






>
>


|
|
|
<
<
|



<
|
<
|
<
|







|


















<







168
169
170
171
172
173
174

175
176
177
178
179
180
181
182
183
184
185
186
187


188
189
190
191

192

193

194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220

221
222
223
224
225
226
227
Tk_CreateOptionTable(
    Tcl_Interp *interp,		/* Interpreter associated with the application
				 * in which this table will be used. */
    const Tk_OptionSpec *templatePtr)
				/* Static information about the configuration
				 * options. */
{

    Tcl_HashEntry *hashEntryPtr;
    int newEntry;
    OptionTable *tablePtr;
    const Tk_OptionSpec *specPtr, *specPtr2;
    Option *optionPtr;
    int numOptions, i;
    ThreadSpecificData *tsdPtr =
	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

    /*
     * We use an TSD in the thread to keep a hash table of
     * all the option tables we've created for this application. This is
     * used for allowing us to share the tables (e.g. in several chains).


     * The code below finds the hash table or creates a new one if it
     * doesn't already exist.
     */


    if (!tsdPtr->initialized) {

	Tcl_InitHashTable(&tsdPtr->hashTable, TCL_ONE_WORD_KEYS);

	tsdPtr->initialized = 1;
    }

    /*
     * See if a table has already been created for this template. If so, just
     * reuse the existing table.
     */

    hashEntryPtr = Tcl_CreateHashEntry(&tsdPtr->hashTable, (char *) templatePtr,
	    &newEntry);
    if (!newEntry) {
	tablePtr = Tcl_GetHashValue(hashEntryPtr);
	tablePtr->refCount++;
	return (Tk_OptionTable) tablePtr;
    }

    /*
     * Count the number of options in the template, then create the table
     * structure.
     */

    numOptions = 0;
    for (specPtr = templatePtr; specPtr->type != TK_OPTION_END; specPtr++) {
	numOptions++;
    }
    tablePtr = ckalloc(sizeof(OptionTable) + (numOptions * sizeof(Option)));
    tablePtr->refCount = 1;

    tablePtr->hashEntryPtr = hashEntryPtr;
    tablePtr->nextPtr = NULL;
    tablePtr->numOptions = numOptions;

    /*
     * Initialize all of the Option structures in the table.
     */
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
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
	if (((optionPtr->specPtr->type == TK_OPTION_COLOR)
		|| (optionPtr->specPtr->type == TK_OPTION_BORDER))
		&& (optionPtr->extra.monoColorPtr != NULL)) {
	    Tcl_DecrRefCount(optionPtr->extra.monoColorPtr);
	}
    }
    Tcl_DeleteHashEntry(tablePtr->hashEntryPtr);
    tablePtr->refCount2--;
    if (tablePtr->refCount2 <= 0) {
	ckfree(tablePtr);
    }
}

/*
 *----------------------------------------------------------------------
 *
 * DestroyOptionHashTable --
 *
 *	This function is the deletion callback associated with the AssocData
 *	entry created by Tk_CreateOptionTable. It is invoked when an
 *	interpreter is deleted, and deletes all of the option tables
 *	associated with that interpreter.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The option hash table is destroyed along with all of the OptionTable
 *	structures that it refers to.
 *
 *----------------------------------------------------------------------
 */

static void
DestroyOptionHashTable(
    ClientData clientData,	/* The hash table we are destroying */
    Tcl_Interp *interp)		/* The interpreter we are destroying */
{
    Tcl_HashTable *hashTablePtr = clientData;
    Tcl_HashSearch search;
    Tcl_HashEntry *hashEntryPtr;

    for (hashEntryPtr = Tcl_FirstHashEntry(hashTablePtr, &search);
	    hashEntryPtr != NULL;
	    hashEntryPtr = Tcl_NextHashEntry(&search)) {
	OptionTable *tablePtr = Tcl_GetHashValue(hashEntryPtr);

	/*
	 * The following statements do two tricky things:
	 * 1. They ensure that the option table is deleted, even if there are
	 *    outstanding references to it.
	 * 2. They ensure that Tk_DeleteOptionTable doesn't delete other
	 *    tables chained from this one; we'll do it when we come across
	 *    the hash table entry for the chained table (in fact, the chained
	 *    table may already have been deleted).
	 */

	tablePtr->refCount = 1;
	tablePtr->nextPtr = NULL;
	Tk_DeleteOptionTable((Tk_OptionTable) tablePtr);
    }
    Tcl_DeleteHashTable(hashTablePtr);
    ckfree(hashTablePtr);
}

/*
 *--------------------------------------------------------------
 *
 * Tk_InitOptions --
 *







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







349
350
351
352
353
354
355


356





















































357
358
359
360
361
362
363
	if (((optionPtr->specPtr->type == TK_OPTION_COLOR)
		|| (optionPtr->specPtr->type == TK_OPTION_BORDER))
		&& (optionPtr->extra.monoColorPtr != NULL)) {
	    Tcl_DecrRefCount(optionPtr->extra.monoColorPtr);
	}
    }
    Tcl_DeleteHashEntry(tablePtr->hashEntryPtr);


    ckfree(tablePtr);





















































}

/*
 *--------------------------------------------------------------
 *
 * Tk_InitOptions --
 *
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
    if ((objPtr->typePtr != NULL)
	    && (objPtr->typePtr->freeIntRepProc != NULL)) {
	objPtr->typePtr->freeIntRepProc(objPtr);
    }
    objPtr->internalRep.twoPtrValue.ptr1 = (void *) tablePtr;
    objPtr->internalRep.twoPtrValue.ptr2 = (void *) bestPtr;
    objPtr->typePtr = &optionObjType;
    tablePtr->refCount2++;
    return bestPtr;

  error:
    if (interp != NULL) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"unknown option \"%s\"", name));
	Tcl_SetErrorCode(interp, "TK", "LOOKUP", "OPTION", name, NULL);







|







1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
    if ((objPtr->typePtr != NULL)
	    && (objPtr->typePtr->freeIntRepProc != NULL)) {
	objPtr->typePtr->freeIntRepProc(objPtr);
    }
    objPtr->internalRep.twoPtrValue.ptr1 = (void *) tablePtr;
    objPtr->internalRep.twoPtrValue.ptr2 = (void *) bestPtr;
    objPtr->typePtr = &optionObjType;
    tablePtr->refCount++;
    return bestPtr;

  error:
    if (interp != NULL) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"unknown option \"%s\"", name));
	Tcl_SetErrorCode(interp, "TK", "LOOKUP", "OPTION", name, NULL);
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236






















1237
1238
1239
1240
1241
1242
1243
 *----------------------------------------------------------------------
 */

static void
FreeOptionInternalRep(
    register Tcl_Obj *objPtr)	/* Object whose internal rep to free. */
{
    register OptionTable *tablePtr = (OptionTable *) objPtr->internalRep.twoPtrValue.ptr1;

    tablePtr->refCount2--;
    if (tablePtr->refCount2 <= 0) {
	ckfree(tablePtr);
    }
    objPtr->typePtr = NULL;
    objPtr->internalRep.twoPtrValue.ptr1 = NULL;
    objPtr->internalRep.twoPtrValue.ptr2 = NULL;
}























/*
 *--------------------------------------------------------------
 *
 * Tk_SetOptions --
 *
 *	Process one or more name-value pairs for configuration options and







|

<
<
|
<




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







1162
1163
1164
1165
1166
1167
1168
1169
1170


1171

1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
 *----------------------------------------------------------------------
 */

static void
FreeOptionInternalRep(
    register Tcl_Obj *objPtr)	/* Object whose internal rep to free. */
{
    register Tk_OptionTable tablePtr = (Tk_OptionTable) objPtr->internalRep.twoPtrValue.ptr1;



    Tk_DeleteOptionTable(tablePtr);

    objPtr->typePtr = NULL;
    objPtr->internalRep.twoPtrValue.ptr1 = NULL;
    objPtr->internalRep.twoPtrValue.ptr2 = NULL;
}

/*
 *---------------------------------------------------------------------------
 *
 * DupOptionInternalRep --
 *
 *	When a cached option object is duplicated, this is called to update the
 *	internal reps.
 *
 *---------------------------------------------------------------------------
 */

static void
DupOptionInternalRep(
    Tcl_Obj *srcObjPtr,		/* The object we are copying from. */
    Tcl_Obj *dupObjPtr)		/* The object we are copying to. */
{
    register OptionTable *tablePtr = (OptionTable *) srcObjPtr->internalRep.twoPtrValue.ptr1;
    tablePtr->refCount++;
    dupObjPtr->typePtr = srcObjPtr->typePtr;
    dupObjPtr->internalRep = srcObjPtr->internalRep;
}

/*
 *--------------------------------------------------------------
 *
 * Tk_SetOptions --
 *
 *	Process one or more name-value pairs for configuration options and
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119


2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
    Tcl_Interp *interp,		/* Interpreter in which the table is
				 * defined. */
    Tk_OptionTable table)	/* Table about which information is to be
				 * returned. May not necessarily exist in the
				 * interpreter anymore. */
{
    OptionTable *tablePtr = (OptionTable *) table;
    Tcl_HashTable *hashTablePtr;
    Tcl_HashEntry *hashEntryPtr;
    Tcl_HashSearch search;
    Tcl_Obj *objPtr;



    objPtr = Tcl_NewObj();
    hashTablePtr = Tcl_GetAssocData(interp, OPTION_HASH_KEY, NULL);
    if (hashTablePtr == NULL) {
	return objPtr;
    }

    /*
     * Scan all the tables for this interpreter to make sure that the one we
     * want still is valid.
     */

    for (hashEntryPtr = Tcl_FirstHashEntry(hashTablePtr, &search);
	    hashEntryPtr != NULL;
	    hashEntryPtr = Tcl_NextHashEntry(&search)) {
	if (tablePtr == (OptionTable *) Tcl_GetHashValue(hashEntryPtr)) {
	    for ( ; tablePtr != NULL; tablePtr = tablePtr->nextPtr) {
		Tcl_ListObjAppendElement(NULL, objPtr,
			Tcl_NewIntObj(tablePtr->refCount));
		Tcl_ListObjAppendElement(NULL, objPtr,







<



>
>


<
|








|







2070
2071
2072
2073
2074
2075
2076

2077
2078
2079
2080
2081
2082
2083

2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
    Tcl_Interp *interp,		/* Interpreter in which the table is
				 * defined. */
    Tk_OptionTable table)	/* Table about which information is to be
				 * returned. May not necessarily exist in the
				 * interpreter anymore. */
{
    OptionTable *tablePtr = (OptionTable *) table;

    Tcl_HashEntry *hashEntryPtr;
    Tcl_HashSearch search;
    Tcl_Obj *objPtr;
    ThreadSpecificData *tsdPtr =
	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

    objPtr = Tcl_NewObj();

    if (!tablePtr || !tsdPtr->initialized) {
	return objPtr;
    }

    /*
     * Scan all the tables for this interpreter to make sure that the one we
     * want still is valid.
     */

    for (hashEntryPtr = Tcl_FirstHashEntry(&tsdPtr->hashTable, &search);
	    hashEntryPtr != NULL;
	    hashEntryPtr = Tcl_NextHashEntry(&search)) {
	if (tablePtr == (OptionTable *) Tcl_GetHashValue(hashEntryPtr)) {
	    for ( ; tablePtr != NULL; tablePtr = tablePtr->nextPtr) {
		Tcl_ListObjAppendElement(NULL, objPtr,
			Tcl_NewIntObj(tablePtr->refCount));
		Tcl_ListObjAppendElement(NULL, objPtr,

Changes to tests/config.test.

130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
    deleteWindows
    testobjconfig delete chain3
    lappend x [testobjconfig info chain2] [testobjconfig info chain1]
    testobjconfig delete chain2
    lappend x [testobjconfig info chain2] [testobjconfig info chain1]
} -cleanup {
    killTables
} -result {{1 4 -three 2 2 -one} {2 2 -one} {} {1 2 -one}}

# No tests for DestroyOptionHashTable; couldn't figure out how to test.

test config-3.1 {Tk_InitOptions - priority of chained tables} -constraints {
    testobjconfig
} -body {
    testobjconfig chain1 .a







|







130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
    deleteWindows
    testobjconfig delete chain3
    lappend x [testobjconfig info chain2] [testobjconfig info chain1]
    testobjconfig delete chain2
    lappend x [testobjconfig info chain2] [testobjconfig info chain1]
} -cleanup {
    killTables
} -result {{3 4 -three 2 2 -one} {2 2 -one} {} {2 2 -one}}

# No tests for DestroyOptionHashTable; couldn't figure out how to test.

test config-3.1 {Tk_InitOptions - priority of chained tables} -constraints {
    testobjconfig
} -body {
    testobjconfig chain1 .a