home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / tcl / tk3.3b1 / tkOption.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-16  |  37.1 KB  |  1,342 lines

  1. /* 
  2.  * tkOption.c --
  3.  *
  4.  *    This module contains procedures to manage the option
  5.  *    database, which allows various strings to be associated
  6.  *    with windows either by name or by class or both.
  7.  *
  8.  * Copyright (c) 1990-1993 The Regents of the University of California.
  9.  * All rights reserved.
  10.  *
  11.  * Permission is hereby granted, without written agreement and without
  12.  * license or royalty fees, to use, copy, modify, and distribute this
  13.  * software and its documentation for any purpose, provided that the
  14.  * above copyright notice and the following two paragraphs appear in
  15.  * all copies of this software.
  16.  * 
  17.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  18.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  19.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  20.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  21.  *
  22.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  23.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  24.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  25.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  26.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  27.  */
  28.  
  29. #ifndef lint
  30. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkOption.c,v 1.27 93/06/16 17:15:05 ouster Exp $ SPRITE (Berkeley)";
  31. #endif
  32.  
  33. #include "tkConfig.h"
  34. #include "tkInt.h"
  35.  
  36. /*
  37.  * The option database is stored as one tree for each main window.
  38.  * Each name or class field in an option is associated with a node or
  39.  * leaf of the tree.  For example, the options "x.y.z" and "x.y*a"
  40.  * each correspond to three nodes in the tree;  they share the nodes
  41.  * "x" and "x.y", but have different leaf nodes.  One of the following
  42.  * structures exists for each node or leaf in the option tree.  It is
  43.  * actually stored as part of the parent node, and describes a particular
  44.  * child of the parent.
  45.  */
  46.  
  47. typedef struct Element {
  48.     Tk_Uid nameUid;            /* Name or class from one element of
  49.                      * an option spec. */
  50.     union {
  51.     struct ElArray *arrayPtr;    /* If this is an intermediate node,
  52.                      * a pointer to a structure describing
  53.                      * the remaining elements of all
  54.                      * options whose prefixes are the
  55.                      * same up through this element. */
  56.     Tk_Uid valueUid;        /* For leaf nodes, this is the string
  57.                      * value of the option. */
  58.     } child;
  59.     int priority;            /* Used to select among matching
  60.                      * options.  Includes both the
  61.                      * priority level and a serial #.
  62.                      * Greater value means higher
  63.                      * priority.  Irrelevant except in
  64.                      * leaf nodes. */
  65.     int flags;                /* OR-ed combination of bits.  See
  66.                      * below for values. */
  67. } Element;
  68.  
  69. /*
  70.  * Flags in NodeElement structures:
  71.  *
  72.  * CLASS -        Non-zero means this element refers to a class,
  73.  *            Zero means this element refers to a name.
  74.  * NODE -        Zero means this is a leaf element (the child
  75.  *            field is a value, not a pointer to another node).
  76.  *            One means this is a node element.
  77.  * WILDCARD -        Non-zero means this there was a star in the
  78.  *            original specification just before this element.
  79.  *            Zero means there was a dot.
  80.  */
  81.  
  82. #define TYPE_MASK        0x7
  83.  
  84. #define CLASS            0x1
  85. #define NODE            0x2
  86. #define WILDCARD        0x4
  87.  
  88. #define EXACT_LEAF_NAME        0x0
  89. #define EXACT_LEAF_CLASS    0x1
  90. #define EXACT_NODE_NAME        0x2
  91. #define EXACT_NODE_CLASS    0x3
  92. #define WILDCARD_LEAF_NAME    0x4
  93. #define WILDCARD_LEAF_CLASS    0x5
  94. #define WILDCARD_NODE_NAME    0x6
  95. #define WILDCARD_NODE_CLASS    0x7
  96.  
  97. /*
  98.  * The following structure is used to manage a dynamic array of
  99.  * Elements.  These structures are used for two purposes:  to store
  100.  * the contents of a node in the option tree, and for the option
  101.  * stacks described below.
  102.  */
  103.  
  104. typedef struct ElArray {
  105.     int arraySize;        /* Number of elements actually
  106.                  * allocated in the "els" array. */
  107.     int numUsed;        /* Number of elements currently in
  108.                  * use out of els. */
  109.     Element *nextToUse;        /* Pointer to &els[numUsed]. */
  110.     Element els[1];        /* Array of structures describing
  111.                  * children of this node.  The
  112.                  * array will actually contain enough
  113.                  * elements for all of the children
  114.                  * (and even a few extras, perhaps).
  115.                  * This must be the last field in
  116.                  * the structure. */
  117. } ElArray;
  118.  
  119. #define EL_ARRAY_SIZE(numEls) ((unsigned) (sizeof(ElArray) \
  120.     + ((numEls)-1)*sizeof(Element)))
  121. #define INITIAL_SIZE 5
  122.  
  123. /*
  124.  * In addition to the option tree, which is a relatively static structure,
  125.  * there are eight additional structures called "stacks", which are used
  126.  * to speed up queries into the option database.  The stack structures
  127.  * are designed for the situation where an individual widget makes repeated
  128.  * requests for its particular options.  The requests differ only in
  129.  * their last name/class, so during the first request we extract all
  130.  * the options pertaining to the particular widget and save them in a
  131.  * stack-like cache;  subsequent requests for the same widget can search
  132.  * the cache relatively quickly.  In fact, the cache is a hierarchical
  133.  * one, storing a list of relevant options for this widget and all of
  134.  * its ancestors up to the application root;  hence the name "stack".
  135.  *
  136.  * Each of the eight stacks consists of an array of Elements, ordered in
  137.  * terms of levels in the window hierarchy.  All the elements relevant
  138.  * for the top-level widget appear first in the array, followed by all
  139.  * those from the next-level widget on the path to the current widget,
  140.  * etc. down to those for the current widget.
  141.  *
  142.  * Cached information is divided into eight stacks according to the
  143.  * CLASS, NODE, and WILDCARD flags.  Leaf and non-leaf information is
  144.  * kept separate to speed up individual probes (non-leaf information is
  145.  * only relevant when building the stacks, but isn't relevant when
  146.  * making probes;  similarly, only non-leaf information is relevant
  147.  * when the stacks are being extended to the next widget down in the
  148.  * widget hierarchy).  Wildcard elements are handled separately from
  149.  * "exact" elements because once they appear at a particular level in
  150.  * the stack they remain active for all deeper levels;  exact elements
  151.  * are only relevant at a particular level.  For example, when searching
  152.  * for options relevant in a particular window, the entire wildcard
  153.  * stacks get checked, but only the portions of the exact stacks that
  154.  * pertain to the window's parent.  Lastly, name and class stacks are
  155.  * kept separate because different search keys are used when searching
  156.  * them;  keeping them separate speeds up the searches.
  157.  */
  158.  
  159. #define NUM_STACKS 8
  160. static ElArray *stacks[NUM_STACKS];
  161. static TkWindow *cachedWindow = NULL;    /* Lowest-level window currently
  162.                      * loaded in stacks at present. 
  163.                      * NULL means stacks have never
  164.                      * been used, or have been
  165.                      * invalidated because of a change
  166.                      * to the database. */
  167.  
  168. /*
  169.  * One of the following structures is used to keep track of each
  170.  * level in the stacks.
  171.  */
  172.  
  173. typedef struct StackLevel {
  174.     TkWindow *winPtr;        /* Window corresponding to this stack
  175.                  * level. */
  176.     int bases[NUM_STACKS];    /* For each stack, index of first
  177.                  * element on stack corresponding to
  178.                  * this level (used to restore "numUsed"
  179.                  * fields when popping out of a level. */
  180. } StackLevel;
  181.  
  182. /*
  183.  * Information about all of the stack levels that are currently
  184.  * active.  This array grows dynamically to become as large as needed.
  185.  */
  186.  
  187. static StackLevel *levels = NULL;
  188.                 /* Array describing current stack. */
  189. static int numLevels = 0;    /* Total space allocated. */
  190. static int curLevel = 0;    /* Highest level currently in use. */
  191.  
  192. /*
  193.  * The variable below is a serial number for all options entered into
  194.  * the database so far.  It increments on each addition to the option
  195.  * database.  It is used in computing option priorities, so that the
  196.  * most recent entry wins when choosing between options at the same
  197.  * priority level.
  198.  */
  199.  
  200. static int serial = 0;
  201.  
  202. /*
  203.  * Special "no match" Element to use as default for searches.
  204.  */
  205.  
  206. static Element defaultMatch;
  207.  
  208. /*
  209.  * Forward declarations for procedures defined in this file:
  210.  */
  211.  
  212. static int        AddFromString _ANSI_ARGS_((Tcl_Interp *interp,
  213.                 Tk_Window tkwin, char *string, int priority));
  214. static void        ClearOptionTree _ANSI_ARGS_((ElArray *arrayPtr));
  215. static ElArray *    ExtendArray _ANSI_ARGS_((ElArray *arrayPtr,
  216.                 Element *elPtr));
  217. static void        ExtendStacks _ANSI_ARGS_((ElArray *arrayPtr,
  218.                 int leaf));
  219. static int        GetDefaultOptions _ANSI_ARGS_((Tcl_Interp *interp,
  220.                 TkWindow *winPtr));    
  221. static ElArray *    NewArray _ANSI_ARGS_((int numEls));    
  222. static void        OptionInit _ANSI_ARGS_((TkMainInfo *mainPtr));
  223. static int        ParsePriority _ANSI_ARGS_((Tcl_Interp *interp,
  224.                 char *string));
  225. static int        ReadOptionFile _ANSI_ARGS_((Tcl_Interp *interp,
  226.                 Tk_Window tkwin, char *fileName, int priority));
  227. static void        SetupStacks _ANSI_ARGS_((TkWindow *winPtr, int leaf));
  228.  
  229. /*
  230.  *--------------------------------------------------------------
  231.  *
  232.  * Tk_AddOption --
  233.  *
  234.  *    Add a new option to the option database.
  235.  *
  236.  * Results:
  237.  *    None.
  238.  *
  239.  * Side effects:
  240.  *    Information is added to the option database.
  241.  *
  242.  *--------------------------------------------------------------
  243.  */
  244.  
  245. void
  246. Tk_AddOption(tkwin, name, value, priority)
  247.     Tk_Window tkwin;        /* Window token;  option will be associated
  248.                  * with main window for this window. */
  249.     char *name;            /* Multi-element name of option. */
  250.     char *value;        /* String value for option. */
  251.     int priority;        /* Overall priority level to use for
  252.                  * this option, such as TK_USER_DEFAULT_PRIO
  253.                  * or TK_INTERACTIVE_PRIO.  Must be between
  254.                  * 0 and TK_MAX_PRIO. */
  255. {
  256.     TkWindow *winPtr = ((TkWindow *) tkwin)->mainPtr->winPtr;
  257.     register ElArray **arrayPtrPtr;
  258.     register Element *elPtr;
  259.     Element newEl;
  260.     register char *p;
  261.     char *field;
  262.     int count, firstField, length;
  263. #define TMP_SIZE 100
  264.     char tmp[TMP_SIZE+1];
  265.  
  266.     if (winPtr->mainPtr->optionRootPtr == NULL) {
  267.     OptionInit(winPtr->mainPtr);
  268.     }
  269.     cachedWindow = NULL;    /* Invalidate the cache. */
  270.  
  271.     /*
  272.      * Compute the priority for the new element, including both the
  273.      * overall level and the serial number (to disambiguate with the
  274.      * level).
  275.      */
  276.  
  277.     if (priority < 0) {
  278.     priority = 0;
  279.     } else if (priority > TK_MAX_PRIO) {
  280.     priority = TK_MAX_PRIO;
  281.     }
  282.     newEl.priority = (priority << 24) + serial;
  283.     serial++;
  284.  
  285.     /*
  286.      * Parse the option one field at a time.
  287.      */
  288.  
  289.     arrayPtrPtr = &(((TkWindow *) tkwin)->mainPtr->optionRootPtr);
  290.     p = name;
  291.     for (firstField = 1; ; firstField = 0) {
  292.  
  293.     /*
  294.      * Scan the next field from the name and convert it to a Tk_Uid.
  295.      * Must copy the field before calling Tk_Uid, so that a terminating
  296.      * NULL may be added without modifying the source string.
  297.      */
  298.  
  299.     if (*p == '*') {
  300.         newEl.flags = WILDCARD;
  301.         p++;
  302.     } else {
  303.         newEl.flags = 0;
  304.     }
  305.     field = p;
  306.     while ((*p != 0) && (*p != '.') && (*p != '*')) {
  307.         p++;
  308.     }
  309.     length = p - field;
  310.     if (length > TMP_SIZE) {
  311.         length = TMP_SIZE;
  312.     }
  313.     strncpy(tmp, field, length);
  314.     tmp[length] = 0;
  315.     newEl.nameUid = Tk_GetUid(tmp);
  316.     if (isupper(*field)) {
  317.         newEl.flags |= CLASS;
  318.     }
  319.  
  320.     if (*p != 0) {
  321.  
  322.         /*
  323.          * New element will be a node.  If this option can't possibly
  324.          * apply to this main window, then just skip it.  Otherwise,
  325.          * add it to the parent, if it isn't already there, and descend
  326.          * into it.
  327.          */
  328.  
  329.         newEl.flags |= NODE;
  330.         if (firstField && !(newEl.flags & WILDCARD)
  331.             && (newEl.nameUid != winPtr->nameUid)
  332.             && (newEl.nameUid != winPtr->classUid)) {
  333.         return;
  334.         }
  335.         for (elPtr = (*arrayPtrPtr)->els, count = (*arrayPtrPtr)->numUsed;
  336.             ; elPtr++, count--) {
  337.         if (count == 0) {
  338.             newEl.child.arrayPtr = NewArray(5);
  339.             *arrayPtrPtr = ExtendArray(*arrayPtrPtr, &newEl);
  340.             arrayPtrPtr = &((*arrayPtrPtr)->nextToUse[-1].child.arrayPtr);
  341.             break;
  342.         }
  343.         if ((elPtr->nameUid == newEl.nameUid)
  344.             && (elPtr->flags == newEl.flags)) {
  345.             arrayPtrPtr = &(elPtr->child.arrayPtr);
  346.             break;
  347.         }
  348.         }
  349.         if (*p == '.') {
  350.         p++;
  351.         }
  352.     } else {
  353.  
  354.         /*
  355.          * New element is a leaf.  Add it to the parent, if it isn't
  356.          * already there.  If it exists already, keep whichever value
  357.          * has highest priority.
  358.          */
  359.  
  360.         newEl.child.valueUid = Tk_GetUid(value);
  361.         for (elPtr = (*arrayPtrPtr)->els, count = (*arrayPtrPtr)->numUsed;
  362.             ; elPtr++, count--) {
  363.         if (count == 0) {
  364.             *arrayPtrPtr = ExtendArray(*arrayPtrPtr, &newEl);
  365.             return;
  366.         }
  367.         if ((elPtr->nameUid == newEl.nameUid)
  368.             && (elPtr->flags == newEl.flags)) {
  369.             if (elPtr->priority < newEl.priority) {
  370.             elPtr->priority = newEl.priority;
  371.             elPtr->child.valueUid = newEl.child.valueUid;
  372.             }
  373.             return;
  374.         }
  375.         }
  376.     }
  377.     }
  378. }
  379.  
  380. /*
  381.  *--------------------------------------------------------------
  382.  *
  383.  * Tk_GetOption --
  384.  *
  385.  *    Retrieve an option from the option database.
  386.  *
  387.  * Results:
  388.  *    The return value is the value specified in the option
  389.  *    database for the given name and class on the given
  390.  *    window.  If there is nothing specified in the database
  391.  *    for that option, then NULL is returned.
  392.  *
  393.  * Side effects:
  394.  *    The internal caches used to speed up option mapping
  395.  *    may be modified, if this tkwin is different from the
  396.  *    last tkwin used for option retrieval.
  397.  *
  398.  *--------------------------------------------------------------
  399.  */
  400.  
  401. Tk_Uid
  402. Tk_GetOption(tkwin, name, className)
  403.     Tk_Window tkwin;        /* Token for window that option is
  404.                  * associated with. */
  405.     char *name;            /* Name of option. */
  406.     char *className;        /* Class of option.  NULL means there
  407.                  * is no class for this option:  just
  408.                  * check for name. */
  409. {
  410.     Tk_Uid nameId, classId;
  411.     register Element *elPtr, *bestPtr;
  412.     register int count;
  413.  
  414.     /*
  415.      * Note:  no need to call OptionInit here:  it will be done by
  416.      * the SetupStacks call below (squeeze out those nanoseconds).
  417.      */
  418.  
  419.     if (tkwin != (Tk_Window) cachedWindow) {
  420.     SetupStacks((TkWindow *) tkwin, 1);
  421.     }
  422.  
  423.     nameId = Tk_GetUid(name);
  424.     bestPtr = &defaultMatch;
  425.     for (elPtr = stacks[EXACT_LEAF_NAME]->els,
  426.         count = stacks[EXACT_LEAF_NAME]->numUsed; count > 0;
  427.         elPtr++, count--) {
  428.     if ((elPtr->nameUid == nameId)
  429.         && (elPtr->priority > bestPtr->priority)) {
  430.         bestPtr = elPtr;
  431.     }
  432.     }
  433.     for (elPtr = stacks[WILDCARD_LEAF_NAME]->els,
  434.         count = stacks[WILDCARD_LEAF_NAME]->numUsed; count > 0;
  435.         elPtr++, count--) {
  436.     if ((elPtr->nameUid == nameId)
  437.         && (elPtr->priority > bestPtr->priority)) {
  438.         bestPtr = elPtr;
  439.     }
  440.     }
  441.     if (className != NULL) {
  442.     classId = Tk_GetUid(className);
  443.     for (elPtr = stacks[EXACT_LEAF_CLASS]->els,
  444.         count = stacks[EXACT_LEAF_CLASS]->numUsed; count > 0;
  445.         elPtr++, count--) {
  446.         if ((elPtr->nameUid == classId)
  447.             && (elPtr->priority > bestPtr->priority)) {
  448.         bestPtr = elPtr;
  449.         }
  450.     }
  451.     for (elPtr = stacks[WILDCARD_LEAF_CLASS]->els,
  452.         count = stacks[WILDCARD_LEAF_CLASS]->numUsed; count > 0;
  453.         elPtr++, count--) {
  454.         if ((elPtr->nameUid == classId)
  455.             && (elPtr->priority > bestPtr->priority)) {
  456.         bestPtr = elPtr;
  457.         }
  458.     }
  459.     }
  460.     return bestPtr->child.valueUid;
  461. }
  462.  
  463. /*
  464.  *--------------------------------------------------------------
  465.  *
  466.  * Tk_OptionCmd --
  467.  *
  468.  *    This procedure is invoked to process the "option" Tcl command.
  469.  *    See the user documentation for details on what it does.
  470.  *
  471.  * Results:
  472.  *    A standard Tcl result.
  473.  *
  474.  * Side effects:
  475.  *    See the user documentation.
  476.  *
  477.  *--------------------------------------------------------------
  478.  */
  479.  
  480. int
  481. Tk_OptionCmd(clientData, interp, argc, argv)
  482.     ClientData clientData;    /* Main window associated with
  483.                  * interpreter. */
  484.     Tcl_Interp *interp;        /* Current interpreter. */
  485.     int argc;            /* Number of arguments. */
  486.     char **argv;        /* Argument strings. */
  487. {
  488.     Tk_Window tkwin = (Tk_Window) clientData;
  489.     int length;
  490.     char c;
  491.  
  492.     if (argc < 2) {
  493.     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
  494.         " cmd arg ?arg ...?\"", (char *) NULL);
  495.     return TCL_ERROR;
  496.     }
  497.     c = argv[1][0];
  498.     length = strlen(argv[1]);
  499.     if ((c == 'a') && (strncmp(argv[1], "add", length) == 0)) {
  500.     int priority;
  501.  
  502.     if ((argc != 4) && (argc != 5)) {
  503.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  504.             argv[0], " add pattern value ?priority?\"", (char *) NULL);
  505.         return TCL_ERROR;
  506.     }
  507.     if (argc == 4) {
  508.         priority = TK_INTERACTIVE_PRIO;
  509.     } else {
  510.         priority = ParsePriority(interp, argv[4]);
  511.         if (priority < 0) {
  512.         return TCL_ERROR;
  513.         }
  514.     }
  515.     Tk_AddOption(tkwin, argv[2], argv[3], priority);
  516.     return TCL_OK;
  517.     } else if ((c == 'c') && (strncmp(argv[1], "clear", length) == 0)) {
  518.     TkMainInfo *mainPtr;
  519.  
  520.     if (argc != 2) {
  521.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  522.             argv[0], " clear\"", (char *) NULL);
  523.         return TCL_ERROR;
  524.     }
  525.     mainPtr = ((TkWindow *) tkwin)->mainPtr;
  526.     if (mainPtr->optionRootPtr != NULL) {
  527.         ClearOptionTree(mainPtr->optionRootPtr);
  528.         mainPtr->optionRootPtr = NULL;
  529.     }
  530.     cachedWindow = NULL;
  531.     return TCL_OK;
  532.     } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) {
  533.     Tk_Window window;
  534.     Tk_Uid value;
  535.  
  536.     if (argc != 5) {
  537.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  538.             argv[0], " get window name class\"", (char *) NULL);
  539.         return TCL_ERROR;
  540.     }
  541.     window = Tk_NameToWindow(interp, argv[2], tkwin);
  542.     if (window == NULL) {
  543.         return TCL_ERROR;
  544.     }
  545.     value = Tk_GetOption(window, argv[3], argv[4]);
  546.     if (value != NULL) {
  547.         interp->result = value;
  548.     }
  549.     return TCL_OK;
  550.     } else if ((c == 'r') && (strncmp(argv[1], "readfile", length) == 0)) {
  551.     int priority;
  552.  
  553.     if ((argc != 3) && (argc != 4)) {
  554.         Tcl_AppendResult(interp, "wrong # args:  should be \"",
  555.             argv[0], " readfile fileName ?priority?\"",
  556.             (char *) NULL);
  557.         return TCL_ERROR;
  558.     }
  559.     if (argc == 4) {
  560.         priority = ParsePriority(interp, argv[3]);
  561.         if (priority < 0) {
  562.         return TCL_ERROR;
  563.         }
  564.     } else {
  565.         priority = TK_INTERACTIVE_PRIO;
  566.     }
  567.     return ReadOptionFile(interp, tkwin, argv[2], priority);
  568.     } else {
  569.     Tcl_AppendResult(interp, "bad option \"", argv[1],
  570.         "\": must be add, clear, get, or readfile", (char *) NULL);
  571.     return TCL_ERROR;
  572.     }
  573. }
  574.  
  575. /*
  576.  *--------------------------------------------------------------
  577.  *
  578.  * TkOptionDeadWindow --
  579.  *
  580.  *    This procedure is called whenever a window is deleted.
  581.  *    It cleans up any option-related stuff associated with
  582.  *    the window.
  583.  *
  584.  * Results:
  585.  *    None.
  586.  *
  587.  * Side effects:
  588.  *    Option-related resources are freed.  See code below
  589.  *    for details.
  590.  *
  591.  *--------------------------------------------------------------
  592.  */
  593.  
  594. void
  595. TkOptionDeadWindow(winPtr)
  596.     register TkWindow *winPtr;        /* Window to be cleaned up. */
  597. {
  598.     /*
  599.      * If this window is in the option stacks, then clear the stacks.
  600.      */
  601.  
  602.     if (winPtr->optionLevel != -1) {
  603.     int i;
  604.  
  605.     for (i = 1; i <= curLevel; i++) {
  606.         levels[curLevel].winPtr->optionLevel = -1;
  607.     }
  608.     curLevel = 0;
  609.     cachedWindow = NULL;
  610.     }
  611.  
  612.     /*
  613.      * If this window was a main window, then delete its option
  614.      * database.
  615.      */
  616.  
  617.     if ((winPtr->mainPtr->winPtr == winPtr)
  618.         && (winPtr->mainPtr->optionRootPtr != NULL)) {
  619.     ClearOptionTree(winPtr->mainPtr->optionRootPtr);
  620.     winPtr->mainPtr->optionRootPtr = NULL;
  621.     }
  622. }
  623.  
  624. /*
  625.  *----------------------------------------------------------------------
  626.  *
  627.  * ParsePriority --
  628.  *
  629.  *    Parse a string priority value.
  630.  *
  631.  * Results:
  632.  *    The return value is the integer priority level corresponding
  633.  *    to string, or -1 if string doesn't point to a valid priority level.
  634.  *    In this case, an error message is left in interp->result.
  635.  *
  636.  * Side effects:
  637.  *    None.
  638.  *
  639.  *----------------------------------------------------------------------
  640.  */
  641.  
  642. static int
  643. ParsePriority(interp, string)
  644.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  645.     char *string;        /* Describes a priority level, either
  646.                  * symbolically or numerically. */
  647. {
  648.     char c;
  649.     int length, priority;
  650.  
  651.     c = string[0];
  652.     length = strlen(string);
  653.     if ((c == 'w')
  654.         && (strncmp(string, "widgetDefault", length) == 0)) {
  655.     return TK_WIDGET_DEFAULT_PRIO;
  656.     } else if ((c == 's')
  657.         && (strncmp(string, "startupFile", length) == 0)) {
  658.     return TK_STARTUP_FILE_PRIO;
  659.     } else if ((c == 'u')
  660.         && (strncmp(string, "userDefault", length) == 0)) {
  661.     return TK_USER_DEFAULT_PRIO;
  662.     } else if ((c == 'i')
  663.         && (strncmp(string, "interactive", length) == 0)) {
  664.     return TK_INTERACTIVE_PRIO;
  665.     } else {
  666.     char *end;
  667.  
  668.     priority = strtoul(string, &end, 0);
  669.     if ((end == string) || (*end != 0) || (priority < 0)
  670.         || (priority > 100)) {
  671.         Tcl_AppendResult(interp,  "bad priority level \"", string,
  672.             "\": must be widgetDefault, startupFile, userDefault, ",
  673.             "interactive, or a number between 0 and 100",
  674.             (char *) NULL);
  675.         return -1;
  676.     }
  677.     }
  678.     return priority;
  679. }
  680.  
  681. /*
  682.  *----------------------------------------------------------------------
  683.  *
  684.  * AddFromString --
  685.  *
  686.  *    Given a string containing lines in the standard format for
  687.  *    X resources (see other documentation for details on what this
  688.  *    is), parse the resource specifications and enter them as options
  689.  *    for tkwin's main window.
  690.  *
  691.  * Results:
  692.  *    The return value is a standard Tcl return code.  In the case of
  693.  *    an error in parsing string, TCL_ERROR will be returned and an
  694.  *    error message will be left in interp->result.  The memory at
  695.  *    string is totally trashed by this procedure.  If you care about
  696.  *    its contents, make a copy before calling here.
  697.  *
  698.  * Side effects:
  699.  *    None.
  700.  *
  701.  *----------------------------------------------------------------------
  702.  */
  703.  
  704. static int
  705. AddFromString(interp, tkwin, string, priority)
  706.     Tcl_Interp *interp;        /* Interpreter to use for reporting results. */
  707.     Tk_Window tkwin;        /* Token for window:  options are entered
  708.                  * for this window's main window. */
  709.     char *string;        /* String containing option specifiers. */
  710.     int priority;        /* Priority level to use for options in
  711.                  * this string, such as TK_USER_DEFAULT_PRIO
  712.                  * or TK_INTERACTIVE_PRIO.  Must be between
  713.                  * 0 and TK_MAX_PRIO. */
  714. {
  715.     register char *src, *dst;
  716.     char *name, *value;
  717.     int lineNum;
  718.  
  719.     src = string;
  720.     lineNum = 1;
  721.     while (1) {
  722.  
  723.     /*
  724.      * Skip leading white space and empty lines and comment lines, and
  725.      * check for the end of the spec.
  726.      */
  727.  
  728.     while ((*src == ' ') || (*src == '\t')) {
  729.         src++;
  730.     }
  731.     if ((*src == '#') || (*src == '!')) {
  732.         do {
  733.         src++;
  734.         if ((src[0] == '\\') && (src[1] == '\n')) {
  735.             src += 2;
  736.             lineNum++;
  737.         }
  738.         } while ((*src != '\n') && (*src != 0));
  739.     }
  740.     if (*src == '\n') {
  741.         src++;
  742.         lineNum++;
  743.         continue;
  744.     } 
  745.     if (*src == '\0') {
  746.         break;
  747.     }
  748.  
  749.     /*
  750.      * Parse off the option name, collapsing out backslash-newline
  751.      * sequences of course.
  752.      */
  753.  
  754.     dst = name = src;
  755.     while (*src != ':') {
  756.         if ((*src == '\0') || (*src == '\n')) {
  757.         sprintf(interp->result, "missing colon on line %d",
  758.             lineNum);
  759.         return TCL_ERROR;
  760.         }
  761.         if ((src[0] == '\\') && (src[1] == '\n')) {
  762.         src += 2;
  763.         lineNum++;
  764.         } else {
  765.         *dst = *src;
  766.         dst++;
  767.         src++;
  768.         }
  769.     }
  770.  
  771.     /*
  772.      * Eliminate trailing white space on the name, and null-terminate
  773.      * it.
  774.      */
  775.  
  776.     while ((dst != name) && ((dst[-1] == ' ') || (dst[-1] == '\t'))) {
  777.         dst--;
  778.     }
  779.     *dst = '\0';
  780.  
  781.     /*
  782.      * Skip white space between the name and the value.
  783.      */
  784.  
  785.     src++;
  786.     while ((*src == ' ') || (*src == '\t')) {
  787.         src++;
  788.     }
  789.     if (*src == '\0') {
  790.         sprintf(interp->result, "missing value on line %d", lineNum);
  791.         return TCL_ERROR;
  792.     }
  793.  
  794.     /*
  795.      * Parse off the value, squeezing out backslash-newline sequences
  796.      * along the way.
  797.      */
  798.  
  799.     dst = value = src;
  800.     while (*src != '\n') {
  801.         if (*src == '\0') {
  802.         sprintf(interp->result, "missing newline on line %d",
  803.             lineNum);
  804.         return TCL_ERROR;
  805.         }
  806.         if ((src[0] == '\\') && (src[1] == '\n')) {
  807.         src += 2;
  808.         lineNum++;
  809.         } else {
  810.         *dst = *src;
  811.         dst++;
  812.         src++;
  813.         }
  814.     }
  815.     *dst = 0;
  816.  
  817.     /*
  818.      * Enter the option into the database.
  819.      */
  820.  
  821.     Tk_AddOption(tkwin, name, value, priority);
  822.     src++;
  823.     lineNum++;
  824.     }
  825.     return TCL_OK;
  826. }
  827.  
  828. /*
  829.  *----------------------------------------------------------------------
  830.  *
  831.  * ReadOptionFile --
  832.  *
  833.  *     Read a file of options ("resources" in the old X terminology)
  834.  *    and load them into the option database.
  835.  *
  836.  * Results:
  837.  *    The return value is a standard Tcl return code.  In the case of
  838.  *    an error in parsing string, TCL_ERROR will be returned and an
  839.  *    error message will be left in interp->result.
  840.  *
  841.  * Side effects:
  842.  *    None.
  843.  *
  844.  *----------------------------------------------------------------------
  845.  */
  846.  
  847. static int
  848. ReadOptionFile(interp, tkwin, fileName, priority)
  849.     Tcl_Interp *interp;        /* Interpreter to use for reporting results. */
  850.     Tk_Window tkwin;        /* Token for window:  options are entered
  851.                  * for this window's main window. */
  852.     char *fileName;        /* Name of file containing options. */
  853.     int priority;        /* Priority level to use for options in
  854.                  * this file, such as TK_USER_DEFAULT_PRIO
  855.                  * or TK_INTERACTIVE_PRIO.  Must be between
  856.                  * 0 and TK_MAX_PRIO. */
  857. {
  858.     char *realName, *buffer;
  859.     int fileId, result;
  860.     struct stat statBuf;
  861.     Tcl_DString newName;
  862.  
  863.     realName = Tcl_TildeSubst(interp, fileName, &newName);
  864.     if (realName == NULL) {
  865.     return TCL_ERROR;
  866.     }
  867.     fileId = open(realName, O_RDONLY, 0);
  868.     Tcl_DStringFree(&newName);
  869.     if (fileId < 0) {
  870.     Tcl_AppendResult(interp, "couldn't read file \"", fileName, "\"",
  871.         (char *) NULL);
  872.     return TCL_ERROR;
  873.     }
  874.     if (fstat(fileId, &statBuf) == -1) {
  875.     Tcl_AppendResult(interp, "couldn't stat file \"", fileName, "\"",
  876.         (char *) NULL);
  877.     close(fileId);
  878.     return TCL_ERROR;
  879.     }
  880.     buffer = (char *) ckalloc((unsigned) statBuf.st_size+1);
  881.     if (read(fileId, buffer, (int) statBuf.st_size) != statBuf.st_size) {
  882.     Tcl_AppendResult(interp, "error reading file \"", fileName, "\"",
  883.         (char *) NULL);
  884.     close(fileId);
  885.     return TCL_ERROR;
  886.     }
  887.     close(fileId);
  888.     buffer[statBuf.st_size] = 0;
  889.     result = AddFromString(interp, tkwin, buffer, priority);
  890.     ckfree(buffer);
  891.     return result;
  892. }
  893.  
  894. /*
  895.  *--------------------------------------------------------------
  896.  *
  897.  * NewArray --
  898.  *
  899.  *    Create a new ElArray structure of a given size.
  900.  *
  901.  * Results:
  902.  *    The return value is a pointer to a properly initialized
  903.  *    element array with "numEls" space.  The array is marked
  904.  *    as having no active elements.
  905.  *
  906.  * Side effects:
  907.  *    Memory is allocated.
  908.  *
  909.  *--------------------------------------------------------------
  910.  */
  911.  
  912. static ElArray *
  913. NewArray(numEls)
  914.     int numEls;            /* How many elements of space to allocate. */
  915. {
  916.     register ElArray *arrayPtr;
  917.  
  918.     arrayPtr = (ElArray *) ckalloc(EL_ARRAY_SIZE(numEls));
  919.     arrayPtr->arraySize = numEls;
  920.     arrayPtr->numUsed = 0;
  921.     arrayPtr->nextToUse = arrayPtr->els;
  922.     return arrayPtr;
  923. }
  924.  
  925. /*
  926.  *--------------------------------------------------------------
  927.  *
  928.  * ExtendArray --
  929.  *
  930.  *    Add a new element to an array, extending the array if
  931.  *    necessary.
  932.  *
  933.  * Results:
  934.  *    The return value is a pointer to the new array, which
  935.  *    will be different from arrayPtr if the array got expanded.
  936.  *
  937.  * Side effects:
  938.  *    Memory may be allocated or freed.
  939.  *
  940.  *--------------------------------------------------------------
  941.  */
  942.  
  943. static ElArray *
  944. ExtendArray(arrayPtr, elPtr)
  945.     register ElArray *arrayPtr;        /* Array to be extended. */
  946.     register Element *elPtr;        /* Element to be copied into array. */
  947. {
  948.     /*
  949.      * If the current array has filled up, make it bigger.
  950.      */
  951.  
  952.     if (arrayPtr->numUsed >= arrayPtr->arraySize) {
  953.     register ElArray *newPtr;
  954.  
  955.     newPtr = (ElArray *) ckalloc(EL_ARRAY_SIZE(2*arrayPtr->arraySize));
  956.     newPtr->arraySize = 2*arrayPtr->arraySize;
  957.     newPtr->numUsed = arrayPtr->numUsed;
  958.     newPtr->nextToUse = &newPtr->els[newPtr->numUsed];
  959.     memcpy((VOID *) newPtr->els, (VOID *) arrayPtr->els,
  960.         (arrayPtr->arraySize*sizeof(Element)));
  961.     ckfree((char *) arrayPtr);
  962.     arrayPtr = newPtr;
  963.     }
  964.  
  965.     *arrayPtr->nextToUse = *elPtr;
  966.     arrayPtr->nextToUse++;
  967.     arrayPtr->numUsed++;
  968.     return arrayPtr;
  969. }
  970.  
  971. /*
  972.  *--------------------------------------------------------------
  973.  *
  974.  * SetupStacks --
  975.  *
  976.  *    Arrange the stacks so that they cache all the option
  977.  *    information for a particular window.
  978.  *
  979.  * Results:
  980.  *    None.
  981.  *
  982.  * Side effects:
  983.  *    The stacks are modified to hold information for tkwin
  984.  *    and all its ancestors in the window hierarchy.
  985.  *
  986.  *--------------------------------------------------------------
  987.  */
  988.  
  989. static void
  990. SetupStacks(winPtr, leaf)
  991.     TkWindow *winPtr;        /* Window for which information is to
  992.                  * be cached. */
  993.     int leaf;            /* Non-zero means this is the leaf
  994.                  * window being probed.  Zero means this
  995.                  * is an ancestor of the desired leaf. */
  996. {
  997.     int level, i, *iPtr;
  998.     register StackLevel *levelPtr;
  999.     register ElArray *arrayPtr;
  1000.  
  1001.     /*
  1002.      * The following array defines the order in which the current
  1003.      * stacks are searched to find matching entries to add to the
  1004.      * stacks.  Given the current priority-based scheme, the order
  1005.      * below is no longer relevant;  all that matters is that an
  1006.      * element is on the list *somewhere*.  The ordering is a relic
  1007.      * of the old days when priorities were determined differently.
  1008.      */
  1009.  
  1010.     static int searchOrder[] = {WILDCARD_NODE_CLASS, WILDCARD_NODE_NAME,
  1011.         EXACT_NODE_CLASS, EXACT_NODE_NAME, -1};
  1012.  
  1013.     if (winPtr->mainPtr->optionRootPtr == NULL) {
  1014.     OptionInit(winPtr->mainPtr);
  1015.     }
  1016.  
  1017.     /*
  1018.      * Step 1:  make sure that options are cached for this window's
  1019.      * parent.
  1020.      */
  1021.  
  1022.     if (winPtr->parentPtr != NULL) {
  1023.     level = winPtr->parentPtr->optionLevel;
  1024.     if ((level == -1) || (cachedWindow == NULL)) {
  1025.         SetupStacks(winPtr->parentPtr, 0);
  1026.         level = winPtr->parentPtr->optionLevel;
  1027.     }
  1028.     level++;
  1029.     } else {
  1030.     level = 1;
  1031.     }
  1032.  
  1033.     /*
  1034.      * Step 2:  pop extra unneeded information off the stacks and
  1035.      * mark those windows as no longer having cached information.
  1036.      */
  1037.  
  1038.     if (curLevel >= level) {
  1039.     while (curLevel >= level) {
  1040.         levels[curLevel].winPtr->optionLevel = -1;
  1041.         curLevel--;
  1042.     }
  1043.     levelPtr = &levels[level];
  1044.     for (i = 0; i < NUM_STACKS; i++) {
  1045.         arrayPtr = stacks[i];
  1046.         arrayPtr->numUsed = levelPtr->bases[i];
  1047.         arrayPtr->nextToUse = &arrayPtr->els[arrayPtr->numUsed];
  1048.     }
  1049.     }
  1050.     curLevel = winPtr->optionLevel = level;
  1051.  
  1052.     /*
  1053.      * Step 3:  if the root database information isn't loaded or
  1054.      * isn't valid, initialize level 0 of the stack from the
  1055.      * database root (this only happens if winPtr is a main window).
  1056.      */
  1057.  
  1058.     if ((curLevel == 1)
  1059.         && ((cachedWindow == NULL)
  1060.         || (cachedWindow->mainPtr != winPtr->mainPtr))) {
  1061.     for (i = 0; i < NUM_STACKS; i++) {
  1062.         arrayPtr = stacks[i];
  1063.         arrayPtr->numUsed = 0;
  1064.         arrayPtr->nextToUse = arrayPtr->els;
  1065.     }
  1066.     ExtendStacks(winPtr->mainPtr->optionRootPtr, 0);
  1067.     }
  1068.  
  1069.     /*
  1070.      * Step 4: create a new stack level;  grow the level array if
  1071.      * we've run out of levels.  Clear the stacks for EXACT_LEAF_NAME
  1072.      * and EXACT_LEAF_CLASS (anything that was there is of no use
  1073.      * any more).
  1074.      */
  1075.  
  1076.     if (curLevel >= numLevels) {
  1077.     StackLevel *newLevels;
  1078.  
  1079.     newLevels = (StackLevel *) ckalloc((unsigned)
  1080.         (numLevels*2*sizeof(StackLevel)));
  1081.     memcpy((VOID *) newLevels, (VOID *) levels,
  1082.         (numLevels*sizeof(StackLevel)));
  1083.     ckfree((char *) levels);
  1084.     numLevels *= 2;
  1085.     levels = newLevels;
  1086.     }
  1087.     levelPtr = &levels[curLevel];
  1088.     levelPtr->winPtr = winPtr;
  1089.     arrayPtr = stacks[EXACT_LEAF_NAME];
  1090.     arrayPtr->numUsed = 0;
  1091.     arrayPtr->nextToUse = arrayPtr->els;
  1092.     arrayPtr = stacks[EXACT_LEAF_CLASS];
  1093.     arrayPtr->numUsed = 0;
  1094.     arrayPtr->nextToUse = arrayPtr->els;
  1095.     levelPtr->bases[EXACT_LEAF_NAME] = stacks[EXACT_LEAF_NAME]->numUsed;
  1096.     levelPtr->bases[EXACT_LEAF_CLASS] = stacks[EXACT_LEAF_CLASS]->numUsed;
  1097.     levelPtr->bases[EXACT_NODE_NAME] = stacks[EXACT_NODE_NAME]->numUsed;
  1098.     levelPtr->bases[EXACT_NODE_CLASS] = stacks[EXACT_NODE_CLASS]->numUsed;
  1099.     levelPtr->bases[WILDCARD_LEAF_NAME] = stacks[WILDCARD_LEAF_NAME]->numUsed;
  1100.     levelPtr->bases[WILDCARD_LEAF_CLASS] = stacks[WILDCARD_LEAF_CLASS]->numUsed;
  1101.     levelPtr->bases[WILDCARD_NODE_NAME] = stacks[WILDCARD_NODE_NAME]->numUsed;
  1102.     levelPtr->bases[WILDCARD_NODE_CLASS] = stacks[WILDCARD_NODE_CLASS]->numUsed;
  1103.  
  1104.  
  1105.     /*
  1106.      * Step 5: scan the current stack level looking for matches to this
  1107.      * window's name or class;  where found, add new information to the
  1108.      * stacks.
  1109.      */
  1110.  
  1111.     for (iPtr = searchOrder; *iPtr != -1; iPtr++) {
  1112.     register Element *elPtr;
  1113.     int count;
  1114.     Tk_Uid id;
  1115.  
  1116.     i = *iPtr;
  1117.     if (i & CLASS) {
  1118.         id = winPtr->classUid;
  1119.     } else {
  1120.         id = winPtr->nameUid;
  1121.     }
  1122.     elPtr = stacks[i]->els;
  1123.     count = levelPtr->bases[i];
  1124.  
  1125.     /*
  1126.      * For wildcard stacks, check all entries;  for non-wildcard
  1127.      * stacks, only check things that matched in the parent.
  1128.      */
  1129.  
  1130.     if (!(i & WILDCARD)) {
  1131.         elPtr += levelPtr[-1].bases[i];
  1132.         count -= levelPtr[-1].bases[i];
  1133.     }
  1134.     for ( ; count > 0; elPtr++, count--) {
  1135.         if (elPtr->nameUid != id) {
  1136.         continue;
  1137.         }
  1138.         ExtendStacks(elPtr->child.arrayPtr, leaf);
  1139.     }
  1140.     }
  1141.     cachedWindow = winPtr;
  1142. }
  1143.  
  1144. /*
  1145.  *--------------------------------------------------------------
  1146.  *
  1147.  * ExtendStacks --
  1148.  *
  1149.  *    Given an element array, copy all the elements from the
  1150.  *    array onto the system stacks (except for irrelevant leaf
  1151.  *    elements).
  1152.  *
  1153.  * Results:
  1154.  *    None.
  1155.  *
  1156.  * Side effects:
  1157.  *    The option stacks are extended.
  1158.  *
  1159.  *--------------------------------------------------------------
  1160.  */
  1161.  
  1162. static void
  1163. ExtendStacks(arrayPtr, leaf)
  1164.     ElArray *arrayPtr;        /* Array of elements to copy onto stacks. */
  1165.     int leaf;            /* If zero, then don't copy exact leaf
  1166.                  * elements. */
  1167. {
  1168.     register int count;
  1169.     register Element *elPtr;
  1170.  
  1171.     for (elPtr = arrayPtr->els, count = arrayPtr->numUsed;
  1172.         count > 0; elPtr++, count--) {
  1173.     if (!(elPtr->flags & (NODE|WILDCARD)) && !leaf) {
  1174.         continue;
  1175.     }
  1176.     stacks[elPtr->flags] = ExtendArray(stacks[elPtr->flags], elPtr);
  1177.     }
  1178. }
  1179.  
  1180. /*
  1181.  *--------------------------------------------------------------
  1182.  *
  1183.  * OptionInit --
  1184.  *
  1185.  *    Initialize data structures for option handling.
  1186.  *
  1187.  * Results:
  1188.  *    None.
  1189.  *
  1190.  * Side effects:
  1191.  *    Option-related data structures get initialized.
  1192.  *
  1193.  *--------------------------------------------------------------
  1194.  */
  1195.  
  1196. static void
  1197. OptionInit(mainPtr)
  1198.     register TkMainInfo *mainPtr;    /* Top-level information about
  1199.                      * window that isn't initialized
  1200.                      * yet. */
  1201. {
  1202.     int i;
  1203.     Tcl_Interp *interp;
  1204.  
  1205.     /*
  1206.      * First, once-only initialization.
  1207.      */
  1208.  
  1209.     if (numLevels == 0) {
  1210.  
  1211.     numLevels = 5;
  1212.     levels = (StackLevel *) ckalloc((unsigned) (5*sizeof(StackLevel)));
  1213.     for (i = 0; i < NUM_STACKS; i++) {
  1214.         stacks[i] = NewArray(10);
  1215.         levels[0].bases[i] = 0;
  1216.     }
  1217.     
  1218.     defaultMatch.nameUid = NULL;
  1219.     defaultMatch.child.valueUid = NULL;
  1220.     defaultMatch.priority = -1;
  1221.     defaultMatch.flags = 0;
  1222.     }
  1223.  
  1224.     /*
  1225.      * Then, per-main-window initialization.  Create and delete dummy
  1226.      * interpreter for message logging.
  1227.      */
  1228.  
  1229.     mainPtr->optionRootPtr = NewArray(20);
  1230.     interp = Tcl_CreateInterp();
  1231.     (void) GetDefaultOptions(interp, mainPtr->winPtr);
  1232.     Tcl_DeleteInterp(interp);
  1233. }
  1234.  
  1235. /*
  1236.  *--------------------------------------------------------------
  1237.  *
  1238.  * ClearOptionTree --
  1239.  *
  1240.  *    This procedure is called to erase everything in a
  1241.  *    hierarchical option database.
  1242.  *
  1243.  * Results:
  1244.  *    None.
  1245.  *
  1246.  * Side effects:
  1247.  *    All the options associated with arrayPtr are deleted,
  1248.  *    along with all option subtrees.  The space pointed to
  1249.  *    by arrayPtr is freed.
  1250.  *
  1251.  *--------------------------------------------------------------
  1252.  */
  1253.  
  1254. static void
  1255. ClearOptionTree(arrayPtr)
  1256.     ElArray *arrayPtr;        /* Array of options;  delete everything
  1257.                  * referred to recursively by this. */
  1258. {
  1259.     register Element *elPtr;
  1260.     int count;
  1261.  
  1262.     for (count = arrayPtr->numUsed, elPtr = arrayPtr->els;  count > 0;
  1263.         count--, elPtr++) {
  1264.     if (elPtr->flags & NODE) {
  1265.         ClearOptionTree(elPtr->child.arrayPtr);
  1266.     }
  1267.     }
  1268.     ckfree((char *) arrayPtr);
  1269. }
  1270.  
  1271. /*
  1272.  *--------------------------------------------------------------
  1273.  *
  1274.  * GetDefaultOptions --
  1275.  *
  1276.  *    This procedure is invoked to load the default set of options
  1277.  *    for a window.
  1278.  *
  1279.  * Results:
  1280.  *    None.
  1281.  *
  1282.  * Side effects:
  1283.  *    Options are added to those for winPtr's main window.  If
  1284.  *    there exists a RESOURCE_MANAGER proprety for winPtr's
  1285.  *    display, that is used.  Otherwise, the .Xdefaults file in
  1286.  *    the user's home directory is used.
  1287.  *
  1288.  *--------------------------------------------------------------
  1289.  */
  1290.  
  1291. static int
  1292. GetDefaultOptions(interp, winPtr)
  1293.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  1294.     TkWindow *winPtr;        /* Fetch option defaults for main window
  1295.                  * associated with this. */
  1296. {
  1297.     char *regProp, *home, *fileName;
  1298.     int result, actualFormat;
  1299.     unsigned long numItems, bytesAfter;
  1300.     Atom actualType;
  1301.  
  1302.     /*
  1303.      * Try the RESOURCE_MANAGER property on the root window first.
  1304.      */
  1305.  
  1306.     regProp = NULL;
  1307.     result = XGetWindowProperty(winPtr->display,
  1308.         DefaultRootWindow(winPtr->display),
  1309.         XA_RESOURCE_MANAGER, 0, 100000,
  1310.         False, XA_STRING, &actualType, &actualFormat,
  1311.         &numItems, &bytesAfter, (unsigned char **) ®Prop);
  1312.  
  1313.     if ((result == Success) && (actualType == XA_STRING)
  1314.         && (actualFormat == 8)) {
  1315.     result = AddFromString(interp, (Tk_Window) winPtr, regProp,
  1316.         TK_USER_DEFAULT_PRIO);
  1317.     XFree(regProp);
  1318.     return result;
  1319.     }
  1320.  
  1321.     /*
  1322.      * No luck there.  Try a .Xdefaults file in the user's home
  1323.      * directory.
  1324.      */
  1325.  
  1326.     if (regProp != NULL) {
  1327.     XFree(regProp);
  1328.     }
  1329.     home = getenv("HOME");
  1330.     if (home == NULL) {
  1331.     sprintf(interp->result,
  1332.         "no RESOURCE_MANAGER property and no HOME envariable");
  1333.     return TCL_ERROR;
  1334.     }
  1335.     fileName = (char *) ckalloc((unsigned) (strlen(home) + 20));
  1336.     sprintf(fileName, "%s/.Xdefaults", home);
  1337.     result = ReadOptionFile(interp, (Tk_Window) winPtr, fileName,
  1338.         TK_USER_DEFAULT_PRIO);
  1339.     ckfree(fileName);
  1340.     return result;
  1341. }
  1342.