Bug Summary

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