Bug Summary

File:src/Xrm.c
Location:line 1343, column 6
Description:Value stored to 'bits' is never read

Annotated Source Code

1
2/***********************************************************
3Copyright 1987, 1988, 1990 by Digital Equipment Corporation, Maynard
4
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the name Digital not be
12used in advertising or publicity pertaining to distribution of the
13software without specific, written prior permission.
14
15DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21SOFTWARE.
22
23******************************************************************/
24/*
25
26Copyright 1987, 1988, 1990, 1998 The Open Group
27
28Permission to use, copy, modify, distribute, and sell this software and its
29documentation for any purpose is hereby granted without fee, provided that
30the above copyright notice appear in all copies and that both that
31copyright notice and this permission notice appear in supporting
32documentation.
33
34The above copyright notice and this permission notice shall be included
35in all copies or substantial portions of the Software.
36
37THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
38OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
39MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
40IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
41OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
42ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
43OTHER DEALINGS IN THE SOFTWARE.
44
45Except as contained in this notice, the name of The Open Group shall
46not be used in advertising or otherwise to promote the sale, use or
47other dealings in this Software without prior written authorization
48from The Open Group.
49
50*/
51
52#ifdef HAVE_CONFIG_H1
53#include <config.h>
54#endif
55#include <stdio.h>
56#include <ctype.h>
57#include "Xlibint.h"
58#include <X11/Xresource.h>
59#include "Xlcint.h"
60#ifdef XTHREADS1
61#include "locking.h"
62#endif
63#include <X11/Xos.h>
64#include <sys/stat.h>
65#include <limits.h>
66#include "Xresinternal.h"
67#include "Xresource.h"
68
69/*
70
71These Xrm routines allow very fast lookup of resources in the resource
72database. Several usage patterns are exploited:
73
74(1) Widgets get a lot of resources at one time. Rather than look up each from
75scratch, we can precompute the prioritized list of database levels once, then
76search for each resource starting at the beginning of the list.
77
78(2) Many database levels don't contain any leaf resource nodes. There is no
79point in looking for resources on a level that doesn't contain any. This
80information is kept on a per-level basis.
81
82(3) Sometimes the widget instance tree is structured such that you get the same
83class name repeated on the fully qualified widget name. This can result in the
84same database level occuring multiple times on the search list. The code below
85only checks to see if you get two identical search lists in a row, rather than
86look back through all database levels, but in practice this removes all
87duplicates I've ever observed.
88
89Joel McCormack
90
91*/
92
93/*
94
95The Xrm representation has been completely redesigned to substantially reduce
96memory and hopefully improve performance.
97
98The database is structured into two kinds of tables: LTables that contain
99only values, and NTables that contain only other tables.
100
101Some invariants:
102
103The next pointer of the top-level node table points to the top-level leaf
104table, if any.
105
106Within an LTable, for a given name, the tight value always precedes the
107loose value, and if both are present the loose value is always right after
108the tight value.
109
110Within an NTable, all of the entries for a given name are contiguous,
111in the order tight NTable, loose NTable, tight LTable, loose LTable.
112
113Bob Scheifler
114
115*/
116
117static XrmQuark XrmQString, XrmQANY;
118
119typedef Boolint (*DBEnumProc)(
120 XrmDatabase* /* db */,
121 XrmBindingList /* bindings */,
122 XrmQuarkList /* quarks */,
123 XrmRepresentation* /* type */,
124 XrmValue* /* value */,
125 XPointer /* closure */
126);
127
128typedef struct _VEntry {
129 struct _VEntry *next; /* next in chain */
130 XrmQuark name; /* name of this entry */
131 unsigned int tight:1; /* 1 if it is a tight binding */
132 unsigned int string:1; /* 1 if type is String */
133 unsigned int size:30; /* size of value */
134} VEntryRec, *VEntry;
135
136
137typedef struct _DEntry {
138 VEntryRec entry; /* entry */
139 XrmRepresentation type; /* representation type */
140} DEntryRec, *DEntry;
141
142/* the value is right after the structure */
143#define StringValue(ve)(XPointer)((ve) + 1) (XPointer)((ve) + 1)
144#define RepType(ve)((DEntry)(ve))->type ((DEntry)(ve))->type
145/* the value is right after the structure */
146#define DataValue(ve)(XPointer)(((DEntry)(ve)) + 1) (XPointer)(((DEntry)(ve)) + 1)
147#define RawValue(ve)(char *)((ve)->string ? (XPointer)((ve) + 1) : (XPointer)(
((DEntry)(ve)) + 1))
(char *)((ve)->string ? StringValue(ve)(XPointer)((ve) + 1) : DataValue(ve)(XPointer)(((DEntry)(ve)) + 1))
148
149typedef struct _NTable {
150 struct _NTable *next; /* next in chain */
151 XrmQuark name; /* name of this entry */
152 unsigned int tight:1; /* 1 if it is a tight binding */
153 unsigned int leaf:1; /* 1 if children are values */
154 unsigned int hasloose:1; /* 1 if has loose children */
155 unsigned int hasany:1; /* 1 if has ANY entry */
156 unsigned int pad:4; /* unused */
157 unsigned int mask:8; /* hash size - 1 */
158 unsigned int entries:16; /* number of children */
159} NTableRec, *NTable;
160
161/* the buckets are right after the structure */
162#define NodeBuckets(ne)((NTable *)((ne) + 1)) ((NTable *)((ne) + 1))
163#define NodeHash(ne,q)((NTable *)((ne) + 1))[(q) & (ne)->mask] NodeBuckets(ne)((NTable *)((ne) + 1))[(q) & (ne)->mask]
164
165/* leaf tables have an extra level of indirection for the buckets,
166 * so that resizing can be done without invalidating a search list.
167 * This is completely ugly, and wastes some memory, but the Xlib
168 * spec doesn't really specify whether invalidation is OK, and the
169 * old implementation did not invalidate.
170 */
171typedef struct _LTable {
172 NTableRec table;
173 VEntry *buckets;
174} LTableRec, *LTable;
175
176#define LeafHash(le,q)(le)->buckets[(q) & (le)->table.mask] (le)->buckets[(q) & (le)->table.mask]
177
178/* An XrmDatabase just holds a pointer to the first top-level table.
179 * The type name is no longer descriptive, but better to not change
180 * the Xresource.h header file. This type also gets used to define
181 * XrmSearchList, which is a complete crock, but we'll just leave it
182 * and caste types as required.
183 */
184typedef struct _XrmHashBucketRec {
185 NTable table;
186 XPointer mbstate;
187 XrmMethods methods;
188#ifdef XTHREADS1
189 LockInfoRec linfo;
190#endif
191} XrmHashBucketRec;
192
193/* closure used in get/put resource */
194typedef struct _VClosure {
195 XrmRepresentation *type; /* type of value */
196 XrmValuePtr value; /* value itself */
197} VClosureRec, *VClosure;
198
199/* closure used in get search list */
200typedef struct _SClosure {
201 LTable *list; /* search list */
202 int idx; /* index of last filled element */
203 int limit; /* maximum index */
204} SClosureRec, *SClosure;
205
206/* placed in XrmSearchList to indicate next table is loose only */
207#define LOOSESEARCH((LTable)1) ((LTable)1)
208
209/* closure used in enumerate database */
210typedef struct _EClosure {
211 XrmDatabase db; /* the database */
212 DBEnumProc proc; /* the user proc */
213 XPointer closure; /* the user closure */
214 XrmBindingList bindings; /* binding list */
215 XrmQuarkList quarks; /* quark list */
216 int mode; /* XrmEnum<kind> */
217} EClosureRec, *EClosure;
218
219/* types for typecasting ETable based functions to NTable based functions */
220typedef Boolint (*getNTableSProcp)(
221 NTable table,
222 XrmNameList names,
223 XrmClassList classes,
224 SClosure closure);
225typedef Boolint (*getNTableVProcp)(
226 NTable table,
227 XrmNameList names,
228 XrmClassList classes,
229 VClosure closure);
230typedef Boolint (*getNTableEProcp)(
231 NTable table,
232 XrmNameList names,
233 XrmClassList classes,
234 register int level,
235 EClosure closure);
236
237/* predicate to determine when to resize a hash table */
238#define GrowthPred(n,m)((unsigned)(n) > (((m) + 1) << 2)) ((unsigned)(n) > (((m) + 1) << 2))
239
240#define GROW(prev)if (((unsigned)((*prev)->entries) > ((((*prev)->mask
) + 1) << 2))) GrowTable(prev)
\
241 if (GrowthPred((*prev)->entries, (*prev)->mask)((unsigned)((*prev)->entries) > ((((*prev)->mask) + 1
) << 2))
) \
242 GrowTable(prev)
243
244/* pick a reasonable value for maximum depth of resource database */
245#define MAXDBDEPTH100 100
246
247/* macro used in get/search functions */
248
249/* find an entry named ename, with leafness given by leaf */
250#define NFIND(ename)q = ename; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }
\
251 q = ename; \
252 entry = NodeHash(table, q)((NTable *)((table) + 1))[(q) & (table)->mask]; \
253 while (entry && entry->name != q) \
254 entry = entry->next; \
255 if (leaf && entry && !entry->leaf) { \
256 entry = entry->next; \
257 if (entry && !entry->leaf) \
258 entry = entry->next; \
259 if (entry && entry->name != q) \
260 entry = (NTable)NULL((void*)0); \
261 }
262
263/* resourceQuarks keeps track of what quarks have been associated with values
264 * in all LTables. If a quark has never been used in an LTable, we don't need
265 * to bother looking for it.
266 */
267
268static unsigned char *resourceQuarks = (unsigned char *)NULL((void*)0);
269static XrmQuark maxResourceQuark = -1;
270
271/* determines if a quark has been used for a value in any database */
272#define IsResourceQuark(q)((q) > 0 && (q) <= maxResourceQuark && resourceQuarks
[(q) >> 3] & (1 << ((q) & 7)))
((q) > 0 && (q) <= maxResourceQuark && \
273 resourceQuarks[(q) >> 3] & (1 << ((q) & 7)))
274
275typedef unsigned char XrmBits;
276
277#define BSLASH((XrmBits) (1 << 5)) ((XrmBits) (1 << 5))
278#define NORMAL((XrmBits) (1 << 4)) ((XrmBits) (1 << 4))
279#define EOQ((XrmBits) (1 << 3)) ((XrmBits) (1 << 3))
280#define SEP((XrmBits) (1 << 2)) ((XrmBits) (1 << 2))
281#define ENDOF((XrmBits) (1 << 1)) ((XrmBits) (1 << 1))
282#define SPACE(((XrmBits) (1 << 4))|((XrmBits) (1 << 3))|((XrmBits
) (1 << 2))|(XrmBits)0)
(NORMAL((XrmBits) (1 << 4))|EOQ((XrmBits) (1 << 3))|SEP((XrmBits) (1 << 2))|(XrmBits)0)
283#define RSEP(((XrmBits) (1 << 4))|((XrmBits) (1 << 3))|((XrmBits
) (1 << 2))|(XrmBits)1)
(NORMAL((XrmBits) (1 << 4))|EOQ((XrmBits) (1 << 3))|SEP((XrmBits) (1 << 2))|(XrmBits)1)
284#define EOS(((XrmBits) (1 << 3))|((XrmBits) (1 << 2))|((XrmBits
) (1 << 1))|(XrmBits)0)
(EOQ((XrmBits) (1 << 3))|SEP((XrmBits) (1 << 2))|ENDOF((XrmBits) (1 << 1))|(XrmBits)0)
285#define EOL(((XrmBits) (1 << 3))|((XrmBits) (1 << 2))|((XrmBits
) (1 << 1))|(XrmBits)1)
(EOQ((XrmBits) (1 << 3))|SEP((XrmBits) (1 << 2))|ENDOF((XrmBits) (1 << 1))|(XrmBits)1)
286#define BINDING(((XrmBits) (1 << 4))|((XrmBits) (1 << 3))) (NORMAL((XrmBits) (1 << 4))|EOQ((XrmBits) (1 << 3)))
287#define ODIGIT(((XrmBits) (1 << 4))|(XrmBits)1) (NORMAL((XrmBits) (1 << 4))|(XrmBits)1)
288
289#define next_char(ch,str)xrmtypes[(unsigned char)((ch) = *(++(str)))] xrmtypes[(unsigned char)((ch) = *(++(str)))]
290#define next_mbchar(ch,len,str)xrmtypes[(unsigned char)(ch = (*db->methods->mbchar)(db
->mbstate, str, &len), str += len, ch)]
xrmtypes[(unsigned char)(ch = (*db->methods->mbchar)(db->mbstate, str, &len), str += len, ch)]
291
292#define is_space(bits)((bits) == (((XrmBits) (1 << 4))|((XrmBits) (1 <<
3))|((XrmBits) (1 << 2))|(XrmBits)0))
((bits) == SPACE(((XrmBits) (1 << 4))|((XrmBits) (1 << 3))|((XrmBits
) (1 << 2))|(XrmBits)0)
)
293#define is_EOQ(bits)((bits) & ((XrmBits) (1 << 3))) ((bits) & EOQ((XrmBits) (1 << 3)))
294#define is_EOF(bits)((bits) == (((XrmBits) (1 << 3))|((XrmBits) (1 <<
2))|((XrmBits) (1 << 1))|(XrmBits)0))
((bits) == EOS(((XrmBits) (1 << 3))|((XrmBits) (1 << 2))|((XrmBits
) (1 << 1))|(XrmBits)0)
)
295#define is_EOL(bits)((bits) & ((XrmBits) (1 << 1))) ((bits) & ENDOF((XrmBits) (1 << 1)))
296#define is_binding(bits)((bits) == (((XrmBits) (1 << 4))|((XrmBits) (1 <<
3))))
((bits) == BINDING(((XrmBits) (1 << 4))|((XrmBits) (1 << 3))))
297#define is_odigit(bits)((bits) == (((XrmBits) (1 << 4))|(XrmBits)1)) ((bits) == ODIGIT(((XrmBits) (1 << 4))|(XrmBits)1))
298#define is_separator(bits)((bits) & ((XrmBits) (1 << 2))) ((bits) & SEP((XrmBits) (1 << 2)))
299#define is_nonpcs(bits)(!(bits)) (!(bits))
300#define is_normal(bits)((bits) & ((XrmBits) (1 << 4))) ((bits) & NORMAL((XrmBits) (1 << 4)))
301#define is_simple(bits)((bits) & (((XrmBits) (1 << 4))|((XrmBits) (1 <<
5))))
((bits) & (NORMAL((XrmBits) (1 << 4))|BSLASH((XrmBits) (1 << 5))))
302#define is_special(bits)((bits) & (((XrmBits) (1 << 1))|((XrmBits) (1 <<
5))))
((bits) & (ENDOF((XrmBits) (1 << 1))|BSLASH((XrmBits) (1 << 5))))
303
304/* parsing types */
305static XrmBits const xrmtypes[256] = {
306 EOS(((XrmBits) (1 << 3))|((XrmBits) (1 << 2))|((XrmBits
) (1 << 1))|(XrmBits)0)
,0,0,0,0,0,0,0,
307 0,SPACE(((XrmBits) (1 << 4))|((XrmBits) (1 << 3))|((XrmBits
) (1 << 2))|(XrmBits)0)
,EOL(((XrmBits) (1 << 3))|((XrmBits) (1 << 2))|((XrmBits
) (1 << 1))|(XrmBits)1)
,0,0,
308#if defined(WIN32) || defined(__UNIXOS2__)
309 EOL(((XrmBits) (1 << 3))|((XrmBits) (1 << 2))|((XrmBits
) (1 << 1))|(XrmBits)1)
, /* treat CR the same as LF, just in case */
310#else
311 0,
312#endif
313 0,0,
314 0,0,0,0,0,0,0,0,
315 0,0,0,0,0,0,0,0,
316 SPACE(((XrmBits) (1 << 4))|((XrmBits) (1 << 3))|((XrmBits
) (1 << 2))|(XrmBits)0)
,NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),
317 NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),BINDING(((XrmBits) (1 << 4))|((XrmBits) (1 << 3))),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),BINDING(((XrmBits) (1 << 4))|((XrmBits) (1 << 3))),NORMAL((XrmBits) (1 << 4)),
318 ODIGIT(((XrmBits) (1 << 4))|(XrmBits)1),ODIGIT(((XrmBits) (1 << 4))|(XrmBits)1),ODIGIT(((XrmBits) (1 << 4))|(XrmBits)1),ODIGIT(((XrmBits) (1 << 4))|(XrmBits)1),ODIGIT(((XrmBits) (1 << 4))|(XrmBits)1),ODIGIT(((XrmBits) (1 << 4))|(XrmBits)1),ODIGIT(((XrmBits) (1 << 4))|(XrmBits)1),ODIGIT(((XrmBits) (1 << 4))|(XrmBits)1),
319 NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),RSEP(((XrmBits) (1 << 4))|((XrmBits) (1 << 3))|((XrmBits
) (1 << 2))|(XrmBits)1)
,NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),
320 NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),
321 NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),
322 NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),
323 NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),BSLASH((XrmBits) (1 << 5)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),
324 NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),
325 NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),
326 NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),
327 NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),NORMAL((XrmBits) (1 << 4)),0
328 /* The rest will be automatically initialized to zero. */
329};
330
331void XrmInitialize(void)
332{
333 XrmQString = XrmPermStringToQuark("String");
334 XrmQANY = XrmPermStringToQuark("?");
335}
336
337XrmDatabase XrmGetDatabase(
338 Display *display)
339{
340 XrmDatabase retval;
341 LockDisplay(display)if ((display)->lock_fns) (*(display)->lock_fns->lock_display
)(display)
;
342 retval = display->db;
343 UnlockDisplay(display)if ((display)->lock_fns) (*(display)->lock_fns->unlock_display
)(display)
;
344 return retval;
345}
346
347void XrmSetDatabase(
348 Display *display,
349 XrmDatabase database)
350{
351 LockDisplay(display)if ((display)->lock_fns) (*(display)->lock_fns->lock_display
)(display)
;
352 /* destroy database if set up implicitly by XGetDefault() */
353 if (display->db && (display->flags & XlibDisplayDfltRMDB(1L << 7))) {
354 XrmDestroyDatabase(display->db);
355 display->flags &= ~XlibDisplayDfltRMDB(1L << 7);
356 }
357 display->db = database;
358 UnlockDisplay(display)if ((display)->lock_fns) (*(display)->lock_fns->unlock_display
)(display)
;
359}
360
361void
362XrmStringToQuarkList(
363 register _Xconstconst char *name,
364 register XrmQuarkList quarks) /* RETURN */
365{
366 register XrmBits bits;
367 register Signature sig = 0;
368 register char ch, *tname;
369 register int i = 0;
370
371 if ((tname = (char *)name)) {
372 tname--;
373 while (!is_EOF(bits = next_char(ch, tname))((bits = xrmtypes[(unsigned char)((ch) = *(++(tname)))]) == (
((XrmBits) (1 << 3))|((XrmBits) (1 << 2))|((XrmBits
) (1 << 1))|(XrmBits)0))
) {
374 if (is_binding (bits)((bits) == (((XrmBits) (1 << 4))|((XrmBits) (1 <<
3))))
) {
375 if (i) {
376 /* Found a complete name */
377 *quarks++ = _XrmInternalStringToQuark(name,tname - name,
378 sig, False0);
379 i = 0;
380 sig = 0;
381 }
382 name = tname+1;
383 }
384 else {
385 sig = (sig << 1) + ch; /* Compute the signature. */
386 i++;
387 }
388 }
389 *quarks++ = _XrmInternalStringToQuark(name, tname - name, sig, False0);
390 }
391 *quarks = NULLQUARK((XrmQuark) 0);
392}
393
394void
395XrmStringToBindingQuarkList(
396 register _Xconstconst char *name,
397 register XrmBindingList bindings, /* RETURN */
398 register XrmQuarkList quarks) /* RETURN */
399{
400 register XrmBits bits;
401 register Signature sig = 0;
402 register char ch, *tname;
403 register XrmBinding binding;
404 register int i = 0;
405
406 if ((tname = (char *)name)) {
407 tname--;
408 binding = XrmBindTightly;
409 while (!is_EOF(bits = next_char(ch, tname))((bits = xrmtypes[(unsigned char)((ch) = *(++(tname)))]) == (
((XrmBits) (1 << 3))|((XrmBits) (1 << 2))|((XrmBits
) (1 << 1))|(XrmBits)0))
) {
410 if (is_binding (bits)((bits) == (((XrmBits) (1 << 4))|((XrmBits) (1 <<
3))))
) {
411 if (i) {
412 /* Found a complete name */
413 *bindings++ = binding;
414 *quarks++ = _XrmInternalStringToQuark(name, tname - name,
415 sig, False0);
416
417 i = 0;
418 sig = 0;
419 binding = XrmBindTightly;
420 }
421 name = tname+1;
422
423 if (ch == '*')
424 binding = XrmBindLoosely;
425 }
426 else {
427 sig = (sig << 1) + ch; /* Compute the signature. */
428 i++;
429 }
430 }
431 *bindings = binding;
432 *quarks++ = _XrmInternalStringToQuark(name, tname - name, sig, False0);
433 }
434 *quarks = NULLQUARK((XrmQuark) 0);
435}
436
437#ifdef DEBUG
438
439static void PrintQuarkList(
440 XrmQuarkList quarks,
441 FILE *stream)
442{
443 Boolint firstNameSeen;
444
445 for (firstNameSeen = False0; *quarks; quarks++) {
446 if (firstNameSeen) {
447 (void) fprintf(stream, ".");
448 }
449 firstNameSeen = True1;
450 (void) fputs(XrmQuarkToString(*quarks), stream);
451 }
452} /* PrintQuarkList */
453
454#endif /* DEBUG */
455
456
457/*
458 * Fallback methods for Xrm parsing.
459 * Simulate a C locale. No state needed here.
460 */
461
462static void
463c_mbnoop(
464 XPointer state)
465{
466}
467
468static char
469c_mbchar(
470 XPointer state,
471 const char *str,
472 int *lenp)
473{
474 *lenp = 1;
475 return *str;
476}
477
478static const char *
479c_lcname(
480 XPointer state)
481{
482 return "C";
483}
484
485static const XrmMethodsRec mb_methods = {
486 c_mbnoop, /* mbinit */
487 c_mbchar, /* mbchar */
488 c_mbnoop, /* mbfinish */
489 c_lcname, /* lcname */
490 c_mbnoop /* destroy */
491};
492
493
494static XrmDatabase NewDatabase(void)
495{
496 register XrmDatabase db;
497
498 db = Xmalloc(sizeof(XrmHashBucketRec))malloc(((sizeof(XrmHashBucketRec)) == 0 ? 1 : (sizeof(XrmHashBucketRec
))))
;
499 if (db) {
500 _XCreateMutex(&db->linfo)if (_XCreateMutex_fn) (*_XCreateMutex_fn)(&db->linfo);;
501 db->table = (NTable)NULL((void*)0);
502 db->mbstate = (XPointer)NULL((void*)0);
503 db->methods = _XrmInitParseInfo(&db->mbstate);
504 if (!db->methods)
505 db->methods = &mb_methods;
506 }
507 return db;
508}
509
510/* move all values from ftable to ttable, and free ftable's buckets.
511 * ttable is guaranteed empty to start with.
512 */
513static void MoveValues(
514 LTable ftable,
515 register LTable ttable)
516{
517 register VEntry fentry, nfentry;
518 register VEntry *prev;
519 register VEntry *bucket;
520 register VEntry tentry;
521 register int i;
522
523 for (i = ftable->table.mask, bucket = ftable->buckets; i >= 0; i--) {
524 for (fentry = *bucket++; fentry; fentry = nfentry) {
525 prev = &LeafHash(ttable, fentry->name)(ttable)->buckets[(fentry->name) & (ttable)->table
.mask]
;
526 tentry = *prev;
527 *prev = fentry;
528 /* chain on all with same name, to preserve invariant order */
529 while ((nfentry = fentry->next) && nfentry->name == fentry->name)
530 fentry = nfentry;
531 fentry->next = tentry;
532 }
533 }
534 Xfree(ftable->buckets)free((ftable->buckets));
535}
536
537/* move all tables from ftable to ttable, and free ftable.
538 * ttable is quaranteed empty to start with.
539 */
540static void MoveTables(
541 NTable ftable,
542 register NTable ttable)
543{
544 register NTable fentry, nfentry;
545 register NTable *prev;
546 register NTable *bucket;
547 register NTable tentry;
548 register int i;
549
550 for (i = ftable->mask, bucket = NodeBuckets(ftable)((NTable *)((ftable) + 1)); i >= 0; i--) {
551 for (fentry = *bucket++; fentry; fentry = nfentry) {
552 prev = &NodeHash(ttable, fentry->name)((NTable *)((ttable) + 1))[(fentry->name) & (ttable)->
mask]
;
553 tentry = *prev;
554 *prev = fentry;
555 /* chain on all with same name, to preserve invariant order */
556 while ((nfentry = fentry->next) && nfentry->name == fentry->name)
557 fentry = nfentry;
558 fentry->next = tentry;
559 }
560 }
561 Xfree(ftable)free((ftable));
562}
563
564/* grow the table, based on current number of entries */
565static void GrowTable(
566 NTable *prev)
567{
568 register NTable table;
569 register int i;
570
571 table = *prev;
572 i = table->mask;
573 if (i == 255) /* biggest it gets */
574 return;
575 while (i < 255 && GrowthPred(table->entries, i)((unsigned)(table->entries) > (((i) + 1) << 2)))
576 i = (i << 1) + 1;
577 i++; /* i is now the new size */
578 if (table->leaf) {
579 register LTable ltable;
580 LTableRec otable;
581
582 ltable = (LTable)table;
583 /* cons up a copy to make MoveValues look symmetric */
584 otable = *ltable;
585 ltable->buckets = Xcalloc(i, sizeof(VEntry))calloc(((i) == 0 ? 1 : (i)), (sizeof(VEntry)));
586 if (!ltable->buckets) {
587 ltable->buckets = otable.buckets;
588 return;
589 }
590 ltable->table.mask = i - 1;
591 MoveValues(&otable, ltable);
592 } else {
593 register NTable ntable;
594
595 ntable = Xcalloc(1, sizeof(NTableRec) + (i * sizeof(NTable)))calloc(((1) == 0 ? 1 : (1)), (sizeof(NTableRec) + (i * sizeof
(NTable))))
;
596 if (!ntable)
597 return;
598 *ntable = *table;
599 ntable->mask = i - 1;
600 *prev = ntable;
601 MoveTables(table, ntable);
602 }
603}
604
605/* merge values from ftable into *pprev, destroy ftable in the process */
606static void MergeValues(
607 LTable ftable,
608 NTable *pprev,
609 Boolint override)
610{
611 register VEntry fentry, tentry;
612 register VEntry *prev;
613 register LTable ttable;
614 VEntry *bucket;
615 int i;
616 register XrmQuark q;
617
618 ttable = (LTable)*pprev;
619 if (ftable->table.hasloose)
620 ttable->table.hasloose = 1;
621 for (i = ftable->table.mask, bucket = ftable->buckets;
622 i >= 0;
623 i--, bucket++) {
624 for (fentry = *bucket; fentry; ) {
625 q = fentry->name;
626 prev = &LeafHash(ttable, q)(ttable)->buckets[(q) & (ttable)->table.mask];
627 tentry = *prev;
628 while (tentry && tentry->name != q)
629 tentry = *(prev = &tentry->next);
630 /* note: test intentionally uses fentry->name instead of q */
631 /* permits serendipitous inserts */
632 while (tentry && tentry->name == fentry->name) {
633 /* if tentry is earlier, skip it */
634 if (!fentry->tight && tentry->tight) {
635 tentry = *(prev = &tentry->next);
636 continue;
637 }
638 if (fentry->tight != tentry->tight) {
639 /* no match, chain in fentry */
640 *prev = fentry;
641 prev = &fentry->next;
642 fentry = *prev;
643 *prev = tentry;
644 ttable->table.entries++;
645 } else if (override) {
646 /* match, chain in fentry, splice out and free tentry */
647 *prev = fentry;
648 prev = &fentry->next;
649 fentry = *prev;
650 *prev = tentry->next;
651 /* free the overridden entry */
652 Xfree(tentry)free((tentry));
653 /* get next tentry */
654 tentry = *prev;
655 } else {
656 /* match, discard fentry */
657 prev = &tentry->next;
658 tentry = fentry; /* use as a temp var */
659 fentry = fentry->next;
660 /* free the overpowered entry */
661 Xfree(tentry)free((tentry));
662 /* get next tentry */
663 tentry = *prev;
664 }
665 if (!fentry)
666 break;
667 }
668 /* at this point, tentry cannot match any fentry named q */
669 /* chain in all bindings together, preserve invariant order */
670 while (fentry && fentry->name == q) {
671 *prev = fentry;
672 prev = &fentry->next;
673 fentry = *prev;
674 *prev = tentry;
675 ttable->table.entries++;
676 }
677 }
678 }
679 Xfree(ftable->buckets)free((ftable->buckets));
680 Xfree(ftable)free((ftable));
681 /* resize if necessary, now that we're all done */
682 GROW(pprev)if (((unsigned)((*pprev)->entries) > ((((*pprev)->mask
) + 1) << 2))) GrowTable(pprev)
;
683}
684
685/* merge tables from ftable into *pprev, destroy ftable in the process */
686static void MergeTables(
687 NTable ftable,
688 NTable *pprev,
689 Boolint override)
690{
691 register NTable fentry, tentry;
692 NTable nfentry;
693 register NTable *prev;
694 register NTable ttable;
695 NTable *bucket;
696 int i;
697 register XrmQuark q;
698
699 ttable = *pprev;
700 if (ftable->hasloose)
701 ttable->hasloose = 1;
702 if (ftable->hasany)
703 ttable->hasany = 1;
704 for (i = ftable->mask, bucket = NodeBuckets(ftable)((NTable *)((ftable) + 1));
705 i >= 0;
706 i--, bucket++) {
707 for (fentry = *bucket; fentry; ) {
708 q = fentry->name;
709 prev = &NodeHash(ttable, q)((NTable *)((ttable) + 1))[(q) & (ttable)->mask];
710 tentry = *prev;
711 while (tentry && tentry->name != q)
712 tentry = *(prev = &tentry->next);
713 /* note: test intentionally uses fentry->name instead of q */
714 /* permits serendipitous inserts */
715 while (tentry && tentry->name == fentry->name) {
716 /* if tentry is earlier, skip it */
717 if ((fentry->leaf && !tentry->leaf) ||
718 (!fentry->tight && tentry->tight &&
719 (fentry->leaf || !tentry->leaf))) {
720 tentry = *(prev = &tentry->next);
721 continue;
722 }
723 nfentry = fentry->next;
724 if (fentry->leaf != tentry->leaf ||
725 fentry->tight != tentry->tight) {
726 /* no match, just chain in */
727 *prev = fentry;
728 *(prev = &fentry->next) = tentry;
729 ttable->entries++;
730 } else {
731 if (fentry->leaf)
732 MergeValues((LTable)fentry, prev, override);
733 else
734 MergeTables(fentry, prev, override);
735 /* bump to next tentry */
736 tentry = *(prev = &(*prev)->next);
737 }
738 /* bump to next fentry */
739 fentry = nfentry;
740 if (!fentry)
741 break;
742 }
743 /* at this point, tentry cannot match any fentry named q */
744 /* chain in all bindings together, preserve invariant order */
745 while (fentry && fentry->name == q) {
746 *prev = fentry;
747 prev = &fentry->next;
748 fentry = *prev;
749 *prev = tentry;
750 ttable->entries++;
751 }
752 }
753 }
754 Xfree(ftable)free((ftable));
755 /* resize if necessary, now that we're all done */
756 GROW(pprev)if (((unsigned)((*pprev)->entries) > ((((*pprev)->mask
) + 1) << 2))) GrowTable(pprev)
;
757}
758
759void XrmCombineDatabase(
760 XrmDatabase from, XrmDatabase *into,
761 Boolint override)
762{
763 register NTable *prev;
764 register NTable ftable, ttable, nftable;
765
766 if (!*into) {
767 *into = from;
768 } else if (from) {
769 _XLockMutex(&from->linfo)if (_XLockMutex_fn) (*_XLockMutex_fn)(&from->linfo);
770 _XLockMutex(&(*into)->linfo)if (_XLockMutex_fn) (*_XLockMutex_fn)(&(*into)->linfo);
771 if ((ftable = from->table)) {
772 prev = &(*into)->table;
773 ttable = *prev;
774 if (!ftable->leaf) {
775 nftable = ftable->next;
776 if (ttable && !ttable->leaf) {
777 /* both have node tables, merge them */
778 MergeTables(ftable, prev, override);
779 /* bump to into's leaf table, if any */
780 ttable = *(prev = &(*prev)->next);
781 } else {
782 /* into has no node table, link from's in */
783 *prev = ftable;
784 *(prev = &ftable->next) = ttable;
785 }
786 /* bump to from's leaf table, if any */
787 ftable = nftable;
788 } else {
789 /* bump to into's leaf table, if any */
790 if (ttable && !ttable->leaf)
791 ttable = *(prev = &ttable->next);
792 }
793 if (ftable) {
794 /* if into has a leaf, merge, else insert */
795 if (ttable)
796 MergeValues((LTable)ftable, prev, override);
797 else
798 *prev = ftable;
799 }
800 }
801 (from->methods->destroy)(from->mbstate);
802 _XUnlockMutex(&from->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&from->linfo
)
;
803 _XFreeMutex(&from->linfo)if (_XFreeMutex_fn) (*_XFreeMutex_fn)(&from->linfo);;
804 Xfree(from)free((from));
805 _XUnlockMutex(&(*into)->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&(*into)->linfo
)
;
806 }
807}
808
809void XrmMergeDatabases(
810 XrmDatabase from, XrmDatabase *into)
811{
812 XrmCombineDatabase(from, into, True1);
813}
814
815/* store a value in the database, overriding any existing entry */
816static void PutEntry(
817 XrmDatabase db,
818 XrmBindingList bindings,
819 XrmQuarkList quarks,
820 XrmRepresentation type,
821 XrmValuePtr value)
822{
823 register NTable *pprev, *prev;
824 register NTable table;
825 register XrmQuark q;
826 register VEntry *vprev;
827 register VEntry entry;
828 NTable *nprev, *firstpprev;
829
830#define NEWTABLE(q,i) \
831 table = Xmalloc(sizeof(LTableRec))malloc(((sizeof(LTableRec)) == 0 ? 1 : (sizeof(LTableRec)))); \
832 if (!table) \
833 return; \
834 table->name = q; \
835 table->hasloose = 0; \
836 table->hasany = 0; \
837 table->mask = 0; \
838 table->entries = 0; \
839 if (quarks[i]) { \
840 table->leaf = 0; \
841 nprev = NodeBuckets(table)((NTable *)((table) + 1)); \
842 } else { \
843 table->leaf = 1; \
844 if (!(nprev = Xmalloc(sizeof(VEntry *))malloc(((sizeof(VEntry *)) == 0 ? 1 : (sizeof(VEntry *)))))) {\
845 Xfree(table)free((table)); \
846 return; \
847 } \
848 ((LTable)table)->buckets = (VEntry *)nprev; \
849 } \
850 *nprev = (NTable)NULL((void*)0); \
851 table->next = *prev; \
852 *prev = table
853
854 if (!db || !*quarks)
855 return;
856 table = *(prev = &db->table);
857 /* if already at leaf, bump to the leaf table */
858 if (!quarks[1] && table && !table->leaf)
859 table = *(prev = &table->next);
860 pprev = prev;
861 if (!table || (quarks[1] && table->leaf)) {
862 /* no top-level node table, create one and chain it in */
863 NEWTABLE(NULLQUARK((XrmQuark) 0),1);
864 table->tight = 1; /* arbitrary */
865 prev = nprev;
866 } else {
867 /* search along until we need a value */
868 while (quarks[1]) {
869 q = *quarks;
870 table = *(prev = &NodeHash(table, q)((NTable *)((table) + 1))[(q) & (table)->mask]);
871 while (table && table->name != q)
872 table = *(prev = &table->next);
873 if (!table)
874 break; /* not found */
875 if (quarks[2]) {
876 if (table->leaf)
877 break; /* not found */
878 } else {
879 if (!table->leaf) {
880 /* bump to leaf table, if any */
881 table = *(prev = &table->next);
882 if (!table || table->name != q)
883 break; /* not found */
884 if (!table->leaf) {
885 /* bump to leaf table, if any */
886 table = *(prev = &table->next);
887 if (!table || table->name != q)
888 break; /* not found */
889 }
890 }
891 }
892 if (*bindings == XrmBindTightly) {
893 if (!table->tight)
894 break; /* not found */
895 } else {
896 if (table->tight) {
897 /* bump to loose table, if any */
898 table = *(prev = &table->next);
899 if (!table || table->name != q ||
900 !quarks[2] != table->leaf)
901 break; /* not found */
902 }
903 }
904 /* found that one, bump to next quark */
905 pprev = prev;
906 quarks++;
907 bindings++;
908 }
909 if (!quarks[1]) {
910 /* found all the way to a leaf */
911 q = *quarks;
912 entry = *(vprev = &LeafHash((LTable)table, q)((LTable)table)->buckets[(q) & ((LTable)table)->table
.mask]
);
913 while (entry && entry->name != q)
914 entry = *(vprev = &entry->next);
915 /* if want loose and have tight, bump to next entry */
916 if (entry && *bindings == XrmBindLoosely && entry->tight)
917 entry = *(vprev = &entry->next);
918 if (entry && entry->name == q &&
919 (*bindings == XrmBindTightly) == entry->tight) {
920 /* match, need to override */
921 if ((type == XrmQString) == entry->string &&
922 entry->size == value->size) {
923 /* update type if not String, can be different */
924 if (!entry->string)
925 RepType(entry)((DEntry)(entry))->type = type;
926 /* identical size, just overwrite value */
927 memcpy(RawValue(entry), (char *)value->addr, value->size)__builtin___memcpy_chk ((char *)((entry)->string ? (XPointer
)((entry) + 1) : (XPointer)(((DEntry)(entry)) + 1)), (char *)
value->addr, value->size, __builtin_object_size ((char *
)((entry)->string ? (XPointer)((entry) + 1) : (XPointer)((
(DEntry)(entry)) + 1)), 0))
;
928 return;
929 }
930 /* splice out and free old entry */
931 *vprev = entry->next;
932 Xfree(entry)free((entry));
933 (*pprev)->entries--;
934 }
935 /* this is where to insert */
936 prev = (NTable *)vprev;
937 }
938 }
939 /* keep the top table, because we may have to grow it */
940 firstpprev = pprev;
941 /* iterate until we get to the leaf */
942 while (quarks[1]) {
943 /* build a new table and chain it in */
944 NEWTABLE(*quarks,2);
945 if (*quarks++ == XrmQANY)
946 (*pprev)->hasany = 1;
947 if (*bindings++ == XrmBindTightly) {
948 table->tight = 1;
949 } else {
950 table->tight = 0;
951 (*pprev)->hasloose = 1;
952 }
953 (*pprev)->entries++;
954 pprev = prev;
955 prev = nprev;
956 }
957 /* now allocate the value entry */
958 entry = Xmalloc(((type == XrmQString) ?malloc(((((type == XrmQString) ? sizeof(VEntryRec) : sizeof(DEntryRec
)) + value->size) == 0 ? 1 : (((type == XrmQString) ? sizeof
(VEntryRec) : sizeof(DEntryRec)) + value->size)))
959 sizeof(VEntryRec) : sizeof(DEntryRec)) + value->size)malloc(((((type == XrmQString) ? sizeof(VEntryRec) : sizeof(DEntryRec
)) + value->size) == 0 ? 1 : (((type == XrmQString) ? sizeof
(VEntryRec) : sizeof(DEntryRec)) + value->size)))
;
960 if (!entry)
961 return;
962 entry->name = q = *quarks;
963 if (*bindings == XrmBindTightly) {
964 entry->tight = 1;
965 } else {
966 entry->tight = 0;
967 (*pprev)->hasloose = 1;
968 }
969 /* chain it in, with a bit of type cast ugliness */
970 entry->next = *((VEntry *)prev);
971 *((VEntry *)prev) = entry;
972 entry->size = value->size;
973 if (type == XrmQString) {
974 entry->string = 1;
975 } else {
976 entry->string = 0;
977 RepType(entry)((DEntry)(entry))->type = type;
978 }
979 /* save a copy of the value */
980 memcpy(RawValue(entry), (char *)value->addr, value->size)__builtin___memcpy_chk ((char *)((entry)->string ? (XPointer
)((entry) + 1) : (XPointer)(((DEntry)(entry)) + 1)), (char *)
value->addr, value->size, __builtin_object_size ((char *
)((entry)->string ? (XPointer)((entry) + 1) : (XPointer)((
(DEntry)(entry)) + 1)), 0))
;
981 (*pprev)->entries++;
982 /* this is a new leaf, need to remember it for search lists */
983 if (q > maxResourceQuark) {
984 unsigned oldsize = (maxResourceQuark + 1) >> 3;
985 unsigned size = ((q | 0x7f) + 1) >> 3; /* reallocate in chunks */
986 if (resourceQuarks) {
987 unsigned char *prevQuarks = resourceQuarks;
988
989 resourceQuarks = Xrealloc(resourceQuarks, size)realloc((resourceQuarks), ((size) == 0 ? 1 : (size)));
990 if (!resourceQuarks) {
991 Xfree(prevQuarks)free((prevQuarks));
992 }
993 } else
994 resourceQuarks = Xmalloc(size)malloc(((size) == 0 ? 1 : (size)));
995 if (resourceQuarks) {
996 bzero((char *)&resourceQuarks[oldsize], size - oldsize)__builtin___memset_chk ((char *)&resourceQuarks[oldsize],
0, size - oldsize, __builtin_object_size ((char *)&resourceQuarks
[oldsize], 0))
;
997 maxResourceQuark = (size << 3) - 1;
998 } else {
999 maxResourceQuark = -1;
1000 }
1001 }
1002 if (q > 0 && resourceQuarks)
1003 resourceQuarks[q >> 3] |= 1 << (q & 0x7);
1004 GROW(firstpprev)if (((unsigned)((*firstpprev)->entries) > ((((*firstpprev
)->mask) + 1) << 2))) GrowTable(firstpprev)
;
1005
1006#undef NEWTABLE
1007}
1008
1009void XrmQPutResource(
1010 XrmDatabase *pdb,
1011 XrmBindingList bindings,
1012 XrmQuarkList quarks,
1013 XrmRepresentation type,
1014 XrmValuePtr value)
1015{
1016 if (!*pdb) *pdb = NewDatabase();
1017 _XLockMutex(&(*pdb)->linfo)if (_XLockMutex_fn) (*_XLockMutex_fn)(&(*pdb)->linfo);
1018 PutEntry(*pdb, bindings, quarks, type, value);
1019 _XUnlockMutex(&(*pdb)->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&(*pdb)->linfo
)
;
1020}
1021
1022void
1023XrmPutResource(
1024 XrmDatabase *pdb,
1025 _Xconstconst char *specifier,
1026 _Xconstconst char *type,
1027 XrmValuePtr value)
1028{
1029 XrmBinding bindings[MAXDBDEPTH100+1];
1030 XrmQuark quarks[MAXDBDEPTH100+1];
1031
1032 if (!*pdb) *pdb = NewDatabase();
1033 _XLockMutex(&(*pdb)->linfo)if (_XLockMutex_fn) (*_XLockMutex_fn)(&(*pdb)->linfo);
1034 XrmStringToBindingQuarkList(specifier, bindings, quarks);
1035 PutEntry(*pdb, bindings, quarks, XrmStringToQuark(type), value);
1036 _XUnlockMutex(&(*pdb)->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&(*pdb)->linfo
)
;
1037}
1038
1039void
1040XrmQPutStringResource(
1041 XrmDatabase *pdb,
1042 XrmBindingList bindings,
1043 XrmQuarkList quarks,
1044 _Xconstconst char *str)
1045{
1046 XrmValue value;
1047
1048 if (!*pdb) *pdb = NewDatabase();
1049 value.addr = (XPointer) str;
1050 value.size = strlen(str)+1;
1051 _XLockMutex(&(*pdb)->linfo)if (_XLockMutex_fn) (*_XLockMutex_fn)(&(*pdb)->linfo);
1052 PutEntry(*pdb, bindings, quarks, XrmQString, &value);
1053 _XUnlockMutex(&(*pdb)->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&(*pdb)->linfo
)
;
1054}
1055
1056/* Function Name: GetDatabase
1057 * Description: Parses a string and stores it as a database.
1058 * Arguments: db - the database.
1059 * str - a pointer to the string containing the database.
1060 * filename - source filename, if any.
1061 * doall - whether to do all lines or just one
1062 */
1063
1064/*
1065 * This function is highly optimized to inline as much as possible.
1066 * Be very careful with modifications, or simplifications, as they
1067 * may adversely affect the performance.
1068 *
1069 * Chris Peterson, MIT X Consortium 5/17/90.
1070 */
1071
1072/*
1073 * Xlib spec says max 100 quarks in a lookup, will stop and return if
1074 * return if any single production's lhs has more than 100 components.
1075 */
1076#define QLIST_SIZE100 100
1077
1078/*
1079 * This should be big enough to handle things like the XKeysymDB or biggish
1080 * ~/.Xdefaults or app-defaults files. Anything bigger will be allocated on
1081 * the heap.
1082 */
1083#define DEF_BUFF_SIZE8192 8192
1084
1085static void GetIncludeFile(
1086 XrmDatabase db,
1087 _Xconstconst char *base,
1088 _Xconstconst char *fname,
1089 int fnamelen,
1090 int depth);
1091
1092static void GetDatabase(
1093 XrmDatabase db,
1094 _Xconstconst char *str,
1095 _Xconstconst char *filename,
1096 Boolint doall,
1097 int depth)
1098{
1099 char *rhs;
1100 char *lhs, lhs_s[DEF_BUFF_SIZE8192];
1101 XrmQuark quarks[QLIST_SIZE100 + 1]; /* allow for a terminal NullQuark */
1102 XrmBinding bindings[QLIST_SIZE100 + 1];
1103
1104 register char *ptr;
1105 register XrmBits bits = 0;
1106 register char c;
1107 register Signature sig;
1108 register char *ptr_max;
1109 register int num_quarks;
1110 register XrmBindingList t_bindings;
1111
1112 int len, alloc_chars;
1113 unsigned long str_len;
1114 XrmValue value;
1115 Boolint only_pcs;
1116 Boolint dolines;
1117
1118 if (!db)
1119 return;
1120
1121 /*
1122 * if strlen (str) < DEF_BUFF_SIZE allocate buffers on the stack for
1123 * speed otherwise malloc the buffer. From a buffer overflow standpoint
1124 * we can be sure that neither: a) a component on the lhs, or b) a
1125 * value on the rhs, will be longer than the overall length of str,
1126 * i.e. strlen(str).
1127 *
1128 * This should give good performance when parsing "*foo: bar" type
1129 * databases as might be passed with -xrm command line options; but
1130 * with larger databases, e.g. .Xdefaults, app-defaults, or KeysymDB
1131 * files, the size of the buffers will be overly large. One way
1132 * around this would be to double-parse each production with a resulting
1133 * performance hit. In any event we can be assured that a lhs component
1134 * name or a rhs value won't be longer than str itself.
1135 */
1136
1137 str_len = strlen (str);
1138 if (DEF_BUFF_SIZE8192 > str_len) lhs = lhs_s;
1139 else if ((lhs = Xmalloc (str_len)malloc(((str_len) == 0 ? 1 : (str_len)))) == NULL((void*)0))
1140 return;
1141
1142 alloc_chars = DEF_BUFF_SIZE8192 < str_len ? str_len : DEF_BUFF_SIZE8192;
1143 if ((rhs = Xmalloc (alloc_chars)malloc(((alloc_chars) == 0 ? 1 : (alloc_chars)))) == NULL((void*)0)) {
1144 if (lhs != lhs_s) Xfree (lhs)free((lhs));
1145 return;
1146 }
1147
1148 (*db->methods->mbinit)(db->mbstate);
1149 str--;
1150 dolines = True1;
1151 while (!is_EOF(bits)((bits) == (((XrmBits) (1 << 3))|((XrmBits) (1 <<
2))|((XrmBits) (1 << 1))|(XrmBits)0))
&& dolines) {
1152 dolines = doall;
1153
1154 /*
1155 * First: Remove extra whitespace.
1156 */
1157
1158 do {
1159 bits = next_char(c, str)xrmtypes[(unsigned char)((c) = *(++(str)))];
1160 } while is_space(bits)((bits) == (((XrmBits) (1 << 4))|((XrmBits) (1 <<
3))|((XrmBits) (1 << 2))|(XrmBits)0))
;
1161
1162 /*
1163 * Ignore empty lines.
1164 */
1165
1166 if (is_EOL(bits)((bits) & ((XrmBits) (1 << 1))))
1167 continue; /* start a new line. */
1168
1169 /*
1170 * Second: check the first character in a line to see if it is
1171 * "!" signifying a comment, or "#" signifying a directive.
1172 */
1173
1174 if (c == '!') { /* Comment, spin to next newline */
1175 while (is_simple(bits = next_char(c, str))((bits = xrmtypes[(unsigned char)((c) = *(++(str)))]) & (
((XrmBits) (1 << 4))|((XrmBits) (1 << 5))))
) {}
1176 if (is_EOL(bits)((bits) & ((XrmBits) (1 << 1))))
1177 continue;
1178 while (!is_EOL(bits = next_mbchar(c, len, str))((bits = xrmtypes[(unsigned char)(c = (*db->methods->mbchar
)(db->mbstate, str, &len), str += len, c)]) & ((XrmBits
) (1 << 1)))
) {}
1179 str--;
1180 continue; /* start a new line. */
1181 }
1182
1183 if (c == '#') { /* Directive */
1184 /* remove extra whitespace */
1185 only_pcs = True1;
1186 while (is_space(bits = next_char(c, str))((bits = xrmtypes[(unsigned char)((c) = *(++(str)))]) == (((XrmBits
) (1 << 4))|((XrmBits) (1 << 3))|((XrmBits) (1 <<
2))|(XrmBits)0))
) {};
1187 /* only "include" directive is currently defined */
1188 if (!strncmp(str, "include", 7)) {
1189 str += (7-1);
1190 /* remove extra whitespace */
1191 while (is_space(bits = next_char(c, str))((bits = xrmtypes[(unsigned char)((c) = *(++(str)))]) == (((XrmBits
) (1 << 4))|((XrmBits) (1 << 3))|((XrmBits) (1 <<
2))|(XrmBits)0))
) {};
1192 /* must have a starting " */
1193 if (c == '"') {
1194 _Xconstconst char *fname = str+1;
1195 len = 0;
1196 do {
1197 if (only_pcs) {
1198 bits = next_char(c, str)xrmtypes[(unsigned char)((c) = *(++(str)))];
1199 if (is_nonpcs(bits)(!(bits)))
1200 only_pcs = False0;
1201 }
1202 if (!only_pcs)
1203 bits = next_mbchar(c, len, str)xrmtypes[(unsigned char)(c = (*db->methods->mbchar)(db->
mbstate, str, &len), str += len, c)]
;
1204 } while (c != '"' && !is_EOL(bits)((bits) & ((XrmBits) (1 << 1))));
1205 /* must have an ending " */
1206 if (c == '"')
1207 GetIncludeFile(db, filename, fname, str - len - fname,
1208 depth);
1209 }
1210 }
1211 /* spin to next newline */
1212 if (only_pcs) {
1213 while (is_simple(bits)((bits) & (((XrmBits) (1 << 4))|((XrmBits) (1 <<
5))))
)
1214 bits = next_char(c, str)xrmtypes[(unsigned char)((c) = *(++(str)))];
1215 if (is_EOL(bits)((bits) & ((XrmBits) (1 << 1))))
1216 continue;
1217 }
1218 while (!is_EOL(bits)((bits) & ((XrmBits) (1 << 1))))
1219 bits = next_mbchar(c, len, str)xrmtypes[(unsigned char)(c = (*db->methods->mbchar)(db->
mbstate, str, &len), str += len, c)]
;
1220 str--;
1221 continue; /* start a new line. */
1222 }
1223
1224 /*
1225 * Third: loop through the LHS of the resource specification
1226 * storing characters and converting this to a Quark.
1227 */
1228
1229 num_quarks = 0;
1230 t_bindings = bindings;
1231
1232 sig = 0;
1233 ptr = lhs;
1234 *t_bindings = XrmBindTightly;
1235 for(;;) {
1236 if (!is_binding(bits)((bits) == (((XrmBits) (1 << 4))|((XrmBits) (1 <<
3))))
) {
1237 while (!is_EOQ(bits)((bits) & ((XrmBits) (1 << 3)))) {
1238 *ptr++ = c;
1239 sig = (sig << 1) + c; /* Compute the signature. */
1240 bits = next_char(c, str)xrmtypes[(unsigned char)((c) = *(++(str)))];
1241 }
1242
1243 quarks[num_quarks++] =
1244 _XrmInternalStringToQuark(lhs, ptr - lhs, sig, False0);
1245
1246 if (num_quarks > QLIST_SIZE100) {
1247 Xfree(rhs)free((rhs));
1248 if (lhs != lhs_s) Xfree (lhs)free((lhs));
1249 (*db->methods->mbfinish)(db->mbstate);
1250 return;
1251 }
1252
1253 if (is_separator(bits)((bits) & ((XrmBits) (1 << 2)))) {
1254 if (!is_space(bits)((bits) == (((XrmBits) (1 << 4))|((XrmBits) (1 <<
3))|((XrmBits) (1 << 2))|(XrmBits)0))
)
1255 break;
1256
1257 /* Remove white space */
1258 do {
1259 *ptr++ = c;
1260 sig = (sig << 1) + c; /* Compute the signature. */
1261 } while (is_space(bits = next_char(c, str))((bits = xrmtypes[(unsigned char)((c) = *(++(str)))]) == (((XrmBits
) (1 << 4))|((XrmBits) (1 << 3))|((XrmBits) (1 <<
2))|(XrmBits)0))
);
1262
1263 /*
1264 * The spec doesn't permit it, but support spaces
1265 * internal to resource name/class
1266 */
1267
1268 if (is_separator(bits)((bits) & ((XrmBits) (1 << 2))))
1269 break;
1270 num_quarks--;
1271 continue;
1272 }
1273
1274 if (c == '.')
1275 *(++t_bindings) = XrmBindTightly;
1276 else
1277 *(++t_bindings) = XrmBindLoosely;
1278
1279 sig = 0;
1280 ptr = lhs;
1281 }
1282 else {
1283 /*
1284 * Magic unspecified feature #254.
1285 *
1286 * If two separators appear with no Text between them then
1287 * ignore them.
1288 *
1289 * If anyone of those separators is a '*' then the binding
1290 * will be loose, otherwise it will be tight.
1291 */
1292
1293 if (c == '*')
1294 *t_bindings = XrmBindLoosely;
1295 }
1296
1297 bits = next_char(c, str)xrmtypes[(unsigned char)((c) = *(++(str)))];
1298 }
1299
1300 quarks[num_quarks] = NULLQUARK((XrmQuark) 0);
1301
1302 /*
1303 * Make sure that there is a ':' in this line.
1304 */
1305
1306 if (c != ':') {
1307 char oldc;
1308
1309 /*
1310 * A parsing error has occured, toss everything on the line
1311 * a new_line can still be escaped with a '\'.
1312 */
1313
1314 while (is_normal(bits)((bits) & ((XrmBits) (1 << 4))))
1315 bits = next_char(c, str)xrmtypes[(unsigned char)((c) = *(++(str)))];
1316 if (is_EOL(bits)((bits) & ((XrmBits) (1 << 1))))
1317 continue;
1318 bits = next_mbchar(c, len, str)xrmtypes[(unsigned char)(c = (*db->methods->mbchar)(db->
mbstate, str, &len), str += len, c)]
;
1319 do {
1320 oldc = c;
1321 bits = next_mbchar(c, len, str)xrmtypes[(unsigned char)(c = (*db->methods->mbchar)(db->
mbstate, str, &len), str += len, c)]
;
1322 } while (c && (c != '\n' || oldc == '\\'));
1323 str--;
1324 continue;
1325 }
1326
1327 /*
1328 * I now have a quark and binding list for the entire left hand
1329 * side. "c" currently points to the ":" separating the left hand
1330 * side for the right hand side. It is time to begin processing
1331 * the right hand side.
1332 */
1333
1334 /*
1335 * Fourth: Remove more whitespace
1336 */
1337
1338 for(;;) {
1339 if (is_space(bits = next_char(c, str))((bits = xrmtypes[(unsigned char)((c) = *(++(str)))]) == (((XrmBits
) (1 << 4))|((XrmBits) (1 << 3))|((XrmBits) (1 <<
2))|(XrmBits)0))
)
1340 continue;
1341 if (c != '\\')
1342 break;
1343 bits = next_char(c, str)xrmtypes[(unsigned char)((c) = *(++(str)))];
Value stored to 'bits' is never read
1344 if (c == '\n')
1345 continue;
1346 str--;
1347 bits = BSLASH((XrmBits) (1 << 5));
1348 c = '\\';
1349 break;
1350 }
1351
1352 /*
1353 * Fifth: Process the right hand side.
1354 */
1355
1356 ptr = rhs;
1357 ptr_max = ptr + alloc_chars - 4;
1358 only_pcs = True1;
1359 len = 1;
1360
1361 for(;;) {
1362
1363 /*
1364 * Tight loop for the normal case: Non backslash, non-end of value
1365 * character that will fit into the allocated buffer.
1366 */
1367
1368 if (only_pcs) {
1369 while (is_normal(bits)((bits) & ((XrmBits) (1 << 4))) && ptr < ptr_max) {
1370 *ptr++ = c;
1371 bits = next_char(c, str)xrmtypes[(unsigned char)((c) = *(++(str)))];
1372 }
1373 if (is_EOL(bits)((bits) & ((XrmBits) (1 << 1))))
1374 break;
1375 if (is_nonpcs(bits)(!(bits))) {
1376 only_pcs = False0;
1377 bits = next_mbchar(c, len, str)xrmtypes[(unsigned char)(c = (*db->methods->mbchar)(db->
mbstate, str, &len), str += len, c)]
;
1378 }
1379 }
1380 while (!is_special(bits)((bits) & (((XrmBits) (1 << 1))|((XrmBits) (1 <<
5))))
&& ptr + len <= ptr_max) {
1381 len = -len;
1382 while (len)
1383 *ptr++ = str[len++];
1384 if (*str == '\0') {
1385 bits = EOS(((XrmBits) (1 << 3))|((XrmBits) (1 << 2))|((XrmBits
) (1 << 1))|(XrmBits)0)
;
1386 break;
1387 }
1388 bits = next_mbchar(c, len, str)xrmtypes[(unsigned char)(c = (*db->methods->mbchar)(db->
mbstate, str, &len), str += len, c)]
;
1389 }
1390
1391 if (is_EOL(bits)((bits) & ((XrmBits) (1 << 1)))) {
1392 str--;
1393 break;
1394 }
1395
1396 if (c == '\\') {
1397 /*
1398 * We need to do some magic after a backslash.
1399 */
1400 Boolint read_next = True1;
1401
1402 if (only_pcs) {
1403 bits = next_char(c, str)xrmtypes[(unsigned char)((c) = *(++(str)))];
1404 if (is_nonpcs(bits)(!(bits)))
1405 only_pcs = False0;
1406 }
1407 if (!only_pcs)
1408 bits = next_mbchar(c, len, str)xrmtypes[(unsigned char)(c = (*db->methods->mbchar)(db->
mbstate, str, &len), str += len, c)]
;
1409
1410 if (is_EOL(bits)((bits) & ((XrmBits) (1 << 1)))) {
1411 if (is_EOF(bits)((bits) == (((XrmBits) (1 << 3))|((XrmBits) (1 <<
2))|((XrmBits) (1 << 1))|(XrmBits)0))
)
1412 continue;
1413 } else if (c == 'n') {
1414 /*
1415 * "\n" means insert a newline.
1416 */
1417 *ptr++ = '\n';
1418 } else if (c == '\\') {
1419 /*
1420 * "\\" completes to just one backslash.
1421 */
1422 *ptr++ = '\\';
1423 } else {
1424 /*
1425 * pick up to three octal digits after the '\'.
1426 */
1427 char temp[3];
1428 int count = 0;
1429 while (is_odigit(bits)((bits) == (((XrmBits) (1 << 4))|(XrmBits)1)) && count < 3) {
1430 temp[count++] = c;
1431 if (only_pcs) {
1432 bits = next_char(c, str)xrmtypes[(unsigned char)((c) = *(++(str)))];
1433 if (is_nonpcs(bits)(!(bits)))
1434 only_pcs = False0;
1435 }
1436 if (!only_pcs)
1437 bits = next_mbchar(c, len, str)xrmtypes[(unsigned char)(c = (*db->methods->mbchar)(db->
mbstate, str, &len), str += len, c)]
;
1438 }
1439
1440 /*
1441 * If we found three digits then insert that octal code
1442 * into the value string as a character.
1443 */
1444
1445 if (count == 3) {
1446 *ptr++ = (unsigned char) ((temp[0] - '0') * 0100 +
1447 (temp[1] - '0') * 010 +
1448 (temp[2] - '0'));
1449 }
1450 else {
1451 int tcount;
1452
1453 /*
1454 * Otherwise just insert those characters into the
1455 * string, since no special processing is needed on
1456 * numerics we can skip the special processing.
1457 */
1458
1459 for (tcount = 0; tcount < count; tcount++) {
1460 *ptr++ = temp[tcount]; /* print them in
1461 the correct order */
1462 }
1463 }
1464 read_next = False0;
1465 }
1466 if (read_next) {
1467 if (only_pcs) {
1468 bits = next_char(c, str)xrmtypes[(unsigned char)((c) = *(++(str)))];
1469 if (is_nonpcs(bits)(!(bits)))
1470 only_pcs = False0;
1471 }
1472 if (!only_pcs)
1473 bits = next_mbchar(c, len, str)xrmtypes[(unsigned char)(c = (*db->methods->mbchar)(db->
mbstate, str, &len), str += len, c)]
;
1474 }
1475 }
1476
1477 /*
1478 * It is important to make sure that there is room for at least
1479 * four more characters in the buffer, since I can add that
1480 * many characters into the buffer after a backslash has occured.
1481 */
1482
1483 if (ptr + len > ptr_max) {
1484 char * temp_str;
1485
1486 alloc_chars += BUFSIZ1024/10;
1487 temp_str = Xrealloc(rhs, sizeof(char) * alloc_chars)realloc((rhs), ((sizeof(char) * alloc_chars) == 0 ? 1 : (sizeof
(char) * alloc_chars)))
;
1488
1489 if (!temp_str) {
1490 Xfree(rhs)free((rhs));
1491 if (lhs != lhs_s) Xfree (lhs)free((lhs));
1492 (*db->methods->mbfinish)(db->mbstate);
1493 return;
1494 }
1495
1496 ptr = temp_str + (ptr - rhs); /* reset pointer. */
1497 rhs = temp_str;
1498 ptr_max = rhs + alloc_chars - 4;
1499 }
1500 }
1501
1502 /*
1503 * Lastly: Terminate the value string, and store this entry
1504 * into the database.
1505 */
1506
1507 *ptr++ = '\0';
1508
1509 /* Store it in database */
1510 value.size = ptr - rhs;
1511 value.addr = (XPointer) rhs;
1512
1513 PutEntry(db, bindings, quarks, XrmQString, &value);
1514 }
1515
1516 if (lhs != lhs_s) Xfree (lhs)free((lhs));
1517 Xfree (rhs)free((rhs));
1518
1519 (*db->methods->mbfinish)(db->mbstate);
1520}
1521
1522void
1523XrmPutStringResource(
1524 XrmDatabase *pdb,
1525 _Xconstconst char*specifier,
1526 _Xconstconst char*str)
1527{
1528 XrmValue value;
1529 XrmBinding bindings[MAXDBDEPTH100+1];
1530 XrmQuark quarks[MAXDBDEPTH100+1];
1531
1532 if (!*pdb) *pdb = NewDatabase();
1533 XrmStringToBindingQuarkList(specifier, bindings, quarks);
1534 value.addr = (XPointer) str;
1535 value.size = strlen(str)+1;
1536 _XLockMutex(&(*pdb)->linfo)if (_XLockMutex_fn) (*_XLockMutex_fn)(&(*pdb)->linfo);
1537 PutEntry(*pdb, bindings, quarks, XrmQString, &value);
1538 _XUnlockMutex(&(*pdb)->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&(*pdb)->linfo
)
;
1539}
1540
1541
1542void
1543XrmPutLineResource(
1544 XrmDatabase *pdb,
1545 _Xconstconst char*line)
1546{
1547 if (!*pdb) *pdb = NewDatabase();
1548 _XLockMutex(&(*pdb)->linfo)if (_XLockMutex_fn) (*_XLockMutex_fn)(&(*pdb)->linfo);
1549 GetDatabase(*pdb, line, (char *)NULL((void*)0), False0, 0);
1550 _XUnlockMutex(&(*pdb)->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&(*pdb)->linfo
)
;
1551}
1552
1553XrmDatabase
1554XrmGetStringDatabase(
1555 _Xconstconst char *data)
1556{
1557 XrmDatabase db;
1558
1559 db = NewDatabase();
1560 _XLockMutex(&db->linfo)if (_XLockMutex_fn) (*_XLockMutex_fn)(&db->linfo);
1561 GetDatabase(db, data, (char *)NULL((void*)0), True1, 0);
1562 _XUnlockMutex(&db->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&db->linfo);
1563 return db;
1564}
1565
1566/* Function Name: ReadInFile
1567 * Description: Reads the file into a buffer.
1568 * Arguments: filename - the name of the file.
1569 * Returns: An allocated string containing the contents of the file.
1570 */
1571
1572static char *
1573ReadInFile(_Xconstconst char *filename)
1574{
1575 register int fd, size;
1576 char * filebuf;
1577
1578#ifdef __UNIXOS2__
1579 filename = __XOS2RedirRoot(filename);
1580#endif
1581
1582 /*
1583 * MS-Windows and OS/2 note: Default open mode includes O_TEXT
1584 */
1585 if ( (fd = _XOpenFile (filename, O_RDONLY)open(filename,0x0000)) == -1 )
1586 return (char *)NULL((void*)0);
1587
1588 /*
1589 * MS-Windows and OS/2 note: depending on how the sources are
1590 * untarred, the newlines in resource files may or may not have
1591 * been expanded to CRLF. Either way the size returned by fstat
1592 * is sufficient to read the file into because in text-mode any
1593 * CRLFs in a file will be converted to newlines (LF) with the
1594 * result that the number of bytes actually read with be <=
1595 * to the size returned by fstat.
1596 */
1597 {
1598 struct stat status_buffer;
1599 if ( ((fstat(fd, &status_buffer)) == -1 ) ||
1600 (status_buffer.st_size >= INT_MAX2147483647) ) {
1601 close (fd);
1602 return (char *)NULL((void*)0);
1603 } else
1604 size = (int) status_buffer.st_size;
1605 }
1606
1607 if (!(filebuf = Xmalloc(size + 1)malloc(((size + 1) == 0 ? 1 : (size + 1))))) { /* leave room for '\0' */
1608 close(fd);
1609 return (char *)NULL((void*)0);
1610 }
1611 size = read (fd, filebuf, size);
1612
1613#ifdef __UNIXOS2__
1614 { /* kill CRLF */
1615 int i,k;
1616 for (i=k=0; i<size; i++)
1617 if (filebuf[i] != 0x0d) {
1618 filebuf[k++] = filebuf[i];
1619 }
1620 filebuf[k] = 0;
1621 }
1622#endif
1623
1624 if (size < 0) {
1625 close (fd);
1626 Xfree(filebuf)free((filebuf));
1627 return (char *)NULL((void*)0);
1628 }
1629 close (fd);
1630
1631 filebuf[size] = '\0'; /* NULL terminate it. */
1632 return filebuf;
1633}
1634
1635static void
1636GetIncludeFile(
1637 XrmDatabase db,
1638 _Xconstconst char *base,
1639 _Xconstconst char *fname,
1640 int fnamelen,
1641 int depth)
1642{
1643 int len;
1644 char *str;
1645 char realfname[BUFSIZ1024];
1646
1647 if (fnamelen <= 0 || fnamelen >= BUFSIZ1024)
1648 return;
1649 if (depth >= MAXDBDEPTH100)
1650 return;
1651 if (*fname != '/' && base && (str = strrchr(base, '/'))) {
1652 len = str - base + 1;
1653 if (len + fnamelen >= BUFSIZ1024)
1654 return;
1655 strncpy(realfname, base, len)__builtin___strncpy_chk (realfname, base, len, __builtin_object_size
(realfname, 2 > 1 ? 1 : 0))
;
1656 strncpy(realfname + len, fname, fnamelen)__builtin___strncpy_chk (realfname + len, fname, fnamelen, __builtin_object_size
(realfname + len, 2 > 1 ? 1 : 0))
;
1657 realfname[len + fnamelen] = '\0';
1658 } else {
1659 strncpy(realfname, fname, fnamelen)__builtin___strncpy_chk (realfname, fname, fnamelen, __builtin_object_size
(realfname, 2 > 1 ? 1 : 0))
;
1660 realfname[fnamelen] = '\0';
1661 }
1662 if (!(str = ReadInFile(realfname)))
1663 return;
1664 GetDatabase(db, str, realfname, True1, depth + 1);
1665 Xfree(str)free((str));
1666}
1667
1668XrmDatabase
1669XrmGetFileDatabase(
1670 _Xconstconst char *filename)
1671{
1672 XrmDatabase db;
1673 char *str;
1674
1675 if (!(str = ReadInFile(filename)))
1676 return (XrmDatabase)NULL((void*)0);
1677
1678 db = NewDatabase();
1679 _XLockMutex(&db->linfo)if (_XLockMutex_fn) (*_XLockMutex_fn)(&db->linfo);
1680 GetDatabase(db, str, filename, True1, 0);
1681 _XUnlockMutex(&db->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&db->linfo);
1682 Xfree(str)free((str));
1683 return db;
1684}
1685
1686Statusint
1687XrmCombineFileDatabase(
1688 _Xconstconst char *filename,
1689 XrmDatabase *target,
1690 Boolint override)
1691{
1692 XrmDatabase db;
1693 char *str;
1694
1695 if (!(str = ReadInFile(filename)))
1696 return 0;
1697 if (override) {
1698 db = *target;
1699 if (!db)
1700 *target = db = NewDatabase();
1701 } else
1702 db = NewDatabase();
1703 _XLockMutex(&db->linfo)if (_XLockMutex_fn) (*_XLockMutex_fn)(&db->linfo);
1704 GetDatabase(db, str, filename, True1, 0);
1705 _XUnlockMutex(&db->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&db->linfo);
1706 Xfree(str)free((str));
1707 if (!override)
1708 XrmCombineDatabase(db, target, False0);
1709 return 1;
1710}
1711
1712/* call the user proc for every value in the table, arbitrary order.
1713 * stop if user proc returns True. level is current depth in database.
1714 */
1715/*ARGSUSED*/
1716static Boolint EnumLTable(
1717 LTable table,
1718 XrmNameList names,
1719 XrmClassList classes,
1720 register int level,
1721 register EClosure closure)
1722{
1723 register VEntry *bucket;
1724 register int i;
1725 register VEntry entry;
1726 XrmValue value;
1727 XrmRepresentation type;
1728 Boolint tightOk;
1729
1730 closure->bindings[level] = (table->table.tight ?
1731 XrmBindTightly : XrmBindLoosely);
1732 closure->quarks[level] = table->table.name;
1733 level++;
1734 tightOk = !*names;
1735 closure->quarks[level + 1] = NULLQUARK((XrmQuark) 0);
1736 for (i = table->table.mask, bucket = table->buckets;
1737 i >= 0;
1738 i--, bucket++) {
1739 for (entry = *bucket; entry; entry = entry->next) {
1740 if (entry->tight && !tightOk)
1741 continue;
1742 closure->bindings[level] = (entry->tight ?
1743 XrmBindTightly : XrmBindLoosely);
1744 closure->quarks[level] = entry->name;
1745 value.size = entry->size;
1746 if (entry->string) {
1747 type = XrmQString;
1748 value.addr = StringValue(entry)(XPointer)((entry) + 1);
1749 } else {
1750 type = RepType(entry)((DEntry)(entry))->type;
1751 value.addr = DataValue(entry)(XPointer)(((DEntry)(entry)) + 1);
1752 }
1753 if ((*closure->proc)(&closure->db, closure->bindings+1,
1754 closure->quarks+1, &type, &value,
1755 closure->closure))
1756 return True1;
1757 }
1758 }
1759 return False0;
1760}
1761
1762static Boolint EnumAllNTable(
1763 NTable table,
1764 register int level,
1765 register EClosure closure)
1766{
1767 register NTable *bucket;
1768 register int i;
1769 register NTable entry;
1770 XrmQuark empty = NULLQUARK((XrmQuark) 0);
1771
1772 if (level >= MAXDBDEPTH100)
1773 return False0;
1774 for (i = table->mask, bucket = NodeBuckets(table)((NTable *)((table) + 1));
1775 i >= 0;
1776 i--, bucket++) {
1777 for (entry = *bucket; entry; entry = entry->next) {
1778 if (entry->leaf) {
1779 if (EnumLTable((LTable)entry, &empty, &empty, level, closure))
1780 return True1;
1781 } else {
1782 closure->bindings[level] = (entry->tight ?
1783 XrmBindTightly : XrmBindLoosely);
1784 closure->quarks[level] = entry->name;
1785 if (EnumAllNTable(entry, level+1, closure))
1786 return True1;
1787 }
1788 }
1789 }
1790 return False0;
1791}
1792
1793/* recurse on every table in the table, arbitrary order.
1794 * stop if user proc returns True. level is current depth in database.
1795 */
1796static Boolint EnumNTable(
1797 NTable table,
1798 XrmNameList names,
1799 XrmClassList classes,
1800 register int level,
1801 register EClosure closure)
1802{
1803 register NTable entry;
1804 register XrmQuark q;
1805 register unsigned int leaf;
1806 Boolint (*get)(
1807 NTable table,
1808 XrmNameList names,
1809 XrmClassList classes,
1810 register int level,
1811 EClosure closure);
1812 Boolint bilevel;
1813
1814/* find entries named ename, leafness leaf, tight or loose, and call get */
1815#define ITIGHTLOOSE(ename) \
1816 NFIND(ename)q = ename; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }
; \
1817 if (entry) { \
1818 if (leaf == entry->leaf) { \
1819 if (!leaf && !entry->tight && entry->next && \
1820 entry->next->name == q && entry->next->tight && \
1821 (bilevel || entry->next->hasloose) && \
1822 EnumLTable((LTable)entry->next, names+1, classes+1, \
1823 level, closure)) \
1824 return True1; \
1825 if ((*get)(entry, names+1, classes+1, level, closure)) \
1826 return True1; \
1827 if (entry->tight && (entry = entry->next) && \
1828 entry->name == q && leaf == entry->leaf && \
1829 (*get)(entry, names+1, classes+1, level, closure)) \
1830 return True1; \
1831 } else if (entry->leaf) { \
1832 if ((bilevel || entry->hasloose) && \
1833 EnumLTable((LTable)entry, names+1, classes+1, level, closure))\
1834 return True1; \
1835 if (entry->tight && (entry = entry->next) && \
1836 entry->name == q && (bilevel || entry->hasloose) && \
1837 EnumLTable((LTable)entry, names+1, classes+1, level, closure))\
1838 return True1; \
1839 } \
1840 }
1841
1842/* find entries named ename, leafness leaf, loose only, and call get */
1843#define ILOOSE(ename) \
1844 NFIND(ename)q = ename; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }
; \
1845 if (entry && entry->tight && (entry = entry->next) && entry->name != q) \
1846 entry = (NTable)NULL((void*)0); \
1847 if (entry) { \
1848 if (leaf == entry->leaf) { \
1849 if ((*get)(entry, names+1, classes+1, level, closure)) \
1850 return True1; \
1851 } else if (entry->leaf && (bilevel || entry->hasloose)) { \
1852 if (EnumLTable((LTable)entry, names+1, classes+1, level, closure))\
1853 return True1; \
1854 } \
1855 }
1856
1857 if (level >= MAXDBDEPTH100)
1858 return False0;
1859 closure->bindings[level] = (table->tight ?
1860 XrmBindTightly : XrmBindLoosely);
1861 closure->quarks[level] = table->name;
1862 level++;
1863 if (!*names) {
1864 if (EnumAllNTable(table, level, closure))
1865 return True1;
1866 } else {
1867 if (names[1] || closure->mode == XrmEnumAllLevels0) {
1868 get = EnumNTable; /* recurse */
1869 leaf = 0;
1870 bilevel = !names[1];
1871 } else {
1872 get = (getNTableEProcp)EnumLTable; /* bottom of recursion */
1873 leaf = 1;
1874 bilevel = False0;
1875 }
1876 if (table->hasloose && closure->mode == XrmEnumAllLevels0) {
1877 NTable *bucket;
1878 int i;
1879 XrmQuark empty = NULLQUARK((XrmQuark) 0);
1880
1881 for (i = table->mask, bucket = NodeBuckets(table)((NTable *)((table) + 1));
1882 i >= 0;
1883 i--, bucket++) {
1884 q = NULLQUARK((XrmQuark) 0);
1885 for (entry = *bucket; entry; entry = entry->next) {
1886 if (!entry->tight && entry->name != q &&
1887 entry->name != *names && entry->name != *classes) {
1888 q = entry->name;
1889 if (entry->leaf) {
1890 if (EnumLTable((LTable)entry, &empty, &empty,
1891 level, closure))
1892 return True1;
1893 } else {
1894 if (EnumNTable(entry, &empty, &empty,
1895 level, closure))
1896 return True1;
1897 }
1898 }
1899 }
1900 }
1901 }
1902
1903 ITIGHTLOOSE(*names); /* do name, tight and loose */
1904 ITIGHTLOOSE(*classes); /* do class, tight and loose */
1905 if (table->hasany) {
1906 ITIGHTLOOSE(XrmQANY); /* do ANY, tight and loose */
1907 }
1908 if (table->hasloose) {
1909 while (1) {
1910 names++;
1911 classes++;
1912 if (!*names)
1913 break;
1914 if (!names[1] && closure->mode != XrmEnumAllLevels0) {
1915 get = (getNTableEProcp)EnumLTable; /* bottom of recursion */
1916 leaf = 1;
1917 }
1918 ILOOSE(*names); /* loose names */
1919 ILOOSE(*classes); /* loose classes */
1920 if (table->hasany) {
1921 ILOOSE(XrmQANY); /* loose ANY */
1922 }
1923 }
1924 names--;
1925 classes--;
1926 }
1927 }
1928 /* now look for matching leaf nodes */
1929 entry = table->next;
1930 if (!entry)
1931 return False0;
1932 if (entry->leaf) {
1933 if (entry->tight && !table->tight)
1934 entry = entry->next;
1935 } else {
1936 entry = entry->next;
1937 if (!entry || !entry->tight)
1938 return False0;
1939 }
1940 if (!entry || entry->name != table->name)
1941 return False0;
1942 /* found one */
1943 level--;
1944 if ((!*names || entry->hasloose) &&
1945 EnumLTable((LTable)entry, names, classes, level, closure))
1946 return True1;
1947 if (entry->tight && entry == table->next && (entry = entry->next) &&
1948 entry->name == table->name && (!*names || entry->hasloose))
1949 return EnumLTable((LTable)entry, names, classes, level, closure);
1950 return False0;
1951
1952#undef ITIGHTLOOSE
1953#undef ILOOSE
1954}
1955
1956/* call the proc for every value in the database, arbitrary order.
1957 * stop if the proc returns True.
1958 */
1959Boolint XrmEnumerateDatabase(
1960 XrmDatabase db,
1961 XrmNameList names,
1962 XrmClassList classes,
1963 int mode,
1964 DBEnumProc proc,
1965 XPointer closure)
1966{
1967 XrmBinding bindings[MAXDBDEPTH100+2];
1968 XrmQuark quarks[MAXDBDEPTH100+2];
1969 register NTable table;
1970 EClosureRec eclosure;
1971 Boolint retval = False0;
1972
1973 if (!db)
1974 return False0;
1975 _XLockMutex(&db->linfo)if (_XLockMutex_fn) (*_XLockMutex_fn)(&db->linfo);
1976 eclosure.db = db;
1977 eclosure.proc = proc;
1978 eclosure.closure = closure;
1979 eclosure.bindings = bindings;
1980 eclosure.quarks = quarks;
1981 eclosure.mode = mode;
1982 table = db->table;
1983 if (table && !table->leaf && !*names && mode == XrmEnumOneLevel1)
1984 table = table->next;
1985 if (table) {
1986 if (!table->leaf)
1987 retval = EnumNTable(table, names, classes, 0, &eclosure);
1988 else
1989 retval = EnumLTable((LTable)table, names, classes, 0, &eclosure);
1990 }
1991 _XUnlockMutex(&db->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&db->linfo);
1992 return retval;
1993}
1994
1995static void PrintBindingQuarkList(
1996 XrmBindingList bindings,
1997 XrmQuarkList quarks,
1998 FILE *stream)
1999{
2000 Boolint firstNameSeen;
2001
2002 for (firstNameSeen = False0; *quarks; bindings++, quarks++) {
2003 if (*bindings == XrmBindLoosely) {
2004 (void) fprintf(stream, "*");
2005 } else if (firstNameSeen) {
2006 (void) fprintf(stream, ".");
2007 }
2008 firstNameSeen = True1;
2009 (void) fputs(XrmQuarkToString(*quarks), stream);
2010 }
2011}
2012
2013/* output out the entry in correct file syntax */
2014/*ARGSUSED*/
2015static Boolint DumpEntry(
2016 XrmDatabase *db,
2017 XrmBindingList bindings,
2018 XrmQuarkList quarks,
2019 XrmRepresentation *type,
2020 XrmValuePtr value,
2021 XPointer data)
2022{
2023 FILE *stream = (FILE *)data;
2024 register unsigned int i;
2025 register char *s;
2026 register char c;
2027
2028 if (*type != XrmQString)
2029 (void) putc('!', stream);
2030 PrintBindingQuarkList(bindings, quarks, stream);
2031 s = value->addr;
2032 i = value->size;
2033 if (*type == XrmQString) {
2034 (void) fputs(":\t", stream);
2035 if (i)
2036 i--;
2037 }
2038 else
2039 (void) fprintf(stream, "=%s:\t", XrmRepresentationToString(*type)XrmQuarkToString(*type));
2040 if (i && (*s == ' ' || *s == '\t'))
2041 (void) putc('\\', stream); /* preserve leading whitespace */
2042 while (i--) {
2043 c = *s++;
2044 if (c == '\n') {
2045 if (i)
2046 (void) fputs("\\n\\\n", stream);
2047 else
2048 (void) fputs("\\n", stream);
2049 } else if (c == '\\')
2050 (void) fputs("\\\\", stream);
2051 else if ((c < ' ' && c != '\t') ||
2052 ((unsigned char)c >= 0x7f && (unsigned char)c < 0xa0))
2053 (void) fprintf(stream, "\\%03o", (unsigned char)c);
2054 else
2055 (void) putc(c, stream);
2056 }
2057 (void) putc('\n', stream);
2058 return ferror(stream) != 0;
2059}
2060
2061#ifdef DEBUG
2062
2063void PrintTable(
2064 NTable table,
2065 FILE *file)
2066{
2067 XrmBinding bindings[MAXDBDEPTH100+1];
2068 XrmQuark quarks[MAXDBDEPTH100+1];
2069 EClosureRec closure;
2070 XrmQuark empty = NULLQUARK((XrmQuark) 0);
2071
2072 closure.db = (XrmDatabase)NULL((void*)0);
2073 closure.proc = DumpEntry;
2074 closure.closure = (XPointer)file;
2075 closure.bindings = bindings;
2076 closure.quarks = quarks;
2077 closure.mode = XrmEnumAllLevels0;
2078 if (table->leaf)
2079 EnumLTable((LTable)table, &empty, &empty, 0, &closure);
2080 else
2081 EnumNTable(table, &empty, &empty, 0, &closure);
2082}
2083
2084#endif /* DEBUG */
2085
2086void
2087XrmPutFileDatabase(
2088 XrmDatabase db,
2089 _Xconstconst char *fileName)
2090{
2091 FILE *file;
2092 XrmQuark empty = NULLQUARK((XrmQuark) 0);
2093
2094 if (!db) return;
2095 if (!(file = fopen(fileName, "w"))) return;
2096 if (XrmEnumerateDatabase(db, &empty, &empty, XrmEnumAllLevels0,
2097 DumpEntry, (XPointer) file))
2098 unlink((char *)fileName);
2099 fclose(file);
2100}
2101
2102/* macros used in get/search functions */
2103
2104/* find entries named ename, leafness leaf, tight or loose, and call get */
2105#define GTIGHTLOOSE(ename,looseleaf)q = ename; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }; if (entry) { if
(leaf == entry->leaf) { if (!leaf && !entry->tight
&& entry->next && entry->next->name
== q && entry->next->tight && entry->
next->hasloose && looseleaf((LTable)entry->next
, names+1, classes+1, closure)) return 1; if ((*get)(entry, names
+1, classes+1, closure)) return 1; if (entry->tight &&
(entry = entry->next) && entry->name == q &&
leaf == entry->leaf && (*get)(entry, names+1, classes
+1, closure)) return 1; } else if (entry->leaf) { if (entry
->hasloose && looseleaf((LTable)entry, names+1, classes
+1, closure)) return 1; if (entry->tight && (entry
= entry->next) && entry->name == q && entry
->hasloose && looseleaf((LTable)entry, names+1, classes
+1, closure)) return 1; } }
\
2106 NFIND(ename)q = ename; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }
; \
2107 if (entry) { \
2108 if (leaf == entry->leaf) { \
2109 if (!leaf && !entry->tight && entry->next && \
2110 entry->next->name == q && entry->next->tight && \
2111 entry->next->hasloose && \
2112 looseleaf((LTable)entry->next, names+1, classes+1, closure)) \
2113 return True1; \
2114 if ((*get)(entry, names+1, classes+1, closure)) \
2115 return True1; \
2116 if (entry->tight && (entry = entry->next) && \
2117 entry->name == q && leaf == entry->leaf && \
2118 (*get)(entry, names+1, classes+1, closure)) \
2119 return True1; \
2120 } else if (entry->leaf) { \
2121 if (entry->hasloose && \
2122 looseleaf((LTable)entry, names+1, classes+1, closure)) \
2123 return True1; \
2124 if (entry->tight && (entry = entry->next) && \
2125 entry->name == q && entry->hasloose && \
2126 looseleaf((LTable)entry, names+1, classes+1, closure)) \
2127 return True1; \
2128 } \
2129 }
2130
2131/* find entries named ename, leafness leaf, loose only, and call get */
2132#define GLOOSE(ename,looseleaf)q = ename; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }; if (entry &&
entry->tight && (entry = entry->next) &&
entry->name != q) entry = (NTable)((void*)0); if (entry) {
if (leaf == entry->leaf) { if ((*get)(entry, names+1, classes
+1, closure)) return 1; } else if (entry->leaf && entry
->hasloose) { if (looseleaf((LTable)entry, names+1, classes
+1, closure)) return 1; } }
\
2133 NFIND(ename)q = ename; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }
; \
2134 if (entry && entry->tight && (entry = entry->next) && entry->name != q) \
2135 entry = (NTable)NULL((void*)0); \
2136 if (entry) { \
2137 if (leaf == entry->leaf) { \
2138 if ((*get)(entry, names+1, classes+1, closure)) \
2139 return True1; \
2140 } else if (entry->leaf && entry->hasloose) { \
2141 if (looseleaf((LTable)entry, names+1, classes+1, closure)) \
2142 return True1; \
2143 } \
2144 }
2145
2146/* add tight/loose entry to the search list, return True if list is full */
2147/*ARGSUSED*/
2148static Boolint AppendLEntry(
2149 LTable table,
2150 XrmNameList names,
2151 XrmClassList classes,
2152 register SClosure closure)
2153{
2154 /* check for duplicate */
2155 if (closure->idx >= 0 && closure->list[closure->idx] == table)
2156 return False0;
2157 if (closure->idx == closure->limit)
2158 return True1;
2159 /* append it */
2160 closure->idx++;
2161 closure->list[closure->idx] = table;
2162 return False0;
2163}
2164
2165/* add loose entry to the search list, return True if list is full */
2166/*ARGSUSED*/
2167static Boolint AppendLooseLEntry(
2168 LTable table,
2169 XrmNameList names,
2170 XrmClassList classes,
2171 register SClosure closure)
2172{
2173 /* check for duplicate */
2174 if (closure->idx >= 0 && closure->list[closure->idx] == table)
2175 return False0;
2176 if (closure->idx >= closure->limit - 1)
2177 return True1;
2178 /* append it */
2179 closure->idx++;
2180 closure->list[closure->idx] = LOOSESEARCH((LTable)1);
2181 closure->idx++;
2182 closure->list[closure->idx] = table;
2183 return False0;
2184}
2185
2186/* search for a leaf table */
2187static Boolint SearchNEntry(
2188 NTable table,
2189 XrmNameList names,
2190 XrmClassList classes,
2191 SClosure closure)
2192{
2193 register NTable entry;
2194 register XrmQuark q;
2195 register unsigned int leaf;
2196 Boolint (*get)(
2197 NTable table,
2198 XrmNameList names,
2199 XrmClassList classes,
2200 SClosure closure);
2201
2202 if (names[1]) {
2203 get = SearchNEntry; /* recurse */
2204 leaf = 0;
2205 } else {
2206 get = (getNTableSProcp)AppendLEntry; /* bottom of recursion */
2207 leaf = 1;
2208 }
2209 GTIGHTLOOSE(*names, AppendLooseLEntry)q = *names; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }; if (entry) { if
(leaf == entry->leaf) { if (!leaf && !entry->tight
&& entry->next && entry->next->name
== q && entry->next->tight && entry->
next->hasloose && AppendLooseLEntry((LTable)entry->
next, names+1, classes+1, closure)) return 1; if ((*get)(entry
, names+1, classes+1, closure)) return 1; if (entry->tight
&& (entry = entry->next) && entry->name
== q && leaf == entry->leaf && (*get)(entry
, names+1, classes+1, closure)) return 1; } else if (entry->
leaf) { if (entry->hasloose && AppendLooseLEntry((
LTable)entry, names+1, classes+1, closure)) return 1; if (entry
->tight && (entry = entry->next) && entry
->name == q && entry->hasloose && AppendLooseLEntry
((LTable)entry, names+1, classes+1, closure)) return 1; } }
; /* do name, tight and loose */
2210 GTIGHTLOOSE(*classes, AppendLooseLEntry)q = *classes; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }; if (entry) { if
(leaf == entry->leaf) { if (!leaf && !entry->tight
&& entry->next && entry->next->name
== q && entry->next->tight && entry->
next->hasloose && AppendLooseLEntry((LTable)entry->
next, names+1, classes+1, closure)) return 1; if ((*get)(entry
, names+1, classes+1, closure)) return 1; if (entry->tight
&& (entry = entry->next) && entry->name
== q && leaf == entry->leaf && (*get)(entry
, names+1, classes+1, closure)) return 1; } else if (entry->
leaf) { if (entry->hasloose && AppendLooseLEntry((
LTable)entry, names+1, classes+1, closure)) return 1; if (entry
->tight && (entry = entry->next) && entry
->name == q && entry->hasloose && AppendLooseLEntry
((LTable)entry, names+1, classes+1, closure)) return 1; } }
; /* do class, tight and loose */
2211 if (table->hasany) {
2212 GTIGHTLOOSE(XrmQANY, AppendLooseLEntry)q = XrmQANY; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }; if (entry) { if
(leaf == entry->leaf) { if (!leaf && !entry->tight
&& entry->next && entry->next->name
== q && entry->next->tight && entry->
next->hasloose && AppendLooseLEntry((LTable)entry->
next, names+1, classes+1, closure)) return 1; if ((*get)(entry
, names+1, classes+1, closure)) return 1; if (entry->tight
&& (entry = entry->next) && entry->name
== q && leaf == entry->leaf && (*get)(entry
, names+1, classes+1, closure)) return 1; } else if (entry->
leaf) { if (entry->hasloose && AppendLooseLEntry((
LTable)entry, names+1, classes+1, closure)) return 1; if (entry
->tight && (entry = entry->next) && entry
->name == q && entry->hasloose && AppendLooseLEntry
((LTable)entry, names+1, classes+1, closure)) return 1; } }
; /* do ANY, tight and loose */
2213 }
2214 if (table->hasloose) {
2215 while (1) {
2216 names++;
2217 classes++;
2218 if (!*names)
2219 break;
2220 if (!names[1]) {
2221 get = (getNTableSProcp)AppendLEntry; /* bottom of recursion */
2222 leaf = 1;
2223 }
2224 GLOOSE(*names, AppendLooseLEntry)q = *names; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }; if (entry &&
entry->tight && (entry = entry->next) &&
entry->name != q) entry = (NTable)((void*)0); if (entry) {
if (leaf == entry->leaf) { if ((*get)(entry, names+1, classes
+1, closure)) return 1; } else if (entry->leaf && entry
->hasloose) { if (AppendLooseLEntry((LTable)entry, names+1
, classes+1, closure)) return 1; } }
; /* loose names */
2225 GLOOSE(*classes, AppendLooseLEntry)q = *classes; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }; if (entry &&
entry->tight && (entry = entry->next) &&
entry->name != q) entry = (NTable)((void*)0); if (entry) {
if (leaf == entry->leaf) { if ((*get)(entry, names+1, classes
+1, closure)) return 1; } else if (entry->leaf && entry
->hasloose) { if (AppendLooseLEntry((LTable)entry, names+1
, classes+1, closure)) return 1; } }
; /* loose classes */
2226 if (table->hasany) {
2227 GLOOSE(XrmQANY, AppendLooseLEntry)q = XrmQANY; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }; if (entry &&
entry->tight && (entry = entry->next) &&
entry->name != q) entry = (NTable)((void*)0); if (entry) {
if (leaf == entry->leaf) { if ((*get)(entry, names+1, classes
+1, closure)) return 1; } else if (entry->leaf && entry
->hasloose) { if (AppendLooseLEntry((LTable)entry, names+1
, classes+1, closure)) return 1; } }
; /* loose ANY */
2228 }
2229 }
2230 }
2231 /* now look for matching leaf nodes */
2232 entry = table->next;
2233 if (!entry)
2234 return False0;
2235 if (entry->leaf) {
2236 if (entry->tight && !table->tight)
2237 entry = entry->next;
2238 } else {
2239 entry = entry->next;
2240 if (!entry || !entry->tight)
2241 return False0;
2242 }
2243 if (!entry || entry->name != table->name)
2244 return False0;
2245 /* found one */
2246 if (entry->hasloose &&
2247 AppendLooseLEntry((LTable)entry, names, classes, closure))
2248 return True1;
2249 if (entry->tight && entry == table->next && (entry = entry->next) &&
2250 entry->name == table->name && entry->hasloose)
2251 return AppendLooseLEntry((LTable)entry, names, classes, closure);
2252 return False0;
2253}
2254
2255Boolint XrmQGetSearchList(
2256 XrmDatabase db,
2257 XrmNameList names,
2258 XrmClassList classes,
2259 XrmSearchList searchList, /* RETURN */
2260 int listLength)
2261{
2262 register NTable table;
2263 SClosureRec closure;
2264
2265 if (listLength <= 0)
2266 return False0;
2267 closure.list = (LTable *)searchList;
2268 closure.idx = -1;
2269 closure.limit = listLength - 2;
2270 if (db) {
2271 _XLockMutex(&db->linfo)if (_XLockMutex_fn) (*_XLockMutex_fn)(&db->linfo);
2272 table = db->table;
2273 if (*names) {
2274 if (table && !table->leaf) {
2275 if (SearchNEntry(table, names, classes, &closure)) {
2276 _XUnlockMutex(&db->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&db->linfo);
2277 return False0;
2278 }
2279 } else if (table && table->hasloose &&
2280 AppendLooseLEntry((LTable)table, names, classes,
2281 &closure)) {
2282 _XUnlockMutex(&db->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&db->linfo);
2283 return False0;
2284 }
2285 } else {
2286 if (table && !table->leaf)
2287 table = table->next;
2288 if (table &&
2289 AppendLEntry((LTable)table, names, classes, &closure)) {
2290 _XUnlockMutex(&db->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&db->linfo);
2291 return False0;
2292 }
2293 }
2294 _XUnlockMutex(&db->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&db->linfo);
2295 }
2296 closure.list[closure.idx + 1] = (LTable)NULL((void*)0);
2297 return True1;
2298}
2299
2300Boolint XrmQGetSearchResource(
2301 XrmSearchList searchList,
2302 register XrmName name,
2303 register XrmClass class,
2304 XrmRepresentation *pType, /* RETURN */
2305 XrmValue *pValue) /* RETURN */
2306{
2307 register LTable *list;
2308 register LTable table;
2309 register VEntry entry = NULL((void*)0);
2310 int flags;
2311
2312/* find tight or loose entry */
2313#define VTIGHTLOOSE(q) \
2314 entry = LeafHash(table, q)(table)->buckets[(q) & (table)->table.mask]; \
2315 while (entry && entry->name != q) \
2316 entry = entry->next; \
2317 if (entry) \
2318 break
2319
2320/* find loose entry */
2321#define VLOOSE(q) \
2322 entry = LeafHash(table, q)(table)->buckets[(q) & (table)->table.mask]; \
2323 while (entry && entry->name != q) \
2324 entry = entry->next; \
2325 if (entry) { \
2326 if (!entry->tight) \
2327 break; \
2328 if ((entry = entry->next) && entry->name == q) \
2329 break; \
2330 }
2331
2332 list = (LTable *)searchList;
2333 /* figure out which combination of name and class we need to search for */
2334 flags = 0;
2335 if (IsResourceQuark(name)((name) > 0 && (name) <= maxResourceQuark &&
resourceQuarks[(name) >> 3] & (1 << ((name) &
7)))
)
2336 flags = 2;
2337 if (IsResourceQuark(class)((class) > 0 && (class) <= maxResourceQuark &&
resourceQuarks[(class) >> 3] & (1 << ((class
) & 7)))
)
2338 flags |= 1;
2339 if (!flags) {
2340 /* neither name nor class has ever been used to name a resource */
2341 table = (LTable)NULL((void*)0);
2342 } else if (flags == 3) {
2343 /* both name and class */
2344 while ((table = *list++)) {
2345 if (table != LOOSESEARCH((LTable)1)) {
2346 VTIGHTLOOSE(name); /* do name, tight and loose */
2347 VTIGHTLOOSE(class); /* do class, tight and loose */
2348 } else {
2349 table = *list++;
2350 VLOOSE(name); /* do name, loose only */
2351 VLOOSE(class); /* do class, loose only */
2352 }
2353 }
2354 } else {
2355 /* just one of name or class */
2356 if (flags == 1)
2357 name = class;
2358 while ((table = *list++)) {
2359 if (table != LOOSESEARCH((LTable)1)) {
2360 VTIGHTLOOSE(name); /* tight and loose */
2361 } else {
2362 table = *list++;
2363 VLOOSE(name); /* loose only */
2364 }
2365 }
2366 }
2367 if (table) {
2368 /* found a match */
2369 if (entry->string) {
2370 *pType = XrmQString;
2371 pValue->addr = StringValue(entry)(XPointer)((entry) + 1);
2372 } else {
2373 *pType = RepType(entry)((DEntry)(entry))->type;
2374 pValue->addr = DataValue(entry)(XPointer)(((DEntry)(entry)) + 1);
2375 }
2376 pValue->size = entry->size;
2377 return True1;
2378 }
2379 *pType = NULLQUARK((XrmQuark) 0);
2380 pValue->addr = (XPointer)NULL((void*)0);
2381 pValue->size = 0;
2382 return False0;
2383
2384#undef VTIGHTLOOSE
2385#undef VLOOSE
2386}
2387
2388/* look for a tight/loose value */
2389static Boolint GetVEntry(
2390 LTable table,
2391 XrmNameList names,
2392 XrmClassList classes,
2393 VClosure closure)
2394{
2395 register VEntry entry;
2396 register XrmQuark q;
2397
2398 /* try name first */
2399 q = *names;
2400 entry = LeafHash(table, q)(table)->buckets[(q) & (table)->table.mask];
2401 while (entry && entry->name != q)
2402 entry = entry->next;
2403 if (!entry) {
2404 /* not found, try class */
2405 q = *classes;
2406 entry = LeafHash(table, q)(table)->buckets[(q) & (table)->table.mask];
2407 while (entry && entry->name != q)
2408 entry = entry->next;
2409 if (!entry)
2410 return False0;
2411 }
2412 if (entry->string) {
2413 *closure->type = XrmQString;
2414 closure->value->addr = StringValue(entry)(XPointer)((entry) + 1);
2415 } else {
2416 *closure->type = RepType(entry)((DEntry)(entry))->type;
2417 closure->value->addr = DataValue(entry)(XPointer)(((DEntry)(entry)) + 1);
2418 }
2419 closure->value->size = entry->size;
2420 return True1;
2421}
2422
2423/* look for a loose value */
2424static Boolint GetLooseVEntry(
2425 LTable table,
2426 XrmNameList names,
2427 XrmClassList classes,
2428 VClosure closure)
2429{
2430 register VEntry entry;
2431 register XrmQuark q;
2432
2433#define VLOOSE(ename) \
2434 q = ename; \
2435 entry = LeafHash(table, q)(table)->buckets[(q) & (table)->table.mask]; \
2436 while (entry && entry->name != q) \
2437 entry = entry->next; \
2438 if (entry && entry->tight && (entry = entry->next) && entry->name != q) \
2439 entry = (VEntry)NULL((void*)0);
2440
2441 /* bump to last component */
2442 while (names[1]) {
2443 names++;
2444 classes++;
2445 }
2446 VLOOSE(*names); /* do name, loose only */
2447 if (!entry) {
2448 VLOOSE(*classes); /* do class, loose only */
2449 if (!entry)
2450 return False0;
2451 }
2452 if (entry->string) {
2453 *closure->type = XrmQString;
2454 closure->value->addr = StringValue(entry)(XPointer)((entry) + 1);
2455 } else {
2456 *closure->type = RepType(entry)((DEntry)(entry))->type;
2457 closure->value->addr = DataValue(entry)(XPointer)(((DEntry)(entry)) + 1);
2458 }
2459 closure->value->size = entry->size;
2460 return True1;
2461
2462#undef VLOOSE
2463}
2464
2465/* recursive search for a value */
2466static Boolint GetNEntry(
2467 NTable table,
2468 XrmNameList names,
2469 XrmClassList classes,
2470 VClosure closure)
2471{
2472 register NTable entry;
2473 register XrmQuark q;
2474 register unsigned int leaf;
2475 Boolint (*get)(
2476 NTable table,
2477 XrmNameList names,
2478 XrmClassList classes,
2479 VClosure closure);
2480 NTable otable;
2481
2482 if (names[2]) {
2483 get = GetNEntry; /* recurse */
2484 leaf = 0;
2485 } else {
2486 get = (getNTableVProcp)GetVEntry; /* bottom of recursion */
2487 leaf = 1;
2488 }
2489 GTIGHTLOOSE(*names, GetLooseVEntry)q = *names; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }; if (entry) { if
(leaf == entry->leaf) { if (!leaf && !entry->tight
&& entry->next && entry->next->name
== q && entry->next->tight && entry->
next->hasloose && GetLooseVEntry((LTable)entry->
next, names+1, classes+1, closure)) return 1; if ((*get)(entry
, names+1, classes+1, closure)) return 1; if (entry->tight
&& (entry = entry->next) && entry->name
== q && leaf == entry->leaf && (*get)(entry
, names+1, classes+1, closure)) return 1; } else if (entry->
leaf) { if (entry->hasloose && GetLooseVEntry((LTable
)entry, names+1, classes+1, closure)) return 1; if (entry->
tight && (entry = entry->next) && entry->
name == q && entry->hasloose && GetLooseVEntry
((LTable)entry, names+1, classes+1, closure)) return 1; } }
; /* do name, tight and loose */
2490 GTIGHTLOOSE(*classes, GetLooseVEntry)q = *classes; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }; if (entry) { if
(leaf == entry->leaf) { if (!leaf && !entry->tight
&& entry->next && entry->next->name
== q && entry->next->tight && entry->
next->hasloose && GetLooseVEntry((LTable)entry->
next, names+1, classes+1, closure)) return 1; if ((*get)(entry
, names+1, classes+1, closure)) return 1; if (entry->tight
&& (entry = entry->next) && entry->name
== q && leaf == entry->leaf && (*get)(entry
, names+1, classes+1, closure)) return 1; } else if (entry->
leaf) { if (entry->hasloose && GetLooseVEntry((LTable
)entry, names+1, classes+1, closure)) return 1; if (entry->
tight && (entry = entry->next) && entry->
name == q && entry->hasloose && GetLooseVEntry
((LTable)entry, names+1, classes+1, closure)) return 1; } }
; /* do class, tight and loose */
2491 if (table->hasany) {
2492 GTIGHTLOOSE(XrmQANY, GetLooseVEntry)q = XrmQANY; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }; if (entry) { if
(leaf == entry->leaf) { if (!leaf && !entry->tight
&& entry->next && entry->next->name
== q && entry->next->tight && entry->
next->hasloose && GetLooseVEntry((LTable)entry->
next, names+1, classes+1, closure)) return 1; if ((*get)(entry
, names+1, classes+1, closure)) return 1; if (entry->tight
&& (entry = entry->next) && entry->name
== q && leaf == entry->leaf && (*get)(entry
, names+1, classes+1, closure)) return 1; } else if (entry->
leaf) { if (entry->hasloose && GetLooseVEntry((LTable
)entry, names+1, classes+1, closure)) return 1; if (entry->
tight && (entry = entry->next) && entry->
name == q && entry->hasloose && GetLooseVEntry
((LTable)entry, names+1, classes+1, closure)) return 1; } }
; /* do ANY, tight and loose */
2493 }
2494 if (table->hasloose) {
2495 while (1) {
2496 names++;
2497 classes++;
2498 if (!names[1])
2499 break;
2500 if (!names[2]) {
2501 get = (getNTableVProcp)GetVEntry; /* bottom of recursion */
2502 leaf = 1;
2503 }
2504 GLOOSE(*names, GetLooseVEntry)q = *names; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }; if (entry &&
entry->tight && (entry = entry->next) &&
entry->name != q) entry = (NTable)((void*)0); if (entry) {
if (leaf == entry->leaf) { if ((*get)(entry, names+1, classes
+1, closure)) return 1; } else if (entry->leaf && entry
->hasloose) { if (GetLooseVEntry((LTable)entry, names+1, classes
+1, closure)) return 1; } }
; /* do name, loose only */
2505 GLOOSE(*classes, GetLooseVEntry)q = *classes; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }; if (entry &&
entry->tight && (entry = entry->next) &&
entry->name != q) entry = (NTable)((void*)0); if (entry) {
if (leaf == entry->leaf) { if ((*get)(entry, names+1, classes
+1, closure)) return 1; } else if (entry->leaf && entry
->hasloose) { if (GetLooseVEntry((LTable)entry, names+1, classes
+1, closure)) return 1; } }
; /* do class, loose only */
2506 if (table->hasany) {
2507 GLOOSE(XrmQANY, GetLooseVEntry)q = XrmQANY; entry = ((NTable *)((table) + 1))[(q) & (table
)->mask]; while (entry && entry->name != q) entry
= entry->next; if (leaf && entry && !entry
->leaf) { entry = entry->next; if (entry && !entry
->leaf) entry = entry->next; if (entry && entry
->name != q) entry = (NTable)((void*)0); }; if (entry &&
entry->tight && (entry = entry->next) &&
entry->name != q) entry = (NTable)((void*)0); if (entry) {
if (leaf == entry->leaf) { if ((*get)(entry, names+1, classes
+1, closure)) return 1; } else if (entry->leaf && entry
->hasloose) { if (GetLooseVEntry((LTable)entry, names+1, classes
+1, closure)) return 1; } }
; /* do ANY, loose only */
2508 }
2509 }
2510 }
2511 /* look for matching leaf tables */
2512 otable = table;
2513 table = table->next;
2514 if (!table)
2515 return False0;
2516 if (table->leaf) {
2517 if (table->tight && !otable->tight)
2518 table = table->next;
2519 } else {
2520 table = table->next;
2521 if (!table || !table->tight)
2522 return False0;
2523 }
2524 if (!table || table->name != otable->name)
2525 return False0;
2526 /* found one */
2527 if (table->hasloose &&
2528 GetLooseVEntry((LTable)table, names, classes, closure))
2529 return True1;
2530 if (table->tight && table == otable->next) {
2531 table = table->next;
2532 if (table && table->name == otable->name && table->hasloose)
2533 return GetLooseVEntry((LTable)table, names, classes, closure);
2534 }
2535 return False0;
2536}
2537
2538Boolint XrmQGetResource(
2539 XrmDatabase db,
2540 XrmNameList names,
2541 XrmClassList classes,
2542 XrmRepresentation *pType, /* RETURN */
2543 XrmValuePtr pValue) /* RETURN */
2544{
2545 register NTable table;
2546 VClosureRec closure;
2547
2548 if (db && *names) {
2549 _XLockMutex(&db->linfo)if (_XLockMutex_fn) (*_XLockMutex_fn)(&db->linfo);
2550 closure.type = pType;
2551 closure.value = pValue;
2552 table = db->table;
2553 if (names[1]) {
2554 if (table && !table->leaf) {
2555 if (GetNEntry(table, names, classes, &closure)) {
2556 _XUnlockMutex(&db->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&db->linfo);
2557 return True1;
2558 }
2559 } else if (table && table->hasloose &&
2560 GetLooseVEntry((LTable)table, names, classes, &closure)) {
2561 _XUnlockMutex (&db->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&db->linfo);
2562 return True1;
2563 }
2564 } else {
2565 if (table && !table->leaf)
2566 table = table->next;
2567 if (table && GetVEntry((LTable)table, names, classes, &closure)) {
2568 _XUnlockMutex(&db->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&db->linfo);
2569 return True1;
2570 }
2571 }
2572 _XUnlockMutex(&db->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&db->linfo);
2573 }
2574 *pType = NULLQUARK((XrmQuark) 0);
2575 pValue->addr = (XPointer)NULL((void*)0);
2576 pValue->size = 0;
2577 return False0;
2578}
2579
2580Boolint
2581XrmGetResource(XrmDatabase db, _Xconstconst char *name_str, _Xconstconst char *class_str,
2582 XrmString *pType_str, XrmValuePtr pValue)
2583{
2584 XrmName names[MAXDBDEPTH100+1];
2585 XrmClass classes[MAXDBDEPTH100+1];
2586 XrmRepresentation fromType;
2587 Boolint result;
2588
2589 XrmStringToNameList(name_str, names)XrmStringToQuarkList(name_str, names);
2590 XrmStringToClassList(class_str, classes)XrmStringToQuarkList(class_str, classes);
2591 result = XrmQGetResource(db, names, classes, &fromType, pValue);
2592 (*pType_str) = XrmQuarkToString(fromType);
2593 return result;
2594}
2595
2596/* destroy all values, plus table itself */
2597static void DestroyLTable(
2598 LTable table)
2599{
2600 register int i;
2601 register VEntry *buckets;
2602 register VEntry entry, next;
2603
2604 buckets = table->buckets;
2605 for (i = table->table.mask; i >= 0; i--, buckets++) {
2606 for (next = *buckets; (entry = next); ) {
2607 next = entry->next;
2608 Xfree(entry)free((entry));
2609 }
2610 }
2611 Xfree(table->buckets)free((table->buckets));
2612 Xfree(table)free((table));
2613}
2614
2615/* destroy all contained tables, plus table itself */
2616static void DestroyNTable(
2617 NTable table)
2618{
2619 register int i;
2620 register NTable *buckets;
2621 register NTable entry, next;
2622
2623 buckets = NodeBuckets(table)((NTable *)((table) + 1));
2624 for (i = table->mask; i >= 0; i--, buckets++) {
2625 for (next = *buckets; (entry = next); ) {
2626 next = entry->next;
2627 if (entry->leaf)
2628 DestroyLTable((LTable)entry);
2629 else
2630 DestroyNTable(entry);
2631 }
2632 }
2633 Xfree(table)free((table));
2634}
2635
2636const char *
2637XrmLocaleOfDatabase(
2638 XrmDatabase db)
2639{
2640 const char* retval;
2641 _XLockMutex(&db->linfo)if (_XLockMutex_fn) (*_XLockMutex_fn)(&db->linfo);
2642 retval = (*db->methods->lcname)(db->mbstate);
2643 _XUnlockMutex(&db->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&db->linfo);
2644 return retval;
2645}
2646
2647void XrmDestroyDatabase(
2648 XrmDatabase db)
2649{
2650 register NTable table, next;
2651
2652 if (db) {
2653 _XLockMutex(&db->linfo)if (_XLockMutex_fn) (*_XLockMutex_fn)(&db->linfo);
2654 for (next = db->table; (table = next); ) {
2655 next = table->next;
2656 if (table->leaf)
2657 DestroyLTable((LTable)table);
2658 else
2659 DestroyNTable(table);
2660 }
2661 _XUnlockMutex(&db->linfo)if (_XUnlockMutex_fn) (*_XUnlockMutex_fn)(&db->linfo);
2662 _XFreeMutex(&db->linfo)if (_XFreeMutex_fn) (*_XFreeMutex_fn)(&db->linfo);;
2663 (*db->methods->destroy)(db->mbstate);
2664 Xfree(db)free((db));
2665 }
2666}