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 dpy->atoms = NULL; 54 } 55} 56 57static 58Atom _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 } 94nomatch: 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 115void 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 162Atom 163XInternAtom ( 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 191typedef 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 200static 201Bool _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 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 = 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