xlsatoms.c revision 2f6f3826
1/* 2 * 3Copyright 1989, 1998 The Open Group 4Copyright 2009 Open Text Corporation 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 in 13all copies or substantial portions of the Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall not be 23used in advertising or otherwise to promote the sale, use or other dealings 24in this Software without prior written authorization from The Open Group. 25 * 26 * Author: Jim Fulton, MIT X Consortium 27 * Author: Peter Harris, Open Text Corporation 28 */ 29 30#ifdef HAVE_CONFIG_H 31# include "config.h" 32#endif 33 34#include <limits.h> 35#include <stdio.h> 36#include <stdlib.h> 37#include <string.h> 38#include <xcb/xcb.h> 39#include <xcb/xproto.h> 40 41#define ATOMS_PER_BATCH 100 /* This number can be tuned 42 higher for fewer round-trips 43 lower for less bandwidth wasted */ 44 45static const char *ProgramName; 46static const char *DisplayString; 47 48static void do_name ( xcb_connection_t *c, const char *format, char *name ); 49static int parse_range ( char *range, xcb_atom_t *lowp, xcb_atom_t *highp ); 50static void do_range ( xcb_connection_t *c, const char *format, char *range ); 51static void list_atoms ( xcb_connection_t *c, const char *format, int mask, 52 xcb_atom_t low, xcb_atom_t high ); 53 54static void 55usage(const char *errmsg) 56{ 57 if (errmsg != NULL) 58 fprintf (stderr, "%s: %s\n\n", ProgramName, errmsg); 59 60 fprintf (stderr, "usage: %s [-options...]\n\n%s\n", ProgramName, 61 "where options include:\n" 62 " -display dpy X server to which to connect\n" 63 " -format string printf-style format to use\n" 64 " -range [num]-[num] atom values to list\n" 65 " -name string name of single atom to print\n" 66 " -version print program version\n" 67 ); 68 exit (1); 69} 70 71int 72main(int argc, char *argv[]) 73{ 74 char *displayname = NULL; 75 const char *format = "%lu\t%s"; 76 int i, doit; 77 int didit = 0; 78 xcb_connection_t *c = NULL; 79 80 ProgramName = argv[0]; 81 82 for (doit = 0; doit < 2; doit++) { /* pre-parse to get display */ 83 for (i = 1; i < argc; i++) { 84 char *arg = argv[i]; 85 86 if (arg[0] == '-') { 87 switch (arg[1]) { 88 case 'd': /* -display dpy */ 89 if (++i >= argc) usage ("-display requires an argument"); 90 if (!doit) displayname = argv[i]; 91 continue; 92 case 'f': /* -format string */ 93 if (++i >= argc) usage ("-format requires an argument"); 94 if (doit) format = argv[i]; 95 continue; 96 case 'r': /* -range num-[num] */ 97 if (++i >= argc) usage ("-range requires an argument"); 98 if (doit) { 99 do_range (c, format, argv[i]); 100 didit = 1; 101 } 102 continue; 103 case 'n': /* -name string */ 104 if (++i >= argc) usage ("-name requires an argument"); 105 if (doit) { 106 do_name (c, format, argv[i]); 107 didit = 1; 108 } 109 continue; 110 case 'v': 111 if (strcmp(arg, "-version") == 0) { 112 puts(PACKAGE_STRING); 113 exit(0); 114 } 115 /* else FALLTHROUGH to unrecognized arg case below */ 116 } 117 } 118 fprintf (stderr, "%s: unrecognized argument %s\n\n", 119 ProgramName, arg); 120 usage (NULL); 121 } 122 if (!doit) { 123 DisplayString = displayname; 124 if (!DisplayString) 125 DisplayString = getenv("DISPLAY"); 126 if (!DisplayString) 127 DisplayString = ""; 128 c = xcb_connect(displayname, NULL); 129 if (!c || xcb_connection_has_error(c)) { 130 fprintf (stderr, "%s: unable to open display \"%s\"\n", 131 ProgramName, DisplayString); 132 exit (1); 133 } 134 } else 135 if (!didit) /* no options, default is list all */ 136 list_atoms(c, format, 0, 0, 0); 137 } 138 139 xcb_disconnect(c); 140 exit (0); 141} 142 143static void 144do_name(xcb_connection_t *c, const char *format, char *name) 145{ 146 xcb_intern_atom_reply_t *a = xcb_intern_atom_reply(c, 147 xcb_intern_atom_unchecked(c, 1, strlen(name), name), NULL); 148 149 if (a && a->atom != XCB_NONE) { 150 printf (format, (unsigned long) a->atom, name); 151 putchar ('\n'); 152 } else { 153 fprintf (stderr, "%s: no atom named \"%s\" on server \"%s\"\n", 154 ProgramName, name, DisplayString); 155 } 156 157 if (a) 158 free(a); 159} 160 161 162#define RangeLow (1 << 0) 163#define RangeHigh (1 << 1) 164 165static int 166strtoatom(char *s, xcb_atom_t *atom) 167{ 168 long long value; 169 char *end; 170 171 value = strtoll(s, &end, 10); 172 if (s == end || *end != '\0' || value < 0 || value > UINT32_MAX) { 173 return 1; 174 } 175 176 *atom = value; 177 return 0; 178} 179 180static int 181parse_range(char *range, xcb_atom_t *lowp, xcb_atom_t *highp) 182{ 183 char *dash; 184 int mask = 0; 185 186 if (!range) { /* NULL means default */ 187 *lowp = 1; 188 return RangeLow; 189 } 190 191 dash = strchr(range, '-'); 192 if (!dash) dash = strchr(range, ':'); 193 if (dash) { 194 if (dash == range) { /* -high */ 195 *lowp = 1; 196 } else { /* low-[high] */ 197 *dash = '\0'; 198 if (strtoatom(range, lowp)) { 199 *dash = '-'; 200 goto invalid; 201 } 202 *dash = '-'; 203 } 204 mask |= RangeLow; 205 dash++; 206 if (*dash) { /* [low]-high */ 207 if (strtoatom(dash, highp) || *highp < *lowp) { 208 goto invalid; 209 } 210 mask |= RangeHigh; 211 } 212 } else { /* number (low == high) */ 213 if (strtoatom(range, lowp)) { 214 goto invalid; 215 } 216 *highp = *lowp; 217 mask |= (RangeLow | RangeHigh); 218 } 219 220 return mask; 221invalid: 222 fprintf(stderr, "%s: invalid range: %s\n", ProgramName, range); 223 exit(1); 224} 225 226static void 227do_range(xcb_connection_t *c, const char *format, char *range) 228{ 229 int mask; 230 xcb_atom_t low, high; 231 232 mask = parse_range (range, &low, &high); 233 list_atoms (c, format, mask, low, high); 234} 235 236static int 237say_batch(xcb_connection_t *c, const char *format, xcb_get_atom_name_cookie_t *cookie, xcb_atom_t low, long count, int stop_error) 238{ 239 xcb_generic_error_t *e; 240 char atom_name[1024]; 241 long i; 242 int done = 0; 243 244 for (i = 0; i < count; i++) 245 cookie[i] = xcb_get_atom_name(c, i + low); 246 247 for (i = 0; i < count; i++) { 248 xcb_get_atom_name_reply_t *r; 249 r = xcb_get_atom_name_reply(c, cookie[i], &e); 250 if (r) { 251 if (!done || !stop_error) { 252 /* We could just use %.*s in 'format', but we want to be compatible 253 with legacy command line usage */ 254 snprintf(atom_name, sizeof(atom_name), "%.*s", 255 r->name_len, xcb_get_atom_name_name(r)); 256 257 printf (format, i + low, atom_name); 258 putchar ('\n'); 259 } 260 free(r); 261 } 262 if (e) { 263 done = 1; 264 free(e); 265 } 266 } 267 268 return done && stop_error; 269} 270 271static void 272list_atoms(xcb_connection_t *c, const char *format, int mask, xcb_atom_t low, xcb_atom_t high) 273{ 274 xcb_get_atom_name_cookie_t cookie_jar[ATOMS_PER_BATCH]; 275 int done = 0; 276 long count; 277 278 if ((mask & RangeLow) == 0) 279 low = 1; 280 if ((mask & RangeHigh) == 0) 281 high = UINT32_MAX; 282 283 while (!done) { 284 count = high - low < ATOMS_PER_BATCH - 1 ? high - low + 1 : ATOMS_PER_BATCH; 285 done = say_batch(c, format, cookie_jar, low, count, (mask & RangeHigh) == 0); 286 if (high - low < UINT32_MAX && low == high - count + 1) { 287 done = 1; 288 } 289 low += count; 290 } 291} 292