atom.c revision e24f450b
1/* 2 3Copyright 1990, 1994, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25*/ 26 27/* 28 * Author: Keith Packard, MIT X Consortium 29 */ 30 31/* lame atom replacement routines for font applications */ 32 33#ifdef HAVE_CONFIG_H 34#include <config.h> 35#endif 36#include "fontmisc.h" 37 38typedef struct _AtomList { 39 char *name; 40 unsigned int len; 41 int hash; 42 Atom atom; 43} AtomListRec, *AtomListPtr; 44 45static AtomListPtr *hashTable; 46 47static int hashSize, hashUsed; 48static int hashMask; 49static int rehash; 50 51static AtomListPtr *reverseMap; 52static size_t reverseMapSize; 53static Atom lastAtom; 54 55static int 56Hash(const char *string, int len) 57{ 58 int h; 59 60 h = 0; 61 while (len--) 62 h = (h << 3) ^ *string++; 63 if (h < 0) 64 return -h; 65 return h; 66} 67 68static int 69ResizeHashTable(void) 70{ 71 int newHashSize; 72 int newHashMask; 73 AtomListPtr *newHashTable; 74 int newRehash; 75 76 if (hashSize == 0) 77 newHashSize = 1024; 78 else 79 newHashSize = hashSize * 2; 80 newHashTable = calloc(newHashSize, sizeof(AtomListPtr)); 81 if (!newHashTable) { 82 fprintf(stderr, "ResizeHashTable(): Error: Couldn't allocate" 83 " newHashTable (%ld)\n", 84 newHashSize * (unsigned long) sizeof(AtomListPtr)); 85 return FALSE; 86 } 87 newHashMask = newHashSize - 1; 88 newRehash = (newHashMask - 2); 89 for (int i = 0; i < hashSize; i++) { 90 if (hashTable[i]) { 91 int h = (hashTable[i]->hash) & newHashMask; 92 if (newHashTable[h]) { 93 int r = hashTable[i]->hash % newRehash | 1; 94 do { 95 h += r; 96 if (h >= newHashSize) 97 h -= newHashSize; 98 } while (newHashTable[h]); 99 } 100 newHashTable[h] = hashTable[i]; 101 } 102 } 103 free(hashTable); 104 hashTable = newHashTable; 105 hashSize = newHashSize; 106 hashMask = newHashMask; 107 rehash = newRehash; 108 return TRUE; 109} 110 111static int 112ResizeReverseMap(void) 113{ 114 AtomListPtr *newMap; 115 size_t newMapSize; 116 117 if (reverseMapSize == 0) 118 newMapSize = 1000; 119 else 120 newMapSize = reverseMapSize * 2; 121 newMap = realloc(reverseMap, newMapSize * sizeof(AtomListPtr)); 122 if (newMap == NULL) { 123 fprintf(stderr, "ResizeReverseMap(): Error: Couldn't reallocate" 124 " reverseMap (%ld)\n", 125 newMapSize * (unsigned long) sizeof(AtomListPtr)); 126 return FALSE; 127 } 128 reverseMap = newMap; 129 reverseMapSize = newMapSize; 130 return TRUE; 131} 132 133static int 134NameEqual(const char *a, const char *b, int l) 135{ 136 while (l--) 137 if (*a++ != *b++) 138 return FALSE; 139 return TRUE; 140} 141 142Atom 143MakeAtom(const char *string, unsigned len, int makeit) 144{ 145 AtomListPtr a; 146 int hash; 147 int h = 0; 148 int r; 149 150 hash = Hash(string, len); 151 if (hashTable) { 152 h = hash & hashMask; 153 if (hashTable[h]) { 154 if (hashTable[h]->hash == hash && hashTable[h]->len == len && 155 NameEqual(hashTable[h]->name, string, len)) { 156 return hashTable[h]->atom; 157 } 158 r = (hash % rehash) | 1; 159 for (;;) { 160 h += r; 161 if (h >= hashSize) 162 h -= hashSize; 163 if (!hashTable[h]) 164 break; 165 if (hashTable[h]->hash == hash && hashTable[h]->len == len && 166 NameEqual(hashTable[h]->name, string, len)) { 167 return hashTable[h]->atom; 168 } 169 } 170 } 171 } 172 if (!makeit) 173 return None; 174 a = malloc(sizeof(AtomListRec) + len + 1); 175 if (a == NULL) { 176 fprintf(stderr, "MakeAtom(): Error: Couldn't allocate AtomListRec" 177 " (%ld)\n", (unsigned long) sizeof(AtomListRec) + len + 1); 178 return None; 179 } 180 a->name = (char *) (a + 1); 181 a->len = len; 182 strncpy(a->name, string, len); 183 a->name[len] = '\0'; 184 a->atom = ++lastAtom; 185 a->hash = hash; 186 if (hashUsed >= hashSize / 2) { 187 ResizeHashTable(); 188 h = hash & hashMask; 189 if (hashTable[h]) { 190 r = (hash % rehash) | 1; 191 do { 192 h += r; 193 if (h >= hashSize) 194 h -= hashSize; 195 } while (hashTable[h]); 196 } 197 } 198 hashTable[h] = a; 199 hashUsed++; 200 if (reverseMapSize <= a->atom) { 201 if (!ResizeReverseMap()) 202 return None; 203 } 204 reverseMap[a->atom] = a; 205 return a->atom; 206} 207 208char * 209NameForAtom(Atom atom) 210{ 211 if (atom != None && atom <= lastAtom) 212 return reverseMap[atom]->name; 213 return NULL; 214} 215