Xrm.c revision 1ab64890
11ab64890Smrg/* $Xorg: Xrm.c,v 1.7 2001/02/09 02:03:39 xorgcvs Exp $ */
21ab64890Smrg
31ab64890Smrg/***********************************************************
41ab64890SmrgCopyright 1987, 1988, 1990 by Digital Equipment Corporation, Maynard
51ab64890Smrg
61ab64890Smrg                        All Rights Reserved
71ab64890Smrg
81ab64890SmrgPermission to use, copy, modify, and distribute this software and its
91ab64890Smrgdocumentation for any purpose and without fee is hereby granted,
101ab64890Smrgprovided that the above copyright notice appear in all copies and that
111ab64890Smrgboth that copyright notice and this permission notice appear in
121ab64890Smrgsupporting documentation, and that the name Digital not be
131ab64890Smrgused in advertising or publicity pertaining to distribution of the
141ab64890Smrgsoftware without specific, written prior permission.
151ab64890Smrg
161ab64890SmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
171ab64890SmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
181ab64890SmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
191ab64890SmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
201ab64890SmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
211ab64890SmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
221ab64890SmrgSOFTWARE.
231ab64890Smrg
241ab64890Smrg******************************************************************/
251ab64890Smrg/*
261ab64890Smrg
271ab64890SmrgCopyright 1987, 1988, 1990, 1998  The Open Group
281ab64890Smrg
291ab64890SmrgPermission to use, copy, modify, distribute, and sell this software and its
301ab64890Smrgdocumentation for any purpose is hereby granted without fee, provided that
311ab64890Smrgthe above copyright notice appear in all copies and that both that
321ab64890Smrgcopyright notice and this permission notice appear in supporting
331ab64890Smrgdocumentation.
341ab64890Smrg
351ab64890SmrgThe above copyright notice and this permission notice shall be included
361ab64890Smrgin all copies or substantial portions of the Software.
371ab64890Smrg
381ab64890SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
391ab64890SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
401ab64890SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
411ab64890SmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
421ab64890SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
431ab64890SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
441ab64890SmrgOTHER DEALINGS IN THE SOFTWARE.
451ab64890Smrg
461ab64890SmrgExcept as contained in this notice, the name of The Open Group shall
471ab64890Smrgnot be used in advertising or otherwise to promote the sale, use or
481ab64890Smrgother dealings in this Software without prior written authorization
491ab64890Smrgfrom The Open Group.
501ab64890Smrg
511ab64890Smrg*/
521ab64890Smrg/* $XFree86: xc/lib/X11/Xrm.c,v 3.22 2003/07/16 01:38:26 dawes Exp $ */
531ab64890Smrg
541ab64890Smrg#ifdef HAVE_CONFIG_H
551ab64890Smrg#include <config.h>
561ab64890Smrg#endif
571ab64890Smrg#include	<stdio.h>
581ab64890Smrg#include	<ctype.h>
591ab64890Smrg#include	"Xlibint.h"
601ab64890Smrg#include	<X11/Xresource.h>
611ab64890Smrg#include	"Xlcint.h"
621ab64890Smrg#ifdef XTHREADS
631ab64890Smrg#include	"locking.h"
641ab64890Smrg#endif
651ab64890Smrg#include 	"XrmI.h"
661ab64890Smrg#include	<X11/Xos.h>
671ab64890Smrg#include "Xresinternal.h"
681ab64890Smrg#include "Xresource.h"
691ab64890Smrg
701ab64890Smrg/*
711ab64890Smrg
721ab64890SmrgThese Xrm routines allow very fast lookup of resources in the resource
731ab64890Smrgdatabase.  Several usage patterns are exploited:
741ab64890Smrg
751ab64890Smrg(1) Widgets get a lot of resources at one time.  Rather than look up each from
761ab64890Smrgscratch, we can precompute the prioritized list of database levels once, then
771ab64890Smrgsearch for each resource starting at the beginning of the list.
781ab64890Smrg
791ab64890Smrg(2) Many database levels don't contain any leaf resource nodes.  There is no
801ab64890Smrgpoint in looking for resources on a level that doesn't contain any.  This
811ab64890Smrginformation is kept on a per-level basis.
821ab64890Smrg
831ab64890Smrg(3) Sometimes the widget instance tree is structured such that you get the same
841ab64890Smrgclass name repeated on the fully qualified widget name.  This can result in the
851ab64890Smrgsame database level occuring multiple times on the search list.  The code below
861ab64890Smrgonly checks to see if you get two identical search lists in a row, rather than
871ab64890Smrglook back through all database levels, but in practice this removes all
881ab64890Smrgduplicates I've ever observed.
891ab64890Smrg
901ab64890SmrgJoel McCormack
911ab64890Smrg
921ab64890Smrg*/
931ab64890Smrg
941ab64890Smrg/*
951ab64890Smrg
961ab64890SmrgThe Xrm representation has been completely redesigned to substantially reduce
971ab64890Smrgmemory and hopefully improve performance.
981ab64890Smrg
991ab64890SmrgThe database is structured into two kinds of tables: LTables that contain
1001ab64890Smrgonly values, and NTables that contain only other tables.
1011ab64890Smrg
1021ab64890SmrgSome invariants:
1031ab64890Smrg
1041ab64890SmrgThe next pointer of the top-level node table points to the top-level leaf
1051ab64890Smrgtable, if any.
1061ab64890Smrg
1071ab64890SmrgWithin an LTable, for a given name, the tight value always precedes the
1081ab64890Smrgloose value, and if both are present the loose value is always right after
1091ab64890Smrgthe tight value.
1101ab64890Smrg
1111ab64890SmrgWithin an NTable, all of the entries for a given name are contiguous,
1121ab64890Smrgin the order tight NTable, loose NTable, tight LTable, loose LTable.
1131ab64890Smrg
1141ab64890SmrgBob Scheifler
1151ab64890Smrg
1161ab64890Smrg*/
1171ab64890Smrg
1181ab64890Smrgstatic XrmQuark XrmQString, XrmQANY;
1191ab64890Smrg
1201ab64890Smrgtypedef	Bool (*DBEnumProc)(
1211ab64890Smrg    XrmDatabase*	/* db */,
1221ab64890Smrg    XrmBindingList	/* bindings */,
1231ab64890Smrg    XrmQuarkList	/* quarks */,
1241ab64890Smrg    XrmRepresentation*	/* type */,
1251ab64890Smrg    XrmValue*		/* value */,
1261ab64890Smrg    XPointer		/* closure */
1271ab64890Smrg);
1281ab64890Smrg
1291ab64890Smrgtypedef struct _VEntry {
1301ab64890Smrg    struct _VEntry	*next;		/* next in chain */
1311ab64890Smrg    XrmQuark		name;		/* name of this entry */
1321ab64890Smrg    unsigned int	tight:1;	/* 1 if it is a tight binding */
1331ab64890Smrg    unsigned int	string:1;	/* 1 if type is String */
1341ab64890Smrg    unsigned int	size:30;	/* size of value */
1351ab64890Smrg} VEntryRec, *VEntry;
1361ab64890Smrg
1371ab64890Smrg
1381ab64890Smrgtypedef struct _DEntry {
1391ab64890Smrg    VEntryRec		entry;		/* entry */
1401ab64890Smrg    XrmRepresentation	type;		/* representation type */
1411ab64890Smrg} DEntryRec, *DEntry;
1421ab64890Smrg
1431ab64890Smrg/* the value is right after the structure */
1441ab64890Smrg#define StringValue(ve) (XPointer)((ve) + 1)
1451ab64890Smrg#define RepType(ve) ((DEntry)(ve))->type
1461ab64890Smrg/* the value is right after the structure */
1471ab64890Smrg#define DataValue(ve) (XPointer)(((DEntry)(ve)) + 1)
1481ab64890Smrg#define RawValue(ve) (char *)((ve)->string ? StringValue(ve) : DataValue(ve))
1491ab64890Smrg
1501ab64890Smrgtypedef struct _NTable {
1511ab64890Smrg    struct _NTable	*next;		/* next in chain */
1521ab64890Smrg    XrmQuark		name;		/* name of this entry */
1531ab64890Smrg    unsigned int	tight:1;	/* 1 if it is a tight binding */
1541ab64890Smrg    unsigned int	leaf:1;		/* 1 if children are values */
1551ab64890Smrg    unsigned int	hasloose:1;	/* 1 if has loose children */
1561ab64890Smrg    unsigned int	hasany:1;	/* 1 if has ANY entry */
1571ab64890Smrg    unsigned int	pad:4;		/* unused */
1581ab64890Smrg    unsigned int	mask:8;		/* hash size - 1 */
1591ab64890Smrg    unsigned int	entries:16;	/* number of children */
1601ab64890Smrg} NTableRec, *NTable;
1611ab64890Smrg
1621ab64890Smrg/* the buckets are right after the structure */
1631ab64890Smrg#define NodeBuckets(ne) ((NTable *)((ne) + 1))
1641ab64890Smrg#define NodeHash(ne,q) NodeBuckets(ne)[(q) & (ne)->mask]
1651ab64890Smrg
1661ab64890Smrg/* leaf tables have an extra level of indirection for the buckets,
1671ab64890Smrg * so that resizing can be done without invalidating a search list.
1681ab64890Smrg * This is completely ugly, and wastes some memory, but the Xlib
1691ab64890Smrg * spec doesn't really specify whether invalidation is OK, and the
1701ab64890Smrg * old implementation did not invalidate.
1711ab64890Smrg */
1721ab64890Smrgtypedef struct _LTable {
1731ab64890Smrg    NTableRec		table;
1741ab64890Smrg    VEntry		*buckets;
1751ab64890Smrg} LTableRec, *LTable;
1761ab64890Smrg
1771ab64890Smrg#define LeafHash(le,q) (le)->buckets[(q) & (le)->table.mask]
1781ab64890Smrg
1791ab64890Smrg/* An XrmDatabase just holds a pointer to the first top-level table.
1801ab64890Smrg * The type name is no longer descriptive, but better to not change
1811ab64890Smrg * the Xresource.h header file.  This type also gets used to define
1821ab64890Smrg * XrmSearchList, which is a complete crock, but we'll just leave it
1831ab64890Smrg * and caste types as required.
1841ab64890Smrg */
1851ab64890Smrgtypedef struct _XrmHashBucketRec {
1861ab64890Smrg    NTable table;
1871ab64890Smrg    XPointer mbstate;
1881ab64890Smrg    XrmMethods methods;
1891ab64890Smrg#ifdef XTHREADS
1901ab64890Smrg    LockInfoRec linfo;
1911ab64890Smrg#endif
1921ab64890Smrg} XrmHashBucketRec;
1931ab64890Smrg
1941ab64890Smrg/* closure used in get/put resource */
1951ab64890Smrgtypedef struct _VClosure {
1961ab64890Smrg    XrmRepresentation	*type;		/* type of value */
1971ab64890Smrg    XrmValuePtr		value;		/* value itself */
1981ab64890Smrg} VClosureRec, *VClosure;
1991ab64890Smrg
2001ab64890Smrg/* closure used in get search list */
2011ab64890Smrgtypedef struct _SClosure {
2021ab64890Smrg    LTable		*list;		/* search list */
2031ab64890Smrg    int			idx;		/* index of last filled element */
2041ab64890Smrg    int			limit;		/* maximum index */
2051ab64890Smrg} SClosureRec, *SClosure;
2061ab64890Smrg
2071ab64890Smrg/* placed in XrmSearchList to indicate next table is loose only */
2081ab64890Smrg#define LOOSESEARCH ((LTable)1)
2091ab64890Smrg
2101ab64890Smrg/* closure used in enumerate database */
2111ab64890Smrgtypedef struct _EClosure {
2121ab64890Smrg    XrmDatabase db;			/* the database */
2131ab64890Smrg    DBEnumProc proc;			/* the user proc */
2141ab64890Smrg    XPointer closure;			/* the user closure */
2151ab64890Smrg    XrmBindingList bindings;		/* binding list */
2161ab64890Smrg    XrmQuarkList quarks;		/* quark list */
2171ab64890Smrg    int mode;				/* XrmEnum<kind> */
2181ab64890Smrg} EClosureRec, *EClosure;
2191ab64890Smrg
2201ab64890Smrg/* types for typecasting ETable based functions to NTable based functions */
2211ab64890Smrgtypedef Bool (*getNTableSProcp)(
2221ab64890Smrg    NTable              table,
2231ab64890Smrg    XrmNameList         names,
2241ab64890Smrg    XrmClassList        classes,
2251ab64890Smrg    SClosure            closure);
2261ab64890Smrgtypedef Bool (*getNTableVProcp)(
2271ab64890Smrg    NTable              table,
2281ab64890Smrg    XrmNameList         names,
2291ab64890Smrg    XrmClassList        classes,
2301ab64890Smrg    VClosure            closure);
2311ab64890Smrgtypedef Bool (*getNTableEProcp)(
2321ab64890Smrg    NTable              table,
2331ab64890Smrg    XrmNameList         names,
2341ab64890Smrg    XrmClassList        classes,
2351ab64890Smrg    register int        level,
2361ab64890Smrg    EClosure            closure);
2371ab64890Smrg
2381ab64890Smrg/* predicate to determine when to resize a hash table */
2391ab64890Smrg#define GrowthPred(n,m) ((unsigned)(n) > (((m) + 1) << 2))
2401ab64890Smrg
2411ab64890Smrg#define GROW(prev) \
2421ab64890Smrg    if (GrowthPred((*prev)->entries, (*prev)->mask)) \
2431ab64890Smrg	GrowTable(prev)
2441ab64890Smrg
2451ab64890Smrg/* pick a reasonable value for maximum depth of resource database */
2461ab64890Smrg#define MAXDBDEPTH 100
2471ab64890Smrg
2481ab64890Smrg/* macro used in get/search functions */
2491ab64890Smrg
2501ab64890Smrg/* find an entry named ename, with leafness given by leaf */
2511ab64890Smrg#define NFIND(ename) \
2521ab64890Smrg    q = ename; \
2531ab64890Smrg    entry = NodeHash(table, q); \
2541ab64890Smrg    while (entry && entry->name != q) \
2551ab64890Smrg	entry = entry->next; \
2561ab64890Smrg    if (leaf && entry && !entry->leaf) { \
2571ab64890Smrg	entry = entry->next; \
2581ab64890Smrg	if (entry && !entry->leaf) \
2591ab64890Smrg	    entry = entry->next; \
2601ab64890Smrg	if (entry && entry->name != q) \
2611ab64890Smrg	    entry = (NTable)NULL; \
2621ab64890Smrg    }
2631ab64890Smrg
2641ab64890Smrg/* resourceQuarks keeps track of what quarks have been associated with values
2651ab64890Smrg * in all LTables.  If a quark has never been used in an LTable, we don't need
2661ab64890Smrg * to bother looking for it.
2671ab64890Smrg */
2681ab64890Smrg
2691ab64890Smrgstatic unsigned char *resourceQuarks = (unsigned char *)NULL;
2701ab64890Smrgstatic XrmQuark maxResourceQuark = -1;
2711ab64890Smrg
2721ab64890Smrg/* determines if a quark has been used for a value in any database */
2731ab64890Smrg#define IsResourceQuark(q)  ((q) > 0 && (q) <= maxResourceQuark && \
2741ab64890Smrg			     resourceQuarks[(q) >> 3] & (1 << ((q) & 7)))
2751ab64890Smrg
2761ab64890Smrgtypedef unsigned char XrmBits;
2771ab64890Smrg
2781ab64890Smrg#define BSLASH  ((XrmBits) (1 << 5))
2791ab64890Smrg#define NORMAL	((XrmBits) (1 << 4))
2801ab64890Smrg#define EOQ	((XrmBits) (1 << 3))
2811ab64890Smrg#define SEP	((XrmBits) (1 << 2))
2821ab64890Smrg#define ENDOF	((XrmBits) (1 << 1))
2831ab64890Smrg#define SPACE	(NORMAL|EOQ|SEP|(XrmBits)0)
2841ab64890Smrg#define RSEP	(NORMAL|EOQ|SEP|(XrmBits)1)
2851ab64890Smrg#define EOS	(EOQ|SEP|ENDOF|(XrmBits)0)
2861ab64890Smrg#define EOL	(EOQ|SEP|ENDOF|(XrmBits)1)
2871ab64890Smrg#define BINDING	(NORMAL|EOQ)
2881ab64890Smrg#define ODIGIT	(NORMAL|(XrmBits)1)
2891ab64890Smrg
2901ab64890Smrg#define next_char(ch,str) xrmtypes[(unsigned char)((ch) = *(++(str)))]
2911ab64890Smrg#define next_mbchar(ch,len,str) xrmtypes[(unsigned char)(ch = (*db->methods->mbchar)(db->mbstate, str, &len), str += len, ch)]
2921ab64890Smrg
2931ab64890Smrg#define is_space(bits)		((bits) == SPACE)
2941ab64890Smrg#define is_EOQ(bits)		((bits) & EOQ)
2951ab64890Smrg#define is_EOF(bits)		((bits) == EOS)
2961ab64890Smrg#define is_EOL(bits)		((bits) & ENDOF)
2971ab64890Smrg#define is_binding(bits)	((bits) == BINDING)
2981ab64890Smrg#define is_odigit(bits)		((bits) == ODIGIT)
2991ab64890Smrg#define is_separator(bits)	((bits) & SEP)
3001ab64890Smrg#define is_nonpcs(bits)		(!(bits))
3011ab64890Smrg#define is_normal(bits)		((bits) & NORMAL)
3021ab64890Smrg#define is_simple(bits)		((bits) & (NORMAL|BSLASH))
3031ab64890Smrg#define is_special(bits)	((bits) & (ENDOF|BSLASH))
3041ab64890Smrg
3051ab64890Smrg/* parsing types */
3061ab64890Smrgstatic XrmBits const xrmtypes[256] = {
3071ab64890Smrg    EOS,0,0,0,0,0,0,0,
3081ab64890Smrg    0,SPACE,EOL,0,0,
3091ab64890Smrg#if defined(WIN32) || defined(__UNIXOS2__)
3101ab64890Smrg                    EOL,	/* treat CR the same as LF, just in case */
3111ab64890Smrg#else
3121ab64890Smrg                    0,
3131ab64890Smrg#endif
3141ab64890Smrg                      0,0,
3151ab64890Smrg    0,0,0,0,0,0,0,0,
3161ab64890Smrg    0,0,0,0,0,0,0,0,
3171ab64890Smrg    SPACE,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,
3181ab64890Smrg    NORMAL,NORMAL,BINDING,NORMAL,NORMAL,NORMAL,BINDING,NORMAL,
3191ab64890Smrg    ODIGIT,ODIGIT,ODIGIT,ODIGIT,ODIGIT,ODIGIT,ODIGIT,ODIGIT,
3201ab64890Smrg    NORMAL,NORMAL,RSEP,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,
3211ab64890Smrg    NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,
3221ab64890Smrg    NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,
3231ab64890Smrg    NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,
3241ab64890Smrg    NORMAL,NORMAL,NORMAL,NORMAL,BSLASH,NORMAL,NORMAL,NORMAL,
3251ab64890Smrg    NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,
3261ab64890Smrg    NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,
3271ab64890Smrg    NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,
3281ab64890Smrg    NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,NORMAL,0
3291ab64890Smrg    /* The rest will be automatically initialized to zero. */
3301ab64890Smrg};
3311ab64890Smrg
3321ab64890Smrgvoid XrmInitialize(void)
3331ab64890Smrg{
3341ab64890Smrg    XrmQString = XrmPermStringToQuark("String");
3351ab64890Smrg    XrmQANY = XrmPermStringToQuark("?");
3361ab64890Smrg}
3371ab64890Smrg
3381ab64890Smrg#ifndef _XP_PRINT_SERVER_
3391ab64890SmrgXrmDatabase XrmGetDatabase(
3401ab64890Smrg    Display *display)
3411ab64890Smrg{
3421ab64890Smrg    XrmDatabase retval;
3431ab64890Smrg    LockDisplay(display);
3441ab64890Smrg    retval = display->db;
3451ab64890Smrg    UnlockDisplay(display);
3461ab64890Smrg    return retval;
3471ab64890Smrg}
3481ab64890Smrg
3491ab64890Smrgvoid XrmSetDatabase(
3501ab64890Smrg    Display *display,
3511ab64890Smrg    XrmDatabase database)
3521ab64890Smrg{
3531ab64890Smrg    LockDisplay(display);
3541ab64890Smrg    /* destroy database if set up imlicitely by XGetDefault() */
3551ab64890Smrg    if (display->db && (display->flags & XlibDisplayDfltRMDB)) {
3561ab64890Smrg	XrmDestroyDatabase(display->db);
3571ab64890Smrg	display->flags &= ~XlibDisplayDfltRMDB;
3581ab64890Smrg    }
3591ab64890Smrg    display->db = database;
3601ab64890Smrg    UnlockDisplay(display);
3611ab64890Smrg}
3621ab64890Smrg#endif /* !_XP_PRINT_SERVER_ */
3631ab64890Smrg
3641ab64890Smrgvoid
3651ab64890SmrgXrmStringToQuarkList(
3661ab64890Smrg    register _Xconst char  *name,
3671ab64890Smrg    register XrmQuarkList quarks)   /* RETURN */
3681ab64890Smrg{
3691ab64890Smrg    register XrmBits		bits;
3701ab64890Smrg    register Signature  	sig = 0;
3711ab64890Smrg    register char       	ch, *tname;
3721ab64890Smrg    register int 		i = 0;
3731ab64890Smrg
3741ab64890Smrg    if ((tname = (char *)name)) {
3751ab64890Smrg	tname--;
3761ab64890Smrg	while (!is_EOF(bits = next_char(ch, tname))) {
3771ab64890Smrg	    if (is_binding (bits)) {
3781ab64890Smrg		if (i) {
3791ab64890Smrg		    /* Found a complete name */
3801ab64890Smrg		    *quarks++ = _XrmInternalStringToQuark(name,tname - name,
3811ab64890Smrg							  sig, False);
3821ab64890Smrg		    i = 0;
3831ab64890Smrg		    sig = 0;
3841ab64890Smrg		}
3851ab64890Smrg		name = tname+1;
3861ab64890Smrg	    }
3871ab64890Smrg	    else {
3881ab64890Smrg		sig = (sig << 1) + ch; /* Compute the signature. */
3891ab64890Smrg		i++;
3901ab64890Smrg	    }
3911ab64890Smrg	}
3921ab64890Smrg	*quarks++ = _XrmInternalStringToQuark(name, tname - name, sig, False);
3931ab64890Smrg    }
3941ab64890Smrg    *quarks = NULLQUARK;
3951ab64890Smrg}
3961ab64890Smrg
3971ab64890Smrgvoid
3981ab64890SmrgXrmStringToBindingQuarkList(
3991ab64890Smrg    register _Xconst char   *name,
4001ab64890Smrg    register XrmBindingList bindings,   /* RETURN */
4011ab64890Smrg    register XrmQuarkList   quarks)     /* RETURN */
4021ab64890Smrg{
4031ab64890Smrg    register XrmBits		bits;
4041ab64890Smrg    register Signature  	sig = 0;
4051ab64890Smrg    register char       	ch, *tname;
4061ab64890Smrg    register XrmBinding 	binding;
4071ab64890Smrg    register int 		i = 0;
4081ab64890Smrg
4091ab64890Smrg    if ((tname = (char *)name)) {
4101ab64890Smrg	tname--;
4111ab64890Smrg	binding = XrmBindTightly;
4121ab64890Smrg	while (!is_EOF(bits = next_char(ch, tname))) {
4131ab64890Smrg	    if (is_binding (bits)) {
4141ab64890Smrg		if (i) {
4151ab64890Smrg		    /* Found a complete name */
4161ab64890Smrg		    *bindings++ = binding;
4171ab64890Smrg		    *quarks++ = _XrmInternalStringToQuark(name, tname - name,
4181ab64890Smrg							  sig, False);
4191ab64890Smrg
4201ab64890Smrg		    i = 0;
4211ab64890Smrg		    sig = 0;
4221ab64890Smrg		    binding = XrmBindTightly;
4231ab64890Smrg		}
4241ab64890Smrg		name = tname+1;
4251ab64890Smrg
4261ab64890Smrg		if (ch == '*')
4271ab64890Smrg		    binding = XrmBindLoosely;
4281ab64890Smrg	    }
4291ab64890Smrg	    else {
4301ab64890Smrg		sig = (sig << 1) + ch; /* Compute the signature. */
4311ab64890Smrg		i++;
4321ab64890Smrg	    }
4331ab64890Smrg	}
4341ab64890Smrg	*bindings = binding;
4351ab64890Smrg	*quarks++ = _XrmInternalStringToQuark(name, tname - name, sig, False);
4361ab64890Smrg    }
4371ab64890Smrg    *quarks = NULLQUARK;
4381ab64890Smrg}
4391ab64890Smrg
4401ab64890Smrg#ifdef DEBUG
4411ab64890Smrg
4421ab64890Smrgstatic void PrintQuarkList(
4431ab64890Smrg    XrmQuarkList    quarks,
4441ab64890Smrg    FILE	    *stream)
4451ab64890Smrg{
4461ab64890Smrg    Bool	    firstNameSeen;
4471ab64890Smrg
4481ab64890Smrg    for (firstNameSeen = False; *quarks; quarks++) {
4491ab64890Smrg	if (firstNameSeen) {
4501ab64890Smrg	    (void) fprintf(stream, ".");
4511ab64890Smrg	}
4521ab64890Smrg	firstNameSeen = True;
4531ab64890Smrg	(void) fputs(XrmQuarkToString(*quarks), stream);
4541ab64890Smrg    }
4551ab64890Smrg} /* PrintQuarkList */
4561ab64890Smrg
4571ab64890Smrg#endif /* DEBUG */
4581ab64890Smrg
4591ab64890Smrg
4601ab64890Smrg/*
4611ab64890Smrg * Fallback methods for Xrm parsing.
4621ab64890Smrg * Simulate a C locale. No state needed here.
4631ab64890Smrg */
4641ab64890Smrg
4651ab64890Smrgstatic void
4661ab64890Smrgc_mbnoop(
4671ab64890Smrg    XPointer state)
4681ab64890Smrg{
4691ab64890Smrg}
4701ab64890Smrg
4711ab64890Smrgstatic char
4721ab64890Smrgc_mbchar(
4731ab64890Smrg    XPointer state,
4741ab64890Smrg    const char *str,
4751ab64890Smrg    int *lenp)
4761ab64890Smrg{
4771ab64890Smrg    *lenp = 1;
4781ab64890Smrg    return *str;
4791ab64890Smrg}
4801ab64890Smrg
4811ab64890Smrgstatic const char *
4821ab64890Smrgc_lcname(
4831ab64890Smrg    XPointer state)
4841ab64890Smrg{
4851ab64890Smrg    return "C";
4861ab64890Smrg}
4871ab64890Smrg
4881ab64890Smrgstatic const XrmMethodsRec mb_methods = {
4891ab64890Smrg    c_mbnoop,	/* mbinit */
4901ab64890Smrg    c_mbchar,	/* mbchar */
4911ab64890Smrg    c_mbnoop,	/* mbfinish */
4921ab64890Smrg    c_lcname,	/* lcname */
4931ab64890Smrg    c_mbnoop	/* destroy */
4941ab64890Smrg};
4951ab64890Smrg
4961ab64890Smrg
4971ab64890Smrgstatic XrmDatabase NewDatabase(void)
4981ab64890Smrg{
4991ab64890Smrg    register XrmDatabase db;
5001ab64890Smrg
5011ab64890Smrg    db = (XrmDatabase) Xmalloc(sizeof(XrmHashBucketRec));
5021ab64890Smrg    if (db) {
5031ab64890Smrg	_XCreateMutex(&db->linfo);
5041ab64890Smrg	db->table = (NTable)NULL;
5051ab64890Smrg	db->mbstate = (XPointer)NULL;
5061ab64890Smrg#ifdef _XP_PRINT_SERVER_
5071ab64890Smrg	db->methods = NULL;
5081ab64890Smrg#else
5091ab64890Smrg	db->methods = _XrmInitParseInfo(&db->mbstate);
5101ab64890Smrg#endif
5111ab64890Smrg	if (!db->methods)
5121ab64890Smrg	    db->methods = &mb_methods;
5131ab64890Smrg    }
5141ab64890Smrg    return db;
5151ab64890Smrg}
5161ab64890Smrg
5171ab64890Smrg/* move all values from ftable to ttable, and free ftable's buckets.
5181ab64890Smrg * ttable is quaranteed empty to start with.
5191ab64890Smrg */
5201ab64890Smrgstatic void MoveValues(
5211ab64890Smrg    LTable ftable,
5221ab64890Smrg    register LTable ttable)
5231ab64890Smrg{
5241ab64890Smrg    register VEntry fentry, nfentry;
5251ab64890Smrg    register VEntry *prev;
5261ab64890Smrg    register VEntry *bucket;
5271ab64890Smrg    register VEntry tentry;
5281ab64890Smrg    register int i;
5291ab64890Smrg
5301ab64890Smrg    for (i = ftable->table.mask, bucket = ftable->buckets; i >= 0; i--) {
5311ab64890Smrg	for (fentry = *bucket++; fentry; fentry = nfentry) {
5321ab64890Smrg	    prev = &LeafHash(ttable, fentry->name);
5331ab64890Smrg	    tentry = *prev;
5341ab64890Smrg	    *prev = fentry;
5351ab64890Smrg	    /* chain on all with same name, to preserve invariant order */
5361ab64890Smrg	    while ((nfentry = fentry->next) && nfentry->name == fentry->name)
5371ab64890Smrg		fentry = nfentry;
5381ab64890Smrg	    fentry->next = tentry;
5391ab64890Smrg	}
5401ab64890Smrg    }
5411ab64890Smrg    Xfree((char *)ftable->buckets);
5421ab64890Smrg}
5431ab64890Smrg
5441ab64890Smrg/* move all tables from ftable to ttable, and free ftable.
5451ab64890Smrg * ttable is quaranteed empty to start with.
5461ab64890Smrg */
5471ab64890Smrgstatic void MoveTables(
5481ab64890Smrg    NTable ftable,
5491ab64890Smrg    register NTable ttable)
5501ab64890Smrg{
5511ab64890Smrg    register NTable fentry, nfentry;
5521ab64890Smrg    register NTable *prev;
5531ab64890Smrg    register NTable *bucket;
5541ab64890Smrg    register NTable tentry;
5551ab64890Smrg    register int i;
5561ab64890Smrg
5571ab64890Smrg    for (i = ftable->mask, bucket = NodeBuckets(ftable); i >= 0; i--) {
5581ab64890Smrg	for (fentry = *bucket++; fentry; fentry = nfentry) {
5591ab64890Smrg	    prev = &NodeHash(ttable, fentry->name);
5601ab64890Smrg	    tentry = *prev;
5611ab64890Smrg	    *prev = fentry;
5621ab64890Smrg	    /* chain on all with same name, to preserve invariant order */
5631ab64890Smrg	    while ((nfentry = fentry->next) && nfentry->name == fentry->name)
5641ab64890Smrg		fentry = nfentry;
5651ab64890Smrg	    fentry->next = tentry;
5661ab64890Smrg	}
5671ab64890Smrg    }
5681ab64890Smrg    Xfree((char *)ftable);
5691ab64890Smrg}
5701ab64890Smrg
5711ab64890Smrg/* grow the table, based on current number of entries */
5721ab64890Smrgstatic void GrowTable(
5731ab64890Smrg    NTable *prev)
5741ab64890Smrg{
5751ab64890Smrg    register NTable table;
5761ab64890Smrg    register int i;
5771ab64890Smrg
5781ab64890Smrg    table = *prev;
5791ab64890Smrg    i = table->mask;
5801ab64890Smrg    if (i == 255) /* biggest it gets */
5811ab64890Smrg	return;
5821ab64890Smrg    while (i < 255 && GrowthPred(table->entries, i))
5831ab64890Smrg	i = (i << 1) + 1;
5841ab64890Smrg    i++; /* i is now the new size */
5851ab64890Smrg    if (table->leaf) {
5861ab64890Smrg	register LTable ltable;
5871ab64890Smrg	LTableRec otable;
5881ab64890Smrg
5891ab64890Smrg	ltable = (LTable)table;
5901ab64890Smrg	/* cons up a copy to make MoveValues look symmetric */
5911ab64890Smrg	otable = *ltable;
5921ab64890Smrg	ltable->buckets = (VEntry *)Xmalloc(i * sizeof(VEntry));
5931ab64890Smrg	if (!ltable->buckets) {
5941ab64890Smrg	    ltable->buckets = otable.buckets;
5951ab64890Smrg	    return;
5961ab64890Smrg	}
5971ab64890Smrg	ltable->table.mask = i - 1;
5981ab64890Smrg	bzero((char *)ltable->buckets, i * sizeof(VEntry));
5991ab64890Smrg	MoveValues(&otable, ltable);
6001ab64890Smrg    } else {
6011ab64890Smrg	register NTable ntable;
6021ab64890Smrg
6031ab64890Smrg	ntable = (NTable)Xmalloc(sizeof(NTableRec) + i * sizeof(NTable));
6041ab64890Smrg	if (!ntable)
6051ab64890Smrg	    return;
6061ab64890Smrg	*ntable = *table;
6071ab64890Smrg	ntable->mask = i - 1;
6081ab64890Smrg	bzero((char *)NodeBuckets(ntable), i * sizeof(NTable));
6091ab64890Smrg	*prev = ntable;
6101ab64890Smrg	MoveTables(table, ntable);
6111ab64890Smrg    }
6121ab64890Smrg}
6131ab64890Smrg
6141ab64890Smrg/* merge values from ftable into *pprev, destroy ftable in the process */
6151ab64890Smrgstatic void MergeValues(
6161ab64890Smrg    LTable ftable,
6171ab64890Smrg    NTable *pprev,
6181ab64890Smrg    Bool override)
6191ab64890Smrg{
6201ab64890Smrg    register VEntry fentry, tentry;
6211ab64890Smrg    register VEntry *prev;
6221ab64890Smrg    register LTable ttable;
6231ab64890Smrg    VEntry *bucket;
6241ab64890Smrg    int i;
6251ab64890Smrg    register XrmQuark q;
6261ab64890Smrg
6271ab64890Smrg    ttable = (LTable)*pprev;
6281ab64890Smrg    if (ftable->table.hasloose)
6291ab64890Smrg	ttable->table.hasloose = 1;
6301ab64890Smrg    for (i = ftable->table.mask, bucket = ftable->buckets;
6311ab64890Smrg	 i >= 0;
6321ab64890Smrg	 i--, bucket++) {
6331ab64890Smrg	for (fentry = *bucket; fentry; ) {
6341ab64890Smrg	    q = fentry->name;
6351ab64890Smrg	    prev = &LeafHash(ttable, q);
6361ab64890Smrg	    tentry = *prev;
6371ab64890Smrg	    while (tentry && tentry->name != q)
6381ab64890Smrg		tentry = *(prev = &tentry->next);
6391ab64890Smrg	    /* note: test intentionally uses fentry->name instead of q */
6401ab64890Smrg	    /* permits serendipitous inserts */
6411ab64890Smrg	    while (tentry && tentry->name == fentry->name) {
6421ab64890Smrg		/* if tentry is earlier, skip it */
6431ab64890Smrg		if (!fentry->tight && tentry->tight) {
6441ab64890Smrg		    tentry = *(prev = &tentry->next);
6451ab64890Smrg		    continue;
6461ab64890Smrg		}
6471ab64890Smrg		if (fentry->tight != tentry->tight) {
6481ab64890Smrg		    /* no match, chain in fentry */
6491ab64890Smrg		    *prev = fentry;
6501ab64890Smrg		    prev = &fentry->next;
6511ab64890Smrg		    fentry = *prev;
6521ab64890Smrg		    *prev = tentry;
6531ab64890Smrg		    ttable->table.entries++;
6541ab64890Smrg		} else if (override) {
6551ab64890Smrg		    /* match, chain in fentry, splice out and free tentry */
6561ab64890Smrg		    *prev = fentry;
6571ab64890Smrg		    prev = &fentry->next;
6581ab64890Smrg		    fentry = *prev;
6591ab64890Smrg		    *prev = tentry->next;
6601ab64890Smrg		    /* free the overridden entry */
6611ab64890Smrg		    Xfree((char *)tentry);
6621ab64890Smrg		    /* get next tentry */
6631ab64890Smrg		    tentry = *prev;
6641ab64890Smrg		} else {
6651ab64890Smrg		    /* match, discard fentry */
6661ab64890Smrg		    prev = &tentry->next;
6671ab64890Smrg		    tentry = fentry; /* use as a temp var */
6681ab64890Smrg		    fentry = fentry->next;
6691ab64890Smrg		    /* free the overpowered entry */
6701ab64890Smrg		    Xfree((char *)tentry);
6711ab64890Smrg		    /* get next tentry */
6721ab64890Smrg		    tentry = *prev;
6731ab64890Smrg		}
6741ab64890Smrg		if (!fentry)
6751ab64890Smrg		    break;
6761ab64890Smrg	    }
6771ab64890Smrg	    /* at this point, tentry cannot match any fentry named q */
6781ab64890Smrg	    /* chain in all bindings together, preserve invariant order */
6791ab64890Smrg	    while (fentry && fentry->name == q) {
6801ab64890Smrg		*prev = fentry;
6811ab64890Smrg		prev = &fentry->next;
6821ab64890Smrg		fentry = *prev;
6831ab64890Smrg		*prev = tentry;
6841ab64890Smrg		ttable->table.entries++;
6851ab64890Smrg	    }
6861ab64890Smrg	}
6871ab64890Smrg    }
6881ab64890Smrg    Xfree((char *)ftable->buckets);
6891ab64890Smrg    Xfree((char *)ftable);
6901ab64890Smrg    /* resize if necessary, now that we're all done */
6911ab64890Smrg    GROW(pprev);
6921ab64890Smrg}
6931ab64890Smrg
6941ab64890Smrg/* merge tables from ftable into *pprev, destroy ftable in the process */
6951ab64890Smrgstatic void MergeTables(
6961ab64890Smrg    NTable ftable,
6971ab64890Smrg    NTable *pprev,
6981ab64890Smrg    Bool override)
6991ab64890Smrg{
7001ab64890Smrg    register NTable fentry, tentry;
7011ab64890Smrg    NTable nfentry;
7021ab64890Smrg    register NTable *prev;
7031ab64890Smrg    register NTable ttable;
7041ab64890Smrg    NTable *bucket;
7051ab64890Smrg    int i;
7061ab64890Smrg    register XrmQuark q;
7071ab64890Smrg
7081ab64890Smrg    ttable = *pprev;
7091ab64890Smrg    if (ftable->hasloose)
7101ab64890Smrg	ttable->hasloose = 1;
7111ab64890Smrg    if (ftable->hasany)
7121ab64890Smrg	ttable->hasany = 1;
7131ab64890Smrg    for (i = ftable->mask, bucket = NodeBuckets(ftable);
7141ab64890Smrg	 i >= 0;
7151ab64890Smrg	 i--, bucket++) {
7161ab64890Smrg	for (fentry = *bucket; fentry; ) {
7171ab64890Smrg	    q = fentry->name;
7181ab64890Smrg	    prev = &NodeHash(ttable, q);
7191ab64890Smrg	    tentry = *prev;
7201ab64890Smrg	    while (tentry && tentry->name != q)
7211ab64890Smrg		tentry = *(prev = &tentry->next);
7221ab64890Smrg	    /* note: test intentionally uses fentry->name instead of q */
7231ab64890Smrg	    /* permits serendipitous inserts */
7241ab64890Smrg	    while (tentry && tentry->name == fentry->name) {
7251ab64890Smrg		/* if tentry is earlier, skip it */
7261ab64890Smrg		if ((fentry->leaf && !tentry->leaf) ||
7271ab64890Smrg		    (!fentry->tight && tentry->tight &&
7281ab64890Smrg		     (fentry->leaf || !tentry->leaf))) {
7291ab64890Smrg		    tentry = *(prev = &tentry->next);
7301ab64890Smrg		    continue;
7311ab64890Smrg		}
7321ab64890Smrg		nfentry = fentry->next;
7331ab64890Smrg		if (fentry->leaf != tentry->leaf ||
7341ab64890Smrg		    fentry->tight != tentry->tight) {
7351ab64890Smrg		    /* no match, just chain in */
7361ab64890Smrg		    *prev = fentry;
7371ab64890Smrg		    *(prev = &fentry->next) = tentry;
7381ab64890Smrg		    ttable->entries++;
7391ab64890Smrg		} else {
7401ab64890Smrg		    if (fentry->leaf)
7411ab64890Smrg			MergeValues((LTable)fentry, prev, override);
7421ab64890Smrg		    else
7431ab64890Smrg			MergeTables(fentry, prev, override);
7441ab64890Smrg		    /* bump to next tentry */
7451ab64890Smrg		    tentry = *(prev = &(*prev)->next);
7461ab64890Smrg		}
7471ab64890Smrg		/* bump to next fentry */
7481ab64890Smrg		fentry = nfentry;
7491ab64890Smrg		if (!fentry)
7501ab64890Smrg		    break;
7511ab64890Smrg	    }
7521ab64890Smrg	    /* at this point, tentry cannot match any fentry named q */
7531ab64890Smrg	    /* chain in all bindings together, preserve invariant order */
7541ab64890Smrg	    while (fentry && fentry->name == q) {
7551ab64890Smrg		*prev = fentry;
7561ab64890Smrg		prev = &fentry->next;
7571ab64890Smrg		fentry = *prev;
7581ab64890Smrg		*prev = tentry;
7591ab64890Smrg		ttable->entries++;
7601ab64890Smrg	    }
7611ab64890Smrg	}
7621ab64890Smrg    }
7631ab64890Smrg    Xfree((char *)ftable);
7641ab64890Smrg    /* resize if necessary, now that we're all done */
7651ab64890Smrg    GROW(pprev);
7661ab64890Smrg}
7671ab64890Smrg
7681ab64890Smrgvoid XrmCombineDatabase(
7691ab64890Smrg    XrmDatabase	from, XrmDatabase *into,
7701ab64890Smrg    Bool override)
7711ab64890Smrg{
7721ab64890Smrg    register NTable *prev;
7731ab64890Smrg    register NTable ftable, ttable, nftable;
7741ab64890Smrg
7751ab64890Smrg    if (!*into) {
7761ab64890Smrg	*into = from;
7771ab64890Smrg    } else if (from) {
7781ab64890Smrg	_XLockMutex(&from->linfo);
7791ab64890Smrg	_XLockMutex(&(*into)->linfo);
7801ab64890Smrg	if ((ftable = from->table)) {
7811ab64890Smrg	    prev = &(*into)->table;
7821ab64890Smrg	    ttable = *prev;
7831ab64890Smrg	    if (!ftable->leaf) {
7841ab64890Smrg		nftable = ftable->next;
7851ab64890Smrg		if (ttable && !ttable->leaf) {
7861ab64890Smrg		    /* both have node tables, merge them */
7871ab64890Smrg		    MergeTables(ftable, prev, override);
7881ab64890Smrg		    /* bump to into's leaf table, if any */
7891ab64890Smrg		    ttable = *(prev = &(*prev)->next);
7901ab64890Smrg		} else {
7911ab64890Smrg		    /* into has no node table, link from's in */
7921ab64890Smrg		    *prev = ftable;
7931ab64890Smrg		    *(prev = &ftable->next) = ttable;
7941ab64890Smrg		}
7951ab64890Smrg		/* bump to from's leaf table, if any */
7961ab64890Smrg		ftable = nftable;
7971ab64890Smrg	    } else {
7981ab64890Smrg		/* bump to into's leaf table, if any */
7991ab64890Smrg		if (ttable && !ttable->leaf)
8001ab64890Smrg		    ttable = *(prev = &ttable->next);
8011ab64890Smrg	    }
8021ab64890Smrg	    if (ftable) {
8031ab64890Smrg		/* if into has a leaf, merge, else insert */
8041ab64890Smrg		if (ttable)
8051ab64890Smrg		    MergeValues((LTable)ftable, prev, override);
8061ab64890Smrg		else
8071ab64890Smrg		    *prev = ftable;
8081ab64890Smrg	    }
8091ab64890Smrg	}
8101ab64890Smrg	(from->methods->destroy)(from->mbstate);
8111ab64890Smrg	_XUnlockMutex(&from->linfo);
8121ab64890Smrg	_XFreeMutex(&from->linfo);
8131ab64890Smrg	Xfree((char *)from);
8141ab64890Smrg	_XUnlockMutex(&(*into)->linfo);
8151ab64890Smrg    }
8161ab64890Smrg}
8171ab64890Smrg
8181ab64890Smrgvoid XrmMergeDatabases(
8191ab64890Smrg    XrmDatabase	from, XrmDatabase *into)
8201ab64890Smrg{
8211ab64890Smrg    XrmCombineDatabase(from, into, True);
8221ab64890Smrg}
8231ab64890Smrg
8241ab64890Smrg/* store a value in the database, overriding any existing entry */
8251ab64890Smrgstatic void PutEntry(
8261ab64890Smrg    XrmDatabase		db,
8271ab64890Smrg    XrmBindingList	bindings,
8281ab64890Smrg    XrmQuarkList	quarks,
8291ab64890Smrg    XrmRepresentation	type,
8301ab64890Smrg    XrmValuePtr		value)
8311ab64890Smrg{
8321ab64890Smrg    register NTable *pprev, *prev;
8331ab64890Smrg    register NTable table;
8341ab64890Smrg    register XrmQuark q;
8351ab64890Smrg    register VEntry *vprev;
8361ab64890Smrg    register VEntry entry;
8371ab64890Smrg    NTable *nprev, *firstpprev;
8381ab64890Smrg
8391ab64890Smrg#define NEWTABLE(q,i) \
8401ab64890Smrg    table = (NTable)Xmalloc(sizeof(LTableRec)); \
8411ab64890Smrg    if (!table) \
8421ab64890Smrg	return; \
8431ab64890Smrg    table->name = q; \
8441ab64890Smrg    table->hasloose = 0; \
8451ab64890Smrg    table->hasany = 0; \
8461ab64890Smrg    table->mask = 0; \
8471ab64890Smrg    table->entries = 0; \
8481ab64890Smrg    if (quarks[i]) { \
8491ab64890Smrg	table->leaf = 0; \
8501ab64890Smrg	nprev = NodeBuckets(table); \
8511ab64890Smrg    } else { \
8521ab64890Smrg	table->leaf = 1; \
8531ab64890Smrg	if (!(nprev = (NTable *)Xmalloc(sizeof(VEntry *)))) \
8541ab64890Smrg	    return; \
8551ab64890Smrg	((LTable)table)->buckets = (VEntry *)nprev; \
8561ab64890Smrg    } \
8571ab64890Smrg    *nprev = (NTable)NULL; \
8581ab64890Smrg    table->next = *prev; \
8591ab64890Smrg    *prev = table
8601ab64890Smrg
8611ab64890Smrg    if (!db || !*quarks)
8621ab64890Smrg	return;
8631ab64890Smrg    table = *(prev = &db->table);
8641ab64890Smrg    /* if already at leaf, bump to the leaf table */
8651ab64890Smrg    if (!quarks[1] && table && !table->leaf)
8661ab64890Smrg	table = *(prev = &table->next);
8671ab64890Smrg    pprev = prev;
8681ab64890Smrg    if (!table || (quarks[1] && table->leaf)) {
8691ab64890Smrg	/* no top-level node table, create one and chain it in */
8701ab64890Smrg	NEWTABLE(NULLQUARK,1);
8711ab64890Smrg	table->tight = 1; /* arbitrary */
8721ab64890Smrg	prev = nprev;
8731ab64890Smrg    } else {
8741ab64890Smrg	/* search along until we need a value */
8751ab64890Smrg	while (quarks[1]) {
8761ab64890Smrg	    q = *quarks;
8771ab64890Smrg	    table = *(prev = &NodeHash(table, q));
8781ab64890Smrg	    while (table && table->name != q)
8791ab64890Smrg		table = *(prev = &table->next);
8801ab64890Smrg	    if (!table)
8811ab64890Smrg		break; /* not found */
8821ab64890Smrg	    if (quarks[2]) {
8831ab64890Smrg		if (table->leaf)
8841ab64890Smrg		    break; /* not found */
8851ab64890Smrg	    } else {
8861ab64890Smrg		if (!table->leaf) {
8871ab64890Smrg		    /* bump to leaf table, if any */
8881ab64890Smrg		    table = *(prev = &table->next);
8891ab64890Smrg		    if (!table || table->name != q)
8901ab64890Smrg			break; /* not found */
8911ab64890Smrg		    if (!table->leaf) {
8921ab64890Smrg			/* bump to leaf table, if any */
8931ab64890Smrg			table = *(prev = &table->next);
8941ab64890Smrg			if (!table || table->name != q)
8951ab64890Smrg			    break; /* not found */
8961ab64890Smrg		    }
8971ab64890Smrg		}
8981ab64890Smrg	    }
8991ab64890Smrg	    if (*bindings == XrmBindTightly) {
9001ab64890Smrg		if (!table->tight)
9011ab64890Smrg		    break; /* not found */
9021ab64890Smrg	    } else {
9031ab64890Smrg		if (table->tight) {
9041ab64890Smrg		    /* bump to loose table, if any */
9051ab64890Smrg		    table = *(prev = &table->next);
9061ab64890Smrg		    if (!table || table->name != q ||
9071ab64890Smrg			!quarks[2] != table->leaf)
9081ab64890Smrg			break; /* not found */
9091ab64890Smrg		}
9101ab64890Smrg	    }
9111ab64890Smrg	    /* found that one, bump to next quark */
9121ab64890Smrg	    pprev = prev;
9131ab64890Smrg	    quarks++;
9141ab64890Smrg	    bindings++;
9151ab64890Smrg	}
9161ab64890Smrg	if (!quarks[1]) {
9171ab64890Smrg	    /* found all the way to a leaf */
9181ab64890Smrg	    q = *quarks;
9191ab64890Smrg	    entry = *(vprev = &LeafHash((LTable)table, q));
9201ab64890Smrg	    while (entry && entry->name != q)
9211ab64890Smrg		entry = *(vprev = &entry->next);
9221ab64890Smrg	    /* if want loose and have tight, bump to next entry */
9231ab64890Smrg	    if (entry && *bindings == XrmBindLoosely && entry->tight)
9241ab64890Smrg		entry = *(vprev = &entry->next);
9251ab64890Smrg	    if (entry && entry->name == q &&
9261ab64890Smrg		(*bindings == XrmBindTightly) == entry->tight) {
9271ab64890Smrg		/* match, need to override */
9281ab64890Smrg		if ((type == XrmQString) == entry->string &&
9291ab64890Smrg		    entry->size == value->size) {
9301ab64890Smrg		    /* update type if not String, can be different */
9311ab64890Smrg		    if (!entry->string)
9321ab64890Smrg			RepType(entry) = type;
9331ab64890Smrg		    /* identical size, just overwrite value */
9341ab64890Smrg		    memcpy(RawValue(entry), (char *)value->addr, value->size);
9351ab64890Smrg		    return;
9361ab64890Smrg		}
9371ab64890Smrg		/* splice out and free old entry */
9381ab64890Smrg		*vprev = entry->next;
9391ab64890Smrg		Xfree((char *)entry);
9401ab64890Smrg		(*pprev)->entries--;
9411ab64890Smrg	    }
9421ab64890Smrg	    /* this is where to insert */
9431ab64890Smrg	    prev = (NTable *)vprev;
9441ab64890Smrg	}
9451ab64890Smrg    }
9461ab64890Smrg    /* keep the top table, because we may have to grow it */
9471ab64890Smrg    firstpprev = pprev;
9481ab64890Smrg    /* iterate until we get to the leaf */
9491ab64890Smrg    while (quarks[1]) {
9501ab64890Smrg	/* build a new table and chain it in */
9511ab64890Smrg	NEWTABLE(*quarks,2);
9521ab64890Smrg	if (*quarks++ == XrmQANY)
9531ab64890Smrg	    (*pprev)->hasany = 1;
9541ab64890Smrg	if (*bindings++ == XrmBindTightly) {
9551ab64890Smrg	    table->tight = 1;
9561ab64890Smrg	} else {
9571ab64890Smrg	    table->tight = 0;
9581ab64890Smrg	    (*pprev)->hasloose = 1;
9591ab64890Smrg	}
9601ab64890Smrg	(*pprev)->entries++;
9611ab64890Smrg	pprev = prev;
9621ab64890Smrg	prev = nprev;
9631ab64890Smrg    }
9641ab64890Smrg    /* now allocate the value entry */
9651ab64890Smrg    entry = (VEntry)Xmalloc(((type == XrmQString) ?
9661ab64890Smrg			     sizeof(VEntryRec) : sizeof(DEntryRec)) +
9671ab64890Smrg			    value->size);
9681ab64890Smrg    if (!entry)
9691ab64890Smrg	return;
9701ab64890Smrg    entry->name = q = *quarks;
9711ab64890Smrg    if (*bindings == XrmBindTightly) {
9721ab64890Smrg	entry->tight = 1;
9731ab64890Smrg    } else {
9741ab64890Smrg	entry->tight = 0;
9751ab64890Smrg	(*pprev)->hasloose = 1;
9761ab64890Smrg    }
9771ab64890Smrg    /* chain it in, with a bit of type cast ugliness */
9781ab64890Smrg    entry->next = *((VEntry *)prev);
9791ab64890Smrg    *((VEntry *)prev) = entry;
9801ab64890Smrg    entry->size = value->size;
9811ab64890Smrg    if (type == XrmQString) {
9821ab64890Smrg	entry->string = 1;
9831ab64890Smrg    } else {
9841ab64890Smrg	entry->string = 0;
9851ab64890Smrg	RepType(entry) = type;
9861ab64890Smrg    }
9871ab64890Smrg    /* save a copy of the value */
9881ab64890Smrg    memcpy(RawValue(entry), (char *)value->addr, value->size);
9891ab64890Smrg    (*pprev)->entries++;
9901ab64890Smrg    /* this is a new leaf, need to remember it for search lists */
9911ab64890Smrg    if (q > maxResourceQuark) {
9921ab64890Smrg	unsigned oldsize = (maxResourceQuark + 1) >> 3;
9931ab64890Smrg	unsigned size = ((q | 0x7f) + 1) >> 3; /* reallocate in chunks */
9941ab64890Smrg	if (resourceQuarks) {
9951ab64890Smrg	    unsigned char *prevQuarks = resourceQuarks;
9961ab64890Smrg
9971ab64890Smrg	    resourceQuarks = (unsigned char *)Xrealloc((char *)resourceQuarks,
9981ab64890Smrg						       size);
9991ab64890Smrg	    if (!resourceQuarks) {
10001ab64890Smrg		Xfree(prevQuarks);
10011ab64890Smrg	    }
10021ab64890Smrg	} else
10031ab64890Smrg	    resourceQuarks = (unsigned char *)Xmalloc(size);
10041ab64890Smrg	if (resourceQuarks) {
10051ab64890Smrg	    bzero((char *)&resourceQuarks[oldsize], size - oldsize);
10061ab64890Smrg	    maxResourceQuark = (size << 3) - 1;
10071ab64890Smrg	} else {
10081ab64890Smrg	    maxResourceQuark = -1;
10091ab64890Smrg	}
10101ab64890Smrg    }
10111ab64890Smrg    if (q > 0 && resourceQuarks)
10121ab64890Smrg	resourceQuarks[q >> 3] |= 1 << (q & 0x7);
10131ab64890Smrg    GROW(firstpprev);
10141ab64890Smrg
10151ab64890Smrg#undef NEWTABLE
10161ab64890Smrg}
10171ab64890Smrg
10181ab64890Smrgvoid XrmQPutResource(
10191ab64890Smrg    XrmDatabase		*pdb,
10201ab64890Smrg    XrmBindingList      bindings,
10211ab64890Smrg    XrmQuarkList	quarks,
10221ab64890Smrg    XrmRepresentation	type,
10231ab64890Smrg    XrmValuePtr		value)
10241ab64890Smrg{
10251ab64890Smrg    if (!*pdb) *pdb = NewDatabase();
10261ab64890Smrg    _XLockMutex(&(*pdb)->linfo);
10271ab64890Smrg    PutEntry(*pdb, bindings, quarks, type, value);
10281ab64890Smrg    _XUnlockMutex(&(*pdb)->linfo);
10291ab64890Smrg}
10301ab64890Smrg
10311ab64890Smrgvoid
10321ab64890SmrgXrmPutResource(
10331ab64890Smrg    XrmDatabase     *pdb,
10341ab64890Smrg    _Xconst char    *specifier,
10351ab64890Smrg    _Xconst char    *type,
10361ab64890Smrg    XrmValuePtr	    value)
10371ab64890Smrg{
10381ab64890Smrg    XrmBinding	    bindings[MAXDBDEPTH+1];
10391ab64890Smrg    XrmQuark	    quarks[MAXDBDEPTH+1];
10401ab64890Smrg
10411ab64890Smrg    if (!*pdb) *pdb = NewDatabase();
10421ab64890Smrg    _XLockMutex(&(*pdb)->linfo);
10431ab64890Smrg    XrmStringToBindingQuarkList(specifier, bindings, quarks);
10441ab64890Smrg    PutEntry(*pdb, bindings, quarks, XrmStringToQuark(type), value);
10451ab64890Smrg    _XUnlockMutex(&(*pdb)->linfo);
10461ab64890Smrg}
10471ab64890Smrg
10481ab64890Smrgvoid
10491ab64890SmrgXrmQPutStringResource(
10501ab64890Smrg    XrmDatabase     *pdb,
10511ab64890Smrg    XrmBindingList  bindings,
10521ab64890Smrg    XrmQuarkList    quarks,
10531ab64890Smrg    _Xconst char    *str)
10541ab64890Smrg{
10551ab64890Smrg    XrmValue	value;
10561ab64890Smrg
10571ab64890Smrg    if (!*pdb) *pdb = NewDatabase();
10581ab64890Smrg    value.addr = (XPointer) str;
10591ab64890Smrg    value.size = strlen(str)+1;
10601ab64890Smrg    _XLockMutex(&(*pdb)->linfo);
10611ab64890Smrg    PutEntry(*pdb, bindings, quarks, XrmQString, &value);
10621ab64890Smrg    _XUnlockMutex(&(*pdb)->linfo);
10631ab64890Smrg}
10641ab64890Smrg
10651ab64890Smrg/*	Function Name: GetDatabase
10661ab64890Smrg *	Description: Parses a string and stores it as a database.
10671ab64890Smrg *	Arguments: db - the database.
10681ab64890Smrg *                 str - a pointer to the string containing the database.
10691ab64890Smrg *                 filename - source filename, if any.
10701ab64890Smrg *                 doall - whether to do all lines or just one
10711ab64890Smrg */
10721ab64890Smrg
10731ab64890Smrg/*
10741ab64890Smrg * This function is highly optimized to inline as much as possible.
10751ab64890Smrg * Be very careful with modifications, or simplifications, as they
10761ab64890Smrg * may adversely affect the performance.
10771ab64890Smrg *
10781ab64890Smrg * Chris Peterson, MIT X Consortium		5/17/90.
10791ab64890Smrg */
10801ab64890Smrg
10811ab64890Smrg/*
10821ab64890Smrg * Xlib spec says max 100 quarks in a lookup, will stop and return if
10831ab64890Smrg * return if any single production's lhs has more than 100 components.
10841ab64890Smrg */
10851ab64890Smrg#define QLIST_SIZE 100
10861ab64890Smrg
10871ab64890Smrg/*
10881ab64890Smrg * This should be big enough to handle things like the XKeysymDB or biggish
10891ab64890Smrg * ~/.Xdefaults or app-defaults files. Anything bigger will be allocated on
10901ab64890Smrg * the heap.
10911ab64890Smrg */
10921ab64890Smrg#define DEF_BUFF_SIZE 8192
10931ab64890Smrg
10941ab64890Smrgstatic void GetIncludeFile(
10951ab64890Smrg    XrmDatabase db,
10961ab64890Smrg    _Xconst char *base,
10971ab64890Smrg    _Xconst char *fname,
10981ab64890Smrg    int fnamelen);
10991ab64890Smrg
11001ab64890Smrgstatic void GetDatabase(
11011ab64890Smrg    XrmDatabase db,
11021ab64890Smrg    _Xconst register char *str,
11031ab64890Smrg    _Xconst char *filename,
11041ab64890Smrg    Bool doall)
11051ab64890Smrg{
11061ab64890Smrg    char *rhs;
11071ab64890Smrg    char *lhs, lhs_s[DEF_BUFF_SIZE];
11081ab64890Smrg    XrmQuark quarks[QLIST_SIZE + 1];	/* allow for a terminal NullQuark */
11091ab64890Smrg    XrmBinding bindings[QLIST_SIZE + 1];
11101ab64890Smrg
11111ab64890Smrg    register char *ptr;
11121ab64890Smrg    register XrmBits bits = 0;
11131ab64890Smrg    register char c;
11141ab64890Smrg    register Signature sig;
11151ab64890Smrg    register char *ptr_max;
11161ab64890Smrg    register int num_quarks;
11171ab64890Smrg    register XrmBindingList t_bindings;
11181ab64890Smrg
11191ab64890Smrg    int len, alloc_chars;
11201ab64890Smrg    unsigned long str_len;
11211ab64890Smrg    XrmValue value;
11221ab64890Smrg    Bool only_pcs;
11231ab64890Smrg    Bool dolines;
11241ab64890Smrg
11251ab64890Smrg    if (!db)
11261ab64890Smrg	return;
11271ab64890Smrg
11281ab64890Smrg    /*
11291ab64890Smrg     * if strlen (str) < DEF_BUFF_SIZE allocate buffers on the stack for
11301ab64890Smrg     * speed otherwise malloc the buffer. From a buffer overflow standpoint
11311ab64890Smrg     * we can be sure that neither: a) a component on the lhs, or b) a
11321ab64890Smrg     * value on the rhs, will be longer than the overall length of str,
11331ab64890Smrg     * i.e. strlen(str).
11341ab64890Smrg     *
11351ab64890Smrg     * This should give good performance when parsing "*foo: bar" type
11361ab64890Smrg     * databases as might be passed with -xrm command line options; but
11371ab64890Smrg     * with larger databases, e.g. .Xdefaults, app-defaults, or KeysymDB
11381ab64890Smrg     * files, the size of the buffers will be overly large. One way
11391ab64890Smrg     * around this would be to double-parse each production with a resulting
11401ab64890Smrg     * performance hit. In any event we can be assured that a lhs component
11411ab64890Smrg     * name or a rhs value won't be longer than str itself.
11421ab64890Smrg     */
11431ab64890Smrg
11441ab64890Smrg    str_len = strlen (str);
11451ab64890Smrg    if (DEF_BUFF_SIZE > str_len) lhs = lhs_s;
11461ab64890Smrg    else if ((lhs = (char*) Xmalloc (str_len)) == NULL)
11471ab64890Smrg	return;
11481ab64890Smrg
11491ab64890Smrg    alloc_chars = DEF_BUFF_SIZE < str_len ? str_len : DEF_BUFF_SIZE;
11501ab64890Smrg    if ((rhs = (char*) Xmalloc (alloc_chars)) == NULL) {
11511ab64890Smrg	if (lhs != lhs_s) Xfree (lhs);
11521ab64890Smrg	return;
11531ab64890Smrg    }
11541ab64890Smrg
11551ab64890Smrg    (*db->methods->mbinit)(db->mbstate);
11561ab64890Smrg    str--;
11571ab64890Smrg    dolines = True;
11581ab64890Smrg    while (!is_EOF(bits) && dolines) {
11591ab64890Smrg	dolines = doall;
11601ab64890Smrg
11611ab64890Smrg	/*
11621ab64890Smrg	 * First: Remove extra whitespace.
11631ab64890Smrg	 */
11641ab64890Smrg
11651ab64890Smrg	do {
11661ab64890Smrg	    bits = next_char(c, str);
11671ab64890Smrg	} while is_space(bits);
11681ab64890Smrg
11691ab64890Smrg	/*
11701ab64890Smrg	 * Ignore empty lines.
11711ab64890Smrg	 */
11721ab64890Smrg
11731ab64890Smrg	if (is_EOL(bits))
11741ab64890Smrg	    continue;		/* start a new line. */
11751ab64890Smrg
11761ab64890Smrg	/*
11771ab64890Smrg	 * Second: check the first character in a line to see if it is
11781ab64890Smrg	 * "!" signifying a comment, or "#" signifying a directive.
11791ab64890Smrg	 */
11801ab64890Smrg
11811ab64890Smrg	if (c == '!') { /* Comment, spin to next newline */
11821ab64890Smrg	    while (is_simple(bits = next_char(c, str))) {}
11831ab64890Smrg	    if (is_EOL(bits))
11841ab64890Smrg		continue;
11851ab64890Smrg	    while (!is_EOL(bits = next_mbchar(c, len, str))) {}
11861ab64890Smrg	    str--;
11871ab64890Smrg	    continue;		/* start a new line. */
11881ab64890Smrg	}
11891ab64890Smrg
11901ab64890Smrg	if (c == '#') { /* Directive */
11911ab64890Smrg	    /* remove extra whitespace */
11921ab64890Smrg	    only_pcs = True;
11931ab64890Smrg	    while (is_space(bits = next_char(c, str))) {};
11941ab64890Smrg	    /* only "include" directive is currently defined */
11951ab64890Smrg	    if (!strncmp(str, "include", 7)) {
11961ab64890Smrg		str += (7-1);
11971ab64890Smrg		/* remove extra whitespace */
11981ab64890Smrg		while (is_space(bits = next_char(c, str))) {};
11991ab64890Smrg		/* must have a starting " */
12001ab64890Smrg		if (c == '"') {
12011ab64890Smrg		    _Xconst char *fname = str+1;
12021ab64890Smrg		    len = 0;
12031ab64890Smrg		    do {
12041ab64890Smrg			if (only_pcs) {
12051ab64890Smrg			    bits = next_char(c, str);
12061ab64890Smrg			    if (is_nonpcs(bits))
12071ab64890Smrg				only_pcs = False;
12081ab64890Smrg			}
12091ab64890Smrg			if (!only_pcs)
12101ab64890Smrg			    bits = next_mbchar(c, len, str);
12111ab64890Smrg		    } while (c != '"' && !is_EOL(bits));
12121ab64890Smrg		    /* must have an ending " */
12131ab64890Smrg		    if (c == '"')
12141ab64890Smrg			GetIncludeFile(db, filename, fname, str - len - fname);
12151ab64890Smrg		}
12161ab64890Smrg	    }
12171ab64890Smrg	    /* spin to next newline */
12181ab64890Smrg	    if (only_pcs) {
12191ab64890Smrg		while (is_simple(bits))
12201ab64890Smrg		    bits = next_char(c, str);
12211ab64890Smrg		if (is_EOL(bits))
12221ab64890Smrg		    continue;
12231ab64890Smrg	    }
12241ab64890Smrg	    while (!is_EOL(bits))
12251ab64890Smrg		bits = next_mbchar(c, len, str);
12261ab64890Smrg	    str--;
12271ab64890Smrg	    continue;		/* start a new line. */
12281ab64890Smrg	}
12291ab64890Smrg
12301ab64890Smrg	/*
12311ab64890Smrg	 * Third: loop through the LHS of the resource specification
12321ab64890Smrg	 * storing characters and converting this to a Quark.
12331ab64890Smrg	 */
12341ab64890Smrg
12351ab64890Smrg	num_quarks = 0;
12361ab64890Smrg	t_bindings = bindings;
12371ab64890Smrg
12381ab64890Smrg	sig = 0;
12391ab64890Smrg	ptr = lhs;
12401ab64890Smrg	*t_bindings = XrmBindTightly;
12411ab64890Smrg	for(;;) {
12421ab64890Smrg	    if (!is_binding(bits)) {
12431ab64890Smrg		while (!is_EOQ(bits)) {
12441ab64890Smrg		    *ptr++ = c;
12451ab64890Smrg		    sig = (sig << 1) + c; /* Compute the signature. */
12461ab64890Smrg		    bits = next_char(c, str);
12471ab64890Smrg		}
12481ab64890Smrg
12491ab64890Smrg		quarks[num_quarks++] =
12501ab64890Smrg			_XrmInternalStringToQuark(lhs, ptr - lhs, sig, False);
12511ab64890Smrg
12521ab64890Smrg		if (num_quarks > QLIST_SIZE) {
12531ab64890Smrg		    Xfree(rhs);
12541ab64890Smrg		    if (lhs != lhs_s) Xfree (lhs);
12551ab64890Smrg		    (*db->methods->mbfinish)(db->mbstate);
12561ab64890Smrg		    return;
12571ab64890Smrg		}
12581ab64890Smrg
12591ab64890Smrg		if (is_separator(bits))  {
12601ab64890Smrg		    if (!is_space(bits))
12611ab64890Smrg			break;
12621ab64890Smrg
12631ab64890Smrg		    /* Remove white space */
12641ab64890Smrg		    do {
12651ab64890Smrg			*ptr++ = c;
12661ab64890Smrg			sig = (sig << 1) + c; /* Compute the signature. */
12671ab64890Smrg		    } while (is_space(bits = next_char(c, str)));
12681ab64890Smrg
12691ab64890Smrg		    /*
12701ab64890Smrg		     * The spec doesn't permit it, but support spaces
12711ab64890Smrg		     * internal to resource name/class
12721ab64890Smrg		     */
12731ab64890Smrg
12741ab64890Smrg		    if (is_separator(bits))
12751ab64890Smrg			break;
12761ab64890Smrg		    num_quarks--;
12771ab64890Smrg		    continue;
12781ab64890Smrg		}
12791ab64890Smrg
12801ab64890Smrg		if (c == '.')
12811ab64890Smrg		    *(++t_bindings) = XrmBindTightly;
12821ab64890Smrg		else
12831ab64890Smrg		    *(++t_bindings) = XrmBindLoosely;
12841ab64890Smrg
12851ab64890Smrg		sig = 0;
12861ab64890Smrg		ptr = lhs;
12871ab64890Smrg	    }
12881ab64890Smrg	    else {
12891ab64890Smrg		/*
12901ab64890Smrg		 * Magic unspecified feature #254.
12911ab64890Smrg		 *
12921ab64890Smrg		 * If two separators appear with no Text between them then
12931ab64890Smrg		 * ignore them.
12941ab64890Smrg		 *
12951ab64890Smrg		 * If anyone of those separators is a '*' then the binding
12961ab64890Smrg		 * will be loose, otherwise it will be tight.
12971ab64890Smrg		 */
12981ab64890Smrg
12991ab64890Smrg		if (c == '*')
13001ab64890Smrg		    *t_bindings = XrmBindLoosely;
13011ab64890Smrg	    }
13021ab64890Smrg
13031ab64890Smrg	    bits = next_char(c, str);
13041ab64890Smrg	}
13051ab64890Smrg
13061ab64890Smrg	quarks[num_quarks] = NULLQUARK;
13071ab64890Smrg
13081ab64890Smrg	/*
13091ab64890Smrg	 * Make sure that there is a ':' in this line.
13101ab64890Smrg	 */
13111ab64890Smrg
13121ab64890Smrg	if (c != ':') {
13131ab64890Smrg	    char oldc;
13141ab64890Smrg
13151ab64890Smrg	    /*
13161ab64890Smrg	     * A parsing error has occured, toss everything on the line
13171ab64890Smrg	     * a new_line can still be escaped with a '\'.
13181ab64890Smrg	     */
13191ab64890Smrg
13201ab64890Smrg	    while (is_normal(bits))
13211ab64890Smrg		bits = next_char(c, str);
13221ab64890Smrg	    if (is_EOL(bits))
13231ab64890Smrg		continue;
13241ab64890Smrg	    bits = next_mbchar(c, len, str);
13251ab64890Smrg	    do {
13261ab64890Smrg		oldc = c;
13271ab64890Smrg		bits = next_mbchar(c, len, str);
13281ab64890Smrg	    } while (c && (c != '\n' || oldc == '\\'));
13291ab64890Smrg	    str--;
13301ab64890Smrg	    continue;
13311ab64890Smrg	}
13321ab64890Smrg
13331ab64890Smrg	/*
13341ab64890Smrg	 * I now have a quark and binding list for the entire left hand
13351ab64890Smrg	 * side.  "c" currently points to the ":" separating the left hand
13361ab64890Smrg	 * side for the right hand side.  It is time to begin processing
13371ab64890Smrg	 * the right hand side.
13381ab64890Smrg	 */
13391ab64890Smrg
13401ab64890Smrg	/*
13411ab64890Smrg	 * Fourth: Remove more whitespace
13421ab64890Smrg	 */
13431ab64890Smrg
13441ab64890Smrg	for(;;) {
13451ab64890Smrg	    if (is_space(bits = next_char(c, str)))
13461ab64890Smrg		continue;
13471ab64890Smrg	    if (c != '\\')
13481ab64890Smrg		break;
13491ab64890Smrg	    bits = next_char(c, str);
13501ab64890Smrg	    if (c == '\n')
13511ab64890Smrg		continue;
13521ab64890Smrg	    str--;
13531ab64890Smrg	    bits = BSLASH;
13541ab64890Smrg	    c = '\\';
13551ab64890Smrg	    break;
13561ab64890Smrg	}
13571ab64890Smrg
13581ab64890Smrg	/*
13591ab64890Smrg	 * Fifth: Process the right hand side.
13601ab64890Smrg	 */
13611ab64890Smrg
13621ab64890Smrg	ptr = rhs;
13631ab64890Smrg	ptr_max = ptr + alloc_chars - 4;
13641ab64890Smrg	only_pcs = True;
13651ab64890Smrg	len = 1;
13661ab64890Smrg
13671ab64890Smrg	for(;;) {
13681ab64890Smrg
13691ab64890Smrg	    /*
13701ab64890Smrg	     * Tight loop for the normal case:  Non backslash, non-end of value
13711ab64890Smrg	     * character that will fit into the allocated buffer.
13721ab64890Smrg	     */
13731ab64890Smrg
13741ab64890Smrg	    if (only_pcs) {
13751ab64890Smrg		while (is_normal(bits) && ptr < ptr_max) {
13761ab64890Smrg		    *ptr++ = c;
13771ab64890Smrg		    bits = next_char(c, str);
13781ab64890Smrg		}
13791ab64890Smrg		if (is_EOL(bits))
13801ab64890Smrg		    break;
13811ab64890Smrg		if (is_nonpcs(bits)) {
13821ab64890Smrg		    only_pcs = False;
13831ab64890Smrg		    bits = next_mbchar(c, len, str);
13841ab64890Smrg		}
13851ab64890Smrg	    }
13861ab64890Smrg	    while (!is_special(bits) && ptr + len <= ptr_max) {
13871ab64890Smrg		len = -len;
13881ab64890Smrg		while (len)
13891ab64890Smrg		    *ptr++ = str[len++];
13901ab64890Smrg		if (*str == '\0') {
13911ab64890Smrg		    bits = EOS;
13921ab64890Smrg		    break;
13931ab64890Smrg		}
13941ab64890Smrg		bits = next_mbchar(c, len, str);
13951ab64890Smrg	    }
13961ab64890Smrg
13971ab64890Smrg	    if (is_EOL(bits)) {
13981ab64890Smrg		str--;
13991ab64890Smrg		break;
14001ab64890Smrg	    }
14011ab64890Smrg
14021ab64890Smrg	    if (c == '\\') {
14031ab64890Smrg		/*
14041ab64890Smrg		 * We need to do some magic after a backslash.
14051ab64890Smrg		 */
14061ab64890Smrg		Bool read_next = True;
14071ab64890Smrg
14081ab64890Smrg		if (only_pcs) {
14091ab64890Smrg		    bits = next_char(c, str);
14101ab64890Smrg		    if (is_nonpcs(bits))
14111ab64890Smrg			only_pcs = False;
14121ab64890Smrg		}
14131ab64890Smrg		if (!only_pcs)
14141ab64890Smrg		    bits = next_mbchar(c, len, str);
14151ab64890Smrg
14161ab64890Smrg		if (is_EOL(bits)) {
14171ab64890Smrg		    if (is_EOF(bits))
14181ab64890Smrg			continue;
14191ab64890Smrg		} else if (c == 'n') {
14201ab64890Smrg		    /*
14211ab64890Smrg		     * "\n" means insert a newline.
14221ab64890Smrg		     */
14231ab64890Smrg		    *ptr++ = '\n';
14241ab64890Smrg		} else if (c == '\\') {
14251ab64890Smrg		    /*
14261ab64890Smrg		     * "\\" completes to just one backslash.
14271ab64890Smrg		     */
14281ab64890Smrg		    *ptr++ = '\\';
14291ab64890Smrg		} else {
14301ab64890Smrg		    /*
14311ab64890Smrg		     * pick up to three octal digits after the '\'.
14321ab64890Smrg		     */
14331ab64890Smrg		    char temp[3];
14341ab64890Smrg		    int count = 0;
14351ab64890Smrg		    while (is_odigit(bits) && count < 3) {
14361ab64890Smrg			temp[count++] = c;
14371ab64890Smrg			if (only_pcs) {
14381ab64890Smrg			    bits = next_char(c, str);
14391ab64890Smrg			    if (is_nonpcs(bits))
14401ab64890Smrg				only_pcs = False;
14411ab64890Smrg			}
14421ab64890Smrg			if (!only_pcs)
14431ab64890Smrg			    bits = next_mbchar(c, len, str);
14441ab64890Smrg		    }
14451ab64890Smrg
14461ab64890Smrg		    /*
14471ab64890Smrg		     * If we found three digits then insert that octal code
14481ab64890Smrg		     * into the value string as a character.
14491ab64890Smrg		     */
14501ab64890Smrg
14511ab64890Smrg		    if (count == 3) {
14521ab64890Smrg			*ptr++ = (unsigned char) ((temp[0] - '0') * 0100 +
14531ab64890Smrg						  (temp[1] - '0') * 010 +
14541ab64890Smrg						  (temp[2] - '0'));
14551ab64890Smrg		    }
14561ab64890Smrg		    else {
14571ab64890Smrg			int tcount;
14581ab64890Smrg
14591ab64890Smrg			/*
14601ab64890Smrg			 * Otherwise just insert those characters into the
14611ab64890Smrg			 * string, since no special processing is needed on
14621ab64890Smrg			 * numerics we can skip the special processing.
14631ab64890Smrg			 */
14641ab64890Smrg
14651ab64890Smrg			for (tcount = 0; tcount < count; tcount++) {
14661ab64890Smrg			    *ptr++ = temp[tcount]; /* print them in
14671ab64890Smrg						      the correct order */
14681ab64890Smrg			}
14691ab64890Smrg		    }
14701ab64890Smrg		    read_next = False;
14711ab64890Smrg		}
14721ab64890Smrg		if (read_next) {
14731ab64890Smrg		    if (only_pcs) {
14741ab64890Smrg			bits = next_char(c, str);
14751ab64890Smrg			if (is_nonpcs(bits))
14761ab64890Smrg			    only_pcs = False;
14771ab64890Smrg		    }
14781ab64890Smrg		    if (!only_pcs)
14791ab64890Smrg			bits = next_mbchar(c, len, str);
14801ab64890Smrg		}
14811ab64890Smrg	    }
14821ab64890Smrg
14831ab64890Smrg	    /*
14841ab64890Smrg	     * It is important to make sure that there is room for at least
14851ab64890Smrg	     * four more characters in the buffer, since I can add that
14861ab64890Smrg	     * many characters into the buffer after a backslash has occured.
14871ab64890Smrg	     */
14881ab64890Smrg
14891ab64890Smrg	    if (ptr + len > ptr_max) {
14901ab64890Smrg		char * temp_str;
14911ab64890Smrg
14921ab64890Smrg		alloc_chars += BUFSIZ/10;
14931ab64890Smrg		temp_str = Xrealloc(rhs, sizeof(char) * alloc_chars);
14941ab64890Smrg
14951ab64890Smrg		if (!temp_str) {
14961ab64890Smrg		    Xfree(rhs);
14971ab64890Smrg		    if (lhs != lhs_s) Xfree (lhs);
14981ab64890Smrg		    (*db->methods->mbfinish)(db->mbstate);
14991ab64890Smrg		    return;
15001ab64890Smrg		}
15011ab64890Smrg
15021ab64890Smrg		ptr = temp_str + (ptr - rhs); /* reset pointer. */
15031ab64890Smrg		rhs = temp_str;
15041ab64890Smrg		ptr_max = rhs + alloc_chars - 4;
15051ab64890Smrg	    }
15061ab64890Smrg	}
15071ab64890Smrg
15081ab64890Smrg	/*
15091ab64890Smrg	 * Lastly: Terminate the value string, and store this entry
15101ab64890Smrg	 * 	   into the database.
15111ab64890Smrg	 */
15121ab64890Smrg
15131ab64890Smrg	*ptr++ = '\0';
15141ab64890Smrg
15151ab64890Smrg	/* Store it in database */
15161ab64890Smrg	value.size = ptr - rhs;
15171ab64890Smrg	value.addr = (XPointer) rhs;
15181ab64890Smrg
15191ab64890Smrg	PutEntry(db, bindings, quarks, XrmQString, &value);
15201ab64890Smrg    }
15211ab64890Smrg
15221ab64890Smrg    if (lhs != lhs_s) Xfree (lhs);
15231ab64890Smrg    Xfree (rhs);
15241ab64890Smrg
15251ab64890Smrg    (*db->methods->mbfinish)(db->mbstate);
15261ab64890Smrg}
15271ab64890Smrg
15281ab64890Smrgvoid
15291ab64890SmrgXrmPutStringResource(
15301ab64890Smrg    XrmDatabase *pdb,
15311ab64890Smrg    _Xconst char*specifier,
15321ab64890Smrg    _Xconst char*str)
15331ab64890Smrg{
15341ab64890Smrg    XrmValue	value;
15351ab64890Smrg    XrmBinding	bindings[MAXDBDEPTH+1];
15361ab64890Smrg    XrmQuark	quarks[MAXDBDEPTH+1];
15371ab64890Smrg
15381ab64890Smrg    if (!*pdb) *pdb = NewDatabase();
15391ab64890Smrg    XrmStringToBindingQuarkList(specifier, bindings, quarks);
15401ab64890Smrg    value.addr = (XPointer) str;
15411ab64890Smrg    value.size = strlen(str)+1;
15421ab64890Smrg    _XLockMutex(&(*pdb)->linfo);
15431ab64890Smrg    PutEntry(*pdb, bindings, quarks, XrmQString, &value);
15441ab64890Smrg    _XUnlockMutex(&(*pdb)->linfo);
15451ab64890Smrg}
15461ab64890Smrg
15471ab64890Smrg
15481ab64890Smrgvoid
15491ab64890SmrgXrmPutLineResource(
15501ab64890Smrg    XrmDatabase *pdb,
15511ab64890Smrg    _Xconst char*line)
15521ab64890Smrg{
15531ab64890Smrg    if (!*pdb) *pdb = NewDatabase();
15541ab64890Smrg    _XLockMutex(&(*pdb)->linfo);
15551ab64890Smrg    GetDatabase(*pdb, line, (char *)NULL, False);
15561ab64890Smrg    _XUnlockMutex(&(*pdb)->linfo);
15571ab64890Smrg}
15581ab64890Smrg
15591ab64890SmrgXrmDatabase
15601ab64890SmrgXrmGetStringDatabase(
15611ab64890Smrg    _Xconst char    *data)
15621ab64890Smrg{
15631ab64890Smrg    XrmDatabase     db;
15641ab64890Smrg
15651ab64890Smrg    db = NewDatabase();
15661ab64890Smrg    _XLockMutex(&db->linfo);
15671ab64890Smrg    GetDatabase(db, data, (char *)NULL, True);
15681ab64890Smrg    _XUnlockMutex(&db->linfo);
15691ab64890Smrg    return db;
15701ab64890Smrg}
15711ab64890Smrg
15721ab64890Smrg/*	Function Name: ReadInFile
15731ab64890Smrg *	Description: Reads the file into a buffer.
15741ab64890Smrg *	Arguments: filename - the name of the file.
15751ab64890Smrg *	Returns: An allocated string containing the contents of the file.
15761ab64890Smrg */
15771ab64890Smrg
15781ab64890Smrgstatic char *
15791ab64890SmrgReadInFile(_Xconst char *filename)
15801ab64890Smrg{
15811ab64890Smrg    register int fd, size;
15821ab64890Smrg    char * filebuf;
15831ab64890Smrg
15841ab64890Smrg#ifdef __UNIXOS2__
15851ab64890Smrg    filename = __XOS2RedirRoot(filename);
15861ab64890Smrg#endif
15871ab64890Smrg
15881ab64890Smrg    /*
15891ab64890Smrg     * MS-Windows and OS/2 note: Default open mode includes O_TEXT
15901ab64890Smrg     */
15911ab64890Smrg    if ( (fd = _XOpenFile (filename, O_RDONLY)) == -1 )
15921ab64890Smrg	return (char *)NULL;
15931ab64890Smrg
15941ab64890Smrg    /*
15951ab64890Smrg     * MS-Windows and OS/2 note: depending on how the sources are
15961ab64890Smrg     * untarred, the newlines in resource files may or may not have
15971ab64890Smrg     * been expanded to CRLF. Either way the size returned by fstat
15981ab64890Smrg     * is sufficient to read the file into because in text-mode any
15991ab64890Smrg     * CRLFs in a file will be converted to newlines (LF) with the
16001ab64890Smrg     * result that the number of bytes actually read with be <=
16011ab64890Smrg     * to the size returned by fstat.
16021ab64890Smrg     */
16031ab64890Smrg    GetSizeOfFile(fd, size);
16041ab64890Smrg
16051ab64890Smrg    if (!(filebuf = Xmalloc(size + 1))) { /* leave room for '\0' */
16061ab64890Smrg	close(fd);
16071ab64890Smrg	return (char *)NULL;
16081ab64890Smrg    }
16091ab64890Smrg    size = read (fd, filebuf, size);
16101ab64890Smrg
16111ab64890Smrg#ifdef __UNIXOS2__
16121ab64890Smrg    { /* kill CRLF */
16131ab64890Smrg      int i,k;
16141ab64890Smrg      for (i=k=0; i<size; i++)
16151ab64890Smrg	if (filebuf[i] != 0x0d) {
16161ab64890Smrg	   filebuf[k++] = filebuf[i];
16171ab64890Smrg	}
16181ab64890Smrg	filebuf[k] = 0;
16191ab64890Smrg    }
16201ab64890Smrg#endif
16211ab64890Smrg
16221ab64890Smrg    if (size < 0) {
16231ab64890Smrg	close (fd);
16241ab64890Smrg	Xfree(filebuf);
16251ab64890Smrg	return (char *)NULL;
16261ab64890Smrg    }
16271ab64890Smrg    close (fd);
16281ab64890Smrg
16291ab64890Smrg    filebuf[size] = '\0';	/* NULL terminate it. */
16301ab64890Smrg    return filebuf;
16311ab64890Smrg}
16321ab64890Smrg
16331ab64890Smrgstatic void
16341ab64890SmrgGetIncludeFile(
16351ab64890Smrg    XrmDatabase db,
16361ab64890Smrg    _Xconst char *base,
16371ab64890Smrg    _Xconst char *fname,
16381ab64890Smrg    int fnamelen)
16391ab64890Smrg{
16401ab64890Smrg    int len;
16411ab64890Smrg    char *str;
16421ab64890Smrg    char realfname[BUFSIZ];
16431ab64890Smrg
16441ab64890Smrg    if (fnamelen <= 0 || fnamelen >= BUFSIZ)
16451ab64890Smrg	return;
16461ab64890Smrg    if (*fname != '/' && base && (str = strrchr(base, '/'))) {
16471ab64890Smrg	len = str - base + 1;
16481ab64890Smrg	if (len + fnamelen >= BUFSIZ)
16491ab64890Smrg	    return;
16501ab64890Smrg	strncpy(realfname, base, len);
16511ab64890Smrg	strncpy(realfname + len, fname, fnamelen);
16521ab64890Smrg	realfname[len + fnamelen] = '\0';
16531ab64890Smrg    } else {
16541ab64890Smrg	strncpy(realfname, fname, fnamelen);
16551ab64890Smrg	realfname[fnamelen] = '\0';
16561ab64890Smrg    }
16571ab64890Smrg    if (!(str = ReadInFile(realfname)))
16581ab64890Smrg	return;
16591ab64890Smrg    GetDatabase(db, str, realfname, True);
16601ab64890Smrg    Xfree(str);
16611ab64890Smrg}
16621ab64890Smrg
16631ab64890SmrgXrmDatabase
16641ab64890SmrgXrmGetFileDatabase(
16651ab64890Smrg    _Xconst char    *filename)
16661ab64890Smrg{
16671ab64890Smrg    XrmDatabase db;
16681ab64890Smrg    char *str;
16691ab64890Smrg
16701ab64890Smrg    if (!(str = ReadInFile(filename)))
16711ab64890Smrg	return (XrmDatabase)NULL;
16721ab64890Smrg
16731ab64890Smrg    db = NewDatabase();
16741ab64890Smrg    _XLockMutex(&db->linfo);
16751ab64890Smrg    GetDatabase(db, str, filename, True);
16761ab64890Smrg    _XUnlockMutex(&db->linfo);
16771ab64890Smrg    Xfree(str);
16781ab64890Smrg    return db;
16791ab64890Smrg}
16801ab64890Smrg
16811ab64890SmrgStatus
16821ab64890SmrgXrmCombineFileDatabase(
16831ab64890Smrg    _Xconst char    *filename,
16841ab64890Smrg    XrmDatabase     *target,
16851ab64890Smrg    Bool             override)
16861ab64890Smrg{
16871ab64890Smrg    XrmDatabase db;
16881ab64890Smrg    char *str;
16891ab64890Smrg
16901ab64890Smrg    if (!(str = ReadInFile(filename)))
16911ab64890Smrg	return 0;
16921ab64890Smrg    if (override) {
16931ab64890Smrg	db = *target;
16941ab64890Smrg	if (!db)
16951ab64890Smrg	    *target = db = NewDatabase();
16961ab64890Smrg    } else
16971ab64890Smrg	db = NewDatabase();
16981ab64890Smrg    _XLockMutex(&db->linfo);
16991ab64890Smrg    GetDatabase(db, str, filename, True);
17001ab64890Smrg    _XUnlockMutex(&db->linfo);
17011ab64890Smrg    Xfree(str);
17021ab64890Smrg    if (!override)
17031ab64890Smrg	XrmCombineDatabase(db, target, False);
17041ab64890Smrg    return 1;
17051ab64890Smrg}
17061ab64890Smrg
17071ab64890Smrg/* call the user proc for every value in the table, arbitrary order.
17081ab64890Smrg * stop if user proc returns True.  level is current depth in database.
17091ab64890Smrg */
17101ab64890Smrg/*ARGSUSED*/
17111ab64890Smrgstatic Bool EnumLTable(
17121ab64890Smrg    LTable		table,
17131ab64890Smrg    XrmNameList		names,
17141ab64890Smrg    XrmClassList 	classes,
17151ab64890Smrg    register int	level,
17161ab64890Smrg    register EClosure	closure)
17171ab64890Smrg{
17181ab64890Smrg    register VEntry *bucket;
17191ab64890Smrg    register int i;
17201ab64890Smrg    register VEntry entry;
17211ab64890Smrg    XrmValue value;
17221ab64890Smrg    XrmRepresentation type;
17231ab64890Smrg    Bool tightOk;
17241ab64890Smrg
17251ab64890Smrg    closure->bindings[level] = (table->table.tight ?
17261ab64890Smrg				XrmBindTightly : XrmBindLoosely);
17271ab64890Smrg    closure->quarks[level] = table->table.name;
17281ab64890Smrg    level++;
17291ab64890Smrg    tightOk = !*names;
17301ab64890Smrg    closure->quarks[level + 1] = NULLQUARK;
17311ab64890Smrg    for (i = table->table.mask, bucket = table->buckets;
17321ab64890Smrg	 i >= 0;
17331ab64890Smrg	 i--, bucket++) {
17341ab64890Smrg	for (entry = *bucket; entry; entry = entry->next) {
17351ab64890Smrg	    if (entry->tight && !tightOk)
17361ab64890Smrg		continue;
17371ab64890Smrg	    closure->bindings[level] = (entry->tight ?
17381ab64890Smrg					XrmBindTightly : XrmBindLoosely);
17391ab64890Smrg	    closure->quarks[level] = entry->name;
17401ab64890Smrg	    value.size = entry->size;
17411ab64890Smrg	    if (entry->string) {
17421ab64890Smrg		type = XrmQString;
17431ab64890Smrg		value.addr = StringValue(entry);
17441ab64890Smrg	    } else {
17451ab64890Smrg		type = RepType(entry);
17461ab64890Smrg		value.addr = DataValue(entry);
17471ab64890Smrg	    }
17481ab64890Smrg	    if ((*closure->proc)(&closure->db, closure->bindings+1,
17491ab64890Smrg				 closure->quarks+1, &type, &value,
17501ab64890Smrg				 closure->closure))
17511ab64890Smrg		return True;
17521ab64890Smrg	}
17531ab64890Smrg    }
17541ab64890Smrg    return False;
17551ab64890Smrg}
17561ab64890Smrg
17571ab64890Smrgstatic Bool EnumAllNTable(
17581ab64890Smrg    NTable		table,
17591ab64890Smrg    register int	level,
17601ab64890Smrg    register EClosure	closure)
17611ab64890Smrg{
17621ab64890Smrg    register NTable *bucket;
17631ab64890Smrg    register int i;
17641ab64890Smrg    register NTable entry;
17651ab64890Smrg    XrmQuark empty = NULLQUARK;
17661ab64890Smrg
17671ab64890Smrg    if (level >= MAXDBDEPTH)
17681ab64890Smrg	return False;
17691ab64890Smrg    for (i = table->mask, bucket = NodeBuckets(table);
17701ab64890Smrg	 i >= 0;
17711ab64890Smrg	 i--, bucket++) {
17721ab64890Smrg	for (entry = *bucket; entry; entry = entry->next) {
17731ab64890Smrg	    if (entry->leaf) {
17741ab64890Smrg		if (EnumLTable((LTable)entry, &empty, &empty, level, closure))
17751ab64890Smrg		    return True;
17761ab64890Smrg	    } else {
17771ab64890Smrg		closure->bindings[level] = (entry->tight ?
17781ab64890Smrg					    XrmBindTightly : XrmBindLoosely);
17791ab64890Smrg		closure->quarks[level] = entry->name;
17801ab64890Smrg		if (EnumAllNTable(entry, level+1, closure))
17811ab64890Smrg		    return True;
17821ab64890Smrg	    }
17831ab64890Smrg	}
17841ab64890Smrg    }
17851ab64890Smrg    return False;
17861ab64890Smrg}
17871ab64890Smrg
17881ab64890Smrg/* recurse on every table in the table, arbitrary order.
17891ab64890Smrg * stop if user proc returns True.  level is current depth in database.
17901ab64890Smrg */
17911ab64890Smrgstatic Bool EnumNTable(
17921ab64890Smrg    NTable		table,
17931ab64890Smrg    XrmNameList		names,
17941ab64890Smrg    XrmClassList 	classes,
17951ab64890Smrg    register int	level,
17961ab64890Smrg    register EClosure	closure)
17971ab64890Smrg{
17981ab64890Smrg    register NTable	entry;
17991ab64890Smrg    register XrmQuark	q;
18001ab64890Smrg    register unsigned int leaf;
18011ab64890Smrg    Bool (*get)(
18021ab64890Smrg            NTable		table,
18031ab64890Smrg            XrmNameList		names,
18041ab64890Smrg            XrmClassList 	classes,
18051ab64890Smrg            register int	level,
18061ab64890Smrg            EClosure		closure);
18071ab64890Smrg    Bool bilevel;
18081ab64890Smrg
18091ab64890Smrg/* find entries named ename, leafness leaf, tight or loose, and call get */
18101ab64890Smrg#define ITIGHTLOOSE(ename) \
18111ab64890Smrg    NFIND(ename); \
18121ab64890Smrg    if (entry) { \
18131ab64890Smrg	if (leaf == entry->leaf) { \
18141ab64890Smrg	    if (!leaf && !entry->tight && entry->next && \
18151ab64890Smrg		entry->next->name == q && entry->next->tight && \
18161ab64890Smrg		(bilevel || entry->next->hasloose) && \
18171ab64890Smrg		EnumLTable((LTable)entry->next, names+1, classes+1, \
18181ab64890Smrg			   level, closure)) \
18191ab64890Smrg		return True; \
18201ab64890Smrg	    if ((*get)(entry, names+1, classes+1, level, closure)) \
18211ab64890Smrg		return True; \
18221ab64890Smrg	    if (entry->tight && (entry = entry->next) && \
18231ab64890Smrg		entry->name == q && leaf == entry->leaf && \
18241ab64890Smrg		(*get)(entry, names+1, classes+1, level, closure)) \
18251ab64890Smrg		return True; \
18261ab64890Smrg	} else if (entry->leaf) { \
18271ab64890Smrg	    if ((bilevel || entry->hasloose) && \
18281ab64890Smrg		EnumLTable((LTable)entry, names+1, classes+1, level, closure))\
18291ab64890Smrg		return True; \
18301ab64890Smrg	    if (entry->tight && (entry = entry->next) && \
18311ab64890Smrg		entry->name == q && (bilevel || entry->hasloose) && \
18321ab64890Smrg		EnumLTable((LTable)entry, names+1, classes+1, level, closure))\
18331ab64890Smrg		return True; \
18341ab64890Smrg	} \
18351ab64890Smrg    }
18361ab64890Smrg
18371ab64890Smrg/* find entries named ename, leafness leaf, loose only, and call get */
18381ab64890Smrg#define ILOOSE(ename) \
18391ab64890Smrg    NFIND(ename); \
18401ab64890Smrg    if (entry && entry->tight && (entry = entry->next) && entry->name != q) \
18411ab64890Smrg	entry = (NTable)NULL; \
18421ab64890Smrg    if (entry) { \
18431ab64890Smrg	if (leaf == entry->leaf) { \
18441ab64890Smrg	    if ((*get)(entry, names+1, classes+1, level, closure)) \
18451ab64890Smrg		return True; \
18461ab64890Smrg	} else if (entry->leaf && (bilevel || entry->hasloose)) { \
18471ab64890Smrg	    if (EnumLTable((LTable)entry, names+1, classes+1, level, closure))\
18481ab64890Smrg		return True; \
18491ab64890Smrg	} \
18501ab64890Smrg    }
18511ab64890Smrg
18521ab64890Smrg    if (level >= MAXDBDEPTH)
18531ab64890Smrg	return False;
18541ab64890Smrg    closure->bindings[level] = (table->tight ?
18551ab64890Smrg				XrmBindTightly : XrmBindLoosely);
18561ab64890Smrg    closure->quarks[level] = table->name;
18571ab64890Smrg    level++;
18581ab64890Smrg    if (!*names) {
18591ab64890Smrg	if (EnumAllNTable(table, level, closure))
18601ab64890Smrg	    return True;
18611ab64890Smrg    } else {
18621ab64890Smrg	if (names[1] || closure->mode == XrmEnumAllLevels) {
18631ab64890Smrg	    get = EnumNTable; /* recurse */
18641ab64890Smrg	    leaf = 0;
18651ab64890Smrg	    bilevel = !names[1];
18661ab64890Smrg	} else {
18671ab64890Smrg	    get = (getNTableEProcp)EnumLTable; /* bottom of recursion */
18681ab64890Smrg	    leaf = 1;
18691ab64890Smrg	    bilevel = False;
18701ab64890Smrg	}
18711ab64890Smrg	if (table->hasloose && closure->mode == XrmEnumAllLevels) {
18721ab64890Smrg	    NTable *bucket;
18731ab64890Smrg	    int i;
18741ab64890Smrg	    XrmQuark empty = NULLQUARK;
18751ab64890Smrg
18761ab64890Smrg	    for (i = table->mask, bucket = NodeBuckets(table);
18771ab64890Smrg		 i >= 0;
18781ab64890Smrg		 i--, bucket++) {
18791ab64890Smrg		q = NULLQUARK;
18801ab64890Smrg		for (entry = *bucket; entry; entry = entry->next) {
18811ab64890Smrg		    if (!entry->tight && entry->name != q &&
18821ab64890Smrg			entry->name != *names && entry->name != *classes) {
18831ab64890Smrg			q = entry->name;
18841ab64890Smrg			if (entry->leaf) {
18851ab64890Smrg			    if (EnumLTable((LTable)entry, &empty, &empty,
18861ab64890Smrg					   level, closure))
18871ab64890Smrg				return True;
18881ab64890Smrg			} else {
18891ab64890Smrg			    if (EnumNTable(entry, &empty, &empty,
18901ab64890Smrg					   level, closure))
18911ab64890Smrg				return True;
18921ab64890Smrg			}
18931ab64890Smrg		    }
18941ab64890Smrg		}
18951ab64890Smrg	    }
18961ab64890Smrg	}
18971ab64890Smrg
18981ab64890Smrg	ITIGHTLOOSE(*names);   /* do name, tight and loose */
18991ab64890Smrg	ITIGHTLOOSE(*classes); /* do class, tight and loose */
19001ab64890Smrg	if (table->hasany) {
19011ab64890Smrg	    ITIGHTLOOSE(XrmQANY); /* do ANY, tight and loose */
19021ab64890Smrg	}
19031ab64890Smrg	if (table->hasloose) {
19041ab64890Smrg	    while (1) {
19051ab64890Smrg		names++;
19061ab64890Smrg		classes++;
19071ab64890Smrg		if (!*names)
19081ab64890Smrg		    break;
19091ab64890Smrg		if (!names[1] && closure->mode != XrmEnumAllLevels) {
19101ab64890Smrg		    get = (getNTableEProcp)EnumLTable; /* bottom of recursion */
19111ab64890Smrg		    leaf = 1;
19121ab64890Smrg		}
19131ab64890Smrg		ILOOSE(*names);   /* loose names */
19141ab64890Smrg		ILOOSE(*classes); /* loose classes */
19151ab64890Smrg		if (table->hasany) {
19161ab64890Smrg		    ILOOSE(XrmQANY); /* loose ANY */
19171ab64890Smrg		}
19181ab64890Smrg	    }
19191ab64890Smrg	    names--;
19201ab64890Smrg	    classes--;
19211ab64890Smrg	}
19221ab64890Smrg    }
19231ab64890Smrg    /* now look for matching leaf nodes */
19241ab64890Smrg    entry = table->next;
19251ab64890Smrg    if (!entry)
19261ab64890Smrg	return False;
19271ab64890Smrg    if (entry->leaf) {
19281ab64890Smrg	if (entry->tight && !table->tight)
19291ab64890Smrg	    entry = entry->next;
19301ab64890Smrg    } else {
19311ab64890Smrg	entry = entry->next;
19321ab64890Smrg	if (!entry || !entry->tight)
19331ab64890Smrg	    return False;
19341ab64890Smrg    }
19351ab64890Smrg    if (!entry || entry->name != table->name)
19361ab64890Smrg	return False;
19371ab64890Smrg    /* found one */
19381ab64890Smrg    level--;
19391ab64890Smrg    if ((!*names || entry->hasloose) &&
19401ab64890Smrg	EnumLTable((LTable)entry, names, classes, level, closure))
19411ab64890Smrg	return True;
19421ab64890Smrg    if (entry->tight && entry == table->next && (entry = entry->next) &&
19431ab64890Smrg	entry->name == table->name && (!*names || entry->hasloose))
19441ab64890Smrg	return EnumLTable((LTable)entry, names, classes, level, closure);
19451ab64890Smrg    return False;
19461ab64890Smrg
19471ab64890Smrg#undef ITIGHTLOOSE
19481ab64890Smrg#undef ILOOSE
19491ab64890Smrg}
19501ab64890Smrg
19511ab64890Smrg/* call the proc for every value in the database, arbitrary order.
19521ab64890Smrg * stop if the proc returns True.
19531ab64890Smrg */
19541ab64890SmrgBool XrmEnumerateDatabase(
19551ab64890Smrg    XrmDatabase		db,
19561ab64890Smrg    XrmNameList		names,
19571ab64890Smrg    XrmClassList	classes,
19581ab64890Smrg    int			mode,
19591ab64890Smrg    DBEnumProc		proc,
19601ab64890Smrg    XPointer		closure)
19611ab64890Smrg{
19621ab64890Smrg    XrmBinding  bindings[MAXDBDEPTH+2];
19631ab64890Smrg    XrmQuark	quarks[MAXDBDEPTH+2];
19641ab64890Smrg    register NTable table;
19651ab64890Smrg    EClosureRec	eclosure;
19661ab64890Smrg    Bool retval = False;
19671ab64890Smrg
19681ab64890Smrg    if (!db)
19691ab64890Smrg	return False;
19701ab64890Smrg    _XLockMutex(&db->linfo);
19711ab64890Smrg    eclosure.db = db;
19721ab64890Smrg    eclosure.proc = proc;
19731ab64890Smrg    eclosure.closure = closure;
19741ab64890Smrg    eclosure.bindings = bindings;
19751ab64890Smrg    eclosure.quarks = quarks;
19761ab64890Smrg    eclosure.mode = mode;
19771ab64890Smrg    table = db->table;
19781ab64890Smrg    if (table && !table->leaf && !*names && mode == XrmEnumOneLevel)
19791ab64890Smrg	table = table->next;
19801ab64890Smrg    if (table) {
19811ab64890Smrg	if (!table->leaf)
19821ab64890Smrg	    retval = EnumNTable(table, names, classes, 0, &eclosure);
19831ab64890Smrg	else
19841ab64890Smrg	    retval = EnumLTable((LTable)table, names, classes, 0, &eclosure);
19851ab64890Smrg    }
19861ab64890Smrg    _XUnlockMutex(&db->linfo);
19871ab64890Smrg    return retval;
19881ab64890Smrg}
19891ab64890Smrg
19901ab64890Smrgstatic void PrintBindingQuarkList(
19911ab64890Smrg    XrmBindingList      bindings,
19921ab64890Smrg    XrmQuarkList	quarks,
19931ab64890Smrg    FILE		*stream)
19941ab64890Smrg{
19951ab64890Smrg    Bool	firstNameSeen;
19961ab64890Smrg
19971ab64890Smrg    for (firstNameSeen = False; *quarks; bindings++, quarks++) {
19981ab64890Smrg	if (*bindings == XrmBindLoosely) {
19991ab64890Smrg	    (void) fprintf(stream, "*");
20001ab64890Smrg	} else if (firstNameSeen) {
20011ab64890Smrg	    (void) fprintf(stream, ".");
20021ab64890Smrg	}
20031ab64890Smrg	firstNameSeen = True;
20041ab64890Smrg	(void) fputs(XrmQuarkToString(*quarks), stream);
20051ab64890Smrg    }
20061ab64890Smrg}
20071ab64890Smrg
20081ab64890Smrg/* output out the entry in correct file syntax */
20091ab64890Smrg/*ARGSUSED*/
20101ab64890Smrgstatic Bool DumpEntry(
20111ab64890Smrg    XrmDatabase		*db,
20121ab64890Smrg    XrmBindingList      bindings,
20131ab64890Smrg    XrmQuarkList	quarks,
20141ab64890Smrg    XrmRepresentation   *type,
20151ab64890Smrg    XrmValuePtr		value,
20161ab64890Smrg    XPointer		data)
20171ab64890Smrg{
20181ab64890Smrg    FILE			*stream = (FILE *)data;
20191ab64890Smrg    register unsigned int	i;
20201ab64890Smrg    register char		*s;
20211ab64890Smrg    register char		c;
20221ab64890Smrg
20231ab64890Smrg    if (*type != XrmQString)
20241ab64890Smrg	(void) putc('!', stream);
20251ab64890Smrg    PrintBindingQuarkList(bindings, quarks, stream);
20261ab64890Smrg    s = value->addr;
20271ab64890Smrg    i = value->size;
20281ab64890Smrg    if (*type == XrmQString) {
20291ab64890Smrg	(void) fputs(":\t", stream);
20301ab64890Smrg	if (i)
20311ab64890Smrg	    i--;
20321ab64890Smrg    }
20331ab64890Smrg    else
20341ab64890Smrg	(void) fprintf(stream, "=%s:\t", XrmRepresentationToString(*type));
20351ab64890Smrg    if (i && (*s == ' ' || *s == '\t'))
20361ab64890Smrg	(void) putc('\\', stream); /* preserve leading whitespace */
20371ab64890Smrg    while (i--) {
20381ab64890Smrg	c = *s++;
20391ab64890Smrg	if (c == '\n') {
20401ab64890Smrg	    if (i)
20411ab64890Smrg		(void) fputs("\\n\\\n", stream);
20421ab64890Smrg	    else
20431ab64890Smrg		(void) fputs("\\n", stream);
20441ab64890Smrg	} else if (c == '\\')
20451ab64890Smrg	    (void) fputs("\\\\", stream);
20461ab64890Smrg	else if ((c < ' ' && c != '\t') ||
20471ab64890Smrg		 ((unsigned char)c >= 0x7f && (unsigned char)c < 0xa0))
20481ab64890Smrg	    (void) fprintf(stream, "\\%03o", (unsigned char)c);
20491ab64890Smrg	else
20501ab64890Smrg	    (void) putc(c, stream);
20511ab64890Smrg    }
20521ab64890Smrg    (void) putc('\n', stream);
20531ab64890Smrg    return ferror(stream) != 0;
20541ab64890Smrg}
20551ab64890Smrg
20561ab64890Smrg#ifdef DEBUG
20571ab64890Smrg
20581ab64890Smrgvoid PrintTable(
20591ab64890Smrg    NTable table,
20601ab64890Smrg    FILE *file)
20611ab64890Smrg{
20621ab64890Smrg    XrmBinding  bindings[MAXDBDEPTH+1];
20631ab64890Smrg    XrmQuark	quarks[MAXDBDEPTH+1];
20641ab64890Smrg    EClosureRec closure;
20651ab64890Smrg    XrmQuark	empty = NULLQUARK;
20661ab64890Smrg
20671ab64890Smrg    closure.db = (XrmDatabase)NULL;
20681ab64890Smrg    closure.proc = DumpEntry;
20691ab64890Smrg    closure.closure = (XPointer)file;
20701ab64890Smrg    closure.bindings = bindings;
20711ab64890Smrg    closure.quarks = quarks;
20721ab64890Smrg    closure.mode = XrmEnumAllLevels;
20731ab64890Smrg    if (table->leaf)
20741ab64890Smrg	EnumLTable((LTable)table, &empty, &empty, 0, &closure);
20751ab64890Smrg    else
20761ab64890Smrg	EnumNTable(table, &empty, &empty, 0, &closure);
20771ab64890Smrg}
20781ab64890Smrg
20791ab64890Smrg#endif /* DEBUG */
20801ab64890Smrg
20811ab64890Smrgvoid
20821ab64890SmrgXrmPutFileDatabase(
20831ab64890Smrg    XrmDatabase db,
20841ab64890Smrg    _Xconst char *fileName)
20851ab64890Smrg{
20861ab64890Smrg    FILE	*file;
20871ab64890Smrg    XrmQuark empty = NULLQUARK;
20881ab64890Smrg
20891ab64890Smrg    if (!db) return;
20901ab64890Smrg    if (!(file = fopen(fileName, "w"))) return;
20911ab64890Smrg    if (XrmEnumerateDatabase(db, &empty, &empty, XrmEnumAllLevels,
20921ab64890Smrg			     DumpEntry, (XPointer) file))
20931ab64890Smrg	unlink((char *)fileName);
20941ab64890Smrg    fclose(file);
20951ab64890Smrg}
20961ab64890Smrg
20971ab64890Smrg/* macros used in get/search functions */
20981ab64890Smrg
20991ab64890Smrg/* find entries named ename, leafness leaf, tight or loose, and call get */
21001ab64890Smrg#define GTIGHTLOOSE(ename,looseleaf) \
21011ab64890Smrg    NFIND(ename); \
21021ab64890Smrg    if (entry) { \
21031ab64890Smrg	if (leaf == entry->leaf) { \
21041ab64890Smrg	    if (!leaf && !entry->tight && entry->next && \
21051ab64890Smrg		entry->next->name == q && entry->next->tight && \
21061ab64890Smrg		entry->next->hasloose && \
21071ab64890Smrg		looseleaf((LTable)entry->next, names+1, classes+1, closure)) \
21081ab64890Smrg		return True; \
21091ab64890Smrg	    if ((*get)(entry, names+1, classes+1, closure)) \
21101ab64890Smrg		return True; \
21111ab64890Smrg	    if (entry->tight && (entry = entry->next) && \
21121ab64890Smrg		entry->name == q && leaf == entry->leaf && \
21131ab64890Smrg		(*get)(entry, names+1, classes+1, closure)) \
21141ab64890Smrg		return True; \
21151ab64890Smrg	} else if (entry->leaf) { \
21161ab64890Smrg	    if (entry->hasloose && \
21171ab64890Smrg		looseleaf((LTable)entry, names+1, classes+1, closure)) \
21181ab64890Smrg		return True; \
21191ab64890Smrg	    if (entry->tight && (entry = entry->next) && \
21201ab64890Smrg		entry->name == q && entry->hasloose && \
21211ab64890Smrg		looseleaf((LTable)entry, names+1, classes+1, closure)) \
21221ab64890Smrg		return True; \
21231ab64890Smrg	} \
21241ab64890Smrg    }
21251ab64890Smrg
21261ab64890Smrg/* find entries named ename, leafness leaf, loose only, and call get */
21271ab64890Smrg#define GLOOSE(ename,looseleaf) \
21281ab64890Smrg    NFIND(ename); \
21291ab64890Smrg    if (entry && entry->tight && (entry = entry->next) && entry->name != q) \
21301ab64890Smrg	entry = (NTable)NULL; \
21311ab64890Smrg    if (entry) { \
21321ab64890Smrg	if (leaf == entry->leaf) { \
21331ab64890Smrg	    if ((*get)(entry, names+1, classes+1, closure)) \
21341ab64890Smrg		return True; \
21351ab64890Smrg	} else if (entry->leaf && entry->hasloose) { \
21361ab64890Smrg	    if (looseleaf((LTable)entry, names+1, classes+1, closure)) \
21371ab64890Smrg		return True; \
21381ab64890Smrg	} \
21391ab64890Smrg    }
21401ab64890Smrg
21411ab64890Smrg/* add tight/loose entry to the search list, return True if list is full */
21421ab64890Smrg/*ARGSUSED*/
21431ab64890Smrgstatic Bool AppendLEntry(
21441ab64890Smrg    LTable		table,
21451ab64890Smrg    XrmNameList		names,
21461ab64890Smrg    XrmClassList 	classes,
21471ab64890Smrg    register SClosure	closure)
21481ab64890Smrg{
21491ab64890Smrg    /* check for duplicate */
21501ab64890Smrg    if (closure->idx >= 0 && closure->list[closure->idx] == table)
21511ab64890Smrg	return False;
21521ab64890Smrg    if (closure->idx == closure->limit)
21531ab64890Smrg	return True;
21541ab64890Smrg    /* append it */
21551ab64890Smrg    closure->idx++;
21561ab64890Smrg    closure->list[closure->idx] = table;
21571ab64890Smrg    return False;
21581ab64890Smrg}
21591ab64890Smrg
21601ab64890Smrg/* add loose entry to the search list, return True if list is full */
21611ab64890Smrg/*ARGSUSED*/
21621ab64890Smrgstatic Bool AppendLooseLEntry(
21631ab64890Smrg    LTable		table,
21641ab64890Smrg    XrmNameList		names,
21651ab64890Smrg    XrmClassList 	classes,
21661ab64890Smrg    register SClosure	closure)
21671ab64890Smrg{
21681ab64890Smrg    /* check for duplicate */
21691ab64890Smrg    if (closure->idx >= 0 && closure->list[closure->idx] == table)
21701ab64890Smrg	return False;
21711ab64890Smrg    if (closure->idx >= closure->limit - 1)
21721ab64890Smrg	return True;
21731ab64890Smrg    /* append it */
21741ab64890Smrg    closure->idx++;
21751ab64890Smrg    closure->list[closure->idx] = LOOSESEARCH;
21761ab64890Smrg    closure->idx++;
21771ab64890Smrg    closure->list[closure->idx] = table;
21781ab64890Smrg    return False;
21791ab64890Smrg}
21801ab64890Smrg
21811ab64890Smrg/* search for a leaf table */
21821ab64890Smrgstatic Bool SearchNEntry(
21831ab64890Smrg    NTable		table,
21841ab64890Smrg    XrmNameList		names,
21851ab64890Smrg    XrmClassList 	classes,
21861ab64890Smrg    SClosure		closure)
21871ab64890Smrg{
21881ab64890Smrg    register NTable	entry;
21891ab64890Smrg    register XrmQuark	q;
21901ab64890Smrg    register unsigned int leaf;
21911ab64890Smrg    Bool		(*get)(
21921ab64890Smrg            NTable		table,
21931ab64890Smrg            XrmNameList		names,
21941ab64890Smrg            XrmClassList 	classes,
21951ab64890Smrg            SClosure		closure);
21961ab64890Smrg
21971ab64890Smrg    if (names[1]) {
21981ab64890Smrg	get = SearchNEntry; /* recurse */
21991ab64890Smrg	leaf = 0;
22001ab64890Smrg    } else {
22011ab64890Smrg	get = (getNTableSProcp)AppendLEntry; /* bottom of recursion */
22021ab64890Smrg	leaf = 1;
22031ab64890Smrg    }
22041ab64890Smrg    GTIGHTLOOSE(*names, AppendLooseLEntry);   /* do name, tight and loose */
22051ab64890Smrg    GTIGHTLOOSE(*classes, AppendLooseLEntry); /* do class, tight and loose */
22061ab64890Smrg    if (table->hasany) {
22071ab64890Smrg	GTIGHTLOOSE(XrmQANY, AppendLooseLEntry); /* do ANY, tight and loose */
22081ab64890Smrg    }
22091ab64890Smrg    if (table->hasloose) {
22101ab64890Smrg	while (1) {
22111ab64890Smrg	    names++;
22121ab64890Smrg	    classes++;
22131ab64890Smrg	    if (!*names)
22141ab64890Smrg		break;
22151ab64890Smrg	    if (!names[1]) {
22161ab64890Smrg		get = (getNTableSProcp)AppendLEntry; /* bottom of recursion */
22171ab64890Smrg		leaf = 1;
22181ab64890Smrg	    }
22191ab64890Smrg	    GLOOSE(*names, AppendLooseLEntry);   /* loose names */
22201ab64890Smrg	    GLOOSE(*classes, AppendLooseLEntry); /* loose classes */
22211ab64890Smrg	    if (table->hasany) {
22221ab64890Smrg		GLOOSE(XrmQANY, AppendLooseLEntry); /* loose ANY */
22231ab64890Smrg	    }
22241ab64890Smrg	}
22251ab64890Smrg    }
22261ab64890Smrg    /* now look for matching leaf nodes */
22271ab64890Smrg    entry = table->next;
22281ab64890Smrg    if (!entry)
22291ab64890Smrg	return False;
22301ab64890Smrg    if (entry->leaf) {
22311ab64890Smrg	if (entry->tight && !table->tight)
22321ab64890Smrg	    entry = entry->next;
22331ab64890Smrg    } else {
22341ab64890Smrg	entry = entry->next;
22351ab64890Smrg	if (!entry || !entry->tight)
22361ab64890Smrg	    return False;
22371ab64890Smrg    }
22381ab64890Smrg    if (!entry || entry->name != table->name)
22391ab64890Smrg	return False;
22401ab64890Smrg    /* found one */
22411ab64890Smrg    if (entry->hasloose &&
22421ab64890Smrg	AppendLooseLEntry((LTable)entry, names, classes, closure))
22431ab64890Smrg	return True;
22441ab64890Smrg    if (entry->tight && entry == table->next && (entry = entry->next) &&
22451ab64890Smrg	entry->name == table->name && entry->hasloose)
22461ab64890Smrg	return AppendLooseLEntry((LTable)entry, names, classes, closure);
22471ab64890Smrg    return False;
22481ab64890Smrg}
22491ab64890Smrg
22501ab64890SmrgBool XrmQGetSearchList(
22511ab64890Smrg    XrmDatabase     db,
22521ab64890Smrg    XrmNameList	    names,
22531ab64890Smrg    XrmClassList    classes,
22541ab64890Smrg    XrmSearchList   searchList,	/* RETURN */
22551ab64890Smrg    int		    listLength)
22561ab64890Smrg{
22571ab64890Smrg    register NTable	table;
22581ab64890Smrg    SClosureRec		closure;
22591ab64890Smrg
22601ab64890Smrg    if (listLength <= 0)
22611ab64890Smrg	return False;
22621ab64890Smrg    closure.list = (LTable *)searchList;
22631ab64890Smrg    closure.idx = -1;
22641ab64890Smrg    closure.limit = listLength - 2;
22651ab64890Smrg    if (db) {
22661ab64890Smrg	_XLockMutex(&db->linfo);
22671ab64890Smrg	table = db->table;
22681ab64890Smrg	if (*names) {
22691ab64890Smrg	    if (table && !table->leaf) {
22701ab64890Smrg		if (SearchNEntry(table, names, classes, &closure)) {
22711ab64890Smrg		    _XUnlockMutex(&db->linfo);
22721ab64890Smrg		    return False;
22731ab64890Smrg		}
22741ab64890Smrg	    } else if (table && table->hasloose &&
22751ab64890Smrg		       AppendLooseLEntry((LTable)table, names, classes,
22761ab64890Smrg					 &closure)) {
22771ab64890Smrg		_XUnlockMutex(&db->linfo);
22781ab64890Smrg		return False;
22791ab64890Smrg	    }
22801ab64890Smrg	} else {
22811ab64890Smrg	    if (table && !table->leaf)
22821ab64890Smrg		table = table->next;
22831ab64890Smrg	    if (table &&
22841ab64890Smrg		AppendLEntry((LTable)table, names, classes, &closure)) {
22851ab64890Smrg		_XUnlockMutex(&db->linfo);
22861ab64890Smrg		return False;
22871ab64890Smrg	    }
22881ab64890Smrg	}
22891ab64890Smrg	_XUnlockMutex(&db->linfo);
22901ab64890Smrg    }
22911ab64890Smrg    closure.list[closure.idx + 1] = (LTable)NULL;
22921ab64890Smrg    return True;
22931ab64890Smrg}
22941ab64890Smrg
22951ab64890SmrgBool XrmQGetSearchResource(
22961ab64890Smrg	     XrmSearchList	searchList,
22971ab64890Smrg    register XrmName		name,
22981ab64890Smrg    register XrmClass		class,
22991ab64890Smrg    	     XrmRepresentation	*pType,  /* RETURN */
23001ab64890Smrg    	     XrmValue		*pValue) /* RETURN */
23011ab64890Smrg{
23021ab64890Smrg    register LTable *list;
23031ab64890Smrg    register LTable table;
23041ab64890Smrg    register VEntry entry = NULL;
23051ab64890Smrg    int flags;
23061ab64890Smrg
23071ab64890Smrg/* find tight or loose entry */
23081ab64890Smrg#define VTIGHTLOOSE(q) \
23091ab64890Smrg    entry = LeafHash(table, q); \
23101ab64890Smrg    while (entry && entry->name != q) \
23111ab64890Smrg	entry = entry->next; \
23121ab64890Smrg    if (entry) \
23131ab64890Smrg	break
23141ab64890Smrg
23151ab64890Smrg/* find loose entry */
23161ab64890Smrg#define VLOOSE(q) \
23171ab64890Smrg    entry = LeafHash(table, q); \
23181ab64890Smrg    while (entry && entry->name != q) \
23191ab64890Smrg	entry = entry->next; \
23201ab64890Smrg    if (entry) { \
23211ab64890Smrg	if (!entry->tight) \
23221ab64890Smrg	    break; \
23231ab64890Smrg	if ((entry = entry->next) && entry->name == q) \
23241ab64890Smrg	    break; \
23251ab64890Smrg    }
23261ab64890Smrg
23271ab64890Smrg    list = (LTable *)searchList;
23281ab64890Smrg    /* figure out which combination of name and class we need to search for */
23291ab64890Smrg    flags = 0;
23301ab64890Smrg    if (IsResourceQuark(name))
23311ab64890Smrg	flags = 2;
23321ab64890Smrg    if (IsResourceQuark(class))
23331ab64890Smrg	flags |= 1;
23341ab64890Smrg    if (!flags) {
23351ab64890Smrg	/* neither name nor class has ever been used to name a resource */
23361ab64890Smrg	table = (LTable)NULL;
23371ab64890Smrg    } else if (flags == 3) {
23381ab64890Smrg	/* both name and class */
23391ab64890Smrg	while ((table = *list++)) {
23401ab64890Smrg	    if (table != LOOSESEARCH) {
23411ab64890Smrg		VTIGHTLOOSE(name);  /* do name, tight and loose */
23421ab64890Smrg		VTIGHTLOOSE(class); /* do class, tight and loose */
23431ab64890Smrg	    } else {
23441ab64890Smrg		table = *list++;
23451ab64890Smrg		VLOOSE(name);  /* do name, loose only */
23461ab64890Smrg		VLOOSE(class); /* do class, loose only */
23471ab64890Smrg	    }
23481ab64890Smrg	}
23491ab64890Smrg    } else {
23501ab64890Smrg	/* just one of name or class */
23511ab64890Smrg	if (flags == 1)
23521ab64890Smrg	    name = class;
23531ab64890Smrg	while ((table = *list++)) {
23541ab64890Smrg	    if (table != LOOSESEARCH) {
23551ab64890Smrg		VTIGHTLOOSE(name); /* tight and loose */
23561ab64890Smrg	    } else {
23571ab64890Smrg		table = *list++;
23581ab64890Smrg		VLOOSE(name); /* loose only */
23591ab64890Smrg	    }
23601ab64890Smrg	}
23611ab64890Smrg    }
23621ab64890Smrg    if (table) {
23631ab64890Smrg	/* found a match */
23641ab64890Smrg	if (entry->string) {
23651ab64890Smrg	    *pType = XrmQString;
23661ab64890Smrg	    pValue->addr = StringValue(entry);
23671ab64890Smrg	} else {
23681ab64890Smrg	    *pType = RepType(entry);
23691ab64890Smrg	    pValue->addr = DataValue(entry);
23701ab64890Smrg	}
23711ab64890Smrg	pValue->size = entry->size;
23721ab64890Smrg	return True;
23731ab64890Smrg    }
23741ab64890Smrg    *pType = NULLQUARK;
23751ab64890Smrg    pValue->addr = (XPointer)NULL;
23761ab64890Smrg    pValue->size = 0;
23771ab64890Smrg    return False;
23781ab64890Smrg
23791ab64890Smrg#undef VTIGHTLOOSE
23801ab64890Smrg#undef VLOOSE
23811ab64890Smrg}
23821ab64890Smrg
23831ab64890Smrg/* look for a tight/loose value */
23841ab64890Smrgstatic Bool GetVEntry(
23851ab64890Smrg    LTable		table,
23861ab64890Smrg    XrmNameList		names,
23871ab64890Smrg    XrmClassList 	classes,
23881ab64890Smrg    VClosure		closure)
23891ab64890Smrg{
23901ab64890Smrg    register VEntry entry;
23911ab64890Smrg    register XrmQuark q;
23921ab64890Smrg
23931ab64890Smrg    /* try name first */
23941ab64890Smrg    q = *names;
23951ab64890Smrg    entry = LeafHash(table, q);
23961ab64890Smrg    while (entry && entry->name != q)
23971ab64890Smrg	entry = entry->next;
23981ab64890Smrg    if (!entry) {
23991ab64890Smrg	/* not found, try class */
24001ab64890Smrg	q = *classes;
24011ab64890Smrg	entry = LeafHash(table, q);
24021ab64890Smrg	while (entry && entry->name != q)
24031ab64890Smrg	    entry = entry->next;
24041ab64890Smrg	if (!entry)
24051ab64890Smrg	    return False;
24061ab64890Smrg    }
24071ab64890Smrg    if (entry->string) {
24081ab64890Smrg	*closure->type = XrmQString;
24091ab64890Smrg	closure->value->addr = StringValue(entry);
24101ab64890Smrg    } else {
24111ab64890Smrg	*closure->type = RepType(entry);
24121ab64890Smrg	closure->value->addr = DataValue(entry);
24131ab64890Smrg    }
24141ab64890Smrg    closure->value->size = entry->size;
24151ab64890Smrg    return True;
24161ab64890Smrg}
24171ab64890Smrg
24181ab64890Smrg/* look for a loose value */
24191ab64890Smrgstatic Bool GetLooseVEntry(
24201ab64890Smrg    LTable		table,
24211ab64890Smrg    XrmNameList		names,
24221ab64890Smrg    XrmClassList 	classes,
24231ab64890Smrg    VClosure		closure)
24241ab64890Smrg{
24251ab64890Smrg    register VEntry	entry;
24261ab64890Smrg    register XrmQuark	q;
24271ab64890Smrg
24281ab64890Smrg#define VLOOSE(ename) \
24291ab64890Smrg    q = ename; \
24301ab64890Smrg    entry = LeafHash(table, q); \
24311ab64890Smrg    while (entry && entry->name != q) \
24321ab64890Smrg	entry = entry->next; \
24331ab64890Smrg    if (entry && entry->tight && (entry = entry->next) && entry->name != q) \
24341ab64890Smrg	entry = (VEntry)NULL;
24351ab64890Smrg
24361ab64890Smrg    /* bump to last component */
24371ab64890Smrg    while (names[1]) {
24381ab64890Smrg	names++;
24391ab64890Smrg	classes++;
24401ab64890Smrg    }
24411ab64890Smrg    VLOOSE(*names);  /* do name, loose only */
24421ab64890Smrg    if (!entry) {
24431ab64890Smrg	VLOOSE(*classes); /* do class, loose only */
24441ab64890Smrg	if (!entry)
24451ab64890Smrg	    return False;
24461ab64890Smrg    }
24471ab64890Smrg    if (entry->string) {
24481ab64890Smrg	*closure->type = XrmQString;
24491ab64890Smrg	closure->value->addr = StringValue(entry);
24501ab64890Smrg    } else {
24511ab64890Smrg	*closure->type = RepType(entry);
24521ab64890Smrg	closure->value->addr = DataValue(entry);
24531ab64890Smrg    }
24541ab64890Smrg    closure->value->size = entry->size;
24551ab64890Smrg    return True;
24561ab64890Smrg
24571ab64890Smrg#undef VLOOSE
24581ab64890Smrg}
24591ab64890Smrg
24601ab64890Smrg/* recursive search for a value */
24611ab64890Smrgstatic Bool GetNEntry(
24621ab64890Smrg    NTable		table,
24631ab64890Smrg    XrmNameList		names,
24641ab64890Smrg    XrmClassList 	classes,
24651ab64890Smrg    VClosure		closure)
24661ab64890Smrg{
24671ab64890Smrg    register NTable	entry;
24681ab64890Smrg    register XrmQuark	q;
24691ab64890Smrg    register unsigned int leaf;
24701ab64890Smrg    Bool		(*get)(
24711ab64890Smrg            NTable              table,
24721ab64890Smrg            XrmNameList         names,
24731ab64890Smrg            XrmClassList        classes,
24741ab64890Smrg            VClosure            closure);
24751ab64890Smrg    NTable		otable;
24761ab64890Smrg
24771ab64890Smrg    if (names[2]) {
24781ab64890Smrg	get = GetNEntry; /* recurse */
24791ab64890Smrg	leaf = 0;
24801ab64890Smrg    } else {
24811ab64890Smrg	get = (getNTableVProcp)GetVEntry; /* bottom of recursion */
24821ab64890Smrg	leaf = 1;
24831ab64890Smrg    }
24841ab64890Smrg    GTIGHTLOOSE(*names, GetLooseVEntry);   /* do name, tight and loose */
24851ab64890Smrg    GTIGHTLOOSE(*classes, GetLooseVEntry); /* do class, tight and loose */
24861ab64890Smrg    if (table->hasany) {
24871ab64890Smrg	GTIGHTLOOSE(XrmQANY, GetLooseVEntry); /* do ANY, tight and loose */
24881ab64890Smrg    }
24891ab64890Smrg    if (table->hasloose) {
24901ab64890Smrg	while (1) {
24911ab64890Smrg	    names++;
24921ab64890Smrg	    classes++;
24931ab64890Smrg	    if (!names[1])
24941ab64890Smrg		break;
24951ab64890Smrg	    if (!names[2]) {
24961ab64890Smrg		get = (getNTableVProcp)GetVEntry; /* bottom of recursion */
24971ab64890Smrg		leaf = 1;
24981ab64890Smrg	    }
24991ab64890Smrg	    GLOOSE(*names, GetLooseVEntry);   /* do name, loose only */
25001ab64890Smrg	    GLOOSE(*classes, GetLooseVEntry); /* do class, loose only */
25011ab64890Smrg	    if (table->hasany) {
25021ab64890Smrg		GLOOSE(XrmQANY, GetLooseVEntry); /* do ANY, loose only */
25031ab64890Smrg	    }
25041ab64890Smrg	}
25051ab64890Smrg    }
25061ab64890Smrg    /* look for matching leaf tables */
25071ab64890Smrg    otable = table;
25081ab64890Smrg    table = table->next;
25091ab64890Smrg    if (!table)
25101ab64890Smrg	return False;
25111ab64890Smrg    if (table->leaf) {
25121ab64890Smrg	if (table->tight && !otable->tight)
25131ab64890Smrg	    table = table->next;
25141ab64890Smrg    } else {
25151ab64890Smrg	table = table->next;
25161ab64890Smrg	if (!table || !table->tight)
25171ab64890Smrg	    return False;
25181ab64890Smrg    }
25191ab64890Smrg    if (!table || table->name != otable->name)
25201ab64890Smrg	return False;
25211ab64890Smrg    /* found one */
25221ab64890Smrg    if (table->hasloose &&
25231ab64890Smrg	GetLooseVEntry((LTable)table, names, classes, closure))
25241ab64890Smrg	return True;
25251ab64890Smrg    if (table->tight && table == otable->next) {
25261ab64890Smrg	table = table->next;
25271ab64890Smrg	if (table && table->name == otable->name && table->hasloose)
25281ab64890Smrg	    return GetLooseVEntry((LTable)table, names, classes, closure);
25291ab64890Smrg    }
25301ab64890Smrg    return False;
25311ab64890Smrg}
25321ab64890Smrg
25331ab64890SmrgBool XrmQGetResource(
25341ab64890Smrg    XrmDatabase         db,
25351ab64890Smrg    XrmNameList		names,
25361ab64890Smrg    XrmClassList 	classes,
25371ab64890Smrg    XrmRepresentation	*pType,  /* RETURN */
25381ab64890Smrg    XrmValuePtr		pValue)  /* RETURN */
25391ab64890Smrg{
25401ab64890Smrg    register NTable table;
25411ab64890Smrg    VClosureRec closure;
25421ab64890Smrg
25431ab64890Smrg    if (db && *names) {
25441ab64890Smrg	_XLockMutex(&db->linfo);
25451ab64890Smrg	closure.type = pType;
25461ab64890Smrg	closure.value = pValue;
25471ab64890Smrg	table = db->table;
25481ab64890Smrg	if (names[1]) {
25491ab64890Smrg	    if (table && !table->leaf) {
25501ab64890Smrg		if (GetNEntry(table, names, classes, &closure)) {
25511ab64890Smrg		    _XUnlockMutex(&db->linfo);
25521ab64890Smrg		    return True;
25531ab64890Smrg		}
25541ab64890Smrg	    } else if (table && table->hasloose &&
25551ab64890Smrg		    GetLooseVEntry((LTable)table, names, classes, &closure)) {
25561ab64890Smrg		_XUnlockMutex (&db->linfo);
25571ab64890Smrg		return True;
25581ab64890Smrg	    }
25591ab64890Smrg	} else {
25601ab64890Smrg	    if (table && !table->leaf)
25611ab64890Smrg		table = table->next;
25621ab64890Smrg	    if (table && GetVEntry((LTable)table, names, classes, &closure)) {
25631ab64890Smrg		_XUnlockMutex(&db->linfo);
25641ab64890Smrg		return True;
25651ab64890Smrg	    }
25661ab64890Smrg	}
25671ab64890Smrg	_XUnlockMutex(&db->linfo);
25681ab64890Smrg    }
25691ab64890Smrg    *pType = NULLQUARK;
25701ab64890Smrg    pValue->addr = (XPointer)NULL;
25711ab64890Smrg    pValue->size = 0;
25721ab64890Smrg    return False;
25731ab64890Smrg}
25741ab64890Smrg
25751ab64890SmrgBool
25761ab64890SmrgXrmGetResource(db, name_str, class_str, pType_str, pValue)
25771ab64890Smrg    XrmDatabase         db;
25781ab64890Smrg    _Xconst char	*name_str;
25791ab64890Smrg    _Xconst char	*class_str;
25801ab64890Smrg    XrmString		*pType_str;  /* RETURN */
25811ab64890Smrg    XrmValuePtr		pValue;      /* RETURN */
25821ab64890Smrg{
25831ab64890Smrg    XrmName		names[MAXDBDEPTH+1];
25841ab64890Smrg    XrmClass		classes[MAXDBDEPTH+1];
25851ab64890Smrg    XrmRepresentation   fromType;
25861ab64890Smrg    Bool		result;
25871ab64890Smrg
25881ab64890Smrg    XrmStringToNameList(name_str, names);
25891ab64890Smrg    XrmStringToClassList(class_str, classes);
25901ab64890Smrg    result = XrmQGetResource(db, names, classes, &fromType, pValue);
25911ab64890Smrg    (*pType_str) = XrmQuarkToString(fromType);
25921ab64890Smrg    return result;
25931ab64890Smrg}
25941ab64890Smrg
25951ab64890Smrg/* destroy all values, plus table itself */
25961ab64890Smrgstatic void DestroyLTable(
25971ab64890Smrg    LTable table)
25981ab64890Smrg{
25991ab64890Smrg    register int i;
26001ab64890Smrg    register VEntry *buckets;
26011ab64890Smrg    register VEntry entry, next;
26021ab64890Smrg
26031ab64890Smrg    buckets = table->buckets;
26041ab64890Smrg    for (i = table->table.mask; i >= 0; i--, buckets++) {
26051ab64890Smrg	for (next = *buckets; (entry = next); ) {
26061ab64890Smrg	    next = entry->next;
26071ab64890Smrg	    Xfree((char *)entry);
26081ab64890Smrg	}
26091ab64890Smrg    }
26101ab64890Smrg    Xfree((char *)table->buckets);
26111ab64890Smrg    Xfree((char *)table);
26121ab64890Smrg}
26131ab64890Smrg
26141ab64890Smrg/* destroy all contained tables, plus table itself */
26151ab64890Smrgstatic void DestroyNTable(
26161ab64890Smrg    NTable table)
26171ab64890Smrg{
26181ab64890Smrg    register int i;
26191ab64890Smrg    register NTable *buckets;
26201ab64890Smrg    register NTable entry, next;
26211ab64890Smrg
26221ab64890Smrg    buckets = NodeBuckets(table);
26231ab64890Smrg    for (i = table->mask; i >= 0; i--, buckets++) {
26241ab64890Smrg	for (next = *buckets; (entry = next); ) {
26251ab64890Smrg	    next = entry->next;
26261ab64890Smrg	    if (entry->leaf)
26271ab64890Smrg		DestroyLTable((LTable)entry);
26281ab64890Smrg	    else
26291ab64890Smrg		DestroyNTable(entry);
26301ab64890Smrg	}
26311ab64890Smrg    }
26321ab64890Smrg    Xfree((char *)table);
26331ab64890Smrg}
26341ab64890Smrg
26351ab64890Smrgconst char *
26361ab64890SmrgXrmLocaleOfDatabase(
26371ab64890Smrg    XrmDatabase db)
26381ab64890Smrg{
26391ab64890Smrg    const char* retval;
26401ab64890Smrg    _XLockMutex(&db->linfo);
26411ab64890Smrg    retval = (*db->methods->lcname)(db->mbstate);
26421ab64890Smrg    _XUnlockMutex(&db->linfo);
26431ab64890Smrg    return retval;
26441ab64890Smrg}
26451ab64890Smrg
26461ab64890Smrgvoid XrmDestroyDatabase(
26471ab64890Smrg    XrmDatabase   db)
26481ab64890Smrg{
26491ab64890Smrg    register NTable table, next;
26501ab64890Smrg
26511ab64890Smrg    if (db) {
26521ab64890Smrg	_XLockMutex(&db->linfo);
26531ab64890Smrg	for (next = db->table; (table = next); ) {
26541ab64890Smrg	    next = table->next;
26551ab64890Smrg	    if (table->leaf)
26561ab64890Smrg		DestroyLTable((LTable)table);
26571ab64890Smrg	    else
26581ab64890Smrg		DestroyNTable(table);
26591ab64890Smrg	}
26601ab64890Smrg	_XUnlockMutex(&db->linfo);
26611ab64890Smrg	_XFreeMutex(&db->linfo);
26621ab64890Smrg	(*db->methods->destroy)(db->mbstate);
26631ab64890Smrg	Xfree((char *)db);
26641ab64890Smrg    }
26651ab64890Smrg}
2666