Annotation of micropolis/src/tk/tkoption.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.