Quarks.c revision eb411b4b
1 2/*********************************************************** 3Copyright 1987, 1988, 1990 by Digital Equipment Corporation, Maynard, 4 5 All Rights Reserved 6 7Permission to use, copy, modify, and distribute this software and its 8documentation for any purpose and without fee is hereby granted, 9provided that the above copyright notice appear in all copies and that 10both that copyright notice and this permission notice appear in 11supporting documentation, and that the name Digital not be 12used in advertising or publicity pertaining to distribution of the 13software without specific, written prior permission. 14 15DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 16ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 17DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 18ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 19WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 20ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 21SOFTWARE. 22 23******************************************************************/ 24/* 25 26Copyright 1987, 1988, 1990, 1998 The Open Group 27 28Permission to use, copy, modify, distribute, and sell this software and its 29documentation for any purpose is hereby granted without fee, provided that 30the above copyright notice appear in all copies and that both that 31copyright notice and this permission notice appear in supporting 32documentation. 33 34The above copyright notice and this permission notice shall be included 35in all copies or substantial portions of the Software. 36 37THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 38OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 39MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 40IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 41OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 42ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 43OTHER DEALINGS IN THE SOFTWARE. 44 45Except as contained in this notice, the name of The Open Group shall 46not be used in advertising or otherwise to promote the sale, use or 47other dealings in this Software without prior written authorization 48from The Open Group. 49 50*/ 51 52#ifdef HAVE_CONFIG_H 53#include <config.h> 54#endif 55#include "Xlibint.h" 56#include <X11/Xresource.h> 57#include "Xresinternal.h" 58 59/* Not cost effective, at least for vanilla MIT clients */ 60/* #define PERMQ */ 61 62#ifdef PERMQ 63typedef unsigned char Bits; 64#endif 65typedef unsigned long Entry; /* dont confuse with EntryRec from Xintatom.h */ 66 67static XrmQuark nextQuark = 1; /* next available quark number */ 68static unsigned long quarkMask = 0; 69static Entry zero = 0; 70static Entry *quarkTable = &zero; /* crock */ 71static unsigned long quarkRehash; 72static XrmString **stringTable = NULL; 73#ifdef PERMQ 74static Bits **permTable = NULL; 75#endif 76static XrmQuark nextUniq = -1; /* next quark from XrmUniqueQuark */ 77 78#define QUANTUMSHIFT 8 79#define QUANTUMMASK ((1 << QUANTUMSHIFT) - 1) 80#define CHUNKPER 8 81#define CHUNKMASK ((CHUNKPER << QUANTUMSHIFT) - 1) 82 83#define LARGEQUARK ((Entry)0x80000000L) 84#define QUARKSHIFT 18 85#define QUARKMASK ((LARGEQUARK - 1) >> QUARKSHIFT) 86#define XSIGMASK ((1L << QUARKSHIFT) - 1) 87 88#define STRQUANTSIZE (sizeof(XrmString) * (QUANTUMMASK + 1)) 89#ifdef PERMQ 90#define QUANTSIZE (STRQUANTSIZE + \ 91 (sizeof(Bits) * ((QUANTUMMASK + 1) >> 3)) 92#else 93#define QUANTSIZE STRQUANTSIZE 94#endif 95 96#define HASH(sig) ((sig) & quarkMask) 97#define REHASHVAL(sig) ((((sig) % quarkRehash) + 2) | 1) 98#define REHASH(idx,rehash) ((idx + rehash) & quarkMask) 99#define NAME(q) stringTable[(q) >> QUANTUMSHIFT][(q) & QUANTUMMASK] 100#ifdef PERMQ 101#define BYTEREF(q) permTable[(q) >> QUANTUMSHIFT][((q) & QUANTUMMASK) >> 3] 102#define ISPERM(q) (BYTEREF(q) & (1 << ((q) & 7))) 103#define SETPERM(q) BYTEREF(q) |= (1 << ((q) & 7)) 104#define CLEARPERM(q) BYTEREF(q) &= ~(1 << ((q) & 7)) 105#endif 106 107/* Permanent memory allocation */ 108 109#define WALIGN sizeof(unsigned long) 110#define DALIGN sizeof(double) 111 112#define NEVERFREETABLESIZE ((8192-12) & ~(DALIGN-1)) 113static char *neverFreeTable = NULL; 114static int neverFreeTableSize = 0; 115 116static char *permalloc(unsigned int length) 117{ 118 char *ret; 119 120 if (neverFreeTableSize < length) { 121 if (length >= NEVERFREETABLESIZE) 122 return Xmalloc(length); 123 if (! (ret = Xmalloc(NEVERFREETABLESIZE))) 124 return (char *) NULL; 125 neverFreeTableSize = NEVERFREETABLESIZE; 126 neverFreeTable = ret; 127 } 128 ret = neverFreeTable; 129 neverFreeTable += length; 130 neverFreeTableSize -= length; 131 return(ret); 132} 133 134typedef struct {char a; double b;} TestType1; 135typedef struct {char a; unsigned long b;} TestType2; 136 137#ifdef XTHREADS 138static char *_Xpermalloc(unsigned int length); 139 140char *Xpermalloc(unsigned int length) 141{ 142 char *p; 143 144 _XLockMutex(_Xglobal_lock); 145 p = _Xpermalloc(length); 146 _XUnlockMutex(_Xglobal_lock); 147 return p; 148} 149#define Xpermalloc _Xpermalloc 150 151static 152#endif /* XTHREADS */ 153char *Xpermalloc(unsigned int length) 154{ 155 int i; 156 157 if (neverFreeTableSize && length < NEVERFREETABLESIZE) { 158 if ((sizeof(TestType1) != 159 (sizeof(TestType2) - sizeof(unsigned long) + sizeof(double))) && 160 !(length & (DALIGN-1)) && 161 ((i = (NEVERFREETABLESIZE - neverFreeTableSize) & (DALIGN-1)))) { 162 neverFreeTableSize -= DALIGN - i; 163 neverFreeTable += DALIGN - i; 164 } else 165 if ((i = (NEVERFREETABLESIZE - neverFreeTableSize) & (WALIGN-1))) { 166 neverFreeTableSize -= WALIGN - i; 167 neverFreeTable += WALIGN - i; 168 } 169 } 170 return permalloc(length); 171} 172 173static Bool 174ExpandQuarkTable(void) 175{ 176 unsigned long oldmask, newmask; 177 register char c, *s; 178 register Entry *oldentries, *entries; 179 register Entry entry; 180 register int oldidx, newidx, rehash; 181 Signature sig; 182 XrmQuark q; 183 184 oldentries = quarkTable; 185 if ((oldmask = quarkMask)) 186 newmask = (oldmask << 1) + 1; 187 else { 188 if (!stringTable) { 189 stringTable = Xmalloc(sizeof(XrmString *) * CHUNKPER); 190 if (!stringTable) 191 return False; 192 stringTable[0] = (XrmString *)NULL; 193 } 194#ifdef PERMQ 195 if (!permTable) 196 permTable = Xmalloc(sizeof(Bits *) * CHUNKPER); 197 if (!permTable) 198 return False; 199#endif 200 stringTable[0] = (XrmString *)Xpermalloc(QUANTSIZE); 201 if (!stringTable[0]) 202 return False; 203#ifdef PERMQ 204 permTable[0] = (Bits *)((char *)stringTable[0] + STRQUANTSIZE); 205#endif 206 newmask = 0x1ff; 207 } 208 entries = Xcalloc(newmask + 1, sizeof(Entry)); 209 if (!entries) 210 return False; 211 quarkTable = entries; 212 quarkMask = newmask; 213 quarkRehash = quarkMask - 2; 214 for (oldidx = 0; oldidx <= oldmask; oldidx++) { 215 if ((entry = oldentries[oldidx])) { 216 if (entry & LARGEQUARK) 217 q = entry & (LARGEQUARK-1); 218 else 219 q = (entry >> QUARKSHIFT) & QUARKMASK; 220 for (sig = 0, s = NAME(q); (c = *s++); ) 221 sig = (sig << 1) + c; 222 newidx = HASH(sig); 223 if (entries[newidx]) { 224 rehash = REHASHVAL(sig); 225 do { 226 newidx = REHASH(newidx, rehash); 227 } while (entries[newidx]); 228 } 229 entries[newidx] = entry; 230 } 231 } 232 if (oldmask) 233 Xfree((char *)oldentries); 234 return True; 235} 236 237XrmQuark 238_XrmInternalStringToQuark( 239 register _Xconst char *name, register int len, register Signature sig, 240 Bool permstring) 241{ 242 register XrmQuark q; 243 register Entry entry; 244 register int idx, rehash; 245 register int i; 246 register char *s1, *s2; 247 char *new; 248 249 rehash = 0; 250 idx = HASH(sig); 251 _XLockMutex(_Xglobal_lock); 252 while ((entry = quarkTable[idx])) { 253 if (entry & LARGEQUARK) 254 q = entry & (LARGEQUARK-1); 255 else { 256 if ((entry - sig) & XSIGMASK) 257 goto nomatch; 258 q = (entry >> QUARKSHIFT) & QUARKMASK; 259 } 260 for (i = len, s1 = (char *)name, s2 = NAME(q); --i >= 0; ) { 261 if (*s1++ != *s2++) 262 goto nomatch; 263 } 264 if (*s2) { 265nomatch: if (!rehash) 266 rehash = REHASHVAL(sig); 267 idx = REHASH(idx, rehash); 268 continue; 269 } 270#ifdef PERMQ 271 if (permstring && !ISPERM(q)) { 272 Xfree(NAME(q)); 273 NAME(q) = (char *)name; 274 SETPERM(q); 275 } 276#endif 277 _XUnlockMutex(_Xglobal_lock); 278 return q; 279 } 280 if (nextUniq == nextQuark) 281 goto fail; 282 if ((nextQuark + (nextQuark >> 2)) > quarkMask) { 283 if (!ExpandQuarkTable()) 284 goto fail; 285 _XUnlockMutex(_Xglobal_lock); 286 return _XrmInternalStringToQuark(name, len, sig, permstring); 287 } 288 q = nextQuark; 289 if (!(q & QUANTUMMASK)) { 290 if (!(q & CHUNKMASK)) { 291 if (!(new = Xrealloc(stringTable, 292 sizeof(XrmString *) * 293 ((q >> QUANTUMSHIFT) + CHUNKPER)))) 294 goto fail; 295 stringTable = (XrmString **)new; 296#ifdef PERMQ 297 if (!(new = Xrealloc(permTable, 298 sizeof(Bits *) * 299 ((q >> QUANTUMSHIFT) + CHUNKPER)))) 300 goto fail; 301 permTable = (Bits **)new; 302#endif 303 } 304 new = Xpermalloc(QUANTSIZE); 305 if (!new) 306 goto fail; 307 stringTable[q >> QUANTUMSHIFT] = (XrmString *)new; 308#ifdef PERMQ 309 permTable[q >> QUANTUMSHIFT] = (Bits *)(new + STRQUANTSIZE); 310#endif 311 } 312 if (!permstring) { 313 s2 = (char *)name; 314#ifdef PERMQ 315 name = Xmalloc(len+1); 316#else 317 name = permalloc(len+1); 318#endif 319 if (!name) 320 goto fail; 321 for (i = len, s1 = (char *)name; --i >= 0; ) 322 *s1++ = *s2++; 323 *s1++ = '\0'; 324#ifdef PERMQ 325 CLEARPERM(q); 326 } 327 else { 328 SETPERM(q); 329#endif 330 } 331 NAME(q) = (char *)name; 332 if (q <= QUARKMASK) 333 entry = (q << QUARKSHIFT) | (sig & XSIGMASK); 334 else 335 entry = q | LARGEQUARK; 336 quarkTable[idx] = entry; 337 nextQuark++; 338 _XUnlockMutex(_Xglobal_lock); 339 return q; 340 fail: 341 _XUnlockMutex(_Xglobal_lock); 342 return NULLQUARK; 343} 344 345XrmQuark 346XrmStringToQuark( 347 _Xconst char *name) 348{ 349 register char c, *tname; 350 register Signature sig = 0; 351 352 if (!name) 353 return (NULLQUARK); 354 355 for (tname = (char *)name; (c = *tname++); ) 356 sig = (sig << 1) + c; 357 358 return _XrmInternalStringToQuark(name, tname-(char *)name-1, sig, False); 359} 360 361XrmQuark 362XrmPermStringToQuark( 363 _Xconst char *name) 364{ 365 register char c, *tname; 366 register Signature sig = 0; 367 368 if (!name) 369 return (NULLQUARK); 370 371 for (tname = (char *)name; (c = *tname++); ) 372 sig = (sig << 1) + c; 373 374 return _XrmInternalStringToQuark(name, tname-(char *)name-1, sig, True); 375} 376 377XrmQuark XrmUniqueQuark(void) 378{ 379 XrmQuark q; 380 381 _XLockMutex(_Xglobal_lock); 382 if (nextUniq == nextQuark) 383 q = NULLQUARK; 384 else 385 q = nextUniq--; 386 _XUnlockMutex(_Xglobal_lock); 387 return q; 388} 389 390XrmString XrmQuarkToString(register XrmQuark quark) 391{ 392 XrmString s; 393 394 _XLockMutex(_Xglobal_lock); 395 if (quark <= 0 || quark >= nextQuark) 396 s = NULLSTRING; 397 else { 398#ifdef PERMQ 399 /* We have to mark the quark as permanent, since the caller might hold 400 * onto the string pointer forver. 401 */ 402 SETPERM(quark); 403#endif 404 s = NAME(quark); 405 } 406 _XUnlockMutex(_Xglobal_lock); 407 return s; 408} 409