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