xprop.c revision a0996ce0
1fc89c0fbSmrg/*
2fc89c0fbSmrg
3fc89c0fbSmrgCopyright 1990, 1998  The Open Group
4fc89c0fbSmrgCopyright (c) 2000  The XFree86 Project, Inc.
5fc89c0fbSmrg
6fc89c0fbSmrgPermission to use, copy, modify, distribute, and sell this software and its
7fc89c0fbSmrgdocumentation for any purpose is hereby granted without fee, provided that
8fc89c0fbSmrgthe above copyright notice appear in all copies and that both that
9fc89c0fbSmrgcopyright notice and this permission notice appear in supporting
10fc89c0fbSmrgdocumentation.
11fc89c0fbSmrg
12fc89c0fbSmrgThe above copyright notice and this permission notice shall be included
13fc89c0fbSmrgin all copies or substantial portions of the Software.
14fc89c0fbSmrg
15fc89c0fbSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16fc89c0fbSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17fc89c0fbSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18fc89c0fbSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
19fc89c0fbSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20fc89c0fbSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21fc89c0fbSmrgOTHER DEALINGS IN THE SOFTWARE.
22fc89c0fbSmrg
23fc89c0fbSmrgExcept as contained in this notice, the name of The Open Group shall
24fc89c0fbSmrgnot be used in advertising or otherwise to promote the sale, use or
25fc89c0fbSmrgother dealings in this Software without prior written authorization
26fc89c0fbSmrgfrom The Open Group.
27fc89c0fbSmrg
28fc89c0fbSmrg*/
29fc89c0fbSmrg
30fc89c0fbSmrg#include "config.h"
31fc89c0fbSmrg
32fc89c0fbSmrg#include <X11/Xlib.h>
33fc89c0fbSmrg#include <X11/Xos.h>
34fc89c0fbSmrg#include <X11/Xfuncs.h>
35fc89c0fbSmrg#include <X11/Xutil.h>
36fc89c0fbSmrg#include <stdlib.h>
37fc89c0fbSmrg#include <stdio.h>
38fc89c0fbSmrg#include <ctype.h>
39fc89c0fbSmrg#ifdef HAVE_WCHAR_H
40fc89c0fbSmrg#include <wchar.h>
41fc89c0fbSmrg#endif
42fc89c0fbSmrg#ifdef HAVE_WCTYPE_H
43fc89c0fbSmrg#include <wctype.h>
44fc89c0fbSmrg#endif
45fc89c0fbSmrg#include <locale.h>
4691ec45ceSmrg#ifdef HAVE_LANGINFO_H
4791ec45ceSmrg#include <langinfo.h>
4891ec45ceSmrg#endif
49fc89c0fbSmrg
50fc89c0fbSmrg#ifndef HAVE_WCTYPE_H
51fc89c0fbSmrg#define iswprint(x) isprint(x)
52fc89c0fbSmrg#endif
53fc89c0fbSmrg
54fc89c0fbSmrg#include <X11/Xatom.h>
55fc89c0fbSmrg
56fc89c0fbSmrg#include "dsimple.h"
57fc89c0fbSmrg
58fc89c0fbSmrg#define MAXSTR 500000
59fc89c0fbSmrg#define MAXELEMENTS 64
60fc89c0fbSmrg
61fc89c0fbSmrg#ifndef min
62fc89c0fbSmrg#define min(a,b)  ((a) < (b) ? (a) : (b))
63fc89c0fbSmrg#endif
64fc89c0fbSmrg
65fc89c0fbSmrg/* isprint() in "C" locale */
66fc89c0fbSmrg#define c_isprint(c) ((c) >= 0x20 && (c) < 0x7f)
67fc89c0fbSmrg
68fc89c0fbSmrg/*
69fc89c0fbSmrg *
70fc89c0fbSmrg * The Thunk Manager - routines to create, add to, and free thunk lists
71fc89c0fbSmrg *
72fc89c0fbSmrg */
73fc89c0fbSmrg
74fc89c0fbSmrgtypedef struct {
75fc89c0fbSmrg  int thunk_count;
76fc89c0fbSmrg  const char *propname;
77fc89c0fbSmrg  long value;
78fc89c0fbSmrg  Atom extra_encoding;
79fc89c0fbSmrg  const char *extra_value;
80fc89c0fbSmrg  const char *format;
81fc89c0fbSmrg  const char *dformat;
82fc89c0fbSmrg} thunk;
83fc89c0fbSmrg
84fc89c0fbSmrgstatic thunk *
85fc89c0fbSmrgCreate_Thunk_List (void)
86fc89c0fbSmrg{
87fc89c0fbSmrg    thunk *tptr;
88fc89c0fbSmrg
89fc89c0fbSmrg    tptr = (thunk *) Malloc(sizeof(thunk));
90fc89c0fbSmrg
91fc89c0fbSmrg    tptr->thunk_count = 0;
92fc89c0fbSmrg
93fc89c0fbSmrg    return tptr;
94fc89c0fbSmrg}
95fc89c0fbSmrg
96fc89c0fbSmrg#ifdef notused
97fc89c0fbSmrgstatic void
98fc89c0fbSmrgFree_Thunk_List (thunk *list)
99fc89c0fbSmrg{
100fc89c0fbSmrg    free(list);
101fc89c0fbSmrg}
102fc89c0fbSmrg#endif
103fc89c0fbSmrg
104fc89c0fbSmrgstatic thunk *
105fc89c0fbSmrgAdd_Thunk (thunk *list, thunk t)
106fc89c0fbSmrg{
107fc89c0fbSmrg    int i;
108fc89c0fbSmrg
109fc89c0fbSmrg    i = list->thunk_count;
110fc89c0fbSmrg
111fc89c0fbSmrg    list = (thunk *) realloc(list, (i+1)*sizeof(thunk));
112fc89c0fbSmrg    if (!list)
113fc89c0fbSmrg	Fatal_Error("Out of memory!");
114fc89c0fbSmrg
115fc89c0fbSmrg    list[i++] = t;
116fc89c0fbSmrg    list->thunk_count = i;
117fc89c0fbSmrg
118fc89c0fbSmrg    return list;
119fc89c0fbSmrg}
120fc89c0fbSmrg
121fc89c0fbSmrg/*
122fc89c0fbSmrg * Misc. routines
123fc89c0fbSmrg */
124fc89c0fbSmrg
125fc89c0fbSmrgstatic char *
126fc89c0fbSmrgCopy_String (const char *string)
127fc89c0fbSmrg{
128fc89c0fbSmrg    char *new;
129fc89c0fbSmrg    int length;
130fc89c0fbSmrg
131fc89c0fbSmrg    length = strlen(string) + 1;
132fc89c0fbSmrg
133fc89c0fbSmrg    new = (char *) Malloc(length);
134fc89c0fbSmrg    memcpy(new, string, length);
135fc89c0fbSmrg
136fc89c0fbSmrg    return new;
137fc89c0fbSmrg}
138fc89c0fbSmrg
139fc89c0fbSmrgstatic int
140fc89c0fbSmrgRead_Char (FILE *stream)
141fc89c0fbSmrg{
142fc89c0fbSmrg    int c;
143fc89c0fbSmrg
144fc89c0fbSmrg    c = getc(stream);
145fc89c0fbSmrg    if (c == EOF)
146fc89c0fbSmrg	Fatal_Error("Bad format file: Unexpected EOF.");
147fc89c0fbSmrg    return c;
148fc89c0fbSmrg}
149fc89c0fbSmrg
150fc89c0fbSmrgstatic void
151fc89c0fbSmrgRead_White_Space (FILE *stream)
152fc89c0fbSmrg{
153fc89c0fbSmrg    int c;
154fc89c0fbSmrg
155fc89c0fbSmrg    while ((c = getc(stream)) == ' ' || c == '\n' || c == '\t');
156fc89c0fbSmrg    ungetc(c, stream);
157fc89c0fbSmrg}
158fc89c0fbSmrg
159fc89c0fbSmrgstatic char _large_buffer[MAXSTR+10];
160fc89c0fbSmrg
161fc89c0fbSmrgstatic char *
162fc89c0fbSmrgRead_Quoted (FILE *stream)
163fc89c0fbSmrg{
164fc89c0fbSmrg    char *ptr;
165fc89c0fbSmrg    int c, length;
166fc89c0fbSmrg
167fc89c0fbSmrg    Read_White_Space(stream);
168fc89c0fbSmrg    if (Read_Char(stream)!='\'')
169fc89c0fbSmrg	Fatal_Error("Bad format file format: missing dformat.");
170fc89c0fbSmrg
171fc89c0fbSmrg    ptr = _large_buffer; length = MAXSTR;
172fc89c0fbSmrg    for (;;) {
173fc89c0fbSmrg	if (length < 0)
174fc89c0fbSmrg	    Fatal_Error("Bad format file format: dformat too long.");
175fc89c0fbSmrg	c = Read_Char(stream);
176fc89c0fbSmrg	if (c == (int) '\'')
177fc89c0fbSmrg	    break;
178fc89c0fbSmrg	ptr++[0] = c; length--;
179fc89c0fbSmrg	if (c == (int) '\\') {
180fc89c0fbSmrg	    c = Read_Char(stream);
181fc89c0fbSmrg	    if (c == '\n') {
182fc89c0fbSmrg		ptr--; length++;
183fc89c0fbSmrg	    } else
184fc89c0fbSmrg		ptr++[0] = c; length--;
185fc89c0fbSmrg	}
186fc89c0fbSmrg    }
187fc89c0fbSmrg    ptr++[0] = '\0';
188fc89c0fbSmrg
189fc89c0fbSmrg    return Copy_String(_large_buffer);
190fc89c0fbSmrg}
191fc89c0fbSmrg
192fc89c0fbSmrg/*
193fc89c0fbSmrg *
194fc89c0fbSmrg * Parsing Routines: a group of routines to parse strings into values
195fc89c0fbSmrg *
196fc89c0fbSmrg * Routines: Parse_Atom, Scan_Long, Skip_Past_Right_Paren, Scan_Octal
197fc89c0fbSmrg *
198fc89c0fbSmrg * Routines of the form Parse_XXX take a string which is parsed to a value.
199fc89c0fbSmrg * Routines of the form Scan_XXX take a string, parse the beginning to a value,
200fc89c0fbSmrg * and return the rest of the string.  The value is returned via. the last
201fc89c0fbSmrg * parameter.  All numeric values are longs!
202fc89c0fbSmrg *
203fc89c0fbSmrg */
204fc89c0fbSmrg
205fc89c0fbSmrgstatic const char *
206fc89c0fbSmrgSkip_Digits (const char *string)
207fc89c0fbSmrg{
208fc89c0fbSmrg    while (isdigit((unsigned char) string[0])) string++;
209fc89c0fbSmrg    return string;
210fc89c0fbSmrg}
211fc89c0fbSmrg
212fc89c0fbSmrgstatic const char *
213fc89c0fbSmrgScan_Long (const char *string, long *value)
214fc89c0fbSmrg{
215fc89c0fbSmrg    if (!isdigit((unsigned char) *string))
216fc89c0fbSmrg	Fatal_Error("Bad number: %s.", string);
217fc89c0fbSmrg
218fc89c0fbSmrg    *value = atol(string);
219fc89c0fbSmrg    return Skip_Digits(string);
220fc89c0fbSmrg}
221fc89c0fbSmrg
222fc89c0fbSmrgstatic const char *
223fc89c0fbSmrgScan_Octal (const char *string, unsigned long *value)
224fc89c0fbSmrg{
225fc89c0fbSmrg    if (sscanf(string, "%lo", value)!=1)
226fc89c0fbSmrg	Fatal_Error("Bad octal number: %s.", string);
227fc89c0fbSmrg    return Skip_Digits(string);
228fc89c0fbSmrg}
229fc89c0fbSmrg
230fc89c0fbSmrgstatic Atom
231fc89c0fbSmrgParse_Atom (const char *name, int only_if_exists)
232fc89c0fbSmrg{
233fc89c0fbSmrg    /* may return None = 0 */
234fc89c0fbSmrg    return XInternAtom(dpy, name, only_if_exists);
235fc89c0fbSmrg}
236fc89c0fbSmrg
237fc89c0fbSmrgstatic const char *
238fc89c0fbSmrgSkip_Past_Right_Paren (const char *string)
239fc89c0fbSmrg{
240fc89c0fbSmrg    char c;
241fc89c0fbSmrg    int nesting = 0;
242fc89c0fbSmrg
243fc89c0fbSmrg    while (c = string++[0], c != ')' || nesting)
244fc89c0fbSmrg	switch (c) {
245fc89c0fbSmrg	  case '\0':
246fc89c0fbSmrg	    Fatal_Error("Missing ')'.");
247fc89c0fbSmrg	  case '(':
248fc89c0fbSmrg	    nesting++;
249fc89c0fbSmrg	    break;
250fc89c0fbSmrg	  case ')':
251fc89c0fbSmrg	    nesting--;
252fc89c0fbSmrg	    break;
253fc89c0fbSmrg	  case '\\':
254fc89c0fbSmrg	    string++;
255fc89c0fbSmrg	    break;
256fc89c0fbSmrg	}
257fc89c0fbSmrg    return string;
258fc89c0fbSmrg}
259fc89c0fbSmrg
260fc89c0fbSmrg/*
261fc89c0fbSmrg *
262fc89c0fbSmrg * Atom to format, dformat mapping Manager
263fc89c0fbSmrg *
264fc89c0fbSmrg */
265fc89c0fbSmrg
266fc89c0fbSmrg#define D_FORMAT "0x"              /* Default format for properties */
267fc89c0fbSmrg#define D_DFORMAT " = $0+\n"       /* Default display pattern for properties */
268fc89c0fbSmrg
269fc89c0fbSmrgstatic thunk *_property_formats = NULL;   /* Holds mapping */
270fc89c0fbSmrg
271fc89c0fbSmrgstatic void
272fc89c0fbSmrgApply_Default_Formats (const char **format, const char **dformat)
273fc89c0fbSmrg{
274fc89c0fbSmrg    if (!*format)
275fc89c0fbSmrg	*format = D_FORMAT;
276fc89c0fbSmrg    if (!*dformat)
277fc89c0fbSmrg	*dformat = D_DFORMAT;
278fc89c0fbSmrg}
279fc89c0fbSmrg
280fc89c0fbSmrgstatic void
281fc89c0fbSmrgLookup_Formats (Atom atom, const char **format, const char **dformat)
282fc89c0fbSmrg{
283fc89c0fbSmrg    int i;
284fc89c0fbSmrg
285fc89c0fbSmrg    if (_property_formats)
286fc89c0fbSmrg	for (i = _property_formats->thunk_count-1; i >= 0; i--)
287fc89c0fbSmrg	    if (_property_formats[i].value == atom) {
288fc89c0fbSmrg		if (!*format)
289fc89c0fbSmrg		    *format = _property_formats[i].format;
290fc89c0fbSmrg		if (!*dformat)
291fc89c0fbSmrg		    *dformat = _property_formats[i].dformat;
292fc89c0fbSmrg		break;
293fc89c0fbSmrg	    }
294fc89c0fbSmrg}
295fc89c0fbSmrg
296fc89c0fbSmrgstatic void
297fc89c0fbSmrgAdd_Mapping (Atom atom, const char *format, const char *dformat)
298fc89c0fbSmrg{
299fc89c0fbSmrg    thunk t;
300fc89c0fbSmrg
301fc89c0fbSmrg    if (!_property_formats)
302fc89c0fbSmrg	_property_formats = Create_Thunk_List();
303fc89c0fbSmrg
304fc89c0fbSmrg    t.value = atom;
305fc89c0fbSmrg    t.format = format;
306fc89c0fbSmrg    t.dformat = dformat;
307fc89c0fbSmrg
308fc89c0fbSmrg    _property_formats = Add_Thunk(_property_formats, t);
309fc89c0fbSmrg}
310fc89c0fbSmrg
311fc89c0fbSmrg/*
312fc89c0fbSmrg *
313fc89c0fbSmrg * Setup_Mapping: Routine to setup default atom to format, dformat mapping:
314fc89c0fbSmrg *
315fc89c0fbSmrg */
316fc89c0fbSmrg
317fc89c0fbSmrgtypedef struct _propertyRec {
318fc89c0fbSmrg    const char *	name;
319fc89c0fbSmrg    Atom		atom;
320fc89c0fbSmrg    const char *	format;
321fc89c0fbSmrg    const char *	dformat;
322fc89c0fbSmrg} propertyRec;
323fc89c0fbSmrg
324fc89c0fbSmrg#define ARC_DFORMAT	":\n"\
325fc89c0fbSmrg"\t\tarc at $0, $1\n"\
326fc89c0fbSmrg"\t\tsize: $2 by $3\n"\
327fc89c0fbSmrg"\t\tfrom angle $4 to angle $5\n"
328fc89c0fbSmrg
329fc89c0fbSmrg#define RECTANGLE_DFORMAT	":\n"\
330fc89c0fbSmrg"\t\tupper left corner: $0, $1\n"\
331fc89c0fbSmrg"\t\tsize: $2 by $3\n"
332fc89c0fbSmrg
333fc89c0fbSmrg#define RGB_COLOR_MAP_DFORMAT	":\n"\
334fc89c0fbSmrg"\t\tcolormap id #: $0\n"\
335fc89c0fbSmrg"\t\tred-max: $1\n"\
336fc89c0fbSmrg"\t\tred-mult: $2\n"\
337fc89c0fbSmrg"\t\tgreen-max: $3\n"\
338fc89c0fbSmrg"\t\tgreen-mult: $4\n"\
339fc89c0fbSmrg"\t\tblue-max: $5\n"\
340fc89c0fbSmrg"\t\tblue-mult: $6\n"\
341fc89c0fbSmrg"\t\tbase-pixel: $7\n"\
342fc89c0fbSmrg"\t\tvisual id #: $8\n"\
343fc89c0fbSmrg"\t\tkill id #: $9\n"
344fc89c0fbSmrg
345fc89c0fbSmrg#define WM_HINTS_DFORMAT	":\n"\
346fc89c0fbSmrg"?m0(\t\tClient accepts input or input focus: $1\n)"\
347fc89c0fbSmrg"?m1(\t\tInitial state is "\
348fc89c0fbSmrg"?$2=0(Don't Care State)"\
349fc89c0fbSmrg"?$2=1(Normal State)"\
350fc89c0fbSmrg"?$2=2(Zoomed State)"\
351fc89c0fbSmrg"?$2=3(Iconic State)"\
352fc89c0fbSmrg"?$2=4(Inactive State)"\
353fc89c0fbSmrg".\n)"\
354fc89c0fbSmrg"?m2(\t\tbitmap id # to use for icon: $3\n)"\
355fc89c0fbSmrg"?m5(\t\tbitmap id # of mask for icon: $7\n)"\
356fc89c0fbSmrg"?m3(\t\twindow id # to use for icon: $4\n)"\
357fc89c0fbSmrg"?m4(\t\tstarting position for icon: $5, $6\n)"\
358fc89c0fbSmrg"?m6(\t\twindow id # of group leader: $8\n)"\
35991ec45ceSmrg"?m8(\t\tThe urgency hint bit is set\n)"
360fc89c0fbSmrg
361fc89c0fbSmrg#define WM_ICON_SIZE_DFORMAT	":\n"\
362fc89c0fbSmrg"\t\tminimum icon size: $0 by $1\n"\
363fc89c0fbSmrg"\t\tmaximum icon size: $2 by $3\n"\
364fc89c0fbSmrg"\t\tincremental size change: $4 by $5\n"
365fc89c0fbSmrg
366fc89c0fbSmrg#define WM_SIZE_HINTS_DFORMAT ":\n"\
367fc89c0fbSmrg"?m0(\t\tuser specified location: $1, $2\n)"\
368fc89c0fbSmrg"?m2(\t\tprogram specified location: $1, $2\n)"\
369fc89c0fbSmrg"?m1(\t\tuser specified size: $3 by $4\n)"\
370fc89c0fbSmrg"?m3(\t\tprogram specified size: $3 by $4\n)"\
371fc89c0fbSmrg"?m4(\t\tprogram specified minimum size: $5 by $6\n)"\
372fc89c0fbSmrg"?m5(\t\tprogram specified maximum size: $7 by $8\n)"\
373fc89c0fbSmrg"?m6(\t\tprogram specified resize increment: $9 by $10\n)"\
374fc89c0fbSmrg"?m7(\t\tprogram specified minimum aspect ratio: $11/$12\n"\
375fc89c0fbSmrg"\t\tprogram specified maximum aspect ratio: $13/$14\n)"\
376fc89c0fbSmrg"?m8(\t\tprogram specified base size: $15 by $16\n)"\
377fc89c0fbSmrg"?m9(\t\twindow gravity: "\
378fc89c0fbSmrg"?$17=0(Forget)"\
379fc89c0fbSmrg"?$17=1(NorthWest)"\
380fc89c0fbSmrg"?$17=2(North)"\
381fc89c0fbSmrg"?$17=3(NorthEast)"\
382fc89c0fbSmrg"?$17=4(West)"\
383fc89c0fbSmrg"?$17=5(Center)"\
384fc89c0fbSmrg"?$17=6(East)"\
385fc89c0fbSmrg"?$17=7(SouthWest)"\
386fc89c0fbSmrg"?$17=8(South)"\
387fc89c0fbSmrg"?$17=9(SouthEast)"\
388fc89c0fbSmrg"?$17=10(Static)"\
389fc89c0fbSmrg"\n)"
390fc89c0fbSmrg
391fc89c0fbSmrg#define WM_STATE_DFORMAT	 ":\n"\
392fc89c0fbSmrg"\t\twindow state: ?$0=0(Withdrawn)?$0=1(Normal)?$0=3(Iconic)\n"\
393fc89c0fbSmrg"\t\ticon window: $1\n"
394fc89c0fbSmrg
395fc89c0fbSmrgstatic propertyRec windowPropTable[] = {
396fc89c0fbSmrg    {"ARC",		XA_ARC,		"16iiccii",   ARC_DFORMAT },
397fc89c0fbSmrg    {"ATOM",		XA_ATOM,	 "32a",	      0 },
398fc89c0fbSmrg    {"BITMAP",		XA_BITMAP,	 "32x",	      ": bitmap id # $0\n" },
399fc89c0fbSmrg    {"CARDINAL",	XA_CARDINAL,	 "0c",	      0 },
400fc89c0fbSmrg    {"COLORMAP",	XA_COLORMAP,	 "32x",	      ": colormap id # $0\n" },
401fc89c0fbSmrg    {"CURSOR",		XA_CURSOR,	 "32x",	      ": cursor id # $0\n" },
402fc89c0fbSmrg    {"DRAWABLE",	XA_DRAWABLE,	 "32x",	      ": drawable id # $0\n" },
403fc89c0fbSmrg    {"FONT",		XA_FONT,	 "32x",	      ": font id # $0\n" },
404fc89c0fbSmrg    {"INTEGER",		XA_INTEGER,	 "0i",	      0 },
405fc89c0fbSmrg    {"PIXMAP",		XA_PIXMAP,	 "32x",	      ": pixmap id # $0\n" },
406fc89c0fbSmrg    {"POINT",		XA_POINT,	 "16ii",      " = $0, $1\n" },
407fc89c0fbSmrg    {"RECTANGLE",	XA_RECTANGLE,	 "16iicc",    RECTANGLE_DFORMAT },
408fc89c0fbSmrg    {"RGB_COLOR_MAP",	XA_RGB_COLOR_MAP,"32xcccccccxx",RGB_COLOR_MAP_DFORMAT},
409fc89c0fbSmrg    {"STRING",		XA_STRING,	 "8s",	      0 },
410a0996ce0Smrg    {"UTF8_STRING",		0,	 "8u",	      0 },
411fc89c0fbSmrg    {"WINDOW",		XA_WINDOW,	 "32x",	      ": window id # $0+\n" },
412fc89c0fbSmrg    {"VISUALID",	XA_VISUALID,	 "32x",	      ": visual id # $0\n" },
413fc89c0fbSmrg    {"WM_COLORMAP_WINDOWS",	0,	 "32x",       ": window id # $0+\n"},
414fc89c0fbSmrg    {"WM_COMMAND",	XA_WM_COMMAND,	 "8s",	      " = { $0+ }\n" },
415fc89c0fbSmrg    {"WM_HINTS",	XA_WM_HINTS,	 "32mbcxxiixx",	WM_HINTS_DFORMAT },
416fc89c0fbSmrg    {"WM_ICON_NAME",	XA_WM_ICON_NAME, "8t",	      0 },
417fc89c0fbSmrg    {"WM_ICON_SIZE",	XA_WM_ICON_SIZE, "32cccccc",  WM_ICON_SIZE_DFORMAT},
418fc89c0fbSmrg    {"WM_NAME",		XA_WM_NAME,	 "8t",	      0 },
419fc89c0fbSmrg    {"WM_PROTOCOLS",		0,	 "32a",	      ": protocols  $0+\n"},
420fc89c0fbSmrg    {"WM_SIZE_HINTS",	XA_WM_SIZE_HINTS,"32mii",     WM_SIZE_HINTS_DFORMAT },
42191ec45ceSmrg    {"_NET_WM_ICON",            0,       "32o",        0 },
422fc89c0fbSmrg    {"WM_STATE",		0,	 "32cx",      WM_STATE_DFORMAT}
423fc89c0fbSmrg};
424fc89c0fbSmrg#undef ARC_DFORMAT
425fc89c0fbSmrg#undef RECTANGLE_DFORMAT
426fc89c0fbSmrg#undef RGB_COLOR_MAP_DFORMAT
427fc89c0fbSmrg#undef WM_ICON_SIZE_DFORMAT
428fc89c0fbSmrg#undef WM_HINTS_DFORMAT
429fc89c0fbSmrg#undef WM_SIZE_HINTS_DFORMAT
430fc89c0fbSmrg#undef WM_STATE_DFORMAT
431fc89c0fbSmrg
432fc89c0fbSmrg/*
433fc89c0fbSmrg * Font-specific mapping of property names to types:
434fc89c0fbSmrg */
435fc89c0fbSmrgstatic propertyRec fontPropTable[] = {
436fc89c0fbSmrg
437fc89c0fbSmrg    /* XLFD name properties */
438fc89c0fbSmrg
439fc89c0fbSmrg    { "FOUNDRY",		0, 	 		"32a",	0 },
440fc89c0fbSmrg    { "FAMILY_NAME",		XA_FAMILY_NAME,		"32a",	0 },
441fc89c0fbSmrg    { "WEIGHT_NAME",		0,			"32a",	0 },
442fc89c0fbSmrg    { "SLANT",			0,			"32a",	0 },
443fc89c0fbSmrg    { "SETWIDTH_NAME",		0,			"32a",	0 },
444fc89c0fbSmrg    { "ADD_STYLE_NAME",		0,			"32a",	0 },
445fc89c0fbSmrg    { "PIXEL_SIZE",		0,			"32c",	0 },
446fc89c0fbSmrg    { "POINT_SIZE",		XA_POINT_SIZE,		"32c",	0 },
447fc89c0fbSmrg    { "RESOLUTION_X",		0,			"32c",	0 },
448fc89c0fbSmrg    { "RESOLUTION_Y",		0,			"32c",	0 },
449fc89c0fbSmrg    { "SPACING",		0,			"32a",	0 },
450fc89c0fbSmrg    { "AVERAGE_WIDTH",		0,			"32c",	0 },
451fc89c0fbSmrg    { "CHARSET_REGISTRY",	0,			"32a",	0 },
452fc89c0fbSmrg    { "CHARSET_ENCODING",	0,			"32a",	0 },
453fc89c0fbSmrg
454fc89c0fbSmrg    /* other font properties referenced in the XLFD */
455fc89c0fbSmrg
456fc89c0fbSmrg    { "QUAD_WIDTH",		XA_QUAD_WIDTH,		"32i",	0 },
457fc89c0fbSmrg    { "RESOLUTION",		XA_RESOLUTION,		"32c",	0 },
458fc89c0fbSmrg    { "MIN_SPACE",		XA_MIN_SPACE,		"32c",	0 },
459fc89c0fbSmrg    { "NORM_SPACE",		XA_NORM_SPACE,		"32c",	0 },
460fc89c0fbSmrg    { "MAX_SPACE",		XA_MAX_SPACE,		"32c",	0 },
461fc89c0fbSmrg    { "END_SPACE",		XA_END_SPACE,		"32c",	0 },
462fc89c0fbSmrg    { "SUPERSCRIPT_X",		XA_SUPERSCRIPT_X,	"32i",	0 },
463fc89c0fbSmrg    { "SUPERSCRIPT_Y",		XA_SUPERSCRIPT_Y,	"32i",	0 },
464fc89c0fbSmrg    { "SUBSCRIPT_X",		XA_SUBSCRIPT_X,		"32i",	0 },
465fc89c0fbSmrg    { "SUBSCRIPT_Y",		XA_SUBSCRIPT_Y,		"32i",	0 },
466fc89c0fbSmrg    { "UNDERLINE_POSITION",	XA_UNDERLINE_POSITION,	"32i",	0 },
467fc89c0fbSmrg    { "UNDERLINE_THICKNESS",	XA_UNDERLINE_THICKNESS,	"32i",	0 },
468fc89c0fbSmrg    { "STRIKEOUT_ASCENT",	XA_STRIKEOUT_ASCENT,	"32i",	0 },
469fc89c0fbSmrg    { "STRIKEOUT_DESCENT",	XA_STRIKEOUT_DESCENT,	"32i",	0 },
470fc89c0fbSmrg    { "ITALIC_ANGLE",		XA_ITALIC_ANGLE,	"32i",	0 },
471fc89c0fbSmrg    { "X_HEIGHT",		XA_X_HEIGHT,		"32i",	0 },
472fc89c0fbSmrg    { "WEIGHT",			XA_WEIGHT,		"32i",	0 },
473fc89c0fbSmrg    { "FACE_NAME",		0,			"32a",	0 },
474fc89c0fbSmrg    { "COPYRIGHT",		XA_COPYRIGHT,		"32a",	0 },
475fc89c0fbSmrg    { "AVG_CAPITAL_WIDTH",	0,			"32i",	0 },
476fc89c0fbSmrg    { "AVG_LOWERCASE_WIDTH",	0,			"32i",	0 },
477fc89c0fbSmrg    { "RELATIVE_SETWIDTH",	0,			"32c",	0 },
478fc89c0fbSmrg    { "RELATIVE_WEIGHT",	0,			"32c",	0 },
479fc89c0fbSmrg    { "CAP_HEIGHT",		XA_CAP_HEIGHT,		"32c",	0 },
480fc89c0fbSmrg    { "SUPERSCRIPT_SIZE",	0,			"32c",	0 },
481fc89c0fbSmrg    { "FIGURE_WIDTH",		0,			"32i",	0 },
482fc89c0fbSmrg    { "SUBSCRIPT_SIZE",		0,			"32c",	0 },
483fc89c0fbSmrg    { "SMALL_CAP_SIZE",		0,			"32i",	0 },
484fc89c0fbSmrg    { "NOTICE",			XA_NOTICE,		"32a",	0 },
485fc89c0fbSmrg    { "DESTINATION",		0,			"32c",	0 },
486fc89c0fbSmrg
487fc89c0fbSmrg    /* other font properties */
488fc89c0fbSmrg
489fc89c0fbSmrg    { "FONT",			XA_FONT,		"32a",	0 },
490fc89c0fbSmrg    { "FONT_NAME",		XA_FONT_NAME,		"32a",	0 },
491fc89c0fbSmrg};
492fc89c0fbSmrg
493fc89c0fbSmrgstatic int XpropMode;
494fc89c0fbSmrg#define XpropWindowProperties 0
495fc89c0fbSmrg#define XpropFontProperties   1
496fc89c0fbSmrg
497fc89c0fbSmrgstatic void
498fc89c0fbSmrgSetup_Mapping (void)
499fc89c0fbSmrg{
500fc89c0fbSmrg    int n;
501fc89c0fbSmrg    propertyRec *p;
502fc89c0fbSmrg
503fc89c0fbSmrg    if (XpropMode == XpropWindowProperties) {
504fc89c0fbSmrg	n = sizeof(windowPropTable) / sizeof(propertyRec);
505fc89c0fbSmrg	p = windowPropTable;
506fc89c0fbSmrg    } else {
507fc89c0fbSmrg	n = sizeof (fontPropTable) / sizeof (propertyRec);
508fc89c0fbSmrg	p = fontPropTable;
509fc89c0fbSmrg    }
510fc89c0fbSmrg    for ( ; --n >= 0; p++) {
511fc89c0fbSmrg	if (! p->atom) {
512fc89c0fbSmrg	    p->atom = XInternAtom(dpy, p->name, True);
513fc89c0fbSmrg	    if (p->atom == None)
514fc89c0fbSmrg		continue;
515fc89c0fbSmrg	}
516fc89c0fbSmrg	Add_Mapping(p->atom, p->format, p->dformat);
517fc89c0fbSmrg    }
518fc89c0fbSmrg}
519fc89c0fbSmrg
520fc89c0fbSmrgstatic const char *
521fc89c0fbSmrgGetAtomName (Atom atom)
522fc89c0fbSmrg{
523fc89c0fbSmrg    int n;
524fc89c0fbSmrg    propertyRec *p;
525fc89c0fbSmrg
526fc89c0fbSmrg    if (XpropMode == XpropWindowProperties) {
527fc89c0fbSmrg	n = sizeof(windowPropTable) / sizeof(propertyRec);
528fc89c0fbSmrg	p = windowPropTable;
529fc89c0fbSmrg    } else {
530fc89c0fbSmrg	n = sizeof (fontPropTable) / sizeof (propertyRec);
531fc89c0fbSmrg	p = fontPropTable;
532fc89c0fbSmrg    }
533fc89c0fbSmrg    for ( ; --n >= 0; p++)
534fc89c0fbSmrg	if (p->atom == atom)
535fc89c0fbSmrg	    return p->name;
536fc89c0fbSmrg
537fc89c0fbSmrg    return NULL;
538fc89c0fbSmrg}
539fc89c0fbSmrg
540fc89c0fbSmrg/*
541fc89c0fbSmrg * Read_Mapping: routine to read in additional mappings from a stream
542fc89c0fbSmrg *               already open for reading.
543fc89c0fbSmrg */
544fc89c0fbSmrg
545fc89c0fbSmrgstatic void
546fc89c0fbSmrgRead_Mappings (FILE *stream)
547fc89c0fbSmrg{
548fc89c0fbSmrg    char format_buffer[100];
549fc89c0fbSmrg    char name[1000], *dformat, *format;
550fc89c0fbSmrg    int count, c;
551fc89c0fbSmrg    Atom atom;
552fc89c0fbSmrg
553fc89c0fbSmrg    while ((count = fscanf(stream," %990s %90s ",name,format_buffer)) != EOF) {
554fc89c0fbSmrg	if (count != 2)
555fc89c0fbSmrg	    Fatal_Error("Bad format file format.");
556fc89c0fbSmrg
557fc89c0fbSmrg	atom = Parse_Atom(name, False);
558fc89c0fbSmrg	format = Copy_String(format_buffer);
559fc89c0fbSmrg
560fc89c0fbSmrg	Read_White_Space(stream);
561fc89c0fbSmrg	dformat = D_DFORMAT;
562fc89c0fbSmrg	c = getc(stream);
563fc89c0fbSmrg	ungetc(c, stream);
564fc89c0fbSmrg	if (c == (int) '\'')
565fc89c0fbSmrg	    dformat = Read_Quoted(stream);
566fc89c0fbSmrg
567fc89c0fbSmrg	Add_Mapping(atom, format, dformat);
568fc89c0fbSmrg    }
569fc89c0fbSmrg}
570fc89c0fbSmrg
571fc89c0fbSmrg/*
572fc89c0fbSmrg *
573fc89c0fbSmrg * Formatting Routines: a group of routines to translate from various
574fc89c0fbSmrg *                      values to a static read-only string useful for output.
575fc89c0fbSmrg *
576fc89c0fbSmrg * Routines: Format_Hex, Format_Unsigned, Format_Signed, Format_Atom,
577fc89c0fbSmrg *           Format_Mask_Word, Format_Bool, Format_String, Format_Len_String.
578fc89c0fbSmrg *
579fc89c0fbSmrg * All of the above routines take a long except for Format_String and
580fc89c0fbSmrg * Format_Len_String.
581fc89c0fbSmrg *
582fc89c0fbSmrg */
583fc89c0fbSmrgstatic char _formatting_buffer[MAXSTR+100];
584fc89c0fbSmrgstatic char _formatting_buffer2[21];
585fc89c0fbSmrg
586fc89c0fbSmrgstatic const char *
587fc89c0fbSmrgFormat_Hex (long wrd)
588fc89c0fbSmrg{
589fc89c0fbSmrg    snprintf(_formatting_buffer2, sizeof(_formatting_buffer2), "0x%lx", wrd);
590fc89c0fbSmrg    return _formatting_buffer2;
591fc89c0fbSmrg}
592fc89c0fbSmrg
593fc89c0fbSmrgstatic const char *
594fc89c0fbSmrgFormat_Unsigned (long wrd)
595fc89c0fbSmrg{
596fc89c0fbSmrg    snprintf(_formatting_buffer2, sizeof(_formatting_buffer2), "%lu", wrd);
597fc89c0fbSmrg    return _formatting_buffer2;
598fc89c0fbSmrg}
599fc89c0fbSmrg
600fc89c0fbSmrgstatic const char *
601fc89c0fbSmrgFormat_Signed (long wrd)
602fc89c0fbSmrg{
603fc89c0fbSmrg    snprintf(_formatting_buffer2, sizeof(_formatting_buffer2), "%ld", wrd);
604fc89c0fbSmrg    return _formatting_buffer2;
605fc89c0fbSmrg}
606fc89c0fbSmrg
607fc89c0fbSmrg/*ARGSUSED*/
608fc89c0fbSmrgstatic int
609fc89c0fbSmrgignore_errors (Display *dpy, XErrorEvent *ev)
610fc89c0fbSmrg{
611fc89c0fbSmrg    return 0;
612fc89c0fbSmrg}
613fc89c0fbSmrg
614fc89c0fbSmrgstatic const char *
615fc89c0fbSmrgFormat_Atom (Atom atom)
616fc89c0fbSmrg{
617fc89c0fbSmrg    const char *found;
618fc89c0fbSmrg    char *name;
619fc89c0fbSmrg    XErrorHandler handler;
620fc89c0fbSmrg
621fc89c0fbSmrg    if ((found = GetAtomName(atom)) != NULL)
622fc89c0fbSmrg	return found;
623fc89c0fbSmrg
624fc89c0fbSmrg    handler = XSetErrorHandler (ignore_errors);
625fc89c0fbSmrg    name = XGetAtomName(dpy, atom);
626fc89c0fbSmrg    XSetErrorHandler(handler);
627fc89c0fbSmrg    if (! name)
628fc89c0fbSmrg	snprintf(_formatting_buffer, sizeof(_formatting_buffer),
629fc89c0fbSmrg		 "undefined atom # 0x%lx", atom);
630fc89c0fbSmrg    else {
631fc89c0fbSmrg	int namelen = strlen(name);
632fc89c0fbSmrg	if (namelen > MAXSTR) namelen = MAXSTR;
633fc89c0fbSmrg	memcpy(_formatting_buffer, name, namelen);
634fc89c0fbSmrg	_formatting_buffer[namelen] = '\0';
635fc89c0fbSmrg	XFree(name);
636fc89c0fbSmrg    }
637fc89c0fbSmrg    return _formatting_buffer;
638fc89c0fbSmrg}
639fc89c0fbSmrg
640fc89c0fbSmrgstatic const char *
641fc89c0fbSmrgFormat_Mask_Word (long wrd)
642fc89c0fbSmrg{
643fc89c0fbSmrg    long bit_mask, bit;
644fc89c0fbSmrg    int seen = 0;
645fc89c0fbSmrg
646fc89c0fbSmrg    strcpy(_formatting_buffer, "{MASK: ");
647fc89c0fbSmrg    for (bit=0, bit_mask=1; bit <= sizeof(long)*8; bit++, bit_mask<<=1) {
648fc89c0fbSmrg	if (bit_mask & wrd) {
649fc89c0fbSmrg	    if (seen) {
650fc89c0fbSmrg		strcat(_formatting_buffer, ", ");
651fc89c0fbSmrg	    }
652fc89c0fbSmrg	    seen = 1;
653fc89c0fbSmrg	    strcat(_formatting_buffer, Format_Unsigned(bit));
654fc89c0fbSmrg	}
655fc89c0fbSmrg    }
656fc89c0fbSmrg    strcat(_formatting_buffer, "}");
657fc89c0fbSmrg
658fc89c0fbSmrg    return _formatting_buffer;
659fc89c0fbSmrg}
660fc89c0fbSmrg
661fc89c0fbSmrgstatic const char *
662fc89c0fbSmrgFormat_Bool (long value)
663fc89c0fbSmrg{
664fc89c0fbSmrg    if (!value)
665fc89c0fbSmrg	return "False";
666fc89c0fbSmrg
667fc89c0fbSmrg    return "True";
668fc89c0fbSmrg}
669fc89c0fbSmrg
670fc89c0fbSmrgstatic char *_buf_ptr;
671fc89c0fbSmrgstatic int _buf_len;
672fc89c0fbSmrg
673fc89c0fbSmrgstatic void
674fc89c0fbSmrg_put_char (char c)
675fc89c0fbSmrg{
676fc89c0fbSmrg    if (_buf_len <= 0) {
677fc89c0fbSmrg	_buf_ptr[0] = '\0';
678fc89c0fbSmrg	return;
679fc89c0fbSmrg    }
680fc89c0fbSmrg    _buf_ptr++[0] = c;
681fc89c0fbSmrg    _buf_len--;
682fc89c0fbSmrg}
683fc89c0fbSmrg
684fc89c0fbSmrgstatic void
685a0996ce0Smrg_format_char (char c, int unicode)
686fc89c0fbSmrg{
687fc89c0fbSmrg    switch (c) {
688fc89c0fbSmrg      case '\\':
689fc89c0fbSmrg      case '\"':
690fc89c0fbSmrg	_put_char('\\');
691fc89c0fbSmrg	_put_char(c);
692fc89c0fbSmrg	break;
693fc89c0fbSmrg      case '\n':
694fc89c0fbSmrg	_put_char('\\');
695fc89c0fbSmrg	_put_char('n');
696fc89c0fbSmrg	break;
697fc89c0fbSmrg      case '\t':
698fc89c0fbSmrg	_put_char('\\');
699fc89c0fbSmrg	_put_char('t');
700fc89c0fbSmrg	break;
701fc89c0fbSmrg      default:
702fc89c0fbSmrg	if (!c_isprint(c)) {
703a0996ce0Smrg	    if (unicode && (c & 0x80)) {
704a0996ce0Smrg		_put_char(c);
705a0996ce0Smrg	    } else {
706a0996ce0Smrg		_put_char('\\');
707a0996ce0Smrg		snprintf(_buf_ptr, _buf_len, "%03o", (unsigned char) c);
708a0996ce0Smrg		_buf_ptr += 3;
709a0996ce0Smrg		_buf_len -= 3;
710a0996ce0Smrg	    }
711fc89c0fbSmrg	} else
712fc89c0fbSmrg	  _put_char(c);
713fc89c0fbSmrg    }
714fc89c0fbSmrg}
715fc89c0fbSmrg
716fc89c0fbSmrgstatic const char *
717a0996ce0SmrgFormat_String (const char *string, int unicode)
718fc89c0fbSmrg{
719fc89c0fbSmrg    char c;
720fc89c0fbSmrg
721fc89c0fbSmrg    _buf_ptr = _formatting_buffer;
722fc89c0fbSmrg    _buf_len = MAXSTR;
723fc89c0fbSmrg    _put_char('\"');
724fc89c0fbSmrg
725fc89c0fbSmrg    while ((c = string++[0]))
726a0996ce0Smrg	_format_char(c, unicode);
727fc89c0fbSmrg
728fc89c0fbSmrg    *_buf_ptr++ = '"';
729fc89c0fbSmrg    *_buf_ptr++ = '\0';
730fc89c0fbSmrg    return _formatting_buffer;
731fc89c0fbSmrg}
732fc89c0fbSmrg
733fc89c0fbSmrgstatic const char *
734fc89c0fbSmrgFormat_Len_String (const char *string, int len)
735fc89c0fbSmrg{
736fc89c0fbSmrg    char *data;
737fc89c0fbSmrg    const char *result;
738fc89c0fbSmrg
739fc89c0fbSmrg    data = (char *) Malloc(len+1);
740fc89c0fbSmrg
741fc89c0fbSmrg    memcpy(data, string, len);
742fc89c0fbSmrg    data[len] = '\0';
743fc89c0fbSmrg
744a0996ce0Smrg    result = Format_String(data, 0);
745fc89c0fbSmrg    free(data);
746fc89c0fbSmrg
747fc89c0fbSmrg    return result;
748fc89c0fbSmrg}
749fc89c0fbSmrg
75091ec45ceSmrgstatic int
75191ec45ceSmrgis_utf8_locale (void)
75291ec45ceSmrg{
75391ec45ceSmrg#ifdef HAVE_LANGINFO_H
75491ec45ceSmrg    char *charmap = nl_langinfo (CODESET);
75591ec45ceSmrg
75691ec45ceSmrg    return charmap && strcmp (charmap, "UTF-8") == 0;
75791ec45ceSmrg#else
75891ec45ceSmrg    return 0;
75991ec45ceSmrg#endif
76091ec45ceSmrg}
76191ec45ceSmrg
76291ec45ceSmrgstatic const char *
76391ec45ceSmrgFormat_Icons (const unsigned long *icon, int len)
76491ec45ceSmrg{
76591ec45ceSmrg    char *result = NULL, *tail = NULL;
76691ec45ceSmrg    int alloced;
76791ec45ceSmrg    const unsigned long *end = icon + len / sizeof (unsigned long);
76891ec45ceSmrg
76991ec45ceSmrg    alloced = 0;
77091ec45ceSmrg
77191ec45ceSmrg    while (icon < end)
77291ec45ceSmrg    {
77391ec45ceSmrg	unsigned long width, height;
77491ec45ceSmrg	int w, h;
77591ec45ceSmrg	int offset;
77691ec45ceSmrg
77791ec45ceSmrg	width = *icon++;
77891ec45ceSmrg	height = *icon++;
77991ec45ceSmrg
78091ec45ceSmrg	offset = (tail - result);
78191ec45ceSmrg
78291ec45ceSmrg	alloced += 80;				/* For the header */
78391ec45ceSmrg	alloced += (width*4 + 8) * height;	/* For the rows (plus padding) */
78491ec45ceSmrg
78591ec45ceSmrg	result = Realloc (result, alloced);
78691ec45ceSmrg	tail = &result[offset];
78791ec45ceSmrg
78891ec45ceSmrg	if (end - icon < width * height)
78991ec45ceSmrg	    break;
79091ec45ceSmrg
79191ec45ceSmrg	tail += sprintf (tail, "\tIcon (%lu x %lu):\n", width, height);
79291ec45ceSmrg
79391ec45ceSmrg	if (width > 144 || height > 144)
79491ec45ceSmrg	{
79591ec45ceSmrg	    tail += sprintf (tail, "\t(not shown)");
79691ec45ceSmrg	    icon += width * height;
79791ec45ceSmrg	    continue;
79891ec45ceSmrg	}
79991ec45ceSmrg
80091ec45ceSmrg	for (h = 0; h < height; ++h)
80191ec45ceSmrg	{
80291ec45ceSmrg	    tail += sprintf (tail, "\t");
80391ec45ceSmrg
80491ec45ceSmrg	    for (w = 0; w < width; ++w)
80591ec45ceSmrg	    {
80691ec45ceSmrg		unsigned char a, r, g, b;
80791ec45ceSmrg		unsigned long pixel = *icon++;
80891ec45ceSmrg		unsigned long brightness;
80991ec45ceSmrg
81091ec45ceSmrg		a = (pixel & 0xff000000) >> 24;
81191ec45ceSmrg		r = (pixel & 0x00ff0000) >> 16;
81291ec45ceSmrg		g = (pixel & 0x0000ff00) >> 8;
81391ec45ceSmrg		b = (pixel & 0x000000ff);
81491ec45ceSmrg
81591ec45ceSmrg		brightness =
81691ec45ceSmrg		    (a / 255.0) * (1000 - ((299 * (r / 255.0)) +
81791ec45ceSmrg					   (587 * (g / 255.0)) +
81891ec45ceSmrg					   (114 * (b / 255.0))));
81991ec45ceSmrg
82091ec45ceSmrg		if (is_utf8_locale())
82191ec45ceSmrg		{
82291ec45ceSmrg		    static const char palette[][4] =
82391ec45ceSmrg		    {
82491ec45ceSmrg			" ",
82591ec45ceSmrg			"\342\226\221",		/* 25% */
82691ec45ceSmrg			"\342\226\222",		/* 50% */
82791ec45ceSmrg			"\342\226\223",		/* 75% */
82891ec45ceSmrg			"\342\226\210",		/* 100% */
82991ec45ceSmrg		    };
83091ec45ceSmrg		    int idx;
83191ec45ceSmrg
83291ec45ceSmrg		    idx = (brightness * ((sizeof (palette)/sizeof(palette[0])) - 1)) / 1000;
83391ec45ceSmrg
83491ec45ceSmrg		    tail += sprintf (tail, "%s", palette[idx]);
83591ec45ceSmrg		}
83691ec45ceSmrg		else
83791ec45ceSmrg		{
83891ec45ceSmrg		    static const char palette[] =
83991ec45ceSmrg			" .'`,^:\";~-_+<>i!lI?/\\|()1{}[]rcvunxzjftLCJUYXZO0Qoahkbdpqwm*WMB8&%$#@";
84091ec45ceSmrg		    int idx;
84191ec45ceSmrg
84291ec45ceSmrg		    idx = (brightness * (sizeof(palette) - 2)) / 1000;
84391ec45ceSmrg
84491ec45ceSmrg		    *tail++ = palette[idx];
84591ec45ceSmrg		}
84691ec45ceSmrg	    }
84791ec45ceSmrg
84891ec45ceSmrg	    tail += sprintf (tail, "\n");
84991ec45ceSmrg	}
85091ec45ceSmrg
85191ec45ceSmrg	tail += sprintf (tail, "\n");
85291ec45ceSmrg    }
85391ec45ceSmrg
85491ec45ceSmrg    return result;
85591ec45ceSmrg}
85691ec45ceSmrg
857fc89c0fbSmrgstatic const char *
858fc89c0fbSmrgFormat_Len_Text (const char *string, int len, Atom encoding)
859fc89c0fbSmrg{
860fc89c0fbSmrg    XTextProperty textprop;
861fc89c0fbSmrg    char **list;
862fc89c0fbSmrg    int count;
863fc89c0fbSmrg
864fc89c0fbSmrg    /* Try to convert to local encoding. */
865fc89c0fbSmrg    textprop.encoding = encoding;
866fc89c0fbSmrg    textprop.format = 8;
867fc89c0fbSmrg    textprop.value = (unsigned char *) string;
868fc89c0fbSmrg    textprop.nitems = len;
869fc89c0fbSmrg    if (XmbTextPropertyToTextList(dpy, &textprop, &list, &count) == Success) {
870fc89c0fbSmrg	_buf_ptr = _formatting_buffer;
871fc89c0fbSmrg	_buf_len = MAXSTR;
872fc89c0fbSmrg	*_buf_ptr++ = '"';
873fc89c0fbSmrg	while (count > 0) {
874fc89c0fbSmrg	    string = *list++;
875fc89c0fbSmrg	    len = strlen(string);
876fc89c0fbSmrg	    while (len > 0) {
877fc89c0fbSmrg		wchar_t wc;
878fc89c0fbSmrg		int n = mbtowc(&wc, string, len);
879fc89c0fbSmrg		if (n > 0 && iswprint(wc)) {
880fc89c0fbSmrg		    if (_buf_len >= n) {
881fc89c0fbSmrg			memcpy(_buf_ptr, string, n);
882fc89c0fbSmrg			_buf_ptr += n;
883fc89c0fbSmrg			_buf_len -= n;
884fc89c0fbSmrg		    }
885fc89c0fbSmrg		    string += n;
886fc89c0fbSmrg		    len -= n;
887fc89c0fbSmrg		} else {
888fc89c0fbSmrg		    _put_char('\\');
889fc89c0fbSmrg		    snprintf(_buf_ptr, _buf_len, "%03o", (unsigned char) *string);
890fc89c0fbSmrg		    _buf_ptr += 3;
891fc89c0fbSmrg		    _buf_len -= 3;
892fc89c0fbSmrg		    string++;
893fc89c0fbSmrg		    len--;
894fc89c0fbSmrg		}
895fc89c0fbSmrg	    }
896fc89c0fbSmrg	    count--;
897fc89c0fbSmrg	    if (count > 0) {
898fc89c0fbSmrg		snprintf(_buf_ptr, _buf_len, "\\000");
899fc89c0fbSmrg	        _buf_ptr += 4;
900fc89c0fbSmrg		_buf_len -= 4;
901fc89c0fbSmrg	    }
902fc89c0fbSmrg	}
903fc89c0fbSmrg	*_buf_ptr++ = '"';
904fc89c0fbSmrg	*_buf_ptr++ = '\0';
905fc89c0fbSmrg	return _formatting_buffer;
906fc89c0fbSmrg    } else
907fc89c0fbSmrg	return Format_Len_String(string, len);
908fc89c0fbSmrg}
909fc89c0fbSmrg
910a0996ce0Smrg/*
911a0996ce0Smrg * Validate a string as UTF-8 encoded according to RFC 3629
912a0996ce0Smrg *
913a0996ce0Smrg * Simply, a unicode code point (up to 21-bits long) is encoded as follows:
914a0996ce0Smrg *
915a0996ce0Smrg *    Char. number range  |        UTF-8 octet sequence
916a0996ce0Smrg *       (hexadecimal)    |              (binary)
917a0996ce0Smrg *    --------------------+---------------------------------------------
918a0996ce0Smrg *    0000 0000-0000 007F | 0xxxxxxx
919a0996ce0Smrg *    0000 0080-0000 07FF | 110xxxxx 10xxxxxx
920a0996ce0Smrg *    0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
921a0996ce0Smrg *    0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
922a0996ce0Smrg *
923a0996ce0Smrg * Validation is done left-to-right, and an error condition, if any, refers to
924a0996ce0Smrg * only the left-most problem in the string.
925a0996ce0Smrg *
926a0996ce0Smrg * Return values:
927a0996ce0Smrg *   UTF8_VALID: Valid UTF-8 encoded string
928a0996ce0Smrg *   UTF8_OVERLONG: Using more bytes than needed for a code point
929a0996ce0Smrg *   UTF8_SHORT_TAIL: Not enough bytes in a multi-byte sequence
930a0996ce0Smrg *   UTF8_LONG_TAIL: Too many bytes in a multi-byte sequence
931a0996ce0Smrg *   UTF8_FORBIDDEN_VALUE: Forbidden prefix or code point outside 0x10FFFF
932a0996ce0Smrg */
933a0996ce0Smrg#define UTF8_VALID 0
934a0996ce0Smrg#define UTF8_FORBIDDEN_VALUE 1
935a0996ce0Smrg#define UTF8_OVERLONG 2
936a0996ce0Smrg#define UTF8_SHORT_TAIL 3
937a0996ce0Smrg#define UTF8_LONG_TAIL 4
938a0996ce0Smrgstatic int
939a0996ce0Smrgis_valid_utf8 (const char *string, int len)
940a0996ce0Smrg{
941a0996ce0Smrg    unsigned long codepoint;
942a0996ce0Smrg    int rem, i;
943a0996ce0Smrg    unsigned char c;
944a0996ce0Smrg
945a0996ce0Smrg    rem = 0;
946a0996ce0Smrg    for (i = 0; i < len; i++) {
947a0996ce0Smrg	c = (unsigned char) string[i];
948a0996ce0Smrg
949a0996ce0Smrg	/* Order of type check:
950a0996ce0Smrg	 *   - Single byte code point
951a0996ce0Smrg	 *   - Non-starting byte of multi-byte sequence
952a0996ce0Smrg	 *   - Start of 2-byte sequence
953a0996ce0Smrg	 *   - Start of 3-byte sequence
954a0996ce0Smrg	 *   - Start of 4-byte sequence
955a0996ce0Smrg	 */
956a0996ce0Smrg	if (!(c & 0x80)) {
957a0996ce0Smrg	    if (rem > 0) return UTF8_SHORT_TAIL;
958a0996ce0Smrg	    rem = 0;
959a0996ce0Smrg	    codepoint = c;
960a0996ce0Smrg	} else if ((c & 0xC0) == 0x80) {
961a0996ce0Smrg	    if (rem == 0) return UTF8_LONG_TAIL;
962a0996ce0Smrg	    rem--;
963a0996ce0Smrg	    codepoint |= (c & 0x3F) << (rem * 6);
964a0996ce0Smrg	    if (codepoint == 0) return UTF8_OVERLONG;
965a0996ce0Smrg	} else if ((c & 0xE0) == 0xC0) {
966a0996ce0Smrg	    if (rem > 0) return UTF8_SHORT_TAIL;
967a0996ce0Smrg	    rem = 1;
968a0996ce0Smrg	    codepoint = (c & 0x1F) << 6;
969a0996ce0Smrg	    if (codepoint == 0) return UTF8_OVERLONG;
970a0996ce0Smrg	} else if ((c & 0xF0) == 0xE0) {
971a0996ce0Smrg	    if (rem > 0) return UTF8_SHORT_TAIL;
972a0996ce0Smrg	    rem = 2;
973a0996ce0Smrg	    codepoint = (c & 0x0F) << 12;
974a0996ce0Smrg	} else if ((c & 0xF8) == 0xF0) {
975a0996ce0Smrg	    if (rem > 0) return UTF8_SHORT_TAIL;
976a0996ce0Smrg	    rem = 3;
977a0996ce0Smrg	    codepoint = (c & 0x07) << 18;
978a0996ce0Smrg	    if (codepoint > 0x10FFFF) return UTF8_FORBIDDEN_VALUE;
979a0996ce0Smrg	} else
980a0996ce0Smrg	    return UTF8_FORBIDDEN_VALUE;
981a0996ce0Smrg    }
982a0996ce0Smrg
983a0996ce0Smrg    return UTF8_VALID;
984a0996ce0Smrg}
985a0996ce0Smrg
986a0996ce0Smrgstatic const char *
987a0996ce0SmrgFormat_Len_Unicode (const char *string, int len)
988a0996ce0Smrg{
989a0996ce0Smrg    char *data;
990a0996ce0Smrg    const char *result, *error;
991a0996ce0Smrg    int len2;
992a0996ce0Smrg
993a0996ce0Smrg    int validity = is_valid_utf8(string, len);
994a0996ce0Smrg
995a0996ce0Smrg    if (validity != UTF8_VALID) {
996a0996ce0Smrg	switch (validity) {
997a0996ce0Smrg	  case UTF8_FORBIDDEN_VALUE:
998a0996ce0Smrg	    error = "<Invalid UTF-8 string: Forbidden value> "; break;
999a0996ce0Smrg	  case UTF8_OVERLONG:
1000a0996ce0Smrg	    error = "<Invalid UTF-8 string: Overlong encoding> "; break;
1001a0996ce0Smrg	  case UTF8_SHORT_TAIL:
1002a0996ce0Smrg	    error = "<Invalid UTF-8 string: Tail too short> "; break;
1003a0996ce0Smrg	  case UTF8_LONG_TAIL:
1004a0996ce0Smrg	    error = "<Invalid UTF-8 string: Tail too long> "; break;
1005a0996ce0Smrg	}
1006a0996ce0Smrg
1007a0996ce0Smrg	result = Format_Len_String(string, len);
1008a0996ce0Smrg	len2 = strlen(result);
1009a0996ce0Smrg	data = (char *) Malloc(len2+1);
1010a0996ce0Smrg	memcpy(data, result, len2+1);
1011a0996ce0Smrg
1012a0996ce0Smrg	memcpy(_formatting_buffer, error, strlen(error)+1);
1013a0996ce0Smrg	strcat(_formatting_buffer, data);
1014a0996ce0Smrg	free(data);
1015a0996ce0Smrg
1016a0996ce0Smrg	return _formatting_buffer;
1017a0996ce0Smrg    }
1018a0996ce0Smrg
1019a0996ce0Smrg    if (!is_utf8_locale())
1020a0996ce0Smrg	return Format_Len_String(string, len);
1021a0996ce0Smrg
1022a0996ce0Smrg    data = (char *) Malloc(len+1);
1023a0996ce0Smrg
1024a0996ce0Smrg    memcpy(data, string, len);
1025a0996ce0Smrg    data[len] = '\0';
1026a0996ce0Smrg
1027a0996ce0Smrg    result = Format_String(data, 1);
1028a0996ce0Smrg    free(data);
1029a0996ce0Smrg
1030a0996ce0Smrg    return result;
1031a0996ce0Smrg}
1032a0996ce0Smrg
1033fc89c0fbSmrg/*
1034fc89c0fbSmrg *
1035fc89c0fbSmrg * The Format Manager: a group of routines to manage "formats"
1036fc89c0fbSmrg *
1037fc89c0fbSmrg */
1038fc89c0fbSmrg
1039fc89c0fbSmrgstatic int
1040fc89c0fbSmrgIs_A_Format (const char *string)
1041fc89c0fbSmrg{
1042fc89c0fbSmrg    return isdigit((unsigned char) string[0]);
1043fc89c0fbSmrg}
1044fc89c0fbSmrg
1045fc89c0fbSmrgstatic int
1046fc89c0fbSmrgGet_Format_Size (const char *format)
1047fc89c0fbSmrg{
1048fc89c0fbSmrg    long size;
1049fc89c0fbSmrg
1050fc89c0fbSmrg    Scan_Long(format, &size);
1051fc89c0fbSmrg
1052fc89c0fbSmrg    /* Check for legal sizes */
1053fc89c0fbSmrg    if (size != 0 && size != 8 && size != 16 && size != 32)
1054fc89c0fbSmrg	Fatal_Error("bad format: %s", format);
1055fc89c0fbSmrg
1056fc89c0fbSmrg    return (int) size;
1057fc89c0fbSmrg}
1058fc89c0fbSmrg
1059fc89c0fbSmrgstatic char
1060fc89c0fbSmrgGet_Format_Char (const char *format, int i)
1061fc89c0fbSmrg{
1062fc89c0fbSmrg    long size;
1063fc89c0fbSmrg
1064fc89c0fbSmrg    /* Remove # at front of format */
1065fc89c0fbSmrg    format = Scan_Long(format, &size);
1066fc89c0fbSmrg    if (!*format)
1067fc89c0fbSmrg	Fatal_Error("bad format: %s", format);
1068fc89c0fbSmrg
1069fc89c0fbSmrg    /* Last character repeats forever... */
1070fc89c0fbSmrg    if (i >= (int)strlen(format))
1071fc89c0fbSmrg	i = strlen(format)-1;
1072fc89c0fbSmrg
1073fc89c0fbSmrg    return format[i];
1074fc89c0fbSmrg}
1075fc89c0fbSmrg
1076fc89c0fbSmrgstatic const char *
1077fc89c0fbSmrgFormat_Thunk (thunk t, char format_char)
1078fc89c0fbSmrg{
1079fc89c0fbSmrg    long value;
1080fc89c0fbSmrg    value = t.value;
1081fc89c0fbSmrg
1082fc89c0fbSmrg    switch (format_char) {
1083fc89c0fbSmrg      case 's':
1084fc89c0fbSmrg	return Format_Len_String(t.extra_value, (int)t.value);
1085a0996ce0Smrg      case 'u':
1086a0996ce0Smrg	return Format_Len_Unicode(t.extra_value, (int)t.value);
1087fc89c0fbSmrg      case 't':
1088fc89c0fbSmrg	return Format_Len_Text(t.extra_value, (int)t.value, t.extra_encoding);
1089fc89c0fbSmrg      case 'x':
1090fc89c0fbSmrg	return Format_Hex(value);
1091fc89c0fbSmrg      case 'c':
1092fc89c0fbSmrg	return Format_Unsigned(value);
1093fc89c0fbSmrg      case 'i':
1094fc89c0fbSmrg	return Format_Signed(value);
1095fc89c0fbSmrg      case 'b':
1096fc89c0fbSmrg	return Format_Bool(value);
1097fc89c0fbSmrg      case 'm':
1098fc89c0fbSmrg	return Format_Mask_Word(value);
1099fc89c0fbSmrg      case 'a':
1100fc89c0fbSmrg	return Format_Atom(value);
110191ec45ceSmrg      case 'o':
110291ec45ceSmrg	  return Format_Icons((const unsigned long *)t.extra_value, (int)t.value);
1103fc89c0fbSmrg      default:
1104fc89c0fbSmrg	Fatal_Error("bad format character: %c", format_char);
1105fc89c0fbSmrg    }
1106fc89c0fbSmrg}
1107fc89c0fbSmrg
1108fc89c0fbSmrgstatic const char *
1109fc89c0fbSmrgFormat_Thunk_I (thunk *thunks, const char *format, int i)
1110fc89c0fbSmrg{
1111fc89c0fbSmrg    if (i >= thunks->thunk_count)
1112fc89c0fbSmrg	return "<field not available>";
1113fc89c0fbSmrg
1114fc89c0fbSmrg    return Format_Thunk(thunks[i], Get_Format_Char(format, i));
1115fc89c0fbSmrg}
1116fc89c0fbSmrg
1117fc89c0fbSmrgstatic long
1118fc89c0fbSmrgMask_Word (thunk *thunks, const char *format)
1119fc89c0fbSmrg{
1120fc89c0fbSmrg    int j;
1121fc89c0fbSmrg
1122fc89c0fbSmrg    for (j = 0; j  < (int)strlen(format); j++)
1123fc89c0fbSmrg	if (Get_Format_Char(format, j) == 'm')
1124fc89c0fbSmrg	    return thunks[j].value;
1125fc89c0fbSmrg    return 0;
1126fc89c0fbSmrg}
1127fc89c0fbSmrg
1128fc89c0fbSmrg/*
1129fc89c0fbSmrg *
1130fc89c0fbSmrg * The Display Format Manager:
1131fc89c0fbSmrg *
1132fc89c0fbSmrg */
1133fc89c0fbSmrg
1134fc89c0fbSmrgstatic int
1135fc89c0fbSmrgIs_A_DFormat (const char *string)
1136fc89c0fbSmrg{
1137fc89c0fbSmrg    return string[0] && string[0] != '-'
1138fc89c0fbSmrg	   && !(isalpha((unsigned char) string[0]) || string[0] == '_');
1139fc89c0fbSmrg}
1140fc89c0fbSmrg
1141fc89c0fbSmrgstatic const char *
1142fc89c0fbSmrgHandle_Backslash (const char *dformat)
1143fc89c0fbSmrg{
1144fc89c0fbSmrg    char c;
1145fc89c0fbSmrg    unsigned long i;
1146fc89c0fbSmrg
1147fc89c0fbSmrg    if (!(c = *(dformat++)))
1148fc89c0fbSmrg	return dformat;
1149fc89c0fbSmrg
1150fc89c0fbSmrg    switch (c) {
1151fc89c0fbSmrg      case 'n':
1152fc89c0fbSmrg	putchar('\n');
1153fc89c0fbSmrg	break;
1154fc89c0fbSmrg      case 't':
1155fc89c0fbSmrg	putchar('\t');
1156fc89c0fbSmrg	break;
1157fc89c0fbSmrg      case '0':
1158fc89c0fbSmrg      case '1':
1159fc89c0fbSmrg      case '2':
1160fc89c0fbSmrg      case '3':
1161fc89c0fbSmrg      case '4':
1162fc89c0fbSmrg      case '5':
1163fc89c0fbSmrg      case '6':
1164fc89c0fbSmrg      case '7':
1165fc89c0fbSmrg	dformat = Scan_Octal(dformat, &i);
1166fc89c0fbSmrg	putchar((int) i);
1167fc89c0fbSmrg	break;
1168fc89c0fbSmrg      default:
1169fc89c0fbSmrg	putchar(c);
1170fc89c0fbSmrg	break;
1171fc89c0fbSmrg    }
1172fc89c0fbSmrg    return dformat;
1173fc89c0fbSmrg}
1174fc89c0fbSmrg
1175fc89c0fbSmrgstatic const char *
1176fc89c0fbSmrgHandle_Dollar_sign (const char *dformat, thunk *thunks, const char *format)
1177fc89c0fbSmrg{
1178fc89c0fbSmrg    long i;
1179fc89c0fbSmrg
1180fc89c0fbSmrg    dformat = Scan_Long(dformat, &i);
1181fc89c0fbSmrg
1182fc89c0fbSmrg    if (dformat[0] == '+') {
1183fc89c0fbSmrg	int seen = 0;
1184fc89c0fbSmrg	dformat++;
1185fc89c0fbSmrg	for (; i < thunks->thunk_count; i++) {
1186fc89c0fbSmrg	    if (seen)
1187fc89c0fbSmrg		printf(", ");
1188fc89c0fbSmrg	    seen = 1;
1189fc89c0fbSmrg	    printf("%s", Format_Thunk_I(thunks, format, (int) i));
1190fc89c0fbSmrg	}
1191fc89c0fbSmrg    } else
1192fc89c0fbSmrg	printf("%s", Format_Thunk_I(thunks, format, (int) i));
1193fc89c0fbSmrg
1194fc89c0fbSmrg    return dformat;
1195fc89c0fbSmrg}
1196fc89c0fbSmrg
1197fc89c0fbSmrgstatic int
1198fc89c0fbSmrgMask_Bit_I (thunk *thunks, const char *format, int i)
1199fc89c0fbSmrg{
1200fc89c0fbSmrg    long value;
1201fc89c0fbSmrg
1202fc89c0fbSmrg    value = Mask_Word(thunks, format);
1203fc89c0fbSmrg
1204fc89c0fbSmrg    value = value & (1L<<i);
1205fc89c0fbSmrg    if (value)
1206fc89c0fbSmrg	value = 1;
1207fc89c0fbSmrg    return value;
1208fc89c0fbSmrg}
1209fc89c0fbSmrg
1210fc89c0fbSmrgstatic const char *
1211fc89c0fbSmrgScan_Term (const char *string, thunk *thunks, const char *format, long *value)
1212fc89c0fbSmrg{
1213fc89c0fbSmrg    long i;
1214fc89c0fbSmrg
1215fc89c0fbSmrg    *value = 0;
1216fc89c0fbSmrg
1217fc89c0fbSmrg    if (isdigit((unsigned char) *string))
1218fc89c0fbSmrg	string = Scan_Long(string, value);
1219fc89c0fbSmrg    else if (*string == '$') {
1220fc89c0fbSmrg	string = Scan_Long(++string, &i);
1221fc89c0fbSmrg	if (i >= thunks->thunk_count)
1222fc89c0fbSmrg	    i = thunks->thunk_count;
1223fc89c0fbSmrg	*value = thunks[i].value;
1224fc89c0fbSmrg    } else if (*string == 'm') {
1225fc89c0fbSmrg	string = Scan_Long(++string, &i);
1226fc89c0fbSmrg	*value = Mask_Bit_I(thunks, format, (int) i);
1227fc89c0fbSmrg    } else
1228fc89c0fbSmrg	Fatal_Error("Bad term: %s.", string);
1229fc89c0fbSmrg
1230fc89c0fbSmrg    return string;
1231fc89c0fbSmrg}
1232fc89c0fbSmrg
1233fc89c0fbSmrgstatic const char *
1234fc89c0fbSmrgScan_Exp (const char *string, thunk *thunks, const char *format, long *value)
1235fc89c0fbSmrg{
1236fc89c0fbSmrg    long temp;
1237fc89c0fbSmrg
1238fc89c0fbSmrg    if (string[0] == '(') {
1239fc89c0fbSmrg	string = Scan_Exp(++string, thunks, format, value);
1240fc89c0fbSmrg	if (string[0]!=')')
1241fc89c0fbSmrg	    Fatal_Error("Missing ')'");
1242fc89c0fbSmrg	return ++string;
1243fc89c0fbSmrg    }
1244fc89c0fbSmrg    if (string[0] == '!') {
1245fc89c0fbSmrg	string = Scan_Exp(++string, thunks, format, value);
1246fc89c0fbSmrg	*value = !*value;
1247fc89c0fbSmrg	return string;
1248fc89c0fbSmrg    }
1249fc89c0fbSmrg
1250fc89c0fbSmrg    string = Scan_Term(string, thunks, format, value);
1251fc89c0fbSmrg
1252fc89c0fbSmrg    if (string[0] == '=') {
1253fc89c0fbSmrg	string = Scan_Exp(++string, thunks, format, &temp);
1254fc89c0fbSmrg	*value = *value == temp;
1255fc89c0fbSmrg    }
1256fc89c0fbSmrg
1257fc89c0fbSmrg    return string;
1258fc89c0fbSmrg}
1259fc89c0fbSmrg
1260fc89c0fbSmrgstatic const char *
1261fc89c0fbSmrgHandle_Question_Mark (const char *dformat, thunk *thunks, const char *format)
1262fc89c0fbSmrg{
1263fc89c0fbSmrg    long true;
1264fc89c0fbSmrg
1265fc89c0fbSmrg    dformat = Scan_Exp(dformat, thunks, format, &true);
1266fc89c0fbSmrg
1267fc89c0fbSmrg    if (*dformat != '(')
1268fc89c0fbSmrg	Fatal_Error("Bad conditional: '(' expected: %s.", dformat);
1269fc89c0fbSmrg    ++dformat;
1270fc89c0fbSmrg
1271fc89c0fbSmrg    if (!true)
1272fc89c0fbSmrg	dformat = Skip_Past_Right_Paren(dformat);
1273fc89c0fbSmrg
1274fc89c0fbSmrg    return dformat;
1275fc89c0fbSmrg}
1276fc89c0fbSmrg
1277fc89c0fbSmrgstatic void
1278fc89c0fbSmrgDisplay_Property (thunk *thunks, const char *dformat, const char *format)
1279fc89c0fbSmrg{
1280fc89c0fbSmrg    char c;
1281fc89c0fbSmrg
1282fc89c0fbSmrg    while ((c = *(dformat++)))
1283fc89c0fbSmrg	switch (c) {
1284fc89c0fbSmrg	  case ')':
1285fc89c0fbSmrg	    continue;
1286fc89c0fbSmrg	  case '\\':
1287fc89c0fbSmrg	    dformat = Handle_Backslash(dformat);
1288fc89c0fbSmrg	    continue;
1289fc89c0fbSmrg	  case '$':
1290fc89c0fbSmrg	    dformat = Handle_Dollar_sign(dformat, thunks, format);
1291fc89c0fbSmrg	    continue;
1292fc89c0fbSmrg	  case '?':
1293fc89c0fbSmrg	    dformat = Handle_Question_Mark(dformat, thunks, format);
1294fc89c0fbSmrg	    continue;
1295fc89c0fbSmrg	  default:
1296fc89c0fbSmrg	    putchar(c);
1297fc89c0fbSmrg	    continue;
1298fc89c0fbSmrg	}
1299fc89c0fbSmrg}
1300fc89c0fbSmrg
1301fc89c0fbSmrg/*
1302fc89c0fbSmrg *
1303fc89c0fbSmrg * Routines to convert property data to thunks
1304fc89c0fbSmrg *
1305fc89c0fbSmrg */
1306fc89c0fbSmrg
1307fc89c0fbSmrgstatic long
1308fc89c0fbSmrgExtract_Value (const char **pointer, int *length, int size, int signedp)
1309fc89c0fbSmrg{
1310fc89c0fbSmrg    long value;
1311fc89c0fbSmrg
1312fc89c0fbSmrg    switch (size) {
1313fc89c0fbSmrg      case 8:
1314fc89c0fbSmrg	if (signedp)
1315fc89c0fbSmrg	    value = * (const signed char *) *pointer;
1316fc89c0fbSmrg	else
1317fc89c0fbSmrg	    value = * (const unsigned char *) *pointer;
1318fc89c0fbSmrg	*pointer += 1;
1319fc89c0fbSmrg	*length -= 1;
1320fc89c0fbSmrg	break;
1321fc89c0fbSmrg      case 16:
1322fc89c0fbSmrg	if (signedp)
1323fc89c0fbSmrg	    value = * (const short *) *pointer;
1324fc89c0fbSmrg	else
1325fc89c0fbSmrg	    value = * (const unsigned short *) *pointer;
1326fc89c0fbSmrg	*pointer += sizeof(short);
1327fc89c0fbSmrg	*length -= sizeof(short);
1328fc89c0fbSmrg	break;
1329fc89c0fbSmrg      case 32:
1330fc89c0fbSmrg	if (signedp)
1331fc89c0fbSmrg	    value = * (const long *) *pointer;
1332fc89c0fbSmrg	else
1333fc89c0fbSmrg	    value = * (const unsigned long *) *pointer & 0xffffffff;
1334fc89c0fbSmrg	*pointer += sizeof(long);
1335fc89c0fbSmrg	*length -= sizeof(long);
1336fc89c0fbSmrg	break;
1337fc89c0fbSmrg      default:
1338fc89c0fbSmrg	abort();
1339fc89c0fbSmrg    }
1340fc89c0fbSmrg    return value;
1341fc89c0fbSmrg}
1342fc89c0fbSmrg
1343fc89c0fbSmrgstatic long
1344fc89c0fbSmrgExtract_Len_String (const char **pointer, int *length, int size, const char **string)
1345fc89c0fbSmrg{
1346fc89c0fbSmrg    int len;
1347fc89c0fbSmrg
1348fc89c0fbSmrg    if (size != 8)
1349fc89c0fbSmrg	Fatal_Error("can't use format character 's' with any size except 8.");
1350fc89c0fbSmrg    len = 0; *string = *pointer;
1351fc89c0fbSmrg    while ((len++, --*length, *((*pointer)++)) && *length>0);
1352fc89c0fbSmrg
1353fc89c0fbSmrg    return len;
1354fc89c0fbSmrg}
1355fc89c0fbSmrg
135691ec45ceSmrgstatic long
135791ec45ceSmrgExtract_Icon (const char **pointer, int *length, int size, const char **icon)
135891ec45ceSmrg{
135991ec45ceSmrg    int len = 0;
136091ec45ceSmrg
136191ec45ceSmrg    if (size != 32)
136291ec45ceSmrg	Fatal_Error("can't use format character 'o' with any size except 32.");
136391ec45ceSmrg
136491ec45ceSmrg    len = *length;
136591ec45ceSmrg    *icon = *pointer;
136691ec45ceSmrg    *length = 0;
136791ec45ceSmrg    return len;
136891ec45ceSmrg}
136991ec45ceSmrg
1370fc89c0fbSmrgstatic thunk *
1371fc89c0fbSmrgBreak_Down_Property (const char *pointer, int length, Atom type, const char *format, int size)
1372fc89c0fbSmrg{
1373fc89c0fbSmrg    thunk *thunks;
1374fc89c0fbSmrg    thunk t;
1375fc89c0fbSmrg    int i;
1376fc89c0fbSmrg    char format_char;
1377fc89c0fbSmrg
1378fc89c0fbSmrg    thunks = Create_Thunk_List();
1379fc89c0fbSmrg    i = 0;
1380fc89c0fbSmrg
1381fc89c0fbSmrg    while (length >= size/8) {
1382fc89c0fbSmrg	format_char = Get_Format_Char(format, i);
1383a0996ce0Smrg	if (format_char == 's' || format_char == 'u')
1384fc89c0fbSmrg	    t.value = Extract_Len_String(&pointer,&length,size,&t.extra_value);
1385fc89c0fbSmrg	else if (format_char == 't') {
1386fc89c0fbSmrg	    t.extra_encoding = type;
1387fc89c0fbSmrg	    t.value = Extract_Len_String(&pointer,&length,size,&t.extra_value);
138891ec45ceSmrg	}
138991ec45ceSmrg	else if (format_char == 'o')
139091ec45ceSmrg	    t.value = Extract_Icon (&pointer,&length,size,&t.extra_value);
139191ec45ceSmrg	else
1392fc89c0fbSmrg	    t.value = Extract_Value(&pointer,&length,size,format_char=='i');
1393fc89c0fbSmrg	thunks = Add_Thunk(thunks, t);
1394fc89c0fbSmrg	i++;
1395fc89c0fbSmrg    }
1396fc89c0fbSmrg
1397fc89c0fbSmrg    return thunks;
1398fc89c0fbSmrg}
1399fc89c0fbSmrg
1400fc89c0fbSmrg/*
1401fc89c0fbSmrg * Variables set by main()
1402fc89c0fbSmrg */
1403fc89c0fbSmrg
1404fc89c0fbSmrgstatic Window target_win = 0;
1405fc89c0fbSmrgstatic int notype = 0;
1406fc89c0fbSmrgstatic int max_len = MAXSTR;
1407fc89c0fbSmrgstatic XFontStruct *font;
1408fc89c0fbSmrgstatic unsigned long _font_prop;
1409fc89c0fbSmrg
1410fc89c0fbSmrg/*
1411fc89c0fbSmrg *
1412fc89c0fbSmrg * Other Stuff (temp.):
1413fc89c0fbSmrg *
1414fc89c0fbSmrg */
1415fc89c0fbSmrg
1416fc89c0fbSmrgstatic const char *
1417fc89c0fbSmrgGet_Font_Property_Data_And_Type (Atom atom,
1418fc89c0fbSmrg                                 long *length, Atom *type, int *size)
1419fc89c0fbSmrg{
1420fc89c0fbSmrg    int i;
1421fc89c0fbSmrg
1422fc89c0fbSmrg    *type = None;
1423fc89c0fbSmrg
1424fc89c0fbSmrg    for (i = 0; i < font->n_properties; i++)
1425fc89c0fbSmrg	if (atom == font->properties[i].name) {
1426fc89c0fbSmrg	    _font_prop = font->properties[i].card32;
1427fc89c0fbSmrg	    *length = sizeof(long);
1428fc89c0fbSmrg	    *size = 32;
1429fc89c0fbSmrg	    return (const char *) &_font_prop;
1430fc89c0fbSmrg	}
1431fc89c0fbSmrg    *size = 0;
1432fc89c0fbSmrg    return NULL;
1433fc89c0fbSmrg}
1434fc89c0fbSmrg
1435fc89c0fbSmrgstatic const char *
1436fc89c0fbSmrgGet_Window_Property_Data_And_Type (Atom atom,
1437fc89c0fbSmrg                                   long *length, Atom *type, int *size)
1438fc89c0fbSmrg{
1439fc89c0fbSmrg    Atom actual_type;
1440fc89c0fbSmrg    int actual_format;
1441fc89c0fbSmrg    unsigned long nitems;
1442fc89c0fbSmrg    unsigned long nbytes;
1443fc89c0fbSmrg    unsigned long bytes_after;
1444fc89c0fbSmrg    unsigned char *prop;
1445fc89c0fbSmrg    int status;
1446fc89c0fbSmrg
1447fc89c0fbSmrg    status = XGetWindowProperty(dpy, target_win, atom, 0, (max_len+3)/4,
1448fc89c0fbSmrg				False, AnyPropertyType, &actual_type,
1449fc89c0fbSmrg				&actual_format, &nitems, &bytes_after,
1450fc89c0fbSmrg				&prop);
1451fc89c0fbSmrg    if (status == BadWindow)
1452fc89c0fbSmrg	Fatal_Error("window id # 0x%lx does not exists!", target_win);
1453fc89c0fbSmrg    if (status != Success)
1454fc89c0fbSmrg	Fatal_Error("XGetWindowProperty failed!");
1455fc89c0fbSmrg
1456fc89c0fbSmrg    if (actual_format == 32)
1457fc89c0fbSmrg	nbytes = sizeof(long);
1458fc89c0fbSmrg    else if (actual_format == 16)
1459fc89c0fbSmrg	nbytes = sizeof(short);
1460fc89c0fbSmrg    else if (actual_format == 8)
1461fc89c0fbSmrg	nbytes = 1;
1462fc89c0fbSmrg    else if (actual_format == 0)
1463fc89c0fbSmrg        nbytes = 0;
1464fc89c0fbSmrg    else
1465fc89c0fbSmrg	abort();
1466fc89c0fbSmrg    *length = min(nitems * nbytes, max_len);
1467fc89c0fbSmrg    *type = actual_type;
1468fc89c0fbSmrg    *size = actual_format;
1469fc89c0fbSmrg    return (const char *)prop;
1470fc89c0fbSmrg}
1471fc89c0fbSmrg
1472fc89c0fbSmrgstatic const char *
1473fc89c0fbSmrgGet_Property_Data_And_Type (Atom atom, long *length, Atom *type, int *size)
1474fc89c0fbSmrg{
1475fc89c0fbSmrg    if (target_win == -1)
1476fc89c0fbSmrg	return Get_Font_Property_Data_And_Type(atom, length, type, size);
1477fc89c0fbSmrg    else
1478fc89c0fbSmrg	return Get_Window_Property_Data_And_Type(atom, length, type, size);
1479fc89c0fbSmrg}
1480fc89c0fbSmrg
1481fc89c0fbSmrgstatic void
1482fc89c0fbSmrgShow_Prop (const char *format, const char *dformat, const char *prop)
1483fc89c0fbSmrg{
1484fc89c0fbSmrg    const char *data;
1485fc89c0fbSmrg    long length;
1486fc89c0fbSmrg    Atom atom, type;
1487fc89c0fbSmrg    thunk *thunks;
1488fc89c0fbSmrg    int size, fsize;
1489fc89c0fbSmrg
1490fc89c0fbSmrg    printf("%s", prop);
1491fc89c0fbSmrg    atom = Parse_Atom(prop, True);
1492fc89c0fbSmrg    if (atom == None) {
1493fc89c0fbSmrg	printf(":  no such atom on any window.\n");
1494fc89c0fbSmrg	return;
1495fc89c0fbSmrg    }
1496fc89c0fbSmrg
1497fc89c0fbSmrg    data = Get_Property_Data_And_Type(atom, &length, &type, &size);
1498fc89c0fbSmrg    if (!size) {
1499fc89c0fbSmrg	puts(":  not found.");
1500fc89c0fbSmrg	return;
1501fc89c0fbSmrg    }
1502fc89c0fbSmrg
1503fc89c0fbSmrg    if (!notype && type != None)
1504fc89c0fbSmrg	printf("(%s)", Format_Atom(type));
1505fc89c0fbSmrg
1506fc89c0fbSmrg    Lookup_Formats(atom, &format, &dformat);
1507fc89c0fbSmrg    if (type != None)
1508fc89c0fbSmrg	Lookup_Formats(type, &format, &dformat);
1509fc89c0fbSmrg    Apply_Default_Formats(&format, &dformat);
1510fc89c0fbSmrg
1511fc89c0fbSmrg    fsize = Get_Format_Size(format);
1512fc89c0fbSmrg    if (fsize != size && fsize != 0) {
1513fc89c0fbSmrg	printf(": Type mismatch: assumed size %d bits, actual size %d bits.\n",
1514fc89c0fbSmrg	       fsize, size);
1515fc89c0fbSmrg	return;
1516fc89c0fbSmrg    }
1517fc89c0fbSmrg
1518fc89c0fbSmrg    thunks = Break_Down_Property(data, (int)length, type, format, size);
1519fc89c0fbSmrg
1520fc89c0fbSmrg    Display_Property(thunks, dformat, format);
1521fc89c0fbSmrg}
1522fc89c0fbSmrg
1523fc89c0fbSmrgstatic void
1524fc89c0fbSmrgShow_All_Props (void)
1525fc89c0fbSmrg{
1526fc89c0fbSmrg    Atom *atoms, atom;
1527fc89c0fbSmrg    const char *name;
1528fc89c0fbSmrg    int count, i;
1529fc89c0fbSmrg
1530fc89c0fbSmrg    if (target_win != -1) {
1531fc89c0fbSmrg	atoms = XListProperties(dpy, target_win, &count);
1532fc89c0fbSmrg	for (i = 0; i < count; i++) {
1533fc89c0fbSmrg	    name = Format_Atom(atoms[i]);
1534fc89c0fbSmrg	    Show_Prop(NULL, NULL, name);
1535fc89c0fbSmrg	}
1536fc89c0fbSmrg    } else
1537fc89c0fbSmrg	for (i = 0; i < font->n_properties; i++) {
1538fc89c0fbSmrg	    atom = font->properties[i].name;
1539fc89c0fbSmrg	    name = Format_Atom(atom);
1540fc89c0fbSmrg	    Show_Prop(NULL, NULL, name);
1541fc89c0fbSmrg	}
1542fc89c0fbSmrg}
1543fc89c0fbSmrg
1544fc89c0fbSmrgstatic thunk *
1545fc89c0fbSmrgHandle_Prop_Requests (int argc, char **argv)
1546fc89c0fbSmrg{
1547fc89c0fbSmrg    char *format, *dformat, *prop;
1548fc89c0fbSmrg    thunk *thunks, t;
1549fc89c0fbSmrg
1550fc89c0fbSmrg    /* if no prop referenced, by default list all properties for given window */
1551fc89c0fbSmrg    if (!argc) {
1552fc89c0fbSmrg	Show_All_Props();
1553fc89c0fbSmrg	return NULL;
1554fc89c0fbSmrg    }
1555fc89c0fbSmrg
1556fc89c0fbSmrg    thunks = Create_Thunk_List();
1557fc89c0fbSmrg
1558fc89c0fbSmrg    while (argc > 0) {
1559fc89c0fbSmrg	format = NULL;
1560fc89c0fbSmrg	dformat = NULL;
1561fc89c0fbSmrg
1562fc89c0fbSmrg	/* Get overriding formats, if any */
1563fc89c0fbSmrg	if (Is_A_Format(argv[0])) {
1564fc89c0fbSmrg	    format = argv++[0]; argc--;
1565fc89c0fbSmrg	    if (!argc) usage();
1566fc89c0fbSmrg	}
1567fc89c0fbSmrg	if (Is_A_DFormat(argv[0])) {
1568fc89c0fbSmrg	    dformat = argv++[0]; argc--;
1569fc89c0fbSmrg	    if (!argc) usage();
1570fc89c0fbSmrg	}
1571fc89c0fbSmrg
1572fc89c0fbSmrg	/* Get property name */
1573fc89c0fbSmrg	prop = argv++[0]; argc--;
1574fc89c0fbSmrg
1575fc89c0fbSmrg	t.propname = prop;
1576fc89c0fbSmrg	t.value = Parse_Atom(prop, True);
1577fc89c0fbSmrg	t.format = format;
1578fc89c0fbSmrg	t.dformat = dformat;
1579fc89c0fbSmrg	if (t.value)
1580fc89c0fbSmrg	    thunks = Add_Thunk(thunks, t);
1581fc89c0fbSmrg	Show_Prop(format, dformat, prop);
1582fc89c0fbSmrg    }
1583fc89c0fbSmrg    return thunks;
1584fc89c0fbSmrg}
1585fc89c0fbSmrg
1586fc89c0fbSmrgstatic void
1587fc89c0fbSmrgRemove_Property (Display *dpy, Window w, const char *propname)
1588fc89c0fbSmrg{
1589fc89c0fbSmrg    Atom id = XInternAtom (dpy, propname, True);
1590fc89c0fbSmrg
1591fc89c0fbSmrg    if (id == None) {
1592fc89c0fbSmrg	fprintf (stderr, "%s:  no such property \"%s\"\n",
1593fc89c0fbSmrg		 program_name, propname);
1594fc89c0fbSmrg	return;
1595fc89c0fbSmrg    }
1596fc89c0fbSmrg    XDeleteProperty (dpy, w, id);
1597fc89c0fbSmrg}
1598fc89c0fbSmrg
1599fc89c0fbSmrgstatic void
1600fc89c0fbSmrgSet_Property (Display *dpy, Window w, const char *propname, const char *value)
1601fc89c0fbSmrg{
1602fc89c0fbSmrg    Atom atom;
1603fc89c0fbSmrg    const char *format;
1604fc89c0fbSmrg    const char *dformat;
1605fc89c0fbSmrg    int size;
1606fc89c0fbSmrg    char format_char;
1607fc89c0fbSmrg    Atom type = 0;
1608fc89c0fbSmrg    unsigned char *data = NULL;
1609fc89c0fbSmrg    int nelements = 0;
1610fc89c0fbSmrg
1611fc89c0fbSmrg    atom = Parse_Atom(propname, False);
1612fc89c0fbSmrg
1613fc89c0fbSmrg    format = dformat = NULL;
1614fc89c0fbSmrg    Lookup_Formats(atom, &format, &dformat);
1615fc89c0fbSmrg    if (format == NULL)
1616fc89c0fbSmrg	Fatal_Error("unsupported conversion for %s", propname);
1617fc89c0fbSmrg
1618fc89c0fbSmrg    size = Get_Format_Size(format);
1619fc89c0fbSmrg
1620fc89c0fbSmrg    format_char = Get_Format_Char(format, 0);
1621fc89c0fbSmrg    switch (format_char) {
1622fc89c0fbSmrg      case 's':
1623fc89c0fbSmrg	if (size != 8)
1624fc89c0fbSmrg	    Fatal_Error("can't use format character 's' with any size except 8.");
1625fc89c0fbSmrg	type = XA_STRING;
1626fc89c0fbSmrg	data = (unsigned char *) value;
1627fc89c0fbSmrg	nelements = strlen(value);
1628fc89c0fbSmrg	break;
1629fc89c0fbSmrg      case 't': {
1630fc89c0fbSmrg	XTextProperty textprop;
1631fc89c0fbSmrg	if (size != 8)
1632fc89c0fbSmrg	    Fatal_Error("can't use format character 't' with any size except 8.");
1633fc89c0fbSmrg	if (XmbTextListToTextProperty(dpy, (char **) &value, 1,
1634fc89c0fbSmrg				      XStdICCTextStyle, &textprop) != Success) {
1635fc89c0fbSmrg	    fprintf(stderr, "cannot convert %s argument to STRING or COMPOUND_TEXT.\n", propname);
1636fc89c0fbSmrg	    return;
1637fc89c0fbSmrg	}
1638fc89c0fbSmrg	type = textprop.encoding;
1639fc89c0fbSmrg	data = textprop.value;
1640fc89c0fbSmrg	nelements = textprop.nitems;
1641fc89c0fbSmrg	break;
1642fc89c0fbSmrg      }
1643fc89c0fbSmrg      case 'x':
1644fc89c0fbSmrg      case 'c': {
1645fc89c0fbSmrg	static unsigned char data8[MAXELEMENTS];
1646fc89c0fbSmrg	static unsigned short data16[MAXELEMENTS];
1647fc89c0fbSmrg	static unsigned long data32[MAXELEMENTS];
1648fc89c0fbSmrg	unsigned long intvalue;
1649fc89c0fbSmrg	char * value2 = strdup(value);
1650fc89c0fbSmrg	char * tmp = strtok(value2,",");
1651fc89c0fbSmrg	nelements = 1;
1652fc89c0fbSmrg	intvalue = strtoul(tmp, NULL, 0);
1653fc89c0fbSmrg	switch(size) {
1654fc89c0fbSmrg	    case 8:
1655fc89c0fbSmrg	        data8[0] = intvalue; data = (unsigned char *) data8; break;
1656fc89c0fbSmrg	    case 16:
1657fc89c0fbSmrg	        data16[0] = intvalue; data = (unsigned char *) data16; break;
1658fc89c0fbSmrg	    case 32:
1659fc89c0fbSmrg	        data32[0] = intvalue; data = (unsigned char *) data32; break;
1660fc89c0fbSmrg	}
1661fc89c0fbSmrg	tmp = strtok(NULL,",");
1662fc89c0fbSmrg	while(tmp != NULL){
1663fc89c0fbSmrg	    intvalue = strtoul(tmp, NULL,0);
1664fc89c0fbSmrg	    switch(size) {
1665fc89c0fbSmrg		case 8:
1666fc89c0fbSmrg	    	    data8[nelements] = intvalue; break;
1667fc89c0fbSmrg		case 16:
1668fc89c0fbSmrg	    	    data16[nelements] = intvalue; break;
1669fc89c0fbSmrg		case 32:
1670fc89c0fbSmrg	    	    data32[nelements] = intvalue; break;
1671fc89c0fbSmrg	    }
1672fc89c0fbSmrg	    nelements++;
1673fc89c0fbSmrg	    if(nelements == MAXELEMENTS){
1674fc89c0fbSmrg		fprintf(stderr, "Maximum number of elements reached (%d). List truncated.\n",MAXELEMENTS);
1675fc89c0fbSmrg		break;
1676fc89c0fbSmrg	    }
1677fc89c0fbSmrg	    tmp = strtok(NULL,",");
1678fc89c0fbSmrg	}
1679fc89c0fbSmrg
1680fc89c0fbSmrg	type = XA_CARDINAL;
1681fc89c0fbSmrg	free(value2);
1682fc89c0fbSmrg	break;
1683fc89c0fbSmrg      }
1684fc89c0fbSmrg      case 'i': {
1685fc89c0fbSmrg	static unsigned char data8[MAXELEMENTS];
1686fc89c0fbSmrg	static unsigned short data16[MAXELEMENTS];
1687fc89c0fbSmrg	static unsigned long data32[MAXELEMENTS];
1688fc89c0fbSmrg	unsigned long intvalue;
1689fc89c0fbSmrg	char * value2 = strdup(value);
1690fc89c0fbSmrg	char * tmp = strtok(value2,",");
1691fc89c0fbSmrg	nelements = 1;
1692fc89c0fbSmrg	intvalue = strtoul(tmp, NULL, 0);
1693fc89c0fbSmrg	switch(size) {
1694fc89c0fbSmrg	    case 8:
1695fc89c0fbSmrg	        data8[0] = intvalue; data = (unsigned char *) data8; break;
1696fc89c0fbSmrg	    case 16:
1697fc89c0fbSmrg	        data16[0] = intvalue; data = (unsigned char *) data16; break;
1698fc89c0fbSmrg	    case 32:
1699fc89c0fbSmrg	        data32[0] = intvalue; data = (unsigned char *) data32; break;
1700fc89c0fbSmrg	}
1701fc89c0fbSmrg	tmp = strtok(NULL,",");
1702fc89c0fbSmrg	while(tmp != NULL){
1703fc89c0fbSmrg	    intvalue = strtoul(tmp, NULL,0);
1704fc89c0fbSmrg	    switch(size) {
1705fc89c0fbSmrg		case 8:
1706fc89c0fbSmrg	    	    data8[nelements] = intvalue; break;
1707fc89c0fbSmrg		case 16:
1708fc89c0fbSmrg	    	    data16[nelements] = intvalue; break;
1709fc89c0fbSmrg		case 32:
1710fc89c0fbSmrg	    	    data32[nelements] = intvalue; break;
1711fc89c0fbSmrg	    }
1712fc89c0fbSmrg	    nelements++;
1713fc89c0fbSmrg	    if(nelements == MAXELEMENTS){
1714fc89c0fbSmrg		fprintf(stderr, "Maximum number of elements reached (%d). List truncated.\n",MAXELEMENTS);
1715fc89c0fbSmrg		break;
1716fc89c0fbSmrg	    }
1717fc89c0fbSmrg	    tmp = strtok(NULL,",");
1718fc89c0fbSmrg	}
1719fc89c0fbSmrg
1720fc89c0fbSmrg	type = XA_INTEGER;
1721fc89c0fbSmrg	free(value2);
1722fc89c0fbSmrg	break;
1723fc89c0fbSmrg      }
1724fc89c0fbSmrg      case 'b': {
1725fc89c0fbSmrg	unsigned long boolvalue;
1726fc89c0fbSmrg	static unsigned char data8;
1727fc89c0fbSmrg	static unsigned short data16;
1728fc89c0fbSmrg	static unsigned long data32;
1729fc89c0fbSmrg	if (!strcmp(value, "True"))
1730fc89c0fbSmrg	    boolvalue = 1;
1731fc89c0fbSmrg	else if (!strcmp(value, "False"))
1732fc89c0fbSmrg	    boolvalue = 0;
1733fc89c0fbSmrg	else {
1734fc89c0fbSmrg	    fprintf(stderr, "cannot convert %s argument to Bool\n", propname);
1735fc89c0fbSmrg	    return;
1736fc89c0fbSmrg	}
1737fc89c0fbSmrg	type = XA_INTEGER;
1738fc89c0fbSmrg	switch (size) {
1739fc89c0fbSmrg	  case 8:
1740fc89c0fbSmrg	    data8 = boolvalue; data = (unsigned char *) &data8; break;
1741fc89c0fbSmrg	  case 16:
1742fc89c0fbSmrg	    data16 = boolvalue; data = (unsigned char *) &data16; break;
1743fc89c0fbSmrg	  case 32: default:
1744fc89c0fbSmrg	    data32 = boolvalue; data = (unsigned char *) &data32; break;
1745fc89c0fbSmrg	}
1746fc89c0fbSmrg	nelements = 1;
1747fc89c0fbSmrg	break;
1748fc89c0fbSmrg      }
1749fc89c0fbSmrg      case 'a': {
1750fc89c0fbSmrg	static Atom avalue;
1751fc89c0fbSmrg	avalue = Parse_Atom(value, False);
1752fc89c0fbSmrg	type = XA_ATOM;
1753fc89c0fbSmrg	data = (unsigned char *) &avalue;
1754fc89c0fbSmrg	nelements = 1;
1755fc89c0fbSmrg	break;
1756fc89c0fbSmrg      }
1757fc89c0fbSmrg      case 'm':
1758fc89c0fbSmrg	/* NYI */
1759fc89c0fbSmrg      default:
1760fc89c0fbSmrg	Fatal_Error("bad format character: %c", format_char);
1761fc89c0fbSmrg    }
1762fc89c0fbSmrg
1763fc89c0fbSmrg    XChangeProperty(dpy, target_win, atom, type, size, PropModeReplace,
1764fc89c0fbSmrg		    data, nelements);
1765fc89c0fbSmrg}
1766fc89c0fbSmrg
1767fc89c0fbSmrg/*
1768fc89c0fbSmrg *
1769fc89c0fbSmrg * Routines for parsing command line:
1770fc89c0fbSmrg *
1771fc89c0fbSmrg */
1772fc89c0fbSmrg
1773fc89c0fbSmrgvoid
1774fc89c0fbSmrgusage (void)
1775fc89c0fbSmrg{
1776fc89c0fbSmrg    static const char help_message[] =
1777fc89c0fbSmrg"where options include:\n"
1778fc89c0fbSmrg"    -grammar                       print out full grammar for command line\n"
1779fc89c0fbSmrg"    -display host:dpy              the X server to contact\n"
1780fc89c0fbSmrg"    -id id                         resource id of window to examine\n"
1781fc89c0fbSmrg"    -name name                     name of window to examine\n"
1782fc89c0fbSmrg"    -font name                     name of font to examine\n"
1783fc89c0fbSmrg"    -remove propname               remove a property\n"
1784fc89c0fbSmrg"    -set propname value            set a property to a given value\n"
1785fc89c0fbSmrg"    -root                          examine the root window\n"
1786fc89c0fbSmrg"    -len n                         display at most n bytes of any property\n"
1787fc89c0fbSmrg"    -notype                        do not display the type field\n"
1788fc89c0fbSmrg"    -fs filename                   where to look for formats for properties\n"
1789fc89c0fbSmrg"    -frame                         don't ignore window manager frames\n"
1790fc89c0fbSmrg"    -f propname format [dformat]   formats to use for property of given name\n"
1791fc89c0fbSmrg"    -spy                           examine window properties forever\n";
1792fc89c0fbSmrg
1793fc89c0fbSmrg
1794fc89c0fbSmrg    fflush (stdout);
1795fc89c0fbSmrg    fprintf (stderr,
1796fc89c0fbSmrg	     "usage:  %s [-options ...] [[format [dformat]] atom] ...\n\n",
1797fc89c0fbSmrg	     program_name);
1798fc89c0fbSmrg    fprintf (stderr, "%s\n", help_message);
1799fc89c0fbSmrg    exit (1);
1800fc89c0fbSmrg}
1801fc89c0fbSmrg
1802fc89c0fbSmrgstatic void
1803fc89c0fbSmrggrammar (void)
1804fc89c0fbSmrg{
1805fc89c0fbSmrg    printf ("Grammar for xprop:\n\n");
1806fc89c0fbSmrg    printf("\t%s [<disp>] [<select option>] <option>* <mapping>* <spec>*",
1807fc89c0fbSmrg	   program_name);
1808fc89c0fbSmrg    printf("\n\n\tdisp ::= -display host:dpy\
1809fc89c0fbSmrg\n\tselect option ::= -root | -id <id> | -font <font> | -name <name>\
1810fc89c0fbSmrg\n\toption ::= -len <n> | -notype | -spy | {-formats|-fs} <format file>\
1811fc89c0fbSmrg\n\tmapping ::= {-f|-format} <atom> <format> [<dformat>]\
1812fc89c0fbSmrg\n\t            | -remove <propname>\
1813fc89c0fbSmrg\n\t            | -set <propname> <value>\
1814fc89c0fbSmrg\n\tspec ::= [<format> [<dformat>]] <atom>\
1815fc89c0fbSmrg\n\tformat ::= {0|8|16|32}{a|b|c|i|m|s|t|x}*\
1816fc89c0fbSmrg\n\tdformat ::= <unit><unit>*             (can't start with a letter or '-')\
1817fc89c0fbSmrg\n\tunit ::= ?<exp>(<unit>*) | $<n> | <display char>\
1818fc89c0fbSmrg\n\texp ::= <term> | <term>=<exp> | !<exp>\
1819fc89c0fbSmrg\n\tterm ::= <n> | $<n> | m<n>\
1820fc89c0fbSmrg\n\tdisplay char ::= <normal char> | \\<non digit char> | \\<octal number>\
1821fc89c0fbSmrg\n\tnormal char ::= <any char except a digit, $, ?, \\, or )>\
1822fc89c0fbSmrg\n\n");
1823fc89c0fbSmrg    exit(0);
1824fc89c0fbSmrg}
1825fc89c0fbSmrg
1826fc89c0fbSmrgstatic void
1827fc89c0fbSmrgParse_Format_Mapping (int *argc, char ***argv)
1828fc89c0fbSmrg{
1829fc89c0fbSmrg#define ARGC (*argc)
1830fc89c0fbSmrg#define ARGV (*argv)
1831fc89c0fbSmrg#define OPTION ARGV[0]
1832fc89c0fbSmrg#define NXTOPT if (++ARGV, --ARGC==0) usage()
1833fc89c0fbSmrg    char *type_name, *format, *dformat;
1834fc89c0fbSmrg
1835fc89c0fbSmrg    NXTOPT; type_name = OPTION;
1836fc89c0fbSmrg
1837fc89c0fbSmrg    NXTOPT; format = OPTION;
1838fc89c0fbSmrg    if (!Is_A_Format(format))
1839fc89c0fbSmrg	Fatal_Error("Bad format: %s.", format);
1840fc89c0fbSmrg
1841fc89c0fbSmrg    dformat = NULL;
1842fc89c0fbSmrg    if (ARGC>1 && Is_A_DFormat(ARGV[1])) {
1843fc89c0fbSmrg	ARGV++; ARGC--; dformat = OPTION;
1844fc89c0fbSmrg    }
1845fc89c0fbSmrg
1846fc89c0fbSmrg    Add_Mapping(Parse_Atom(type_name, False), format, dformat);
1847fc89c0fbSmrg}
1848fc89c0fbSmrg
1849fc89c0fbSmrg/*
1850fc89c0fbSmrg *
1851fc89c0fbSmrg * The Main Program:
1852fc89c0fbSmrg *
1853fc89c0fbSmrg */
1854fc89c0fbSmrg
1855fc89c0fbSmrgstatic int spy = 0;
1856fc89c0fbSmrg
185791ec45ceSmrgstatic int (*old_error_handler)(Display *dpy, XErrorEvent *ev);
185891ec45ceSmrg
185991ec45ceSmrgstatic int spy_error_handler(Display *dpy, XErrorEvent *ev)
186091ec45ceSmrg{
186191ec45ceSmrg    if (ev->error_code == BadWindow || ev->error_code == BadMatch) {
186291ec45ceSmrg	/* Window was destroyed */
186391ec45ceSmrg	puts("");
186491ec45ceSmrg	exit(0);
186591ec45ceSmrg    }
186691ec45ceSmrg
186791ec45ceSmrg    if (old_error_handler)
186891ec45ceSmrg	return old_error_handler(dpy, ev);
186991ec45ceSmrg
187091ec45ceSmrg    return 0;
187191ec45ceSmrg}
187291ec45ceSmrg
1873fc89c0fbSmrgint
1874fc89c0fbSmrgmain (int argc, char **argv)
1875fc89c0fbSmrg{
1876fc89c0fbSmrg    FILE *stream;
1877fc89c0fbSmrg    char *name;
1878fc89c0fbSmrg    thunk *props;
1879fc89c0fbSmrg    thunk *remove_props = NULL;
1880fc89c0fbSmrg    thunk *set_props = NULL;
1881fc89c0fbSmrg    Bool frame_only = False;
1882fc89c0fbSmrg    int n;
1883fc89c0fbSmrg    char **nargv;
1884fc89c0fbSmrg
1885fc89c0fbSmrg    INIT_NAME;
1886fc89c0fbSmrg
1887fc89c0fbSmrg    /* Set locale for XmbTextProptertyToTextList and iswprint(). */
1888fc89c0fbSmrg    setlocale(LC_CTYPE, "");
1889fc89c0fbSmrg
1890fc89c0fbSmrg    /* Handle display name, opening the display */
1891fc89c0fbSmrg    Setup_Display_And_Screen(&argc, argv);
1892fc89c0fbSmrg
1893fc89c0fbSmrg    /* Handle selecting the window to display properties for */
1894fc89c0fbSmrg    target_win = Select_Window_Args(&argc, argv);
1895fc89c0fbSmrg
1896fc89c0fbSmrg    /* Set up default atom to format, dformat mapping */
1897fc89c0fbSmrg    XpropMode = XpropWindowProperties;
1898fc89c0fbSmrg    for (n = argc, nargv = argv; n; nargv++, n--)
1899fc89c0fbSmrg	if (! strcmp(nargv[0], "-font")) {
1900fc89c0fbSmrg	    XpropMode = XpropFontProperties;
1901fc89c0fbSmrg	    break;
1902fc89c0fbSmrg	}
1903fc89c0fbSmrg    Setup_Mapping();
1904fc89c0fbSmrg    if ((name = getenv("XPROPFORMATS"))) {
1905fc89c0fbSmrg	if (!(stream = fopen(name, "r")))
1906fc89c0fbSmrg	    Fatal_Error("unable to open file %s for reading.", name);
1907fc89c0fbSmrg	Read_Mappings(stream);
1908fc89c0fbSmrg	fclose(stream);
1909fc89c0fbSmrg    }
1910fc89c0fbSmrg
1911fc89c0fbSmrg    /* Handle '-' options to setup xprop, select window to work on */
1912fc89c0fbSmrg    while (argv++, --argc>0 && **argv == '-') {
1913fc89c0fbSmrg	if (!strcmp(argv[0], "-"))
1914fc89c0fbSmrg	    continue;
1915fc89c0fbSmrg	if (!strcmp(argv[0], "-grammar")) {
1916fc89c0fbSmrg	    grammar ();
1917fc89c0fbSmrg	    /* NOTREACHED */
1918fc89c0fbSmrg	}
1919fc89c0fbSmrg	if (!strcmp(argv[0], "-notype")) {
1920fc89c0fbSmrg	    notype = 1;
1921fc89c0fbSmrg	    continue;
1922fc89c0fbSmrg	}
1923fc89c0fbSmrg	if (!strcmp(argv[0], "-spy")) {
1924fc89c0fbSmrg	    spy = 1;
1925fc89c0fbSmrg	    continue;
1926fc89c0fbSmrg	}
1927fc89c0fbSmrg	if (!strcmp(argv[0], "-len")) {
1928fc89c0fbSmrg	    if (++argv, --argc == 0) usage();
1929fc89c0fbSmrg	    max_len = atoi(argv[0]);
1930fc89c0fbSmrg	    continue;
1931fc89c0fbSmrg	}
1932fc89c0fbSmrg	if (!strcmp(argv[0], "-formats") || !strcmp(argv[0], "-fs")) {
1933fc89c0fbSmrg	    if (++argv, --argc == 0) usage();
1934fc89c0fbSmrg	    if (!(stream = fopen(argv[0], "r")))
1935fc89c0fbSmrg		Fatal_Error("unable to open file %s for reading.", argv[0]);
1936fc89c0fbSmrg	    Read_Mappings(stream);
1937fc89c0fbSmrg	    fclose(stream);
1938fc89c0fbSmrg	    continue;
1939fc89c0fbSmrg	}
1940fc89c0fbSmrg	if (!strcmp(argv[0], "-font")) {
1941fc89c0fbSmrg	    if (++argv, --argc == 0) usage();
1942fc89c0fbSmrg	    font = Open_Font(argv[0]);
1943fc89c0fbSmrg	    target_win = -1;
1944fc89c0fbSmrg	    continue;
1945fc89c0fbSmrg	}
1946fc89c0fbSmrg	if (!strcmp(argv[0], "-remove")) {
1947fc89c0fbSmrg	    thunk t;
1948fc89c0fbSmrg	    if (++argv, --argc == 0) usage();
1949fc89c0fbSmrg	    t.propname = argv[0];
1950fc89c0fbSmrg	    if (remove_props == NULL) remove_props = Create_Thunk_List();
1951fc89c0fbSmrg	    remove_props = Add_Thunk(remove_props, t);
1952fc89c0fbSmrg	    continue;
1953fc89c0fbSmrg	}
1954fc89c0fbSmrg	if (!strcmp(argv[0], "-set")) {
1955fc89c0fbSmrg	    thunk t;
1956fc89c0fbSmrg	    if (argc < 3) usage();
1957fc89c0fbSmrg	    t.propname = argv[1];
1958fc89c0fbSmrg	    t.extra_value = argv[2];
1959fc89c0fbSmrg	    argv += 3; argc -= 3;
1960fc89c0fbSmrg	    if (set_props == NULL) set_props = Create_Thunk_List();
1961fc89c0fbSmrg	    set_props = Add_Thunk(set_props, t);
1962fc89c0fbSmrg	    continue;
1963fc89c0fbSmrg	}
1964fc89c0fbSmrg	if (!strcmp(argv[0], "-frame")) {
1965fc89c0fbSmrg	    frame_only = True;
1966fc89c0fbSmrg	    continue;
1967fc89c0fbSmrg	}
1968fc89c0fbSmrg	if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "-format")) {
1969fc89c0fbSmrg	    Parse_Format_Mapping(&argc, &argv);
1970fc89c0fbSmrg	    continue;
1971fc89c0fbSmrg	}
1972fc89c0fbSmrg	usage();
1973fc89c0fbSmrg    }
1974fc89c0fbSmrg
1975fc89c0fbSmrg    if ((remove_props != NULL || set_props != NULL) && argc > 0)
1976fc89c0fbSmrg	usage();
1977fc89c0fbSmrg
197891ec45ceSmrg    if (target_win == None)
197991ec45ceSmrg	target_win = Select_Window(dpy, !frame_only);
1980fc89c0fbSmrg
1981fc89c0fbSmrg    if (remove_props != NULL) {
1982fc89c0fbSmrg	int count;
1983fc89c0fbSmrg
1984fc89c0fbSmrg	if (target_win == -1)
1985fc89c0fbSmrg	    Fatal_Error("-remove works only on windows, not fonts");
1986fc89c0fbSmrg
1987fc89c0fbSmrg	count = remove_props->thunk_count;
1988fc89c0fbSmrg	for (; count > 0; remove_props++, count--)
1989fc89c0fbSmrg	    Remove_Property (dpy, target_win, remove_props->propname);
1990fc89c0fbSmrg    }
1991fc89c0fbSmrg
1992fc89c0fbSmrg    if (set_props != NULL) {
1993fc89c0fbSmrg	int count;
1994fc89c0fbSmrg
1995fc89c0fbSmrg	if (target_win == -1)
1996fc89c0fbSmrg	    Fatal_Error("-set works only on windows, not fonts");
1997fc89c0fbSmrg
1998fc89c0fbSmrg	count = set_props->thunk_count;
1999fc89c0fbSmrg	for (; count > 0; set_props++, count--)
2000fc89c0fbSmrg	    Set_Property (dpy, target_win, set_props->propname,
2001fc89c0fbSmrg			  set_props->extra_value);
2002fc89c0fbSmrg    }
2003fc89c0fbSmrg
2004fc89c0fbSmrg    if (remove_props != NULL || set_props != NULL) {
2005fc89c0fbSmrg	XCloseDisplay (dpy);
2006fc89c0fbSmrg	exit (0);
2007fc89c0fbSmrg    }
2008fc89c0fbSmrg
2009fc89c0fbSmrg    props = Handle_Prop_Requests(argc, argv);
2010fc89c0fbSmrg
2011fc89c0fbSmrg    if (spy && target_win != -1) {
2012fc89c0fbSmrg	XEvent event;
2013fc89c0fbSmrg	const char *format, *dformat;
2014fc89c0fbSmrg
201591ec45ceSmrg	XSelectInput(dpy, target_win, PropertyChangeMask | StructureNotifyMask);
201691ec45ceSmrg 	old_error_handler = XSetErrorHandler(spy_error_handler);
2017fc89c0fbSmrg	for (;;) {
201891ec45ceSmrg	    fflush(stdout);
2019fc89c0fbSmrg	    XNextEvent(dpy, &event);
202091ec45ceSmrg 	    if (event.type == DestroyNotify)
202191ec45ceSmrg 		break;
202291ec45ceSmrg 	    if (event.type != PropertyNotify)
202391ec45ceSmrg 		continue;
2024fc89c0fbSmrg	    format = dformat = NULL;
2025fc89c0fbSmrg	    if (props) {
2026fc89c0fbSmrg		int i;
2027fc89c0fbSmrg		for (i = 0; i < props->thunk_count; i++)
2028fc89c0fbSmrg		    if (props[i].value == event.xproperty.atom)
2029fc89c0fbSmrg			break;
2030fc89c0fbSmrg		if (i >= props->thunk_count)
2031fc89c0fbSmrg		    continue;
2032fc89c0fbSmrg		format = props[i].format;
2033fc89c0fbSmrg		dformat = props[i].dformat;
2034fc89c0fbSmrg	    }
2035fc89c0fbSmrg	    Show_Prop(format, dformat, Format_Atom(event.xproperty.atom));
2036fc89c0fbSmrg	}
2037fc89c0fbSmrg    }
2038fc89c0fbSmrg    exit (0);
2039fc89c0fbSmrg}
2040