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