Home | History | Annotate | Line # | Download | only in src
      1 /*
      2 
      3 Copyright 1986, 1990, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included
     12 in all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 OTHER DEALINGS IN THE SOFTWARE.
     21 
     22 Except as contained in this notice, the name of The Open Group shall
     23 not be used in advertising or otherwise to promote the sale, use or
     24 other dealings in this Software without prior written authorization
     25 from 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 
     39 void
     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 	dpy->atoms = NULL;
     54     }
     55 }
     56 
     57 static
     58 Atom _XInternAtom(
     59     Display *dpy,
     60     _Xconst char *name,
     61     Bool onlyIfExists,
     62     unsigned long *psig,
     63     int *pidx,
     64     int *pn)
     65 {
     66     register AtomTable *atoms;
     67     register char *s1, c, *s2;
     68     register unsigned long sig;
     69     register int idx = 0, i;
     70     Entry e;
     71     int n, firstidx, rehash = 0;
     72     xInternAtomReq *req;
     73 
     74     /* look in the cache first */
     75     if (!(atoms = dpy->atoms)) {
     76 	dpy->atoms = atoms = Xcalloc(1, sizeof(AtomTable));
     77 	dpy->free_funcs->atoms = _XFreeAtomTable;
     78     }
     79     sig = 0;
     80     for (s1 = (char *)name; (c = *s1++); )
     81 	sig += c;
     82     n = s1 - (char *)name - 1;
     83     if (atoms) {
     84 	firstidx = idx = HASH(sig);
     85 	while ((e = atoms->table[idx])) {
     86 	    if (e != RESERVED && e->sig == sig) {
     87 	    	for (i = n, s1 = (char *)name, s2 = EntryName(e); --i >= 0; ) {
     88 		    if (*s1++ != *s2++)
     89 		    	goto nomatch;
     90 	    	}
     91 	    	if (!*s2)
     92 		    return e->atom;
     93 	    }
     94 nomatch:    if (idx == firstidx)
     95 		rehash = REHASHVAL(sig);
     96 	    idx = REHASH(idx, rehash);
     97 	    if (idx == firstidx)
     98 		break;
     99 	}
    100     }
    101     *psig = sig;
    102     *pidx = idx;
    103     if (atoms && !atoms->table[idx])
    104 	atoms->table[idx] = RESERVED; /* reserve slot */
    105     *pn = n;
    106     /* not found, go to the server */
    107     GetReq(InternAtom, req);
    108     req->nbytes = n;
    109     req->onlyIfExists = onlyIfExists;
    110     req->length += (n+3)>>2;
    111     Data(dpy, name, n);
    112     return None;
    113 }
    114 
    115 void
    116 _XUpdateAtomCache(
    117     Display *dpy,
    118     const char *name,
    119     Atom atom,
    120     unsigned long sig,
    121     int idx,
    122     int n)
    123 {
    124     Entry e, oe;
    125     register char *s1;
    126     register char c;
    127     int firstidx, rehash;
    128 
    129     if (!dpy->atoms) {
    130 	if (idx < 0) {
    131 	    dpy->atoms = Xcalloc(1, sizeof(AtomTable));
    132 	    dpy->free_funcs->atoms = _XFreeAtomTable;
    133 	}
    134 	if (!dpy->atoms)
    135 	    return;
    136     }
    137     if (!sig) {
    138 	for (s1 = (char *)name; (c = *s1++); )
    139 	    sig += c;
    140 	n = s1 - (char *)name - 1;
    141 	if (idx < 0) {
    142 	    firstidx = idx = HASH(sig);
    143 	    if (dpy->atoms->table[idx]) {
    144 		rehash = REHASHVAL(sig);
    145 		do
    146 		    idx = REHASH(idx, rehash);
    147 		while (idx != firstidx && dpy->atoms->table[idx]);
    148 	    }
    149 	}
    150     }
    151     e = Xmalloc(sizeof(EntryRec) + n + 1);
    152     if (e) {
    153 	e->sig = sig;
    154 	e->atom = atom;
    155 	strcpy(EntryName(e), name);
    156 	if ((oe = dpy->atoms->table[idx]) && (oe != RESERVED))
    157 	    Xfree(oe);
    158 	dpy->atoms->table[idx] = e;
    159     }
    160 }
    161 
    162 Atom
    163 XInternAtom (
    164     Display *dpy,
    165     const char *name,
    166     Bool onlyIfExists)
    167 {
    168     Atom atom;
    169     unsigned long sig;
    170     int idx, n;
    171     xInternAtomReply rep;
    172 
    173     if (!name)
    174 	name = "";
    175     LockDisplay(dpy);
    176     if ((atom = _XInternAtom(dpy, name, onlyIfExists, &sig, &idx, &n))) {
    177 	UnlockDisplay(dpy);
    178 	return atom;
    179     }
    180     if (dpy->atoms && dpy->atoms->table[idx] == RESERVED)
    181 	dpy->atoms->table[idx] = NULL; /* unreserve slot */
    182     if (_XReply (dpy, (xReply *)&rep, 0, xTrue)) {
    183 	if ((atom = rep.atom))
    184 	    _XUpdateAtomCache(dpy, name, atom, sig, idx, n);
    185     }
    186     UnlockDisplay(dpy);
    187     SyncHandle();
    188     return (rep.atom);
    189 }
    190 
    191 typedef struct {
    192     uint64_t start_seq;
    193     uint64_t stop_seq;
    194     char **names;
    195     Atom *atoms;
    196     int count;
    197     Status status;
    198 } _XIntAtomState;
    199 
    200 static
    201 Bool _XIntAtomHandler(
    202     register Display *dpy,
    203     register xReply *rep,
    204     char *buf,
    205     int len,
    206     XPointer data)
    207 {
    208     register _XIntAtomState *state;
    209     register int i, idx = 0;
    210     xInternAtomReply replbuf;
    211     register xInternAtomReply *repl;
    212     uint64_t last_request_read = X_DPY_GET_LAST_REQUEST_READ(dpy);
    213 
    214     state = (_XIntAtomState *)data;
    215 
    216     if (last_request_read < state->start_seq ||
    217 	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 
    242 Status
    243 XInternAtoms (
    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 = X_DPY_GET_REQUEST(dpy) + 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 = X_DPY_GET_REQUEST(dpy);
    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