1fdb3d228Smrg/* 2fdb3d228Smrg * 3fdb3d228SmrgCopyright 1989, 1998 The Open Group 4f5effb2eSmrgCopyright 2009 Open Text Corporation 5fdb3d228Smrg 6fdb3d228SmrgPermission to use, copy, modify, distribute, and sell this software and its 7fdb3d228Smrgdocumentation for any purpose is hereby granted without fee, provided that 8fdb3d228Smrgthe above copyright notice appear in all copies and that both that 9fdb3d228Smrgcopyright notice and this permission notice appear in supporting 10fdb3d228Smrgdocumentation. 11fdb3d228Smrg 12fdb3d228SmrgThe above copyright notice and this permission notice shall be included in 13fdb3d228Smrgall copies or substantial portions of the Software. 14fdb3d228Smrg 15fdb3d228SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16fdb3d228SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17fdb3d228SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18fdb3d228SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 19fdb3d228SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20fdb3d228SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21fdb3d228Smrg 22fdb3d228SmrgExcept as contained in this notice, the name of The Open Group shall not be 23fdb3d228Smrgused in advertising or otherwise to promote the sale, use or other dealings 24fdb3d228Smrgin this Software without prior written authorization from The Open Group. 25fdb3d228Smrg * 26fdb3d228Smrg * Author: Jim Fulton, MIT X Consortium 27f5effb2eSmrg * Author: Peter Harris, Open Text Corporation 28fdb3d228Smrg */ 29fdb3d228Smrg 30585aa3f7Smrg#ifdef HAVE_CONFIG_H 31585aa3f7Smrg# include "config.h" 32585aa3f7Smrg#endif 33585aa3f7Smrg 342f6f3826Smrg#include <limits.h> 35fdb3d228Smrg#include <stdio.h> 36fdb3d228Smrg#include <stdlib.h> 37f5effb2eSmrg#include <string.h> 38f5effb2eSmrg#include <xcb/xcb.h> 39f5effb2eSmrg#include <xcb/xproto.h> 40f5effb2eSmrg 41f5effb2eSmrg#define ATOMS_PER_BATCH 100 /* This number can be tuned 42f5effb2eSmrg higher for fewer round-trips 43f5effb2eSmrg lower for less bandwidth wasted */ 44fdb3d228Smrg 457d575c90Smrgstatic const char *ProgramName; 467d575c90Smrgstatic const char *DisplayString; 47fdb3d228Smrg 487d575c90Smrgstatic void do_name ( xcb_connection_t *c, const char *format, char *name ); 492f6f3826Smrgstatic int parse_range ( char *range, xcb_atom_t *lowp, xcb_atom_t *highp ); 507d575c90Smrgstatic void do_range ( xcb_connection_t *c, const char *format, char *range ); 517d575c90Smrgstatic void list_atoms ( xcb_connection_t *c, const char *format, int mask, 522f6f3826Smrg xcb_atom_t low, xcb_atom_t high ); 53fdb3d228Smrg 5474b35aa8Smrg#ifndef __has_attribute 5574b35aa8Smrg# define __has_attribute(x) 0 /* Compatibility with older compilers. */ 5674b35aa8Smrg#endif 5774b35aa8Smrg 5874b35aa8Smrgstatic void 5974b35aa8Smrg#if __has_attribute(__cold__) 6074b35aa8Smrg__attribute__((__cold__)) 6174b35aa8Smrg#endif 6274b35aa8Smrg#if __has_attribute(noreturn) 6374b35aa8Smrg__attribute__((noreturn)) 6474b35aa8Smrg#endif 65585aa3f7Smrgusage(const char *errmsg) 66fdb3d228Smrg{ 67585aa3f7Smrg if (errmsg != NULL) 68585aa3f7Smrg fprintf (stderr, "%s: %s\n\n", ProgramName, errmsg); 69585aa3f7Smrg 70585aa3f7Smrg fprintf (stderr, "usage: %s [-options...]\n\n%s\n", ProgramName, 71585aa3f7Smrg "where options include:\n" 72585aa3f7Smrg " -display dpy X server to which to connect\n" 73585aa3f7Smrg " -format string printf-style format to use\n" 74585aa3f7Smrg " -range [num]-[num] atom values to list\n" 75585aa3f7Smrg " -name string name of single atom to print\n" 76585aa3f7Smrg " -version print program version\n" 77585aa3f7Smrg ); 78fdb3d228Smrg exit (1); 79fdb3d228Smrg} 80fdb3d228Smrg 81fdb3d228Smrgint 82fdb3d228Smrgmain(int argc, char *argv[]) 83fdb3d228Smrg{ 84fdb3d228Smrg char *displayname = NULL; 857d575c90Smrg const char *format = "%lu\t%s"; 86fdb3d228Smrg int didit = 0; 87f5effb2eSmrg xcb_connection_t *c = NULL; 88fdb3d228Smrg 89fdb3d228Smrg ProgramName = argv[0]; 90fdb3d228Smrg 9174b35aa8Smrg for (int doit = 0; doit < 2; doit++) { /* pre-parse to get display */ 9274b35aa8Smrg for (int i = 1; i < argc; i++) { 93fdb3d228Smrg char *arg = argv[i]; 94fdb3d228Smrg 95fdb3d228Smrg if (arg[0] == '-') { 96fdb3d228Smrg switch (arg[1]) { 97fdb3d228Smrg case 'd': /* -display dpy */ 98585aa3f7Smrg if (++i >= argc) usage ("-display requires an argument"); 99fdb3d228Smrg if (!doit) displayname = argv[i]; 100fdb3d228Smrg continue; 101fdb3d228Smrg case 'f': /* -format string */ 102585aa3f7Smrg if (++i >= argc) usage ("-format requires an argument"); 103fdb3d228Smrg if (doit) format = argv[i]; 104fdb3d228Smrg continue; 105fdb3d228Smrg case 'r': /* -range num-[num] */ 106585aa3f7Smrg if (++i >= argc) usage ("-range requires an argument"); 107fdb3d228Smrg if (doit) { 108f5effb2eSmrg do_range (c, format, argv[i]); 109fdb3d228Smrg didit = 1; 110fdb3d228Smrg } 111fdb3d228Smrg continue; 112fdb3d228Smrg case 'n': /* -name string */ 113585aa3f7Smrg if (++i >= argc) usage ("-name requires an argument"); 114fdb3d228Smrg if (doit) { 115f5effb2eSmrg do_name (c, format, argv[i]); 116fdb3d228Smrg didit = 1; 117fdb3d228Smrg } 118fdb3d228Smrg continue; 119585aa3f7Smrg case 'v': 120585aa3f7Smrg if (strcmp(arg, "-version") == 0) { 121585aa3f7Smrg puts(PACKAGE_STRING); 122585aa3f7Smrg exit(0); 123585aa3f7Smrg } 124585aa3f7Smrg /* else FALLTHROUGH to unrecognized arg case below */ 125fdb3d228Smrg } 126fdb3d228Smrg } 127585aa3f7Smrg fprintf (stderr, "%s: unrecognized argument %s\n\n", 128585aa3f7Smrg ProgramName, arg); 129585aa3f7Smrg usage (NULL); 130fdb3d228Smrg } 131fdb3d228Smrg if (!doit) { 132f5effb2eSmrg DisplayString = displayname; 133f5effb2eSmrg if (!DisplayString) 134f5effb2eSmrg DisplayString = getenv("DISPLAY"); 135f5effb2eSmrg if (!DisplayString) 136f5effb2eSmrg DisplayString = ""; 137f5effb2eSmrg c = xcb_connect(displayname, NULL); 138f5effb2eSmrg if (!c || xcb_connection_has_error(c)) { 139fdb3d228Smrg fprintf (stderr, "%s: unable to open display \"%s\"\n", 140f5effb2eSmrg ProgramName, DisplayString); 141fdb3d228Smrg exit (1); 142fdb3d228Smrg } 143fdb3d228Smrg } else 144fdb3d228Smrg if (!didit) /* no options, default is list all */ 145f5effb2eSmrg list_atoms(c, format, 0, 0, 0); 146fdb3d228Smrg } 147fdb3d228Smrg 148f5effb2eSmrg xcb_disconnect(c); 149fdb3d228Smrg exit (0); 150fdb3d228Smrg} 151fdb3d228Smrg 152fdb3d228Smrgstatic void 1537d575c90Smrgdo_name(xcb_connection_t *c, const char *format, char *name) 154fdb3d228Smrg{ 155f5effb2eSmrg xcb_intern_atom_reply_t *a = xcb_intern_atom_reply(c, 156f5effb2eSmrg xcb_intern_atom_unchecked(c, 1, strlen(name), name), NULL); 157fdb3d228Smrg 158f5effb2eSmrg if (a && a->atom != XCB_NONE) { 159f5effb2eSmrg printf (format, (unsigned long) a->atom, name); 160fdb3d228Smrg putchar ('\n'); 161fdb3d228Smrg } else { 162fdb3d228Smrg fprintf (stderr, "%s: no atom named \"%s\" on server \"%s\"\n", 163f5effb2eSmrg ProgramName, name, DisplayString); 164fdb3d228Smrg } 165f5effb2eSmrg 166f5effb2eSmrg if (a) 167f5effb2eSmrg free(a); 168fdb3d228Smrg} 169fdb3d228Smrg 170fdb3d228Smrg 171fdb3d228Smrg#define RangeLow (1 << 0) 172fdb3d228Smrg#define RangeHigh (1 << 1) 173fdb3d228Smrg 1742f6f3826Smrgstatic int 1752f6f3826Smrgstrtoatom(char *s, xcb_atom_t *atom) 1762f6f3826Smrg{ 1772f6f3826Smrg long long value; 1782f6f3826Smrg char *end; 1792f6f3826Smrg 1802f6f3826Smrg value = strtoll(s, &end, 10); 1812f6f3826Smrg if (s == end || *end != '\0' || value < 0 || value > UINT32_MAX) { 1822f6f3826Smrg return 1; 1832f6f3826Smrg } 1842f6f3826Smrg 18574b35aa8Smrg *atom = (xcb_atom_t) value; 1862f6f3826Smrg return 0; 1872f6f3826Smrg} 1882f6f3826Smrg 189fdb3d228Smrgstatic int 1902f6f3826Smrgparse_range(char *range, xcb_atom_t *lowp, xcb_atom_t *highp) 191fdb3d228Smrg{ 192fdb3d228Smrg char *dash; 193fdb3d228Smrg int mask = 0; 194fdb3d228Smrg 195fdb3d228Smrg if (!range) { /* NULL means default */ 196fdb3d228Smrg *lowp = 1; 197fdb3d228Smrg return RangeLow; 198fdb3d228Smrg } 199fdb3d228Smrg 200fdb3d228Smrg dash = strchr(range, '-'); 201fdb3d228Smrg if (!dash) dash = strchr(range, ':'); 202fdb3d228Smrg if (dash) { 203fdb3d228Smrg if (dash == range) { /* -high */ 204fdb3d228Smrg *lowp = 1; 205fdb3d228Smrg } else { /* low-[high] */ 206fdb3d228Smrg *dash = '\0'; 2072f6f3826Smrg if (strtoatom(range, lowp)) { 2082f6f3826Smrg *dash = '-'; 2092f6f3826Smrg goto invalid; 2102f6f3826Smrg } 211fdb3d228Smrg *dash = '-'; 212fdb3d228Smrg } 213fdb3d228Smrg mask |= RangeLow; 214fdb3d228Smrg dash++; 215fdb3d228Smrg if (*dash) { /* [low]-high */ 2162f6f3826Smrg if (strtoatom(dash, highp) || *highp < *lowp) { 2172f6f3826Smrg goto invalid; 2182f6f3826Smrg } 219fdb3d228Smrg mask |= RangeHigh; 220fdb3d228Smrg } 221fdb3d228Smrg } else { /* number (low == high) */ 2222f6f3826Smrg if (strtoatom(range, lowp)) { 2232f6f3826Smrg goto invalid; 2242f6f3826Smrg } 2252f6f3826Smrg *highp = *lowp; 226fdb3d228Smrg mask |= (RangeLow | RangeHigh); 227fdb3d228Smrg } 228fdb3d228Smrg 229fdb3d228Smrg return mask; 2302f6f3826Smrginvalid: 2312f6f3826Smrg fprintf(stderr, "%s: invalid range: %s\n", ProgramName, range); 2322f6f3826Smrg exit(1); 233fdb3d228Smrg} 234fdb3d228Smrg 235fdb3d228Smrgstatic void 2367d575c90Smrgdo_range(xcb_connection_t *c, const char *format, char *range) 237fdb3d228Smrg{ 238fdb3d228Smrg int mask; 2392f6f3826Smrg xcb_atom_t low, high; 240fdb3d228Smrg 241fdb3d228Smrg mask = parse_range (range, &low, &high); 242f5effb2eSmrg list_atoms (c, format, mask, low, high); 243fdb3d228Smrg} 244fdb3d228Smrg 245f5effb2eSmrgstatic int 2462f6f3826Smrgsay_batch(xcb_connection_t *c, const char *format, xcb_get_atom_name_cookie_t *cookie, xcb_atom_t low, long count, int stop_error) 247fdb3d228Smrg{ 248f5effb2eSmrg xcb_generic_error_t *e; 249f5effb2eSmrg char atom_name[1024]; 250f5effb2eSmrg long i; 251f5effb2eSmrg int done = 0; 252f5effb2eSmrg 253f5effb2eSmrg for (i = 0; i < count; i++) 25474b35aa8Smrg cookie[i] = xcb_get_atom_name(c, (xcb_atom_t)i + low); 255f5effb2eSmrg 256f5effb2eSmrg for (i = 0; i < count; i++) { 257f5effb2eSmrg xcb_get_atom_name_reply_t *r; 258f5effb2eSmrg r = xcb_get_atom_name_reply(c, cookie[i], &e); 259f5effb2eSmrg if (r) { 2602f6f3826Smrg if (!done || !stop_error) { 2612f6f3826Smrg /* We could just use %.*s in 'format', but we want to be compatible 2622f6f3826Smrg with legacy command line usage */ 2632f6f3826Smrg snprintf(atom_name, sizeof(atom_name), "%.*s", 2642f6f3826Smrg r->name_len, xcb_get_atom_name_name(r)); 2652f6f3826Smrg 2662f6f3826Smrg printf (format, i + low, atom_name); 2672f6f3826Smrg putchar ('\n'); 2682f6f3826Smrg } 269f5effb2eSmrg free(r); 270f5effb2eSmrg } 271f5effb2eSmrg if (e) { 272f5effb2eSmrg done = 1; 273f5effb2eSmrg free(e); 274f5effb2eSmrg } 275fdb3d228Smrg } 276f5effb2eSmrg 2772f6f3826Smrg return done && stop_error; 278fdb3d228Smrg} 279fdb3d228Smrg 280fdb3d228Smrgstatic void 2812f6f3826Smrglist_atoms(xcb_connection_t *c, const char *format, int mask, xcb_atom_t low, xcb_atom_t high) 282fdb3d228Smrg{ 2832f6f3826Smrg xcb_get_atom_name_cookie_t cookie_jar[ATOMS_PER_BATCH]; 284f5effb2eSmrg int done = 0; 285fdb3d228Smrg 2862f6f3826Smrg if ((mask & RangeLow) == 0) 287fdb3d228Smrg low = 1; 2882f6f3826Smrg if ((mask & RangeHigh) == 0) 2892f6f3826Smrg high = UINT32_MAX; 290fdb3d228Smrg 2912f6f3826Smrg while (!done) { 29274b35aa8Smrg long count = (high - low < ATOMS_PER_BATCH - 1) ? 29374b35aa8Smrg (high - low + 1) : ATOMS_PER_BATCH; 2942f6f3826Smrg done = say_batch(c, format, cookie_jar, low, count, (mask & RangeHigh) == 0); 2952f6f3826Smrg if (high - low < UINT32_MAX && low == high - count + 1) { 2962f6f3826Smrg done = 1; 297fdb3d228Smrg } 2982f6f3826Smrg low += count; 299fdb3d228Smrg } 300fdb3d228Smrg} 301