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