tkConfig.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:63k
源码类别:

通讯编程

开发平台:

Visual C++

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