Annotation of micropolis/src/tk/tkoption.c, revision 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.