1/*
2 * tkConfig.c --
3 *
4 *	This file contains functions that manage configuration options for
5 *	widgets and other things.
6 *
7 * Copyright (c) 1997-1998 Sun Microsystems, Inc.
8 *
9 * See the file "license.terms" for information on usage and redistribution of
10 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 *
12 * RCS: @(#) $Id$
13 */
14
15/*
16 * Temporary flag for working on new config package.
17 */
18
19#if 0
20
21/*
22 * used only for removing the old config code
23 */
24
25#define __NO_OLD_CONFIG
26#endif
27
28#include "tkInt.h"
29#include "tkFont.h"
30
31/*
32 * The following definition is an AssocData key used to keep track of all of
33 * the option tables that have been created for an interpreter.
34 */
35
36#define OPTION_HASH_KEY "TkOptionTable"
37
38/*
39 * The following two structures are used along with Tk_OptionSpec structures
40 * to manage configuration options. Tk_OptionSpec is static templates that are
41 * compiled into the code of a widget or other object manager. However, to
42 * look up options efficiently we need to supplement the static information
43 * with additional dynamic information, and this dynamic information may be
44 * different for each application. Thus we create structures of the following
45 * two types to hold all of the dynamic information; this is done by
46 * Tk_CreateOptionTable.
47 *
48 * One of the following structures corresponds to each Tk_OptionSpec. These
49 * structures exist as arrays inside TkOptionTable structures.
50 */
51
52typedef struct TkOption {
53    CONST Tk_OptionSpec *specPtr;
54				/* The original spec from the template passed
55				 * to Tk_CreateOptionTable.*/
56    Tk_Uid dbNameUID;	 	/* The Uid form of the option database
57				 * name. */
58    Tk_Uid dbClassUID;		/* The Uid form of the option database class
59				 * name. */
60    Tcl_Obj *defaultPtr;	/* Default value for this option. */
61    union {
62	Tcl_Obj *monoColorPtr;	/* For color and border options, this is an
63				 * alternate default value to use on
64				 * monochrome displays. */
65	struct TkOption *synonymPtr;
66				/* For synonym options, this points to the
67				 * master entry. */
68	struct Tk_ObjCustomOption *custom;
69				/* For TK_OPTION_CUSTOM. */
70    } extra;
71    int flags;			/* Miscellaneous flag values; see below for
72				 * definitions. */
73} Option;
74
75/*
76 * Flag bits defined for Option structures:
77 *
78 * OPTION_NEEDS_FREEING -	1 means that FreeResources must be invoked to
79 *				free resources associated with the option when
80 *				it is no longer needed.
81 */
82
83#define OPTION_NEEDS_FREEING		1
84
85/*
86 * One of the following exists for each Tk_OptionSpec array that has been
87 * passed to Tk_CreateOptionTable.
88 */
89
90typedef struct OptionTable {
91    int refCount;		/* Counts the number of uses of this table
92				 * (the number of times Tk_CreateOptionTable
93				 * has returned it). This can be greater than
94				 * 1 if it is shared along several option
95				 * table chains, or if the same table is used
96				 * for multiple purposes. */
97    Tcl_HashEntry *hashEntryPtr;/* Hash table entry that refers to this table;
98				 * used to delete the entry. */
99    struct OptionTable *nextPtr;/* If templatePtr was part of a chain of
100				 * templates, this points to the table
101				 * corresponding to the next template in the
102				 * chain. */
103    int numOptions;		/* The number of items in the options array
104				 * below. */
105    Option options[1];		/* Information about the individual options in
106				 * the table. This must be the last field in
107				 * the structure: the actual size of the array
108				 * will be numOptions, not 1. */
109} OptionTable;
110
111/*
112 * Forward declarations for functions defined later in this file:
113 */
114
115static int		DoObjConfig(Tcl_Interp *interp, char *recordPtr,
116			    Option *optionPtr, Tcl_Obj *valuePtr,
117			    Tk_Window tkwin, Tk_SavedOption *savePtr);
118static void		DestroyOptionHashTable(ClientData clientData,
119			    Tcl_Interp *interp);
120static void		FreeResources(Option *optionPtr, Tcl_Obj *objPtr,
121			    char *internalPtr, Tk_Window tkwin);
122static Tcl_Obj *	GetConfigList(char *recordPtr,
123			    Option *optionPtr, Tk_Window tkwin);
124static Tcl_Obj *	GetObjectForOption(char *recordPtr,
125			    Option *optionPtr, Tk_Window tkwin);
126static Option *		GetOption(CONST char *name, OptionTable *tablePtr);
127static Option *		GetOptionFromObj(Tcl_Interp *interp,
128			    Tcl_Obj *objPtr, OptionTable *tablePtr);
129static int		ObjectIsEmpty(Tcl_Obj *objPtr);
130static int		SetOptionFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
131
132/*
133 * The structure below defines an object type that is used to cache the result
134 * of looking up an option name. If an object has this type, then its
135 * internalPtr1 field points to the OptionTable in which it was looked up, and
136 * the internalPtr2 field points to the entry that matched.
137 */
138
139Tcl_ObjType tkOptionObjType = {
140    "option",			/* name */
141    NULL,			/* freeIntRepProc */
142    NULL,			/* dupIntRepProc */
143    NULL,			/* updateStringProc */
144    SetOptionFromAny		/* setFromAnyProc */
145};
146
147/*
148 *--------------------------------------------------------------
149 *
150 * Tk_CreateOptionTable --
151 *
152 *	Given a template for configuration options, this function creates a
153 *	table that may be used to look up options efficiently.
154 *
155 * Results:
156 *	Returns a token to a structure that can be passed to functions such as
157 *	Tk_InitOptions, Tk_SetOptions, and Tk_FreeConfigOptions.
158 *
159 * Side effects:
160 *	Storage is allocated.
161 *
162 *--------------------------------------------------------------
163 */
164
165Tk_OptionTable
166Tk_CreateOptionTable(
167    Tcl_Interp *interp,		/* Interpreter associated with the application
168				 * in which this table will be used. */
169    CONST Tk_OptionSpec *templatePtr)
170				/* Static information about the configuration
171				 * options. */
172{
173    Tcl_HashTable *hashTablePtr;
174    Tcl_HashEntry *hashEntryPtr;
175    int newEntry;
176    OptionTable *tablePtr;
177    CONST Tk_OptionSpec *specPtr, *specPtr2;
178    Option *optionPtr;
179    int numOptions, i;
180
181    /*
182     * We use an AssocData value in the interpreter to keep a hash table of
183     * all the option tables we've created for this application. This is used
184     * for two purposes. First, it allows us to share the tables (e.g. in
185     * several chains) and second, we use the deletion callback for the
186     * AssocData to delete all the option tables when the interpreter is
187     * deleted. The code below finds the hash table or creates a new one if it
188     * doesn't already exist.
189     */
190
191    hashTablePtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, OPTION_HASH_KEY,
192	    NULL);
193    if (hashTablePtr == NULL) {
194	hashTablePtr = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
195	Tcl_InitHashTable(hashTablePtr, TCL_ONE_WORD_KEYS);
196	Tcl_SetAssocData(interp, OPTION_HASH_KEY, DestroyOptionHashTable,
197		(ClientData) hashTablePtr);
198    }
199
200    /*
201     * See if a table has already been created for this template. If so, just
202     * reuse the existing table.
203     */
204
205    hashEntryPtr = Tcl_CreateHashEntry(hashTablePtr, (char *) templatePtr,
206	    &newEntry);
207    if (!newEntry) {
208	tablePtr = (OptionTable *) Tcl_GetHashValue(hashEntryPtr);
209	tablePtr->refCount++;
210	return (Tk_OptionTable) tablePtr;
211    }
212
213    /*
214     * Count the number of options in the template, then create the table
215     * structure.
216     */
217
218    numOptions = 0;
219    for (specPtr = templatePtr; specPtr->type != TK_OPTION_END; specPtr++) {
220	numOptions++;
221    }
222    tablePtr = (OptionTable *) (ckalloc(sizeof(OptionTable)
223	    + (numOptions * sizeof(Option))));
224    tablePtr->refCount = 1;
225    tablePtr->hashEntryPtr = hashEntryPtr;
226    tablePtr->nextPtr = NULL;
227    tablePtr->numOptions = numOptions;
228
229    /*
230     * Initialize all of the Option structures in the table.
231     */
232
233    for (specPtr = templatePtr, optionPtr = tablePtr->options;
234	    specPtr->type != TK_OPTION_END; specPtr++, optionPtr++) {
235	optionPtr->specPtr = specPtr;
236	optionPtr->dbNameUID = NULL;
237	optionPtr->dbClassUID = NULL;
238	optionPtr->defaultPtr = NULL;
239	optionPtr->extra.monoColorPtr = NULL;
240	optionPtr->flags = 0;
241
242	if (specPtr->type == TK_OPTION_SYNONYM) {
243	    /*
244	     * This is a synonym option; find the master option that it refers
245	     * to and create a pointer from the synonym to the master.
246	     */
247
248	    for (specPtr2 = templatePtr, i = 0; ; specPtr2++, i++) {
249		if (specPtr2->type == TK_OPTION_END) {
250		    Tcl_Panic("Tk_CreateOptionTable couldn't find synonym");
251		}
252		if (strcmp(specPtr2->optionName,
253			(char *) specPtr->clientData) == 0) {
254		    optionPtr->extra.synonymPtr = tablePtr->options + i;
255		    break;
256		}
257	    }
258	} else {
259	    if (specPtr->dbName != NULL) {
260		optionPtr->dbNameUID = Tk_GetUid(specPtr->dbName);
261	    }
262	    if (specPtr->dbClass != NULL) {
263		optionPtr->dbClassUID = Tk_GetUid(specPtr->dbClass);
264	    }
265	    if (specPtr->defValue != NULL) {
266		optionPtr->defaultPtr = Tcl_NewStringObj(specPtr->defValue,-1);
267		Tcl_IncrRefCount(optionPtr->defaultPtr);
268	    }
269	    if (((specPtr->type == TK_OPTION_COLOR)
270		    || (specPtr->type == TK_OPTION_BORDER))
271		    && (specPtr->clientData != NULL)) {
272		optionPtr->extra.monoColorPtr =
273			Tcl_NewStringObj((char *) specPtr->clientData, -1);
274		Tcl_IncrRefCount(optionPtr->extra.monoColorPtr);
275	    }
276
277	    if (specPtr->type == TK_OPTION_CUSTOM) {
278		/*
279		 * Get the custom parsing, etc., functions.
280		 */
281		optionPtr->extra.custom =
282			(Tk_ObjCustomOption *) specPtr->clientData;
283	    }
284	}
285	if (((specPtr->type == TK_OPTION_STRING)
286		&& (specPtr->internalOffset >= 0))
287		|| (specPtr->type == TK_OPTION_COLOR)
288		|| (specPtr->type == TK_OPTION_FONT)
289		|| (specPtr->type == TK_OPTION_BITMAP)
290		|| (specPtr->type == TK_OPTION_BORDER)
291		|| (specPtr->type == TK_OPTION_CURSOR)
292		|| (specPtr->type == TK_OPTION_CUSTOM)) {
293	    optionPtr->flags |= OPTION_NEEDS_FREEING;
294	}
295    }
296    tablePtr->hashEntryPtr = hashEntryPtr;
297    Tcl_SetHashValue(hashEntryPtr, tablePtr);
298
299    /*
300     * Finally, check to see if this template chains to another template with
301     * additional options. If so, call ourselves recursively to create the
302     * next table(s).
303     */
304
305    if (specPtr->clientData != NULL) {
306	tablePtr->nextPtr = (OptionTable *) Tk_CreateOptionTable(interp,
307		(Tk_OptionSpec *) specPtr->clientData);
308    }
309
310    return (Tk_OptionTable) tablePtr;
311}
312
313/*
314 *----------------------------------------------------------------------
315 *
316 * Tk_DeleteOptionTable --
317 *
318 *	Called to release resources used by an option table when the table is
319 *	no longer needed.
320 *
321 * Results:
322 *	None.
323 *
324 * Side effects:
325 *	The option table and associated resources (such as additional option
326 *	tables chained off it) are destroyed.
327 *
328 *----------------------------------------------------------------------
329 */
330
331void
332Tk_DeleteOptionTable(
333    Tk_OptionTable optionTable)	/* The option table to delete. */
334{
335    OptionTable *tablePtr = (OptionTable *) optionTable;
336    Option *optionPtr;
337    int count;
338
339    tablePtr->refCount--;
340    if (tablePtr->refCount > 0) {
341	return;
342    }
343
344    if (tablePtr->nextPtr != NULL) {
345	Tk_DeleteOptionTable((Tk_OptionTable) tablePtr->nextPtr);
346    }
347
348    for (count = tablePtr->numOptions, optionPtr = tablePtr->options;
349	    count > 0;  count--, optionPtr++) {
350	if (optionPtr->defaultPtr != NULL) {
351	    Tcl_DecrRefCount(optionPtr->defaultPtr);
352	}
353	if (((optionPtr->specPtr->type == TK_OPTION_COLOR)
354		|| (optionPtr->specPtr->type == TK_OPTION_BORDER))
355		&& (optionPtr->extra.monoColorPtr != NULL)) {
356	    Tcl_DecrRefCount(optionPtr->extra.monoColorPtr);
357	}
358    }
359    Tcl_DeleteHashEntry(tablePtr->hashEntryPtr);
360    ckfree((char *) tablePtr);
361}
362
363/*
364 *----------------------------------------------------------------------
365 *
366 * DestroyOptionHashTable --
367 *
368 *	This function is the deletion callback associated with the AssocData
369 *	entry created by Tk_CreateOptionTable. It is invoked when an
370 *	interpreter is deleted, and deletes all of the option tables
371 *	associated with that interpreter.
372 *
373 * Results:
374 *	None.
375 *
376 * Side effects:
377 *	The option hash table is destroyed along with all of the OptionTable
378 *	structures that it refers to.
379 *
380 *----------------------------------------------------------------------
381 */
382
383static void
384DestroyOptionHashTable(
385    ClientData clientData,	/* The hash table we are destroying */
386    Tcl_Interp *interp)		/* The interpreter we are destroying */
387{
388    Tcl_HashTable *hashTablePtr = (Tcl_HashTable *) clientData;
389    Tcl_HashSearch search;
390    Tcl_HashEntry *hashEntryPtr;
391    OptionTable *tablePtr;
392
393    for (hashEntryPtr = Tcl_FirstHashEntry(hashTablePtr, &search);
394	    hashEntryPtr != NULL;
395	    hashEntryPtr = Tcl_NextHashEntry(&search)) {
396	tablePtr = (OptionTable *) Tcl_GetHashValue(hashEntryPtr);
397
398	/*
399	 * The following statements do two tricky things:
400	 * 1. They ensure that the option table is deleted, even if there are
401	 *    outstanding references to it.
402	 * 2. They ensure that Tk_DeleteOptionTable doesn't delete other
403	 *    tables chained from this one; we'll do it when we come across
404	 *    the hash table entry for the chained table (in fact, the chained
405	 *    table may already have been deleted).
406	 */
407
408	tablePtr->refCount = 1;
409	tablePtr->nextPtr = NULL;
410	Tk_DeleteOptionTable((Tk_OptionTable) tablePtr);
411    }
412    Tcl_DeleteHashTable(hashTablePtr);
413    ckfree((char *) hashTablePtr);
414}
415
416/*
417 *--------------------------------------------------------------
418 *
419 * Tk_InitOptions --
420 *
421 *	This function is invoked when an object such as a widget is created.
422 *	It supplies an initial value for each configuration option (the value
423 *	may come from the option database, a system default, or the default in
424 *	the option table).
425 *
426 * Results:
427 *	The return value is TCL_OK if the function completed successfully, and
428 *	TCL_ERROR if one of the initial values was bogus. If an error occurs
429 *	and interp isn't NULL, then an error message will be left in its
430 *	result.
431 *
432 * Side effects:
433 *	Fields of recordPtr are filled in with initial values.
434 *
435 *--------------------------------------------------------------
436 */
437
438int
439Tk_InitOptions(
440    Tcl_Interp *interp,		/* Interpreter for error reporting. NULL means
441				 * don't leave an error message. */
442    char *recordPtr,		/* Pointer to the record to configure. Note:
443				 * the caller should have properly initialized
444				 * the record with NULL pointers for each
445				 * option value. */
446    Tk_OptionTable optionTable,	/* The token which matches the config specs
447				 * for the widget in question. */
448    Tk_Window tkwin)		/* Certain options types (such as
449				 * TK_OPTION_COLOR) need fields out of the
450				 * window they are used in to be able to
451				 * calculate their values. Not needed unless
452				 * one of these options is in the configSpecs
453				 * record. */
454{
455    OptionTable *tablePtr = (OptionTable *) optionTable;
456    Option *optionPtr;
457    int count;
458    Tk_Uid value;
459    Tcl_Obj *valuePtr;
460    enum {
461	OPTION_DATABASE, SYSTEM_DEFAULT, TABLE_DEFAULT
462    } source;
463
464    /*
465     * If this table chains to other tables, handle their initialization
466     * first. That way, if both tables refer to the same field of the record,
467     * the value in the first table will win.
468     */
469
470    if (tablePtr->nextPtr != NULL) {
471	if (Tk_InitOptions(interp, recordPtr,
472		(Tk_OptionTable) tablePtr->nextPtr, tkwin) != TCL_OK) {
473	    return TCL_ERROR;
474	}
475    }
476
477    /*
478     * Iterate over all of the options in the table, initializing each in
479     * turn.
480     */
481
482    for (optionPtr = tablePtr->options, count = tablePtr->numOptions;
483	    count > 0; optionPtr++, count--) {
484	/*
485	 * If we specify TK_OPTION_DONT_SET_DEFAULT, then the user has
486	 * processed and set a default for this already.
487	 */
488
489	if ((optionPtr->specPtr->type == TK_OPTION_SYNONYM) ||
490		(optionPtr->specPtr->flags & TK_OPTION_DONT_SET_DEFAULT)) {
491	    continue;
492	}
493	source = TABLE_DEFAULT;
494
495	/*
496	 * We look in three places for the initial value, using the first
497	 * non-NULL value that we find. First, check the option database.
498	 */
499
500	valuePtr = NULL;
501	if (optionPtr->dbNameUID != NULL) {
502	    value = Tk_GetOption(tkwin, optionPtr->dbNameUID,
503		    optionPtr->dbClassUID);
504	    if (value != NULL) {
505		valuePtr = Tcl_NewStringObj(value, -1);
506		source = OPTION_DATABASE;
507	    }
508	}
509
510	/*
511	 * Second, check for a system-specific default value.
512	 */
513
514	if ((valuePtr == NULL)
515		&& (optionPtr->dbNameUID != NULL)) {
516	    valuePtr = TkpGetSystemDefault(tkwin, optionPtr->dbNameUID,
517		    optionPtr->dbClassUID);
518	    if (valuePtr != NULL) {
519		source = SYSTEM_DEFAULT;
520	    }
521	}
522
523	/*
524	 * Third and last, use the default value supplied by the option table.
525	 * In the case of color objects, we pick one of two values depending
526	 * on whether the screen is mono or color.
527	 */
528
529	if (valuePtr == NULL) {
530	    if ((tkwin != NULL)
531		    && ((optionPtr->specPtr->type == TK_OPTION_COLOR)
532		    || (optionPtr->specPtr->type == TK_OPTION_BORDER))
533		    && (Tk_Depth(tkwin) <= 1)
534		    && (optionPtr->extra.monoColorPtr != NULL)) {
535		valuePtr = optionPtr->extra.monoColorPtr;
536	    } else {
537		valuePtr = optionPtr->defaultPtr;
538	    }
539	}
540
541	if (valuePtr == NULL) {
542	    continue;
543	}
544
545	/*
546	 * Bump the reference count on valuePtr, so that it is strongly
547	 * referenced here, and will be properly free'd when finished,
548	 * regardless of what DoObjConfig does.
549	 */
550
551	Tcl_IncrRefCount(valuePtr);
552
553	if (DoObjConfig(interp, recordPtr, optionPtr, valuePtr, tkwin,
554		NULL) != TCL_OK) {
555	    if (interp != NULL) {
556		char msg[200];
557
558		switch (source) {
559		case OPTION_DATABASE:
560		    sprintf(msg, "\n    (database entry for \"%.50s\")",
561			    optionPtr->specPtr->optionName);
562		    break;
563		case SYSTEM_DEFAULT:
564		    sprintf(msg, "\n    (system default for \"%.50s\")",
565			    optionPtr->specPtr->optionName);
566		    break;
567		case TABLE_DEFAULT:
568		    sprintf(msg, "\n    (default value for \"%.50s\")",
569			    optionPtr->specPtr->optionName);
570		}
571		if (tkwin != NULL) {
572		    sprintf(msg + strlen(msg) - 1, " in widget \"%.50s\")",
573			    Tk_PathName(tkwin));
574		}
575		Tcl_AddErrorInfo(interp, msg);
576	    }
577	    Tcl_DecrRefCount(valuePtr);
578	    return TCL_ERROR;
579	}
580	Tcl_DecrRefCount(valuePtr);
581    }
582    return TCL_OK;
583}
584
585/*
586 *--------------------------------------------------------------
587 *
588 * DoObjConfig --
589 *
590 *	This function applies a new value for a configuration option to the
591 *	record being configured.
592 *
593 * Results:
594 *	The return value is TCL_OK if the function completed successfully. If
595 *	an error occurred then TCL_ERROR is returned and an error message is
596 *	left in interp's result, if interp isn't NULL. In addition, if
597 *	oldValuePtrPtr isn't NULL then it *oldValuePtrPtr is filled in with a
598 *	pointer to the option's old value.
599 *
600 * Side effects:
601 *	RecordPtr gets modified to hold the new value in the form of a
602 *	Tcl_Obj, an internal representation, or both. The old value is freed
603 *	if oldValuePtrPtr is NULL.
604 *
605 *--------------------------------------------------------------
606 */
607
608static int
609DoObjConfig(
610    Tcl_Interp *interp,		/* Interpreter for error reporting. If NULL,
611				 * then no message is left if an error
612				 * occurs. */
613    char *recordPtr,		/* The record to modify to hold the new option
614				 * value. */
615    Option *optionPtr,		/* Pointer to information about the option. */
616    Tcl_Obj *valuePtr,		/* New value for option. */
617    Tk_Window tkwin,		/* Window in which option will be used (needed
618				 * to allocate resources for some options).
619				 * May be NULL if the option doesn't require
620				 * window-related resources. */
621    Tk_SavedOption *savedOptionPtr)
622				/* If NULL, the old value for the option will
623				 * be freed. If non-NULL, the old value will
624				 * be stored here, and it becomes the property
625				 * of the caller (the caller must eventually
626				 * free the old value). */
627{
628    Tcl_Obj **slotPtrPtr, *oldPtr;
629    char *internalPtr;		/* Points to location in record where internal
630				 * representation of value should be stored,
631				 * or NULL. */
632    char *oldInternalPtr;	/* Points to location in which to save old
633				 * internal representation of value. */
634    Tk_SavedOption internal;	/* Used to save the old internal
635				 * representation of the value if
636				 * savedOptionPtr is NULL. */
637    CONST Tk_OptionSpec *specPtr;
638    int nullOK;
639
640    /*
641     * Save the old object form for the value, if there is one.
642     */
643
644    specPtr = optionPtr->specPtr;
645    if (specPtr->objOffset >= 0) {
646	slotPtrPtr = (Tcl_Obj **) (recordPtr + specPtr->objOffset);
647	oldPtr = *slotPtrPtr;
648    } else {
649	slotPtrPtr = NULL;
650	oldPtr = NULL;
651    }
652
653    /*
654     * Apply the new value in a type-specific way. Also remember the old
655     * object and internal forms, if they exist.
656     */
657
658    if (specPtr->internalOffset >= 0) {
659	internalPtr = recordPtr + specPtr->internalOffset;
660    } else {
661	internalPtr = NULL;
662    }
663    if (savedOptionPtr != NULL) {
664	savedOptionPtr->optionPtr = optionPtr;
665	savedOptionPtr->valuePtr = oldPtr;
666	oldInternalPtr = (char *) &savedOptionPtr->internalForm;
667    } else {
668	oldInternalPtr = (char *) &internal.internalForm;
669    }
670    nullOK = (optionPtr->specPtr->flags & TK_OPTION_NULL_OK);
671    switch (optionPtr->specPtr->type) {
672    case TK_OPTION_BOOLEAN: {
673	int newBool;
674
675	if (Tcl_GetBooleanFromObj(interp, valuePtr, &newBool) != TCL_OK) {
676	    return TCL_ERROR;
677	}
678	if (internalPtr != NULL) {
679	    *((int *) oldInternalPtr) = *((int *) internalPtr);
680	    *((int *) internalPtr) = newBool;
681	}
682	break;
683    }
684    case TK_OPTION_INT: {
685	int newInt;
686
687	if (Tcl_GetIntFromObj(interp, valuePtr, &newInt) != TCL_OK) {
688	    return TCL_ERROR;
689	}
690	if (internalPtr != NULL) {
691	    *((int *) oldInternalPtr) = *((int *) internalPtr);
692	    *((int *) internalPtr) = newInt;
693	}
694	break;
695    }
696    case TK_OPTION_DOUBLE: {
697	double newDbl;
698
699	if (nullOK && ObjectIsEmpty(valuePtr)) {
700	    valuePtr = NULL;
701	    newDbl = 0;
702	} else {
703	    if (Tcl_GetDoubleFromObj(interp, valuePtr, &newDbl) != TCL_OK) {
704		return TCL_ERROR;
705	    }
706	}
707
708	if (internalPtr != NULL) {
709	    *((double *) oldInternalPtr) = *((double *) internalPtr);
710	    *((double *) internalPtr) = newDbl;
711	}
712	break;
713    }
714    case TK_OPTION_STRING: {
715	char *newStr, *value;
716	int length;
717
718	if (nullOK && ObjectIsEmpty(valuePtr)) {
719	    valuePtr = NULL;
720	}
721	if (internalPtr != NULL) {
722	    if (valuePtr != NULL) {
723		value = Tcl_GetStringFromObj(valuePtr, &length);
724		newStr = ckalloc((unsigned) (length + 1));
725		strcpy(newStr, value);
726	    } else {
727		newStr = NULL;
728	    }
729	    *((char **) oldInternalPtr) = *((char **) internalPtr);
730	    *((char **) internalPtr) = newStr;
731	}
732	break;
733    }
734    case TK_OPTION_STRING_TABLE: {
735	int newValue;
736
737	if (Tcl_GetIndexFromObj(interp, valuePtr,
738		(CONST char **) optionPtr->specPtr->clientData,
739		optionPtr->specPtr->optionName+1, 0, &newValue) != TCL_OK) {
740	    return TCL_ERROR;
741	}
742	if (internalPtr != NULL) {
743	    *((int *) oldInternalPtr) = *((int *) internalPtr);
744	    *((int *) internalPtr) = newValue;
745	}
746	break;
747    }
748    case TK_OPTION_COLOR: {
749	XColor *newPtr;
750
751	if (nullOK && ObjectIsEmpty(valuePtr)) {
752	    valuePtr = NULL;
753	    newPtr = NULL;
754	} else {
755	    newPtr = Tk_AllocColorFromObj(interp, tkwin, valuePtr);
756	    if (newPtr == NULL) {
757		return TCL_ERROR;
758	    }
759	}
760	if (internalPtr != NULL) {
761	    *((XColor **) oldInternalPtr) = *((XColor **) internalPtr);
762	    *((XColor **) internalPtr) = newPtr;
763	}
764	break;
765    }
766    case TK_OPTION_FONT: {
767	Tk_Font newFont;
768
769	if (nullOK && ObjectIsEmpty(valuePtr)) {
770	    valuePtr = NULL;
771	    newFont = NULL;
772	} else {
773	    newFont = Tk_AllocFontFromObj(interp, tkwin, valuePtr);
774	    if (newFont == NULL) {
775		return TCL_ERROR;
776	    }
777	}
778	if (internalPtr != NULL) {
779	    *((Tk_Font *) oldInternalPtr) = *((Tk_Font *) internalPtr);
780	    *((Tk_Font *) internalPtr) = newFont;
781	}
782	break;
783    }
784    case TK_OPTION_STYLE: {
785	Tk_Style newStyle;
786
787	if (nullOK && ObjectIsEmpty(valuePtr)) {
788	    valuePtr = NULL;
789	    newStyle = NULL;
790	} else {
791	    newStyle = Tk_AllocStyleFromObj(interp, valuePtr);
792	    if (newStyle == NULL) {
793		return TCL_ERROR;
794	    }
795	}
796	if (internalPtr != NULL) {
797	    *((Tk_Style *) oldInternalPtr) = *((Tk_Style *) internalPtr);
798	    *((Tk_Style *) internalPtr) = newStyle;
799	}
800	break;
801    }
802    case TK_OPTION_BITMAP: {
803	Pixmap newBitmap;
804
805	if (nullOK && ObjectIsEmpty(valuePtr)) {
806	    valuePtr = NULL;
807	    newBitmap = None;
808	} else {
809	    newBitmap = Tk_AllocBitmapFromObj(interp, tkwin, valuePtr);
810	    if (newBitmap == None) {
811		return TCL_ERROR;
812	    }
813	}
814	if (internalPtr != NULL) {
815	    *((Pixmap *) oldInternalPtr) = *((Pixmap *) internalPtr);
816	    *((Pixmap *) internalPtr) = newBitmap;
817	}
818	break;
819    }
820    case TK_OPTION_BORDER: {
821	Tk_3DBorder newBorder;
822
823	if (nullOK && ObjectIsEmpty(valuePtr)) {
824	    valuePtr = NULL;
825	    newBorder = NULL;
826	} else {
827	    newBorder = Tk_Alloc3DBorderFromObj(interp, tkwin, valuePtr);
828	    if (newBorder == NULL) {
829		return TCL_ERROR;
830	    }
831	}
832	if (internalPtr != NULL) {
833	    *((Tk_3DBorder *) oldInternalPtr) = *((Tk_3DBorder *) internalPtr);
834	    *((Tk_3DBorder *) internalPtr) = newBorder;
835	}
836	break;
837    }
838    case TK_OPTION_RELIEF: {
839	int newRelief;
840
841	if (nullOK && ObjectIsEmpty(valuePtr)) {
842	    valuePtr = NULL;
843	    newRelief = TK_RELIEF_NULL;
844	} else {
845	    if (Tk_GetReliefFromObj(interp, valuePtr, &newRelief) != TCL_OK) {
846		return TCL_ERROR;
847	    }
848	}
849	if (internalPtr != NULL) {
850	    *((int *) oldInternalPtr) = *((int *) internalPtr);
851	    *((int *) internalPtr) = newRelief;
852	}
853	break;
854    }
855    case TK_OPTION_CURSOR: {
856	Tk_Cursor newCursor;
857
858	if (nullOK && ObjectIsEmpty(valuePtr)) {
859	    newCursor = None;
860	    valuePtr = NULL;
861	} else {
862	    newCursor = Tk_AllocCursorFromObj(interp, tkwin, valuePtr);
863	    if (newCursor == None) {
864		return TCL_ERROR;
865	    }
866	}
867	if (internalPtr != NULL) {
868	    *((Tk_Cursor *) oldInternalPtr) = *((Tk_Cursor *) internalPtr);
869	    *((Tk_Cursor *) internalPtr) = newCursor;
870	}
871	Tk_DefineCursor(tkwin, newCursor);
872	break;
873    }
874    case TK_OPTION_JUSTIFY: {
875	Tk_Justify newJustify;
876
877	if (Tk_GetJustifyFromObj(interp, valuePtr, &newJustify) != TCL_OK) {
878	    return TCL_ERROR;
879	}
880	if (internalPtr != NULL) {
881	    *((Tk_Justify *) oldInternalPtr) = *((Tk_Justify *) internalPtr);
882	    *((Tk_Justify *) internalPtr) = newJustify;
883	}
884	break;
885    }
886    case TK_OPTION_ANCHOR: {
887	Tk_Anchor newAnchor;
888
889	if (Tk_GetAnchorFromObj(interp, valuePtr, &newAnchor) != TCL_OK) {
890	    return TCL_ERROR;
891	}
892	if (internalPtr != NULL) {
893	    *((Tk_Anchor *) oldInternalPtr) = *((Tk_Anchor *) internalPtr);
894	    *((Tk_Anchor *) internalPtr) = newAnchor;
895	}
896	break;
897    }
898    case TK_OPTION_PIXELS: {
899	int newPixels;
900
901	if (nullOK && ObjectIsEmpty(valuePtr)) {
902	    valuePtr = NULL;
903	    newPixels = 0;
904	} else {
905	    if (Tk_GetPixelsFromObj(interp, tkwin, valuePtr,
906		    &newPixels) != TCL_OK) {
907		return TCL_ERROR;
908	    }
909	}
910	if (internalPtr != NULL) {
911	    *((int *) oldInternalPtr) = *((int *) internalPtr);
912	    *((int *) internalPtr) = newPixels;
913	}
914	break;
915    }
916    case TK_OPTION_WINDOW: {
917	Tk_Window newWin;
918
919	if (nullOK && ObjectIsEmpty(valuePtr)) {
920	    valuePtr = NULL;
921	    newWin = None;
922	} else {
923	    if (TkGetWindowFromObj(interp, tkwin, valuePtr,
924		    &newWin) != TCL_OK) {
925		return TCL_ERROR;
926	    }
927	}
928	if (internalPtr != NULL) {
929	    *((Tk_Window *) oldInternalPtr) = *((Tk_Window *) internalPtr);
930	    *((Tk_Window *) internalPtr) = newWin;
931	}
932	break;
933    }
934    case TK_OPTION_CUSTOM: {
935	Tk_ObjCustomOption *custom = optionPtr->extra.custom;
936
937	if (custom->setProc(custom->clientData, interp, tkwin,
938		&valuePtr, recordPtr, optionPtr->specPtr->internalOffset,
939		(char *)oldInternalPtr, optionPtr->specPtr->flags) != TCL_OK) {
940	    return TCL_ERROR;
941	}
942	break;
943    }
944
945    {
946	char buf[40+TCL_INTEGER_SPACE];
947
948    default:
949	sprintf(buf, "bad config table: unknown type %d",
950		optionPtr->specPtr->type);
951	Tcl_SetResult(interp, buf, TCL_VOLATILE);
952	return TCL_ERROR;
953    }
954    }
955
956    /*
957     * Release resources associated with the old value, if we're not returning
958     * it to the caller, then install the new object value into the record.
959     */
960
961    if (savedOptionPtr == NULL) {
962	if (optionPtr->flags & OPTION_NEEDS_FREEING) {
963	    FreeResources(optionPtr, oldPtr, oldInternalPtr, tkwin);
964	}
965	if (oldPtr != NULL) {
966	    Tcl_DecrRefCount(oldPtr);
967	}
968    }
969    if (slotPtrPtr != NULL) {
970	*slotPtrPtr = valuePtr;
971	if (valuePtr != NULL) {
972	    Tcl_IncrRefCount(valuePtr);
973	}
974    }
975    return TCL_OK;
976}
977
978/*
979 *----------------------------------------------------------------------
980 *
981 * ObjectIsEmpty --
982 *
983 *	This function tests whether the string value of an object is empty.
984 *
985 * Results:
986 *	The return value is 1 if the string value of objPtr has length zero,
987 *	and 0 otherwise.
988 *
989 * Side effects:
990 *	None.
991 *
992 *----------------------------------------------------------------------
993 */
994
995static int
996ObjectIsEmpty(
997    Tcl_Obj *objPtr)		/* Object to test. May be NULL. */
998{
999    int length;
1000
1001    if (objPtr == NULL) {
1002	return 1;
1003    }
1004    if (objPtr->bytes != NULL) {
1005	return (objPtr->length == 0);
1006    }
1007    Tcl_GetStringFromObj(objPtr, &length);
1008    return (length == 0);
1009}
1010
1011/*
1012 *----------------------------------------------------------------------
1013 *
1014 * GetOption --
1015 *
1016 *	This function searches through a chained option table to find the
1017 *	entry for a particular option name.
1018 *
1019 * Results:
1020 *	The return value is a pointer to the matching entry, or NULL if no
1021 *	matching entry could be found. Note: if the matching entry is a
1022 *	synonym then this function returns a pointer to the synonym entry,
1023 *	*not* the "real" entry that the synonym refers to.
1024 *
1025 * Side effects:
1026 *	None.
1027 *
1028 *----------------------------------------------------------------------
1029 */
1030
1031static Option *
1032GetOption(
1033    CONST char *name,		/* String balue to be looked up in the option
1034				 * table. */
1035    OptionTable *tablePtr)	/* Table in which to look up name. */
1036{
1037    Option *bestPtr, *optionPtr;
1038    OptionTable *tablePtr2;
1039    CONST char *p1, *p2;
1040    int count;
1041
1042    /*
1043     * Search through all of the option tables in the chain to find the best
1044     * match. Some tricky aspects:
1045     *
1046     * 1. We have to accept unique abbreviations.
1047     * 2. The same name could appear in different tables in the chain. If this
1048     *    happens, we use the entry from the first table. We have to be
1049     *    careful to distinguish this case from an ambiguous abbreviation.
1050     */
1051
1052    bestPtr = NULL;
1053    for (tablePtr2 = tablePtr; tablePtr2 != NULL;
1054	    tablePtr2 = tablePtr2->nextPtr) {
1055	for (optionPtr = tablePtr2->options, count = tablePtr2->numOptions;
1056		count > 0; optionPtr++, count--) {
1057	    for (p1 = name, p2 = optionPtr->specPtr->optionName;
1058		    *p1 == *p2; p1++, p2++) {
1059		if (*p1 == 0) {
1060		    /*
1061		     * This is an exact match. We're done.
1062		     */
1063
1064		    return optionPtr;
1065		}
1066	    }
1067	    if (*p1 == 0) {
1068		/*
1069		 * The name is an abbreviation for this option. Keep to make
1070		 * sure that the abbreviation only matches one option name.
1071		 * If we've already found a match in the past, then it is an
1072		 * error unless the full names for the two options are
1073		 * identical; in this case, the first option overrides the
1074		 * second.
1075		 */
1076
1077		if (bestPtr == NULL) {
1078		    bestPtr = optionPtr;
1079		} else if (strcmp(bestPtr->specPtr->optionName,
1080			optionPtr->specPtr->optionName) != 0) {
1081		    return NULL;
1082		}
1083	    }
1084	}
1085    }
1086
1087    /*
1088     * Return whatever we have found, which could be NULL if nothing
1089     * matched. The multiple-matching case is handled above.
1090     */
1091
1092    return bestPtr;
1093}
1094
1095/*
1096 *----------------------------------------------------------------------
1097 *
1098 * GetOptionFromObj --
1099 *
1100 *	This function searches through a chained option table to find the
1101 *	entry for a particular option name.
1102 *
1103 * Results:
1104 *	The return value is a pointer to the matching entry, or NULL if no
1105 *	matching entry could be found. If NULL is returned and interp is not
1106 *	NULL than an error message is left in its result. Note: if the
1107 *	matching entry is a synonym then this function returns a pointer to
1108 *	the synonym entry, *not* the "real" entry that the synonym refers to.
1109 *
1110 * Side effects:
1111 *	Information about the matching entry is cached in the object
1112 *	containing the name, so that future lookups can proceed more quickly.
1113 *
1114 *----------------------------------------------------------------------
1115 */
1116
1117static Option *
1118GetOptionFromObj(
1119    Tcl_Interp *interp,		/* Used only for error reporting; if NULL no
1120				 * message is left after an error. */
1121    Tcl_Obj *objPtr,		/* Object whose string value is to be looked
1122				 * up in the option table. */
1123    OptionTable *tablePtr)	/* Table in which to look up objPtr. */
1124{
1125    Option *bestPtr;
1126    char *name;
1127
1128    /*
1129     * First, check to see if the object already has the answer cached.
1130     */
1131
1132    if (objPtr->typePtr == &tkOptionObjType) {
1133	if (objPtr->internalRep.twoPtrValue.ptr1 == (void *) tablePtr) {
1134	    return (Option *) objPtr->internalRep.twoPtrValue.ptr2;
1135	}
1136    }
1137
1138    /*
1139     * The answer isn't cached.
1140     */
1141
1142    name = Tcl_GetString(objPtr);
1143    bestPtr = GetOption(name, tablePtr);
1144    if (bestPtr == NULL) {
1145	goto error;
1146    }
1147
1148    if ((objPtr->typePtr != NULL)
1149	    && (objPtr->typePtr->freeIntRepProc != NULL)) {
1150	objPtr->typePtr->freeIntRepProc(objPtr);
1151    }
1152    objPtr->internalRep.twoPtrValue.ptr1 = (void *) tablePtr;
1153    objPtr->internalRep.twoPtrValue.ptr2 = (void *) bestPtr;
1154    objPtr->typePtr = &tkOptionObjType;
1155    return bestPtr;
1156
1157  error:
1158    if (interp != NULL) {
1159	Tcl_AppendResult(interp, "unknown option \"", name, "\"", NULL);
1160    }
1161    return NULL;
1162}
1163
1164/*
1165 *----------------------------------------------------------------------
1166 *
1167 * TkGetOptionSpec --
1168 *
1169 *	This function searches through a chained option table to find the
1170 *	option spec for a particular option name.
1171 *
1172 * Results:
1173 *	The return value is a pointer to the option spec of the matching
1174 *	entry, or NULL if no matching entry could be found. Note: if the
1175 *	matching entry is a synonym then this function returns a pointer to
1176 *	the option spec of the synonym entry, *not* the "real" entry that the
1177 *	synonym refers to. Note: this call is primarily used by the style
1178 *	management code (tkStyle.c) to look up an element's option spec into a
1179 *	widget's option table.
1180 *
1181 * Side effects:
1182 *	None.
1183 *
1184 *----------------------------------------------------------------------
1185 */
1186
1187CONST Tk_OptionSpec *
1188TkGetOptionSpec(
1189    CONST char *name,		/* String value to be looked up. */
1190    Tk_OptionTable optionTable)	/* Table in which to look up name. */
1191{
1192    Option *optionPtr;
1193
1194    optionPtr = GetOption(name, (OptionTable *) optionTable);
1195    if (optionPtr == NULL) {
1196	return NULL;
1197    }
1198    return optionPtr->specPtr;
1199}
1200
1201/*
1202 *----------------------------------------------------------------------
1203 *
1204 * SetOptionFromAny --
1205 *
1206 *	This function is called to convert a Tcl object to option internal
1207 *	form. However, this doesn't make sense (need to have a table of
1208 *	options in order to do the conversion) so the function always
1209 *	generates an error.
1210 *
1211 * Results:
1212 *	The return value is always TCL_ERROR, and an error message is left in
1213 *	interp's result if interp isn't NULL.
1214 *
1215 * Side effects:
1216 *	None.
1217 *
1218 *----------------------------------------------------------------------
1219 */
1220
1221static int
1222SetOptionFromAny(
1223    Tcl_Interp *interp,		/* Used for error reporting if not NULL. */
1224    register Tcl_Obj *objPtr)	/* The object to convert. */
1225{
1226    Tcl_AppendToObj(Tcl_GetObjResult(interp),
1227	    "can't convert value to option except via GetOptionFromObj API",
1228	    -1);
1229    return TCL_ERROR;
1230}
1231
1232/*
1233 *--------------------------------------------------------------
1234 *
1235 * Tk_SetOptions --
1236 *
1237 *	Process one or more name-value pairs for configuration options and
1238 *	fill in fields of a record with new values.
1239 *
1240 * Results:
1241 *	If all goes well then TCL_OK is returned and the old values of any
1242 *	modified objects are saved in *savePtr, if it isn't NULL (the caller
1243 *	must eventually call Tk_RestoreSavedOptions or Tk_FreeSavedOptions to
1244 *	free the contents of *savePtr). In addition, if maskPtr isn't NULL
1245 *	then *maskPtr is filled in with the OR of the typeMask bits from all
1246 *	modified options. If an error occurs then TCL_ERROR is returned and a
1247 *	message is left in interp's result unless interp is NULL; nothing is
1248 *	saved in *savePtr or *maskPtr in this case.
1249 *
1250 * Side effects:
1251 *	The fields of recordPtr get filled in with object pointers from
1252 *	objc/objv. Old information in widgRec's fields gets recycled.
1253 *	Information may be left at *savePtr.
1254 *
1255 *--------------------------------------------------------------
1256 */
1257
1258int
1259Tk_SetOptions(
1260    Tcl_Interp *interp,		/* Interpreter for error reporting. If NULL,
1261				 * then no error message is returned.*/
1262    char *recordPtr,	    	/* The record to configure. */
1263    Tk_OptionTable optionTable,	/* Describes valid options. */
1264    int objc,			/* The number of elements in objv. */
1265    Tcl_Obj *CONST objv[],	/* Contains one or more name-value pairs. */
1266    Tk_Window tkwin,		/* Window associated with the thing being
1267				 * configured; needed for some options (such
1268				 * as colors). */
1269    Tk_SavedOptions *savePtr,	/* If non-NULL, the old values of modified
1270				 * options are saved here so that they can be
1271				 * restored after an error. */
1272    int *maskPtr)		/* It non-NULL, this word is modified on a
1273				 * successful return to hold the bit-wise OR
1274				 * of the typeMask fields of all options that
1275				 * were modified by this call. Used by the
1276				 * caller to figure out which options actually
1277				 * changed. */
1278{
1279    OptionTable *tablePtr = (OptionTable *) optionTable;
1280    Option *optionPtr;
1281    Tk_SavedOptions *lastSavePtr, *newSavePtr;
1282    int mask;
1283
1284    if (savePtr != NULL) {
1285	savePtr->recordPtr = recordPtr;
1286	savePtr->tkwin = tkwin;
1287	savePtr->numItems = 0;
1288	savePtr->nextPtr = NULL;
1289    }
1290    lastSavePtr = savePtr;
1291
1292    /*
1293     * Scan through all of the arguments, processing those that match entries
1294     * in the option table.
1295     */
1296
1297    mask = 0;
1298    for ( ; objc > 0; objc -= 2, objv += 2) {
1299	optionPtr = GetOptionFromObj(interp, objv[0], tablePtr);
1300	if (optionPtr == NULL) {
1301	    goto error;
1302	}
1303	if (optionPtr->specPtr->type == TK_OPTION_SYNONYM) {
1304	    optionPtr = optionPtr->extra.synonymPtr;
1305	}
1306
1307	if (objc < 2) {
1308	    if (interp != NULL) {
1309		Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
1310			"value for \"", Tcl_GetStringFromObj(*objv, NULL),
1311			"\" missing", NULL);
1312		goto error;
1313	    }
1314	}
1315	if ((savePtr != NULL)
1316		&& (lastSavePtr->numItems >= TK_NUM_SAVED_OPTIONS)) {
1317	    /*
1318	     * We've run out of space for saving old option values. Allocate
1319	     * more space.
1320	     */
1321
1322	    newSavePtr = (Tk_SavedOptions *) ckalloc(sizeof(Tk_SavedOptions));
1323	    newSavePtr->recordPtr = recordPtr;
1324	    newSavePtr->tkwin = tkwin;
1325	    newSavePtr->numItems = 0;
1326	    newSavePtr->nextPtr = NULL;
1327	    lastSavePtr->nextPtr = newSavePtr;
1328	    lastSavePtr = newSavePtr;
1329	}
1330	if (DoObjConfig(interp, recordPtr, optionPtr, objv[1], tkwin,
1331		(savePtr != NULL) ? &lastSavePtr->items[lastSavePtr->numItems]
1332		: NULL) != TCL_OK) {
1333	    char msg[100];
1334
1335	    sprintf(msg, "\n    (processing \"%.40s\" option)",
1336		    Tcl_GetStringFromObj(*objv, NULL));
1337	    Tcl_AddErrorInfo(interp, msg);
1338	    goto error;
1339	}
1340	if (savePtr != NULL) {
1341	    lastSavePtr->numItems++;
1342	}
1343	mask |= optionPtr->specPtr->typeMask;
1344    }
1345    if (maskPtr != NULL) {
1346	*maskPtr = mask;
1347    }
1348    return TCL_OK;
1349
1350  error:
1351    if (savePtr != NULL) {
1352	Tk_RestoreSavedOptions(savePtr);
1353    }
1354    return TCL_ERROR;
1355}
1356
1357/*
1358 *----------------------------------------------------------------------
1359 *
1360 * Tk_RestoreSavedOptions --
1361 *
1362 *	This function undoes the effect of a previous call to Tk_SetOptions by
1363 *	restoring all of the options to their value before the call to
1364 *	Tk_SetOptions.
1365 *
1366 * Results:
1367 *	None.
1368 *
1369 * Side effects:
1370 *	The configutation record is restored and all the information stored in
1371 *	savePtr is freed.
1372 *
1373 *----------------------------------------------------------------------
1374 */
1375
1376void
1377Tk_RestoreSavedOptions(
1378    Tk_SavedOptions *savePtr)	/* Holds saved option information; must have
1379				 * been passed to Tk_SetOptions. */
1380{
1381    int i;
1382    Option *optionPtr;
1383    Tcl_Obj *newPtr;		/* New object value of option, which we
1384				 * replace with old value and free. Taken from
1385				 * record. */
1386    char *internalPtr;		/* Points to internal value of option in
1387				 * record. */
1388    CONST Tk_OptionSpec *specPtr;
1389
1390    /*
1391     * Be sure to restore the options in the opposite order they were set.
1392     * This is important because it's possible that the same option name was
1393     * used twice in a single call to Tk_SetOptions.
1394     */
1395
1396    if (savePtr->nextPtr != NULL) {
1397	Tk_RestoreSavedOptions(savePtr->nextPtr);
1398	ckfree((char *) savePtr->nextPtr);
1399	savePtr->nextPtr = NULL;
1400    }
1401    for (i = savePtr->numItems - 1; i >= 0; i--) {
1402	optionPtr = savePtr->items[i].optionPtr;
1403	specPtr = optionPtr->specPtr;
1404
1405	/*
1406	 * First free the new value of the option, which is currently in the
1407	 * record.
1408	 */
1409
1410	if (specPtr->objOffset >= 0) {
1411	    newPtr = *((Tcl_Obj **) (savePtr->recordPtr + specPtr->objOffset));
1412	} else {
1413	    newPtr = NULL;
1414	}
1415	if (specPtr->internalOffset >= 0) {
1416	    internalPtr = savePtr->recordPtr + specPtr->internalOffset;
1417	} else {
1418	    internalPtr = NULL;
1419	}
1420	if (optionPtr->flags & OPTION_NEEDS_FREEING) {
1421	    FreeResources(optionPtr, newPtr, internalPtr, savePtr->tkwin);
1422	}
1423	if (newPtr != NULL) {
1424	    Tcl_DecrRefCount(newPtr);
1425	}
1426
1427	/*
1428	 * Now restore the old value of the option.
1429	 */
1430
1431	if (specPtr->objOffset >= 0) {
1432	    *((Tcl_Obj **) (savePtr->recordPtr + specPtr->objOffset))
1433		    = savePtr->items[i].valuePtr;
1434	}
1435	if (specPtr->internalOffset >= 0) {
1436	    register char *ptr = (char *) &savePtr->items[i].internalForm;
1437
1438	    switch (specPtr->type) {
1439	    case TK_OPTION_BOOLEAN:
1440		*((int *) internalPtr) = *((int *) ptr);
1441		break;
1442	    case TK_OPTION_INT:
1443		*((int *) internalPtr) = *((int *) ptr);
1444		break;
1445	    case TK_OPTION_DOUBLE:
1446		*((double *) internalPtr) = *((double *) ptr);
1447		break;
1448	    case TK_OPTION_STRING:
1449		*((char **) internalPtr) = *((char **) ptr);
1450		break;
1451	    case TK_OPTION_STRING_TABLE:
1452		*((int *) internalPtr) = *((int *) ptr);
1453		break;
1454	    case TK_OPTION_COLOR:
1455		*((XColor **) internalPtr) = *((XColor **) ptr);
1456		break;
1457	    case TK_OPTION_FONT:
1458		*((Tk_Font *) internalPtr) = *((Tk_Font *) ptr);
1459		break;
1460	    case TK_OPTION_STYLE:
1461		*((Tk_Style *) internalPtr) = *((Tk_Style *) ptr);
1462		break;
1463	    case TK_OPTION_BITMAP:
1464		*((Pixmap *) internalPtr) = *((Pixmap *) ptr);
1465		break;
1466	    case TK_OPTION_BORDER:
1467		*((Tk_3DBorder *) internalPtr) = *((Tk_3DBorder *) ptr);
1468		break;
1469	    case TK_OPTION_RELIEF:
1470		*((int *) internalPtr) = *((int *) ptr);
1471		break;
1472	    case TK_OPTION_CURSOR:
1473		*((Tk_Cursor *) internalPtr) = *((Tk_Cursor *) ptr);
1474		Tk_DefineCursor(savePtr->tkwin, *((Tk_Cursor *) internalPtr));
1475		break;
1476	    case TK_OPTION_JUSTIFY:
1477		*((Tk_Justify *) internalPtr) = *((Tk_Justify *) ptr);
1478		break;
1479	    case TK_OPTION_ANCHOR:
1480		*((Tk_Anchor *) internalPtr) = *((Tk_Anchor *) ptr);
1481		break;
1482	    case TK_OPTION_PIXELS:
1483		*((int *) internalPtr) = *((int *) ptr);
1484		break;
1485	    case TK_OPTION_WINDOW:
1486		*((Tk_Window *) internalPtr) = *((Tk_Window *) ptr);
1487		break;
1488	    case TK_OPTION_CUSTOM: {
1489		Tk_ObjCustomOption *custom = optionPtr->extra.custom;
1490
1491		if (custom->restoreProc != NULL) {
1492		    custom->restoreProc(custom->clientData, savePtr->tkwin,
1493			    internalPtr, ptr);
1494		}
1495		break;
1496	    }
1497	    default:
1498		Tcl_Panic("bad option type in Tk_RestoreSavedOptions");
1499	    }
1500	}
1501    }
1502    savePtr->numItems = 0;
1503}
1504
1505/*
1506 *--------------------------------------------------------------
1507 *
1508 * Tk_FreeSavedOptions --
1509 *
1510 *	Free all of the saved configuration option values from a previous call
1511 *	to Tk_SetOptions.
1512 *
1513 * Results:
1514 *	None.
1515 *
1516 * Side effects:
1517 *	Storage and system resources are freed.
1518 *
1519 *--------------------------------------------------------------
1520 */
1521
1522void
1523Tk_FreeSavedOptions(
1524    Tk_SavedOptions *savePtr)	/* Contains options saved in a previous call
1525				 * to Tk_SetOptions. */
1526{
1527    int count;
1528    Tk_SavedOption *savedOptionPtr;
1529
1530    if (savePtr->nextPtr != NULL) {
1531	Tk_FreeSavedOptions(savePtr->nextPtr);
1532	ckfree((char *) savePtr->nextPtr);
1533    }
1534    for (count = savePtr->numItems,
1535	    savedOptionPtr = &savePtr->items[savePtr->numItems-1];
1536	    count > 0;  count--, savedOptionPtr--) {
1537	if (savedOptionPtr->optionPtr->flags & OPTION_NEEDS_FREEING) {
1538	    FreeResources(savedOptionPtr->optionPtr, savedOptionPtr->valuePtr,
1539		    (char *) &savedOptionPtr->internalForm, savePtr->tkwin);
1540	}
1541	if (savedOptionPtr->valuePtr != NULL) {
1542	    Tcl_DecrRefCount(savedOptionPtr->valuePtr);
1543	}
1544    }
1545}
1546
1547/*
1548 *----------------------------------------------------------------------
1549 *
1550 * Tk_FreeConfigOptions --
1551 *
1552 *	Free all resources associated with configuration options.
1553 *
1554 * Results:
1555 *	None.
1556 *
1557 * Side effects:
1558 *	All of the Tcl_Obj's in recordPtr that are controlled by configuration
1559 *	options in optionTable are freed.
1560 *
1561 *----------------------------------------------------------------------
1562 */
1563
1564	/* ARGSUSED */
1565void
1566Tk_FreeConfigOptions(
1567    char *recordPtr,		/* Record whose fields contain current values
1568				 * for options. */
1569    Tk_OptionTable optionTable,	/* Describes legal options. */
1570    Tk_Window tkwin)		/* Window associated with recordPtr; needed
1571				 * for freeing some options. */
1572{
1573    OptionTable *tablePtr;
1574    Option *optionPtr;
1575    int count;
1576    Tcl_Obj **oldPtrPtr, *oldPtr;
1577    char *oldInternalPtr;
1578    CONST Tk_OptionSpec *specPtr;
1579
1580    for (tablePtr = (OptionTable *) optionTable; tablePtr != NULL;
1581	    tablePtr = tablePtr->nextPtr) {
1582	for (optionPtr = tablePtr->options, count = tablePtr->numOptions;
1583		count > 0; optionPtr++, count--) {
1584	    specPtr = optionPtr->specPtr;
1585	    if (specPtr->type == TK_OPTION_SYNONYM) {
1586		continue;
1587	    }
1588	    if (specPtr->objOffset >= 0) {
1589		oldPtrPtr = (Tcl_Obj **) (recordPtr + specPtr->objOffset);
1590		oldPtr = *oldPtrPtr;
1591		*oldPtrPtr = NULL;
1592	    } else {
1593		oldPtr = NULL;
1594	    }
1595	    if (specPtr->internalOffset >= 0) {
1596		oldInternalPtr = recordPtr + specPtr->internalOffset;
1597	    } else {
1598		oldInternalPtr = NULL;
1599	    }
1600	    if (optionPtr->flags & OPTION_NEEDS_FREEING) {
1601		FreeResources(optionPtr, oldPtr, oldInternalPtr, tkwin);
1602	    }
1603	    if (oldPtr != NULL) {
1604		Tcl_DecrRefCount(oldPtr);
1605	    }
1606	}
1607    }
1608}
1609
1610/*
1611 *----------------------------------------------------------------------
1612 *
1613 * FreeResources --
1614 *
1615 *	Free system resources associated with a configuration option, such as
1616 *	colors or fonts.
1617 *
1618 * Results:
1619 *	None.
1620 *
1621 * Side effects:
1622 *	Any system resources associated with objPtr are released. However,
1623 *	objPtr itself is not freed.
1624 *
1625 *----------------------------------------------------------------------
1626 */
1627
1628static void
1629FreeResources(
1630    Option *optionPtr,		/* Description of the configuration option. */
1631    Tcl_Obj *objPtr,		/* The current value of the option, specified
1632				 * as an object. */
1633    char *internalPtr,		/* A pointer to an internal representation for
1634				 * the option's value, such as an int or
1635				 * (XColor *). Only valid if
1636				 * optionPtr->specPtr->internalOffset >= 0. */
1637    Tk_Window tkwin)		/* The window in which this option is used. */
1638{
1639    int internalFormExists;
1640
1641    /*
1642     * If there exists an internal form for the value, use it to free
1643     * resources (also zero out the internal form). If there is no internal
1644     * form, then use the object form.
1645     */
1646
1647    internalFormExists = optionPtr->specPtr->internalOffset >= 0;
1648    switch (optionPtr->specPtr->type) {
1649    case TK_OPTION_STRING:
1650	if (internalFormExists) {
1651	    if (*((char **) internalPtr) != NULL) {
1652		ckfree(*((char **) internalPtr));
1653		*((char **) internalPtr) = NULL;
1654	    }
1655	}
1656	break;
1657    case TK_OPTION_COLOR:
1658	if (internalFormExists) {
1659	    if (*((XColor **) internalPtr) != NULL) {
1660		Tk_FreeColor(*((XColor **) internalPtr));
1661		*((XColor **) internalPtr) = NULL;
1662	    }
1663	} else if (objPtr != NULL) {
1664	    Tk_FreeColorFromObj(tkwin, objPtr);
1665	}
1666	break;
1667    case TK_OPTION_FONT:
1668	if (internalFormExists) {
1669	    Tk_FreeFont(*((Tk_Font *) internalPtr));
1670	    *((Tk_Font *) internalPtr) = NULL;
1671	} else if (objPtr != NULL) {
1672	    Tk_FreeFontFromObj(tkwin, objPtr);
1673	}
1674	break;
1675    case TK_OPTION_STYLE:
1676	if (internalFormExists) {
1677	    Tk_FreeStyle(*((Tk_Style *) internalPtr));
1678	    *((Tk_Style *) internalPtr) = NULL;
1679	} else if (objPtr != NULL) {
1680	    Tk_FreeStyleFromObj(objPtr);
1681	}
1682	break;
1683    case TK_OPTION_BITMAP:
1684	if (internalFormExists) {
1685	    if (*((Pixmap *) internalPtr) != None) {
1686		Tk_FreeBitmap(Tk_Display(tkwin), *((Pixmap *) internalPtr));
1687		*((Pixmap *) internalPtr) = None;
1688	    }
1689	} else if (objPtr != NULL) {
1690	    Tk_FreeBitmapFromObj(tkwin, objPtr);
1691	}
1692	break;
1693    case TK_OPTION_BORDER:
1694	if (internalFormExists) {
1695	    if (*((Tk_3DBorder *) internalPtr) != NULL) {
1696		Tk_Free3DBorder(*((Tk_3DBorder *) internalPtr));
1697		*((Tk_3DBorder *) internalPtr) = NULL;
1698	    }
1699	} else if (objPtr != NULL) {
1700	    Tk_Free3DBorderFromObj(tkwin, objPtr);
1701	}
1702	break;
1703    case TK_OPTION_CURSOR:
1704	if (internalFormExists) {
1705	    if (*((Tk_Cursor *) internalPtr) != None) {
1706		Tk_FreeCursor(Tk_Display(tkwin), *((Tk_Cursor *) internalPtr));
1707		*((Tk_Cursor *) internalPtr) = None;
1708	    }
1709	} else if (objPtr != NULL) {
1710	    Tk_FreeCursorFromObj(tkwin, objPtr);
1711	}
1712	break;
1713    case TK_OPTION_CUSTOM: {
1714	Tk_ObjCustomOption *custom = optionPtr->extra.custom;
1715	if (internalFormExists && custom->freeProc != NULL) {
1716	    custom->freeProc(custom->clientData, tkwin, internalPtr);
1717	}
1718	break;
1719    }
1720    default:
1721	break;
1722    }
1723}
1724
1725/*
1726 *--------------------------------------------------------------
1727 *
1728 * Tk_GetOptionInfo --
1729 *
1730 *	Returns a list object containing complete information about either a
1731 *	single option or all the configuration options in a table.
1732 *
1733 * Results:
1734
1735 *	This function normally returns a pointer to an object. If namePtr
1736 *	isn't NULL, then the result object is a list with five elements: the
1737 *	option's name, its database name, database class, default value, and
1738 *	current value. If the option is a synonym then the list will contain
1739 *	only two values: the option name and the name of the option it refers
1740 *	to. If namePtr is NULL, then information is returned for every option
1741 *	in the option table: the result will have one sub-list (in the form
1742 *	described above) for each option in the table. If an error occurs
1743 *	(e.g. because namePtr isn't valid) then NULL is returned and an error
1744 *	message will be left in interp's result unless interp is NULL.
1745 *
1746 * Side effects:
1747 *	None.
1748 *
1749 *--------------------------------------------------------------
1750 */
1751
1752Tcl_Obj *
1753Tk_GetOptionInfo(
1754    Tcl_Interp *interp,		/* Interpreter for error reporting. If NULL,
1755				 * then no error message is created. */
1756    char *recordPtr,		/* Record whose fields contain current values
1757				 * for options. */
1758    Tk_OptionTable optionTable,	/* Describes all the legal options. */
1759    Tcl_Obj *namePtr,		/* If non-NULL, the string value selects a
1760				 * single option whose info is to be returned.
1761				 * Otherwise info is returned for all options
1762				 * in optionTable. */
1763    Tk_Window tkwin)		/* Window associated with recordPtr; needed to
1764				 * compute correct default value for some
1765				 * options. */
1766{
1767    Tcl_Obj *resultPtr;
1768    OptionTable *tablePtr = (OptionTable *) optionTable;
1769    Option *optionPtr;
1770    int count;
1771
1772    /*
1773     * If information is only wanted for a single configuration spec, then
1774     * handle that one spec specially.
1775     */
1776
1777    if (namePtr != NULL) {
1778	optionPtr = GetOptionFromObj(interp, namePtr, tablePtr);
1779	if (optionPtr == NULL) {
1780	    return NULL;
1781	}
1782	if (optionPtr->specPtr->type == TK_OPTION_SYNONYM) {
1783	    optionPtr = optionPtr->extra.synonymPtr;
1784	}
1785	return GetConfigList(recordPtr, optionPtr, tkwin);
1786    }
1787
1788    /*
1789     * Loop through all the specs, creating a big list with all their
1790     * information.
1791     */
1792
1793    resultPtr = Tcl_NewListObj(0, NULL);
1794    for (; tablePtr != NULL; tablePtr = tablePtr->nextPtr) {
1795	for (optionPtr = tablePtr->options, count = tablePtr->numOptions;
1796		count > 0; optionPtr++, count--) {
1797	    Tcl_ListObjAppendElement(interp, resultPtr,
1798		    GetConfigList(recordPtr, optionPtr, tkwin));
1799	}
1800    }
1801    return resultPtr;
1802}
1803
1804/*
1805 *--------------------------------------------------------------
1806 *
1807 * GetConfigList --
1808 *
1809 *	Create a valid Tcl list holding the configuration information for a
1810 *	single configuration option.
1811 *
1812 * Results:
1813 *	A Tcl list, dynamically allocated. The caller is expected to arrange
1814 *	for this list to be freed eventually.
1815 *
1816 * Side effects:
1817 *	Memory is allocated.
1818 *
1819 *--------------------------------------------------------------
1820 */
1821
1822static Tcl_Obj *
1823GetConfigList(
1824    char *recordPtr,		/* Pointer to record holding current values of
1825				 * configuration options. */
1826    Option *optionPtr,		/* Pointer to information describing a
1827				 * particular option. */
1828    Tk_Window tkwin)		/* Window corresponding to recordPtr. */
1829{
1830    Tcl_Obj *listPtr, *elementPtr;
1831
1832    listPtr = Tcl_NewListObj(0, NULL);
1833    Tcl_ListObjAppendElement(NULL, listPtr,
1834	    Tcl_NewStringObj(optionPtr->specPtr->optionName, -1));
1835
1836    if (optionPtr->specPtr->type == TK_OPTION_SYNONYM) {
1837	elementPtr = Tcl_NewStringObj(
1838		optionPtr->extra.synonymPtr->specPtr->optionName, -1);
1839	Tcl_ListObjAppendElement(NULL, listPtr, elementPtr);
1840    } else {
1841	if (optionPtr->dbNameUID == NULL) {
1842	    elementPtr = Tcl_NewObj();
1843	} else {
1844	    elementPtr = Tcl_NewStringObj(optionPtr->dbNameUID, -1);
1845	}
1846	Tcl_ListObjAppendElement(NULL, listPtr, elementPtr);
1847
1848	if (optionPtr->dbClassUID == NULL) {
1849	    elementPtr = Tcl_NewObj();
1850	} else {
1851	    elementPtr = Tcl_NewStringObj(optionPtr->dbClassUID, -1);
1852	}
1853	Tcl_ListObjAppendElement(NULL, listPtr, elementPtr);
1854
1855	if ((tkwin != NULL) && ((optionPtr->specPtr->type == TK_OPTION_COLOR)
1856		|| (optionPtr->specPtr->type == TK_OPTION_BORDER))
1857		&& (Tk_Depth(tkwin) <= 1)
1858		&& (optionPtr->extra.monoColorPtr != NULL)) {
1859	    elementPtr = optionPtr->extra.monoColorPtr;
1860	} else if (optionPtr->defaultPtr != NULL) {
1861	    elementPtr = optionPtr->defaultPtr;
1862	} else {
1863	    elementPtr = Tcl_NewObj();
1864	}
1865	Tcl_ListObjAppendElement(NULL, listPtr, elementPtr);
1866
1867	if (optionPtr->specPtr->objOffset >= 0) {
1868	    elementPtr = *((Tcl_Obj **) (recordPtr
1869		    + optionPtr->specPtr->objOffset));
1870	    if (elementPtr == NULL) {
1871		elementPtr = Tcl_NewObj();
1872	    }
1873	} else {
1874	    elementPtr = GetObjectForOption(recordPtr, optionPtr, tkwin);
1875	}
1876	Tcl_ListObjAppendElement(NULL, listPtr, elementPtr);
1877    }
1878    return listPtr;
1879}
1880
1881/*
1882 *----------------------------------------------------------------------
1883 *
1884 * GetObjectForOption --
1885 *
1886 *	This function is called to create an object that contains the value
1887 *	for an option. It is invoked by GetConfigList and Tk_GetOptionValue
1888 *	when only the internal form of an option is stored in the record.
1889 *
1890 * Results:
1891 *	The return value is a pointer to a Tcl object. The caller must call
1892 *	Tcl_IncrRefCount on this object to preserve it.
1893 *
1894 * Side effects:
1895 *	None.
1896 *
1897 *----------------------------------------------------------------------
1898 */
1899
1900static Tcl_Obj *
1901GetObjectForOption(
1902    char *recordPtr,		/* Pointer to record holding current values of
1903				 * configuration options. */
1904    Option *optionPtr,		/* Pointer to information describing an option
1905				 * whose internal value is stored in
1906				 * *recordPtr. */
1907    Tk_Window tkwin)		/* Window corresponding to recordPtr. */
1908{
1909    Tcl_Obj *objPtr;
1910    char *internalPtr;		/* Points to internal value of option in
1911				 * record. */
1912
1913    internalPtr = recordPtr + optionPtr->specPtr->internalOffset;
1914    objPtr = NULL;
1915    switch (optionPtr->specPtr->type) {
1916    case TK_OPTION_BOOLEAN:
1917	objPtr = Tcl_NewIntObj(*((int *) internalPtr));
1918	break;
1919    case TK_OPTION_INT:
1920	objPtr = Tcl_NewIntObj(*((int *) internalPtr));
1921	break;
1922    case TK_OPTION_DOUBLE:
1923	objPtr = Tcl_NewDoubleObj(*((double *) internalPtr));
1924	break;
1925    case TK_OPTION_STRING:
1926	objPtr = Tcl_NewStringObj(*((char **) internalPtr), -1);
1927	break;
1928    case TK_OPTION_STRING_TABLE:
1929	objPtr = Tcl_NewStringObj(((char **) optionPtr->specPtr->clientData)[
1930		*((int *) internalPtr)], -1);
1931	break;
1932    case TK_OPTION_COLOR: {
1933	XColor *colorPtr = *((XColor **) internalPtr);
1934
1935	if (colorPtr != NULL) {
1936	    objPtr = Tcl_NewStringObj(Tk_NameOfColor(colorPtr), -1);
1937	}
1938	break;
1939    }
1940    case TK_OPTION_FONT: {
1941	Tk_Font tkfont = *((Tk_Font *) internalPtr);
1942
1943	if (tkfont != NULL) {
1944	    objPtr = Tcl_NewStringObj(Tk_NameOfFont(tkfont), -1);
1945	}
1946	break;
1947    }
1948    case TK_OPTION_STYLE: {
1949	Tk_Style style = *((Tk_Style *) internalPtr);
1950
1951	if (style != NULL) {
1952	    objPtr = Tcl_NewStringObj(Tk_NameOfStyle(style), -1);
1953	}
1954	break;
1955    }
1956    case TK_OPTION_BITMAP: {
1957	Pixmap pixmap = *((Pixmap *) internalPtr);
1958
1959	if (pixmap != None) {
1960	    objPtr = Tcl_NewStringObj(
1961		    Tk_NameOfBitmap(Tk_Display(tkwin), pixmap), -1);
1962	}
1963	break;
1964    }
1965    case TK_OPTION_BORDER: {
1966	Tk_3DBorder border = *((Tk_3DBorder *) internalPtr);
1967
1968	if (border != NULL) {
1969	    objPtr = Tcl_NewStringObj(Tk_NameOf3DBorder(border), -1);
1970	}
1971	break;
1972    }
1973    case TK_OPTION_RELIEF:
1974	objPtr = Tcl_NewStringObj(Tk_NameOfRelief(*((int *) internalPtr)), -1);
1975	break;
1976    case TK_OPTION_CURSOR: {
1977	Tk_Cursor cursor = *((Tk_Cursor *) internalPtr);
1978
1979	if (cursor != None) {
1980	    objPtr = Tcl_NewStringObj(
1981		    Tk_NameOfCursor(Tk_Display(tkwin), cursor), -1);
1982	}
1983	break;
1984    }
1985    case TK_OPTION_JUSTIFY:
1986	objPtr = Tcl_NewStringObj(Tk_NameOfJustify(
1987		*((Tk_Justify *) internalPtr)), -1);
1988	break;
1989    case TK_OPTION_ANCHOR:
1990	objPtr = Tcl_NewStringObj(Tk_NameOfAnchor(
1991		*((Tk_Anchor *) internalPtr)), -1);
1992	break;
1993    case TK_OPTION_PIXELS:
1994	objPtr = Tcl_NewIntObj(*((int *) internalPtr));
1995	break;
1996    case TK_OPTION_WINDOW: {
1997	Tk_Window tkwin = *((Tk_Window *) internalPtr);
1998
1999	if (tkwin != NULL) {
2000	    objPtr = Tcl_NewStringObj(Tk_PathName(tkwin), -1);
2001	}
2002	break;
2003    }
2004    case TK_OPTION_CUSTOM: {
2005	Tk_ObjCustomOption *custom = optionPtr->extra.custom;
2006
2007	objPtr = custom->getProc(custom->clientData, tkwin, recordPtr,
2008		optionPtr->specPtr->internalOffset);
2009	break;
2010    }
2011    default:
2012	Tcl_Panic("bad option type in GetObjectForOption");
2013    }
2014    if (objPtr == NULL) {
2015	objPtr = Tcl_NewObj();
2016    }
2017    return objPtr;
2018}
2019
2020/*
2021 *----------------------------------------------------------------------
2022 *
2023 * Tk_GetOptionValue --
2024 *
2025 *	This function returns the current value of a configuration option.
2026 *
2027 * Results:
2028 *	The return value is the object holding the current value of the option
2029 *	given by namePtr. If no such option exists, then the return value is
2030 *	NULL and an error message is left in interp's result (if interp isn't
2031 *	NULL).
2032 *
2033 * Side effects:
2034 *	None.
2035 *
2036 *----------------------------------------------------------------------
2037 */
2038
2039Tcl_Obj *
2040Tk_GetOptionValue(
2041    Tcl_Interp *interp,		/* Interpreter for error reporting. If NULL
2042				 * then no messages are provided for
2043				 * errors. */
2044    char *recordPtr,		/* Record whose fields contain current values
2045				 * for options. */
2046    Tk_OptionTable optionTable,	/* Describes legal options. */
2047    Tcl_Obj *namePtr,		/* Gives the command-line name for the option
2048				 * whose value is to be returned. */
2049    Tk_Window tkwin)		/* Window corresponding to recordPtr. */
2050{
2051    OptionTable *tablePtr = (OptionTable *) optionTable;
2052    Option *optionPtr;
2053    Tcl_Obj *resultPtr;
2054
2055    optionPtr = GetOptionFromObj(interp, namePtr, tablePtr);
2056    if (optionPtr == NULL) {
2057	return NULL;
2058    }
2059    if (optionPtr->specPtr->type == TK_OPTION_SYNONYM) {
2060	optionPtr = optionPtr->extra.synonymPtr;
2061    }
2062    if (optionPtr->specPtr->objOffset >= 0) {
2063	resultPtr = *((Tcl_Obj **) (recordPtr+optionPtr->specPtr->objOffset));
2064	if (resultPtr == NULL) {
2065	    /*
2066	     * This option has a null value and is represented by a null
2067	     * object pointer. We can't return the null pointer, since that
2068	     * would indicate an error. Instead, return a new empty object.
2069	     */
2070
2071	    resultPtr = Tcl_NewObj();
2072	}
2073    } else {
2074	resultPtr = GetObjectForOption(recordPtr, optionPtr, tkwin);
2075    }
2076    return resultPtr;
2077}
2078
2079/*
2080 *----------------------------------------------------------------------
2081 *
2082 * TkDebugConfig --
2083 *
2084 *	This is a debugging function that returns information about one of the
2085 *	configuration tables that currently exists for an interpreter.
2086 *
2087 * Results:
2088 *	If the specified table exists in the given interpreter, then a list is
2089 *	returned describing the table and any other tables that it chains to:
2090 *	for each table there will be three list elements giving the reference
2091 *	count for the table, the number of elements in the table, and the
2092 *	command-line name for the first option in the table. If the table
2093 *	doesn't exist in the interpreter then an empty object is returned.
2094 *	The reference count for the returned object is 0.
2095 *
2096 * Side effects:
2097 *	None.
2098 *
2099 *----------------------------------------------------------------------
2100 */
2101
2102Tcl_Obj *
2103TkDebugConfig(
2104    Tcl_Interp *interp,		/* Interpreter in which the table is
2105				 * defined. */
2106    Tk_OptionTable table)	/* Table about which information is to be
2107				 * returned. May not necessarily exist in the
2108				 * interpreter anymore. */
2109{
2110    OptionTable *tablePtr = (OptionTable *) table;
2111    Tcl_HashTable *hashTablePtr;
2112    Tcl_HashEntry *hashEntryPtr;
2113    Tcl_HashSearch search;
2114    Tcl_Obj *objPtr;
2115
2116    objPtr = Tcl_NewObj();
2117    hashTablePtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, OPTION_HASH_KEY,
2118	    NULL);
2119    if (hashTablePtr == NULL) {
2120	return objPtr;
2121    }
2122
2123    /*
2124     * Scan all the tables for this interpreter to make sure that the one we
2125     * want still is valid.
2126     */
2127
2128    for (hashEntryPtr = Tcl_FirstHashEntry(hashTablePtr, &search);
2129	    hashEntryPtr != NULL;
2130	    hashEntryPtr = Tcl_NextHashEntry(&search)) {
2131	if (tablePtr == (OptionTable *) Tcl_GetHashValue(hashEntryPtr)) {
2132	    for ( ; tablePtr != NULL; tablePtr = tablePtr->nextPtr) {
2133		Tcl_ListObjAppendElement(NULL, objPtr,
2134			Tcl_NewIntObj(tablePtr->refCount));
2135		Tcl_ListObjAppendElement(NULL, objPtr,
2136			Tcl_NewIntObj(tablePtr->numOptions));
2137		Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewStringObj(
2138			tablePtr->options[0].specPtr->optionName, -1));
2139	    }
2140	    break;
2141	}
2142    }
2143    return objPtr;
2144}
2145
2146/*
2147 * Local Variables:
2148 * mode: c
2149 * c-basic-offset: 4
2150 * fill-column: 78
2151 * End:
2152 */
2153