IntAtom.c revision eb411b4b
1/*
2
3Copyright 1986, 1990, 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
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29#ifdef HAVE_CONFIG_H
30#include <config.h>
31#endif
32#include "Xlibint.h"
33#include "Xintatom.h"
34
35#define HASH(sig) ((sig) & (TABLESIZE-1))
36#define REHASHVAL(sig) ((((sig) % (TABLESIZE-3)) + 2) | 1)
37#define REHASH(idx,rehash) ((idx + rehash) & (TABLESIZE-1))
38
39void
40_XFreeAtomTable(Display *dpy)
41{
42    register Entry *table;
43    register int i;
44    register Entry e;
45
46    if (dpy->atoms) {
47	table = dpy->atoms->table;
48	for (i = TABLESIZE; --i >= 0; ) {
49	    if ((e = *table++) && (e != RESERVED))
50		Xfree((char *)e);
51	}
52	Xfree((char *)dpy->atoms);
53    }
54}
55
56static
57Atom _XInternAtom(
58    Display *dpy,
59    _Xconst char *name,
60    Bool onlyIfExists,
61    unsigned long *psig,
62    int *pidx,
63    int *pn)
64{
65    register AtomTable *atoms;
66    register char *s1, c, *s2;
67    register unsigned long sig;
68    register int idx = 0, i;
69    Entry e;
70    int n, firstidx, rehash = 0;
71    xInternAtomReq *req;
72
73    /* look in the cache first */
74    if (!(atoms = dpy->atoms)) {
75	dpy->atoms = atoms = Xcalloc(1, sizeof(AtomTable));
76	dpy->free_funcs->atoms = _XFreeAtomTable;
77    }
78    sig = 0;
79    for (s1 = (char *)name; (c = *s1++); )
80	sig += c;
81    n = s1 - (char *)name - 1;
82    if (atoms) {
83	firstidx = idx = HASH(sig);
84	while ((e = atoms->table[idx])) {
85	    if (e != RESERVED && e->sig == sig) {
86	    	for (i = n, s1 = (char *)name, s2 = EntryName(e); --i >= 0; ) {
87		    if (*s1++ != *s2++)
88		    	goto nomatch;
89	    	}
90	    	if (!*s2)
91		    return e->atom;
92	    }
93nomatch:    if (idx == firstidx)
94		rehash = REHASHVAL(sig);
95	    idx = REHASH(idx, rehash);
96	    if (idx == firstidx)
97		break;
98	}
99    }
100    *psig = sig;
101    *pidx = idx;
102    if (atoms && !atoms->table[idx])
103	atoms->table[idx] = RESERVED; /* reserve slot */
104    *pn = n;
105    /* not found, go to the server */
106    GetReq(InternAtom, req);
107    req->nbytes = n;
108    req->onlyIfExists = onlyIfExists;
109    req->length += (n+3)>>2;
110    Data(dpy, name, n);
111    return None;
112}
113
114void
115_XUpdateAtomCache(
116    Display *dpy,
117    const char *name,
118    Atom atom,
119    unsigned long sig,
120    int idx,
121    int n)
122{
123    Entry e, oe;
124    register char *s1;
125    register char c;
126    int firstidx, rehash;
127
128    if (!dpy->atoms) {
129	if (idx < 0) {
130	    dpy->atoms = Xcalloc(1, sizeof(AtomTable));
131	    dpy->free_funcs->atoms = _XFreeAtomTable;
132	}
133	if (!dpy->atoms)
134	    return;
135    }
136    if (!sig) {
137	for (s1 = (char *)name; (c = *s1++); )
138	    sig += c;
139	n = s1 - (char *)name - 1;
140	if (idx < 0) {
141	    firstidx = idx = HASH(sig);
142	    if (dpy->atoms->table[idx]) {
143		rehash = REHASHVAL(sig);
144		do
145		    idx = REHASH(idx, rehash);
146		while (idx != firstidx && dpy->atoms->table[idx]);
147	    }
148	}
149    }
150    e = Xmalloc(sizeof(EntryRec) + n + 1);
151    if (e) {
152	e->sig = sig;
153	e->atom = atom;
154	strcpy(EntryName(e), name);
155	if ((oe = dpy->atoms->table[idx]) && (oe != RESERVED))
156	    Xfree((char *)oe);
157	dpy->atoms->table[idx] = e;
158    }
159}
160
161Atom
162XInternAtom (
163    Display *dpy,
164    const char *name,
165    Bool onlyIfExists)
166{
167    Atom atom;
168    unsigned long sig;
169    int idx, n;
170    xInternAtomReply rep;
171
172    if (!name)
173	name = "";
174    LockDisplay(dpy);
175    if ((atom = _XInternAtom(dpy, name, onlyIfExists, &sig, &idx, &n))) {
176	UnlockDisplay(dpy);
177	return atom;
178    }
179    if (dpy->atoms && dpy->atoms->table[idx] == RESERVED)
180	dpy->atoms->table[idx] = NULL; /* unreserve slot */
181    if (_XReply (dpy, (xReply *)&rep, 0, xTrue)) {
182	if ((atom = rep.atom))
183	    _XUpdateAtomCache(dpy, name, atom, sig, idx, n);
184    }
185    UnlockDisplay(dpy);
186    SyncHandle();
187    return (rep.atom);
188}
189
190typedef struct {
191    unsigned long start_seq;
192    unsigned long stop_seq;
193    char **names;
194    Atom *atoms;
195    int count;
196    Status status;
197} _XIntAtomState;
198
199static
200Bool _XIntAtomHandler(
201    register Display *dpy,
202    register xReply *rep,
203    char *buf,
204    int len,
205    XPointer data)
206{
207    register _XIntAtomState *state;
208    register int i, idx = 0;
209    xInternAtomReply replbuf;
210    register xInternAtomReply *repl;
211
212    state = (_XIntAtomState *)data;
213    if (dpy->last_request_read < state->start_seq ||
214	dpy->last_request_read > state->stop_seq)
215	return False;
216    for (i = 0; i < state->count; i++) {
217	if (state->atoms[i] & 0x80000000) {
218	    idx = ~state->atoms[i];
219	    state->atoms[i] = None;
220	    break;
221	}
222    }
223    if (i >= state->count)
224	return False;
225    if (rep->generic.type == X_Error) {
226	state->status = 0;
227	return False;
228    }
229    repl = (xInternAtomReply *)
230	_XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
231			(SIZEOF(xInternAtomReply) - SIZEOF(xReply)) >> 2,
232			True);
233    if ((state->atoms[i] = repl->atom))
234	_XUpdateAtomCache(dpy, state->names[i], (Atom) repl->atom,
235			  (unsigned long)0, idx, 0);
236    return True;
237}
238
239Status
240XInternAtoms (
241    Display *dpy,
242    char **names,
243    int count,
244    Bool onlyIfExists,
245    Atom *atoms_return)
246{
247    int i, idx, n, tidx;
248    unsigned long sig;
249    _XAsyncHandler async;
250    _XIntAtomState async_state;
251    int missed = -1;
252    xInternAtomReply rep;
253
254    LockDisplay(dpy);
255    async_state.start_seq = dpy->request + 1;
256    async_state.atoms = atoms_return;
257    async_state.names = names;
258    async_state.count = count - 1;
259    async_state.status = 1;
260    async.next = dpy->async_handlers;
261    async.handler = _XIntAtomHandler;
262    async.data = (XPointer)&async_state;
263    dpy->async_handlers = &async;
264    for (i = 0; i < count; i++) {
265	if (!(atoms_return[i] = _XInternAtom(dpy, names[i], onlyIfExists,
266					     &sig, &idx, &n))) {
267	    missed = i;
268	    atoms_return[i] = ~((Atom)idx);
269	    async_state.stop_seq = dpy->request;
270	}
271    }
272    if (missed >= 0) {
273        if (dpy->atoms) {
274	    /* unreserve anything we just reserved */
275	    for (i = 0; i < count; i++) {
276		if (atoms_return[i] & 0x80000000) {
277		    tidx = ~atoms_return[i];
278		    if (dpy->atoms->table[tidx] == RESERVED)
279			dpy->atoms->table[tidx] = NULL;
280		}
281	    }
282        }
283	if (_XReply (dpy, (xReply *)&rep, 0, xTrue)) {
284	    if ((atoms_return[missed] = rep.atom))
285		_XUpdateAtomCache(dpy, names[missed], (Atom) rep.atom,
286				  sig, idx, n);
287	} else {
288	    atoms_return[missed] = None;
289	    async_state.status = 0;
290	}
291    }
292    DeqAsyncHandler(dpy, &async);
293    UnlockDisplay(dpy);
294    if (missed >= 0)
295	SyncHandle();
296    return async_state.status;
297}
298