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