xlsatoms.c revision f5effb2e
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#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <xcb/xcb.h>
34#include <xcb/xproto.h>
35
36#define ATOMS_PER_BATCH 100 /* This number can be tuned
37				higher for fewer round-trips
38				lower for less bandwidth wasted */
39
40static char *ProgramName;
41static char *DisplayString;
42
43static void do_name ( xcb_connection_t *c, char *format, char *name );
44static int parse_range ( char *range, long *lowp, long *highp );
45static void do_range ( xcb_connection_t *c, char *format, char *range );
46static void list_atoms ( xcb_connection_t *c, char *format, int mask,
47			 long low, long high );
48
49static void
50usage(void)
51{
52    fprintf (stderr, "usage:  %s [-options...]\n\n", ProgramName);
53    fprintf (stderr, "where options include:\n");
54    fprintf (stderr,
55	     "    -display dpy            X server to which to connect\n");
56    fprintf (stderr,
57	     "    -format string          printf-style format to use\n");
58    fprintf (stderr,
59	     "    -range [num]-[num]      atom values to list\n");
60    fprintf (stderr,
61	     "    -name string            name of single atom to print\n");
62    putc ('\n', stderr);
63    exit (1);
64}
65
66int
67main(int argc, char *argv[])
68{
69    char *displayname = NULL;
70    char *format = "%lu\t%s";
71    int i, doit;
72    int didit = 0;
73    xcb_connection_t *c = NULL;
74
75    ProgramName = argv[0];
76
77    for (doit = 0; doit < 2; doit++) {	/* pre-parse to get display */
78	for (i = 1; i < argc; i++) {
79	    char *arg = argv[i];
80
81	    if (arg[0] == '-') {
82		switch (arg[1]) {
83		  case 'd':			/* -display dpy */
84		    if (++i >= argc) usage ();
85		    if (!doit) displayname = argv[i];
86		    continue;
87		  case 'f':			/* -format string */
88		    if (++i >= argc) usage ();
89		    if (doit) format = argv[i];
90		    continue;
91		  case 'r':			/* -range num-[num] */
92		    if (++i >= argc) usage ();
93		    if (doit) {
94			do_range (c, format, argv[i]);
95			didit = 1;
96		    }
97		    continue;
98		  case 'n':			/* -name string */
99		    if (++i >= argc) usage ();
100		    if (doit) {
101			do_name (c, format, argv[i]);
102			didit = 1;
103		    }
104		    continue;
105		}
106	    }
107	    usage ();
108	}
109	if (!doit) {
110	    DisplayString = displayname;
111	    if (!DisplayString)
112		DisplayString = getenv("DISPLAY");
113	    if (!DisplayString)
114		DisplayString = "";
115	    c = xcb_connect(displayname, NULL);
116	    if (!c || xcb_connection_has_error(c)) {
117		fprintf (stderr, "%s:  unable to open display \"%s\"\n",
118			 ProgramName, DisplayString);
119		exit (1);
120	    }
121	} else
122	    if (!didit)		/* no options, default is list all */
123		list_atoms(c, format, 0, 0, 0);
124    }
125
126    xcb_disconnect(c);
127    exit (0);
128}
129
130static void
131do_name(xcb_connection_t *c, char *format, char *name)
132{
133    xcb_intern_atom_reply_t *a = xcb_intern_atom_reply(c,
134	xcb_intern_atom_unchecked(c, 1, strlen(name), name), NULL);
135
136    if (a && a->atom != XCB_NONE) {
137	printf (format, (unsigned long) a->atom, name);
138	putchar ('\n');
139    } else {
140	fprintf (stderr, "%s:  no atom named \"%s\" on server \"%s\"\n",
141		 ProgramName, name, DisplayString);
142    }
143
144    if (a)
145	free(a);
146}
147
148
149#define RangeLow (1 << 0)
150#define RangeHigh (1 << 1)
151
152static int
153parse_range(char *range, long *lowp, long *highp)
154{
155    char *dash;
156    int mask = 0;
157
158    if (!range) {			/* NULL means default */
159	*lowp = 1;
160	return RangeLow;
161    }
162
163    dash = strchr(range, '-');
164    if (!dash) dash = strchr(range, ':');
165    if (dash) {
166	if (dash == range) {		/* -high */
167	    *lowp = 1;
168	} else {			/* low-[high] */
169	    *dash = '\0';
170	    *lowp = atoi (range);
171	    *dash = '-';
172	}
173	mask |= RangeLow;
174	dash++;
175	if (*dash) {			/* [low]-high */
176	    *highp = atoi (dash);
177	    mask |= RangeHigh;
178	}
179    } else {				/* number (low == high) */
180	*lowp = *highp = atoi (range);
181	mask |= (RangeLow | RangeHigh);
182    }
183
184    return mask;
185}
186
187static void
188do_range(xcb_connection_t *c, char *format, char *range)
189{
190    int mask;
191    long low, high;
192
193    mask = parse_range (range, &low, &high);
194    list_atoms (c, format, mask, low, high);
195}
196
197static int
198say_batch(xcb_connection_t *c, char *format, xcb_get_atom_name_cookie_t *cookie, long low, long count)
199{
200    xcb_generic_error_t *e;
201    char atom_name[1024];
202    long i;
203    int done = 0;
204
205    for (i = 0; i < count; i++)
206	cookie[i] = xcb_get_atom_name(c, i + low);
207
208    for (i = 0; i < count; i++) {
209	xcb_get_atom_name_reply_t *r;
210	r = xcb_get_atom_name_reply(c, cookie[i], &e);
211	if (r) {
212	    /* We could just use %.*s in 'format', but we want to be compatible
213	       with legacy command line usage */
214	    snprintf(atom_name, sizeof(atom_name), "%.*s",
215		r->name_len, xcb_get_atom_name_name(r));
216
217	    printf (format, i + low, atom_name);
218	    putchar ('\n');
219	    free(r);
220	}
221	if (e) {
222	    done = 1;
223	    free(e);
224	}
225    }
226
227    return done;
228}
229
230static void
231list_atoms(xcb_connection_t *c, char *format, int mask, long low, long high)
232{
233    xcb_get_atom_name_cookie_t *cookie_jar;
234    int done = 0;
235
236    switch (mask) {
237      case RangeHigh:
238	low = 1;
239	/* fall through */
240      case (RangeLow | RangeHigh):
241	cookie_jar = malloc((high - low + 1) * sizeof(xcb_get_atom_name_cookie_t));
242        if (!cookie_jar) {
243	    fprintf(stderr, "Out of memory allocating space for %ld atom requests\n", high - low);
244	    return;
245	}
246
247	say_batch(c, format, cookie_jar, low, high - low + 1);
248	free(cookie_jar);
249	break;
250
251      default:
252	low = 1;
253	/* fall through */
254      case RangeLow:
255	cookie_jar = malloc(ATOMS_PER_BATCH * sizeof(xcb_get_atom_name_cookie_t));
256        if (!cookie_jar) {
257	    fprintf(stderr, "Out of memory allocating space for %ld atom requests\n", (long) ATOMS_PER_BATCH);
258	    return;
259	}
260	while (!done) {
261	    done = say_batch(c, format, cookie_jar, low, ATOMS_PER_BATCH);
262	    low += ATOMS_PER_BATCH;
263	}
264	free(cookie_jar);
265	break;
266    }
267
268    return;
269}
270