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