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