IntAtom.c revision 2d67cb4f
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(e);
51	}
52	Xfree(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(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    uint64_t start_seq;
192    uint64_t 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    uint64_t last_request_read = X_DPY_GET_LAST_REQUEST_READ(dpy);
212
213    state = (_XIntAtomState *)data;
214
215    if (last_request_read < state->start_seq ||
216	last_request_read > state->stop_seq)
217	return False;
218    for (i = 0; i < state->count; i++) {
219	if (state->atoms[i] & 0x80000000) {
220	    idx = ~state->atoms[i];
221	    state->atoms[i] = None;
222	    break;
223	}
224    }
225    if (i >= state->count)
226	return False;
227    if (rep->generic.type == X_Error) {
228	state->status = 0;
229	return False;
230    }
231    repl = (xInternAtomReply *)
232	_XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
233			(SIZEOF(xInternAtomReply) - SIZEOF(xReply)) >> 2,
234			True);
235    if ((state->atoms[i] = repl->atom))
236	_XUpdateAtomCache(dpy, state->names[i], (Atom) repl->atom,
237			  (unsigned long)0, idx, 0);
238    return True;
239}
240
241Status
242XInternAtoms (
243    Display *dpy,
244    char **names,
245    int count,
246    Bool onlyIfExists,
247    Atom *atoms_return)
248{
249    int i, idx, n, tidx;
250    unsigned long sig;
251    _XAsyncHandler async;
252    _XIntAtomState async_state;
253    int missed = -1;
254    xInternAtomReply rep;
255
256    LockDisplay(dpy);
257    async_state.start_seq = X_DPY_GET_REQUEST(dpy) + 1;
258    async_state.atoms = atoms_return;
259    async_state.names = names;
260    async_state.count = count - 1;
261    async_state.status = 1;
262    async.next = dpy->async_handlers;
263    async.handler = _XIntAtomHandler;
264    async.data = (XPointer)&async_state;
265    dpy->async_handlers = &async;
266    for (i = 0; i < count; i++) {
267	if (!(atoms_return[i] = _XInternAtom(dpy, names[i], onlyIfExists,
268					     &sig, &idx, &n))) {
269	    missed = i;
270	    atoms_return[i] = ~((Atom)idx);
271	    async_state.stop_seq = X_DPY_GET_REQUEST(dpy);
272	}
273    }
274    if (missed >= 0) {
275        if (dpy->atoms) {
276	    /* unreserve anything we just reserved */
277	    for (i = 0; i < count; i++) {
278		if (atoms_return[i] & 0x80000000) {
279		    tidx = ~atoms_return[i];
280		    if (dpy->atoms->table[tidx] == RESERVED)
281			dpy->atoms->table[tidx] = NULL;
282		}
283	    }
284        }
285	if (_XReply (dpy, (xReply *)&rep, 0, xTrue)) {
286	    if ((atoms_return[missed] = rep.atom))
287		_XUpdateAtomCache(dpy, names[missed], (Atom) rep.atom,
288				  sig, idx, n);
289	} else {
290	    atoms_return[missed] = None;
291	    async_state.status = 0;
292	}
293    }
294    DeqAsyncHandler(dpy, &async);
295    UnlockDisplay(dpy);
296    if (missed >= 0)
297	SyncHandle();
298    return async_state.status;
299}
300