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