summaryrefslogtreecommitdiff
path: root/xprop.c
diff options
context:
space:
mode:
Diffstat (limited to 'xprop.c')
-rw-r--r--xprop.c1516
1 files changed, 1516 insertions, 0 deletions
diff --git a/xprop.c b/xprop.c
new file mode 100644
index 0000000..0d8f32d
--- /dev/null
+++ b/xprop.c
@@ -0,0 +1,1516 @@
+/* $Xorg: xprop.c,v 1.6 2001/02/09 02:05:56 xorgcvs Exp $ */
+/*
+
+Copyright 1990, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+
+
+#include <X11/Xlib.h>
+#include <X11/Xos.h>
+#include <X11/Xfuncs.h>
+#include <X11/Xutil.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include <X11/Xatom.h>
+#include <X11/Xmu/WinUtil.h>
+
+#include "dsimple.h"
+
+#ifndef X_NOT_STDC_ENV
+#include <stdlib.h>
+#else
+char *getenv();
+#endif
+
+#define MAXSTR 10000
+
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+/*
+ *
+ * The Thunk Manager - routines to create, add to, and free thunk lists
+ *
+ */
+
+typedef struct {
+ int thunk_count;
+ long value;
+ char *extra_value;
+ char *format;
+ char *dformat;
+} thunk;
+
+thunk *Create_Thunk_List()
+{
+ thunk *tptr;
+
+ tptr = (thunk *) Malloc( sizeof(thunk) );
+
+ tptr->thunk_count = 0;
+
+ return(tptr);
+}
+
+Free_Thunk_List(list)
+thunk *list;
+{
+ free(list);
+}
+
+thunk *Add_Thunk(list, t)
+thunk *list;
+thunk t;
+{
+ int i;
+
+ i = list->thunk_count;
+
+ list = (thunk *) realloc(list, (i+1)*sizeof(thunk) );
+ if (!list)
+ Fatal_Error("Out of memory!");
+
+ list[i++] = t;
+ list->thunk_count = i;
+
+ return(list);
+}
+
+/*
+ * Misc. routines
+ */
+
+char *Copy_String(string)
+ char *string;
+{
+ char *new;
+ int length;
+
+ length = strlen(string) + 1;
+
+ new = (char *) Malloc(length);
+ memmove( new, string, length);
+
+ return(new);
+}
+
+int Read_Char(stream)
+ FILE *stream;
+{
+ int c;
+
+ c = getc(stream);
+ if (c==EOF)
+ Fatal_Error("Bad format file: Unexpected EOF.");
+ return(c);
+}
+
+Read_White_Space(stream)
+ FILE *stream;
+{
+ int c;
+
+ while ((c=getc(stream))==' ' || c=='\n' || c=='\t');
+ ungetc(c, stream);
+}
+
+static char _large_buffer[MAXSTR+10];
+
+char *Read_Quoted(stream)
+ FILE *stream;
+{
+ char *ptr;
+ int c, length;
+
+ Read_White_Space(stream);
+ if (Read_Char(stream)!='\'')
+ Fatal_Error("Bad format file format: missing dformat.");
+
+ ptr = _large_buffer; length=MAXSTR;
+ for (;;) {
+ if (length<0)
+ Fatal_Error("Bad format file format: dformat too long.");
+ c = Read_Char(stream);
+ if (c==(int) '\'')
+ break;
+ ptr++[0]=c; length--;
+ if (c== (int) '\\') {
+ c=Read_Char(stream);
+ if (c=='\n') {
+ ptr--; length++;
+ } else
+ ptr++[0]=c; length--;
+ }
+ }
+ ptr++[0]='\0';
+
+ return(Copy_String(_large_buffer));
+}
+
+/*
+ *
+ * Atom to format, dformat mapping Manager
+ *
+ */
+
+#define D_FORMAT "0x" /* Default format for properties */
+#define D_DFORMAT " = $0+\n" /* Default display pattern for properties */
+
+static thunk *_property_formats = 0; /* Holds mapping */
+
+Apply_Default_Formats(format, dformat)
+ char **format;
+ char **dformat;
+{
+ if (!*format)
+ *format = D_FORMAT;
+ if (!*dformat)
+ *dformat = D_DFORMAT;
+}
+
+Lookup_Formats(atom, format, dformat)
+ Atom atom;
+ char **format;
+ char **dformat;
+{
+ int i;
+
+ if (_property_formats)
+ for (i=_property_formats->thunk_count-1; i>=0; i--)
+ if (_property_formats[i].value==atom) {
+ if (!*format)
+ *format = _property_formats[i].format;
+ if (!*dformat)
+ *dformat = _property_formats[i].dformat;
+ break;
+ }
+}
+
+Add_Mapping(atom, format, dformat)
+ Atom atom;
+ char *format;
+ char *dformat;
+{
+ thunk t;
+
+ if (!_property_formats)
+ _property_formats = Create_Thunk_List();
+
+ t.value=atom;
+ t.format=format;
+ t.dformat=dformat;
+
+ _property_formats = Add_Thunk(_property_formats, t);
+}
+
+/*
+ *
+ * Setup_Mapping: Routine to setup default atom to format, dformat mapping:
+ *
+ */
+
+typedef struct _propertyRec {
+ char * name;
+ Atom atom;
+ char * format;
+ char * dformat;
+} propertyRec;
+
+#define ARC_DFORMAT ":\n\
+\t\tarc at $0, $1\n\
+\t\tsize: $2 by $3\n\
+\t\tfrom angle $4 to angle $5\n"
+
+#define RECTANGLE_DFORMAT ":\n\
+\t\tupper left corner: $0, $1\n\
+\t\tsize: $2 by $3\n"
+
+#define RGB_COLOR_MAP_DFORMAT ":\n\
+\t\tcolormap id #: $0\n\
+\t\tred-max: $1\n\
+\t\tred-mult: $2\n\
+\t\tgreen-max: $3\n\
+\t\tgreen-mult: $4\n\
+\t\tblue-max: $5\n\
+\t\tblue-mult: $6\n\
+\t\tbase-pixel: $7\n\
+\t\tvisual id #: $8\n\
+\t\tkill id #: $9\n"
+
+#define WM_HINTS_DFORMAT ":\n\
+?m0(\t\tClient accepts input or input focus: $1\n)\
+?m1(\t\tInitial state is \
+?$2=0(Don't Care State)\
+?$2=1(Normal State)\
+?$2=2(Zoomed State)\
+?$2=3(Iconic State)\
+?$2=4(Inactive State)\
+.\n)\
+?m2(\t\tbitmap id # to use for icon: $3\n)\
+?m5(\t\tbitmap id # of mask for icon: $7\n)\
+?m3(\t\twindow id # to use for icon: $4\n)\
+?m4(\t\tstarting position for icon: $5, $6\n)\
+?m6(\t\twindow id # of group leader: $8\n)\
+?m8(\t\tThe visible hint bit is set\n)"
+
+#define WM_ICON_SIZE_DFORMAT ":\n\
+\t\tminimum icon size: $0 by $1\n\
+\t\tmaximum icon size: $2 by $3\n\
+\t\tincremental size change: $4 by $5\n"
+
+#define WM_SIZE_HINTS_DFORMAT ":\n\
+?m0(\t\tuser specified location: $1, $2\n)\
+?m2(\t\tprogram specified location: $1, $2\n)\
+?m1(\t\tuser specified size: $3 by $4\n)\
+?m3(\t\tprogram specified size: $3 by $4\n)\
+?m4(\t\tprogram specified minimum size: $5 by $6\n)\
+?m5(\t\tprogram specified maximum size: $7 by $8\n)\
+?m6(\t\tprogram specified resize increment: $9 by $10\n)\
+?m7(\t\tprogram specified minimum aspect ratio: $11/$12\n\
+\t\tprogram specified maximum aspect ratio: $13/$14\n)\
+?m8(\t\tprogram specified base size: $15 by $16\n)\
+?m9(\t\twindow gravity: \
+?$17=0(Forget)\
+?$17=1(NorthWest)\
+?$17=2(North)\
+?$17=3(NorthEast)\
+?$17=4(West)\
+?$17=5(Center)\
+?$17=6(East)\
+?$17=7(SouthWest)\
+?$17=8(South)\
+?$17=9(SouthEast)\
+?$17=10(Static)\
+\n)"
+
+#define WM_STATE_DFORMAT ":\n\
+\t\twindow state: ?$0=0(Withdrawn)?$0=1(Normal)?$0=3(Iconic)\n\
+\t\ticon window: $1\n"
+
+propertyRec windowPropTable[] = {
+ {"ARC", XA_ARC, "16iiccii", ARC_DFORMAT },
+ {"ATOM", XA_ATOM, "32a", 0 },
+ {"BITMAP", XA_BITMAP, "32x", ": bitmap id # $0\n" },
+ {"CARDINAL", XA_CARDINAL, "0c", 0 },
+ {"COLORMAP", XA_COLORMAP, "32x", ": colormap id # $0\n" },
+ {"CURSOR", XA_CURSOR, "32x", ": cursor id # $0\n" },
+ {"DRAWABLE", XA_DRAWABLE, "32x", ": drawable id # $0\n" },
+ {"FONT", XA_FONT, "32x", ": font id # $0\n" },
+ {"INTEGER", XA_INTEGER, "0i", 0 },
+ {"PIXMAP", XA_PIXMAP, "32x", ": pixmap id # $0\n" },
+ {"POINT", XA_POINT, "16ii", " = $0, $1\n" },
+ {"RECTANGLE", XA_RECTANGLE, "16iicc", RECTANGLE_DFORMAT },
+ {"RGB_COLOR_MAP", XA_RGB_COLOR_MAP,"32xcccccccxx",RGB_COLOR_MAP_DFORMAT},
+ {"STRING", XA_STRING, "8s", 0 },
+ {"WINDOW", XA_WINDOW, "32x", ": window id # $0\n" },
+ {"VISUALID", XA_VISUALID, "32x", ": visual id # $0\n" },
+ {"WM_COLORMAP_WINDOWS", 0, "32x", ": window id # $0+\n"},
+ {"WM_COMMAND", XA_WM_COMMAND, "8s", " = { $0+ }\n" },
+ {"WM_HINTS", XA_WM_HINTS, "32mbcxxiixx", WM_HINTS_DFORMAT },
+ {"WM_ICON_SIZE", XA_WM_ICON_SIZE, "32cccccc", WM_ICON_SIZE_DFORMAT},
+ {"WM_PROTOCOLS", 0, "32a", ": protocols $0+\n"},
+ {"WM_SIZE_HINTS", XA_WM_SIZE_HINTS,"32mii", WM_SIZE_HINTS_DFORMAT },
+ {"WM_STATE", 0, "32cx", WM_STATE_DFORMAT}
+};
+#undef ARC_DFORMAT
+#undef RECTANGLE_DFORMAT
+#undef RGB_COLOR_MAP_DFORMAT
+#undef WM_ICON_SIZE_DFORMAT
+#undef WM_HINTS_DFORMAT
+#undef WM_SIZE_HINTS_DFORMAT
+#undef WM_STATE_DFORMAT
+
+/*
+ * Font-specific mapping of property names to types:
+ */
+propertyRec fontPropTable[] = {
+
+ /* XLFD name properties */
+
+ "FOUNDRY", 0, "32a", 0,
+ "FAMILY_NAME", XA_FAMILY_NAME, "32a", 0,
+ "WEIGHT_NAME", 0, "32a", 0,
+ "SLANT", 0, "32a", 0,
+ "SETWIDTH_NAME", 0, "32a", 0,
+ "ADD_STYLE_NAME", 0, "32a", 0,
+ "PIXEL_SIZE", 0, "32c", 0,
+ "POINT_SIZE", XA_POINT_SIZE, "32c", 0,
+ "RESOLUTION_X", 0, "32c", 0,
+ "RESOLUTION_Y", 0, "32c", 0,
+ "SPACING", 0, "32a", 0,
+ "AVERAGE_WIDTH", 0, "32c", 0,
+ "CHARSET_REGISTRY", 0, "32a", 0,
+ "CHARSET_ENCODING", 0, "32a", 0,
+
+ /* other font properties referenced in the XLFD */
+
+ "QUAD_WIDTH", XA_QUAD_WIDTH, "32i", 0,
+ "RESOLUTION", XA_RESOLUTION, "32c", 0,
+ "MIN_SPACE", XA_MIN_SPACE, "32c", 0,
+ "NORM_SPACE", XA_NORM_SPACE, "32c", 0,
+ "MAX_SPACE", XA_MAX_SPACE, "32c", 0,
+ "END_SPACE", XA_END_SPACE, "32c", 0,
+ "SUPERSCRIPT_X", XA_SUPERSCRIPT_X, "32i", 0,
+ "SUPERSCRIPT_Y", XA_SUPERSCRIPT_Y, "32i", 0,
+ "SUBSCRIPT_X", XA_SUBSCRIPT_X, "32i", 0,
+ "SUBSCRIPT_Y", XA_SUBSCRIPT_Y, "32i", 0,
+ "UNDERLINE_POSITION", XA_UNDERLINE_POSITION, "32i", 0,
+ "UNDERLINE_THICKNESS", XA_UNDERLINE_THICKNESS, "32i", 0,
+ "STRIKEOUT_ASCENT", XA_STRIKEOUT_ASCENT, "32i", 0,
+ "STRIKEOUT_DESCENT", XA_STRIKEOUT_DESCENT, "32i", 0,
+ "ITALIC_ANGLE", XA_ITALIC_ANGLE, "32i", 0,
+ "X_HEIGHT", XA_X_HEIGHT, "32i", 0,
+ "WEIGHT", XA_WEIGHT, "32i", 0,
+ "FACE_NAME", 0, "32a", 0,
+ "COPYRIGHT", XA_COPYRIGHT, "32a", 0,
+ "AVG_CAPITAL_WIDTH", 0, "32i", 0,
+ "AVG_LOWERCASE_WIDTH", 0, "32i", 0,
+ "RELATIVE_SETWIDTH", 0, "32c", 0,
+ "RELATIVE_WEIGHT", 0, "32c", 0,
+ "CAP_HEIGHT", XA_CAP_HEIGHT, "32c", 0,
+ "SUPERSCRIPT_SIZE", 0, "32c", 0,
+ "FIGURE_WIDTH", 0, "32i", 0,
+ "SUBSCRIPT_SIZE", 0, "32c", 0,
+ "SMALL_CAP_SIZE", 0, "32i", 0,
+ "NOTICE", XA_NOTICE, "32a", 0,
+ "DESTINATION", 0, "32c", 0,
+
+ /* other font properties */
+
+ "FONT", XA_FONT, "32a", 0,
+ "FONT_NAME", XA_FONT_NAME, "32a", 0,
+};
+
+static int XpropMode;
+#define XpropWindowProperties 0
+#define XpropFontProperties 1
+
+Setup_Mapping()
+{
+ int n;
+ propertyRec *p;
+
+ if (XpropMode == XpropWindowProperties) {
+ n = sizeof(windowPropTable) / sizeof(propertyRec);
+ p = windowPropTable;
+ } else {
+ n = sizeof (fontPropTable) / sizeof (propertyRec);
+ p = fontPropTable;
+ }
+ for ( ; --n >= 0; p++) {
+ if (! p->atom) {
+ p->atom = XInternAtom(dpy, p->name, True);
+ if (p->atom == None)
+ continue;
+ }
+ Add_Mapping(p->atom, p->format, p->dformat);
+ }
+}
+
+char *GetAtomName(atom)
+ Atom atom;
+{
+ int n;
+ propertyRec *p;
+
+ if (XpropMode == XpropWindowProperties) {
+ n = sizeof(windowPropTable) / sizeof(propertyRec);
+ p = windowPropTable;
+ } else {
+ n = sizeof (fontPropTable) / sizeof (propertyRec);
+ p = fontPropTable;
+ }
+ for ( ; --n >= 0; p++)
+ if (p->atom == atom)
+ return p->name;
+
+ return (char *) NULL;
+}
+
+/*
+ * Read_Mapping: routine to read in additional mappings from a stream
+ * already open for reading.
+ */
+
+Read_Mappings(stream)
+ FILE *stream;
+{
+ char format_buffer[100];
+ char name[1000], *dformat, *format;
+ int count, c;
+ Atom atom, Parse_Atom();
+
+ while ((count=fscanf(stream," %990s %90s ",name,format_buffer))!=EOF) {
+ if (count != 2)
+ Fatal_Error("Bad format file format.");
+
+ atom = Parse_Atom(name, False);
+ format = Copy_String(format_buffer);
+
+ Read_White_Space(stream);
+ dformat = D_DFORMAT;
+ c = getc(stream);
+ ungetc(c, stream);
+ if (c==(int)'\'')
+ dformat = Read_Quoted(stream);
+
+ Add_Mapping(atom, format, dformat);
+ }
+}
+
+/*
+ *
+ * Formatting Routines: a group of routines to translate from various
+ * values to a static read-only string useful for output.
+ *
+ * Routines: Format_Hex, Format_Unsigned, Format_Signed, Format_Atom,
+ * Format_Mask_Word, Format_Bool, Format_String, Format_Len_String.
+ *
+ * All of the above routines take a long except for Format_String and
+ * Format_Len_String.
+ *
+ */
+static char _formatting_buffer[MAXSTR+100];
+static char _formatting_buffer2[10];
+
+char *Format_Hex(wrd)
+ long wrd;
+{
+ sprintf(_formatting_buffer2, "0x%lx", wrd);
+ return(_formatting_buffer2);
+}
+
+char *Format_Unsigned(wrd)
+ long wrd;
+{
+ sprintf(_formatting_buffer2, "%lu", wrd);
+ return(_formatting_buffer2);
+}
+
+char *Format_Signed(wrd)
+ long wrd;
+{
+ sprintf(_formatting_buffer2, "%ld", wrd);
+ return(_formatting_buffer2);
+}
+
+/*ARGSUSED*/
+int ignore_errors (dpy, ev)
+ Display *dpy;
+ XErrorEvent *ev;
+{
+ return 0;
+}
+
+char *Format_Atom(atom)
+ Atom atom;
+{
+ char *name;
+ int (*handler)();
+
+ if ((name = GetAtomName(atom))) {
+ strncpy(_formatting_buffer, name, MAXSTR);
+ return(_formatting_buffer);
+ }
+
+ handler = XSetErrorHandler (ignore_errors);
+ name=XGetAtomName(dpy, atom);
+ XSetErrorHandler(handler);
+ if (! name)
+ sprintf(_formatting_buffer, "undefined atom # 0x%lx", atom);
+ else {
+ strncpy(_formatting_buffer, name, MAXSTR);
+ XFree(name);
+ }
+ return(_formatting_buffer);
+}
+
+char *Format_Mask_Word(wrd)
+ long wrd;
+{
+ long bit_mask, bit;
+ int seen = 0;
+
+ strcpy(_formatting_buffer, "{MASK: ");
+ for (bit=0, bit_mask=1; bit<=sizeof(long)*8; bit++, bit_mask<<=1) {
+ if (bit_mask & wrd) {
+ if (seen) {
+ strcat(_formatting_buffer, ", ");
+ }
+ seen=1;
+ strcat(_formatting_buffer, Format_Unsigned(bit));
+ }
+ }
+ strcat(_formatting_buffer, "}");
+
+ return(_formatting_buffer);
+}
+
+char *Format_Bool(value)
+ long value;
+{
+ if (!value)
+ return("False");
+
+ return("True");
+}
+
+static char *_buf_ptr;
+static int _buf_len;
+
+_put_char(c)
+ char c;
+{
+ if (--_buf_len<0) {
+ _buf_ptr[0]='\0';
+ return;
+ }
+ _buf_ptr++[0] = c;
+}
+
+_format_char(c)
+ char c;
+{
+ switch (c) {
+ case '\\':
+ case '\"':
+ _put_char('\\');
+ _put_char(c);
+ break;
+ case '\n':
+ _put_char('\\');
+ _put_char('n');
+ break;
+ case '\t':
+ _put_char('\\');
+ _put_char('t');
+ break;
+ default:
+ if (!isprint (c)) {
+ _put_char('\\');
+ sprintf(_buf_ptr, "%o", (int) c);
+ _buf_ptr += strlen(_buf_ptr);
+ _buf_len -= strlen(_buf_ptr);
+ } else
+ _put_char(c);
+ }
+}
+
+char *Format_String(string)
+ char *string;
+{
+ char c;
+
+ _buf_ptr = _formatting_buffer;
+ _buf_len = MAXSTR;
+ _put_char('\"');
+
+ while ((c = string++[0]))
+ _format_char(c);
+
+ _buf_len += 3;
+ _put_char('\"');
+ _put_char('\0');
+ return(_formatting_buffer);
+}
+
+char *Format_Len_String(string, len)
+ char *string;
+ int len;
+{
+ char *data, *result;
+
+ data = (char *) Malloc(len+1);
+
+ memmove( data, string, len);
+ data[len]='\0';
+
+ result = Format_String(data);
+ free(data);
+
+ return(result);
+}
+
+/*
+ *
+ * Parsing Routines: a group of routines to parse strings into values
+ *
+ * Routines: Parse_Atom, Scan_Long, Skip_Past_Right_Paran, Scan_Octal
+ *
+ * Routines of the form Parse_XXX take a string which is parsed to a value.
+ * Routines of the form Scan_XXX take a string, parse the beginning to a value,
+ * and return the rest of the string. The value is returned via. the last
+ * parameter. All numeric values are longs!
+ *
+ */
+
+char *Skip_Digits(string)
+ char *string;
+{
+ while (isdigit(string[0])) string++;
+ return(string);
+}
+
+char *Scan_Long(string, value)
+ char *string;
+ long *value;
+{
+ if (!isdigit(*string))
+ Fatal_Error("Bad number: %s.", string);
+
+ *value = atol(string);
+ return(Skip_Digits(string));
+}
+
+char *Scan_Octal(string, value)
+ char *string;
+ long *value;
+{
+ if (sscanf(string, "%lo", value)!=1)
+ Fatal_Error("Bad octal number: %s.", string);
+ return(Skip_Digits(string));
+}
+
+Atom Parse_Atom(name, only_if_exists)
+ char *name;
+ int only_if_exists;
+{
+ Atom atom;
+
+ if ((atom = XInternAtom(dpy, name, only_if_exists))==None)
+ return(0);
+
+ return(atom);
+}
+
+char *Skip_Past_Right_Paran(string)
+ char *string;
+{
+ char c;
+ int nesting=0;
+
+ while (c=string++[0], c!=')' || nesting)
+ switch (c) {
+ case '\0':
+ Fatal_Error("Missing ')'.");
+ case '(':
+ nesting++;
+ break;
+ case ')':
+ nesting--;
+ break;
+ case '\\':
+ string++;
+ break;
+ }
+ return(string);
+}
+
+/*
+ *
+ * The Format Manager: a group of routines to manage "formats"
+ *
+ */
+
+int Is_A_Format(string)
+char *string;
+{
+ return(isdigit(string[0]));
+}
+
+int Get_Format_Size(format)
+ char *format;
+{
+ long size;
+
+ Scan_Long(format, &size);
+
+ /* Check for legal sizes */
+ if (size != 0 && size != 8 && size != 16 && size != 32)
+ Fatal_Error("bad format: %s", format);
+
+ return((int) size);
+}
+
+char Get_Format_Char(format, i)
+ char *format;
+ int i;
+{
+ long size;
+
+ /* Remove # at front of format */
+ format = Scan_Long(format, &size);
+ if (!*format)
+ Fatal_Error("bad format: %s", format);
+
+ /* Last character repeats forever... */
+ if (i >= (int)strlen(format))
+ i=strlen(format)-1;
+
+ return(format[i]);
+}
+
+char *Format_Thunk(t, format_char)
+ thunk t;
+ char format_char;
+{
+ long value;
+ value = t.value;
+
+ switch (format_char) {
+ case 's':
+ return(Format_Len_String(t.extra_value, (int)t.value));
+ case 'x':
+ return(Format_Hex(value));
+ case 'c':
+ return(Format_Unsigned(value));
+ case 'i':
+ return(Format_Signed(value));
+ case 'b':
+ return(Format_Bool(value));
+ case 'm':
+ return(Format_Mask_Word(value));
+ case 'a':
+ return(Format_Atom(value));
+ default:
+ Fatal_Error("bad format character: %c", format_char);
+ }
+}
+
+char *Format_Thunk_I(thunks, format, i)
+ thunk *thunks;
+ char *format;
+ int i;
+{
+ if (i >= thunks->thunk_count)
+ return("<field not available>");
+
+ return(Format_Thunk(thunks[i], Get_Format_Char(format, i)));
+}
+
+long Mask_Word(thunks, format)
+ thunk *thunks;
+ char *format;
+{
+ int j;
+
+ for (j=0; j<(int)strlen(format); j++)
+ if (Get_Format_Char(format, j) == 'm')
+ return(thunks[j].value);
+ return(0L);
+}
+
+/*
+ *
+ * The Display Format Manager:
+ *
+ */
+
+int Is_A_DFormat(string)
+ char *string;
+{
+ return( string[0] && string[0] != '-' &&
+ !(isalpha(string[0]) || string[0] == '_') );
+}
+
+char *Handle_Backslash(dformat)
+ char *dformat;
+{
+ char c;
+ long i;
+
+ if (!(c = *(dformat++)))
+ return(dformat);
+
+ switch (c) {
+ case 'n':
+ putchar('\n');
+ break;
+ case 't':
+ putchar('\t');
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ dformat = Scan_Octal(dformat, &i);
+ putchar((int) i);
+ break;
+ default:
+ putchar(c);
+ break;
+ }
+ return(dformat);
+}
+
+char *Handle_Dollar_sign(dformat, thunks, format)
+ char *dformat;
+ thunk *thunks;
+ char *format;
+{
+ long i;
+
+ dformat = Scan_Long(dformat, &i);
+
+ if (dformat[0]=='+') {
+ int seen=0;
+ dformat++;
+ for (; i<thunks->thunk_count; i++) {
+ if (seen)
+ printf(", ");
+ seen = 1;
+ printf("%s", Format_Thunk_I(thunks, format, (int) i));
+ }
+ } else
+ printf("%s", Format_Thunk_I(thunks, format, (int) i));
+
+ return(dformat);
+}
+
+int Mask_Bit_I(thunks, format, i)
+ thunk *thunks;
+ char *format;
+ int i;
+{
+ long value;
+
+ value = Mask_Word(thunks, format);
+
+ value = value & (1L<<i);
+ if (value)
+ value=1;
+ return(value);
+}
+
+char *Scan_Term(string, thunks, format, value)
+ thunk *thunks;
+ char *string, *format;
+ long *value;
+{
+ long i;
+
+ *value=0;
+
+ if (isdigit(*string))
+ string = Scan_Long(string, value);
+ else if (*string=='$') {
+ string = Scan_Long(++string, &i);
+ if (i>=thunks->thunk_count)
+ i=thunks->thunk_count;
+ *value = thunks[i].value;
+ } else if (*string=='m') {
+ string = Scan_Long(++string, &i);
+ *value = Mask_Bit_I(thunks, format, (int) i);
+ } else
+ Fatal_Error("Bad term: %s.", string);
+
+ return(string);
+}
+
+char *Scan_Exp(string, thunks, format, value)
+ thunk *thunks;
+ char *string, *format;
+ long *value;
+{
+ long temp;
+
+ if (string[0]=='(') {
+ string = Scan_Exp(++string, thunks, format, value);
+ if (string[0]!=')')
+ Fatal_Error("Missing ')'");
+ return(++string);
+ }
+ if (string[0]=='!') {
+ string = Scan_Exp(++string, thunks, format, value);
+ *value = !*value;
+ return(string);
+ }
+
+ string = Scan_Term(string, thunks, format, value);
+
+ if (string[0]=='=') {
+ string = Scan_Exp(++string, thunks, format, &temp);
+ *value = *value == temp;
+ }
+
+ return(string);
+}
+
+char *Handle_Question_Mark(dformat, thunks, format)
+ thunk *thunks;
+ char *dformat, *format;
+{
+ long true;
+
+ dformat = Scan_Exp(dformat, thunks, format, &true);
+
+ if (*dformat!='(')
+ Fatal_Error("Bad conditional: '(' expected: %s.", dformat);
+ ++dformat;
+
+ if (!true)
+ dformat = Skip_Past_Right_Paran(dformat);
+
+ return(dformat);
+}
+
+Display_Property(thunks, dformat, format)
+ thunk *thunks;
+ char *dformat, *format;
+{
+ char c;
+
+ while ((c = *(dformat++)))
+ switch (c) {
+ case ')':
+ continue;
+ case '\\':
+ dformat = Handle_Backslash(dformat);
+ continue;
+ case '$':
+ dformat = Handle_Dollar_sign(dformat, thunks, format);
+ continue;
+ case '?':
+ dformat = Handle_Question_Mark(dformat, thunks, format);
+ continue;
+ default:
+ putchar(c);
+ continue;
+ }
+}
+
+/*
+ *
+ * Routines to convert property data to and from thunks
+ *
+ */
+
+long Extract_Value(pointer, length, size, signedp)
+ char **pointer;
+ int *length;
+ int size;
+{
+ long value, mask;
+
+ switch (size) {
+ case 8:
+ value = (long) * (char *) *pointer;
+ *pointer += 1;
+ *length -= 1;
+ mask = 0xff;
+ break;
+ case 16:
+ value = (long) * (short *) *pointer;
+ *pointer += sizeof(short);
+ *length -= sizeof(short);
+ mask = 0xffff;
+ break;
+ default:
+ /* Error */
+ case 32:
+ value = (long) * (long *) *pointer;
+ *pointer += sizeof(long);
+ *length -= sizeof(long);
+ mask = 0xffffffff;
+ break;
+ }
+ if (!signedp)
+ value &= mask;
+ return(value);
+}
+
+long Extract_Len_String(pointer, length, size, string)
+ char **pointer;
+ int *length;
+ int size;
+ char **string;
+{
+ int len;
+
+ if (size!=8)
+ Fatal_Error("can't use format character 's' with any size except 8.");
+ len=0; *string = *pointer;
+ while ((len++, --*length, *((*pointer)++)) && *length>0);
+
+ return(len);
+}
+
+thunk *Break_Down_Property(pointer, length, format, size)
+ char *pointer, *format;
+ int length, size;
+{
+ thunk *thunks;
+ thunk t;
+ int i;
+ char format_char;
+
+ thunks = Create_Thunk_List();
+ i=0;
+
+ while (length>=(size/8)) {
+ format_char = Get_Format_Char(format, i);
+ if (format_char=='s')
+ t.value=Extract_Len_String(&pointer,&length,size,&t.extra_value);
+ else
+ t.value=Extract_Value(&pointer,&length,size,format_char=='i');
+ thunks = Add_Thunk(thunks, t);
+ i++;
+ }
+
+ return(thunks);
+}
+
+/*
+ *
+ * Routines for parsing command line:
+ *
+ */
+
+usage()
+{
+ char **cpp;
+ static char *help_message[] = {
+"where options include:",
+" -grammar print out full grammar for command line",
+" -display host:dpy the X server to contact",
+" -id id resource id of window to examine",
+" -name name name of window to examine",
+" -font name name of font to examine",
+" -remove propname name of property to remove",
+" -root examine the root window",
+" -len n display at most n bytes of any property",
+" -notype do not display the type field",
+" -fs filename where to look for formats for properties",
+" -frame don't ignore window manager frames",
+" -f propname format [dformat] formats to use for property of given name",
+" -spy examine window properties forever",
+NULL};
+
+ fflush (stdout);
+ fprintf (stderr, "usage: %s [-options ...] [[format [dformat]] atom]\n\n",
+ program_name);
+ for (cpp = help_message; *cpp; cpp++) {
+ fprintf (stderr, "%s\n", *cpp);
+ }
+ fprintf (stderr, "\n");
+ exit (1);
+}
+
+grammar ()
+{
+ printf ("Grammar for xprop:\n\n");
+ printf("\t%s [<disp>] [<select option>] <option>* <mapping>* <spec>*",
+ program_name);
+ printf("\n\n\tdisp ::= -display host:dpy\
+\n\tselect option ::= -root | -id <id> | -font <font> | -name <name>\
+\n\toption ::= -len <n> | -notype | -spy | {-formats|-fs} <format file>\
+\n\tmapping ::= {-f|-format} <atom> <format> [<dformat>] | -remove <propname>\
+\n\tspec ::= [<format> [<dformat>]] <atom>\
+\n\tformat ::= {0|8|16|32}{a|b|c|i|m|s|x}*\
+\n\tdformat ::= <unit><unit>* (can't start with a letter or '-')\
+\n\tunit ::= ?<exp>(<unit>*) | $<n> | <display char>\
+\n\texp ::= <term> | <term>=<exp> | !<exp>\
+\n\tterm ::= <n> | $<n> | m<n>\
+\n\tdisplay char ::= <normal char> | \\<non digit char> | \\<octal number>\
+\n\tnormal char ::= <any char except a digit, $, ?, \\, or )>\
+\n\n");
+ exit(0);
+}
+
+Parse_Format_Mapping(argc, argv)
+ int *argc;
+ char ***argv;
+#define ARGC (*argc)
+#define ARGV (*argv)
+#define OPTION ARGV[0]
+#define NXTOPT if (++ARGV, --ARGC==0) usage()
+{
+ char *type_name, *format, *dformat;
+
+ NXTOPT; type_name = OPTION;
+
+ NXTOPT; format = OPTION;
+ if (!Is_A_Format(format))
+ Fatal_Error("Bad format: %s.", format);
+
+ dformat=0;
+ if (ARGC>0 && Is_A_DFormat(ARGV[1])) {
+ ARGV++; ARGC--; dformat=OPTION;
+ }
+
+ Add_Mapping( Parse_Atom(type_name, False), format, dformat);
+}
+
+/*
+ *
+ * The Main Program:
+ *
+ */
+
+Window target_win=0;
+int notype=0;
+int spy=0;
+int max_len=MAXSTR;
+XFontStruct *font;
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+ FILE *stream;
+ char *name;
+ thunk *props, *Handle_Prop_Requests();
+ char *remove_propname = NULL;
+ Bool frame_only = False;
+ int n;
+ char **nargv;
+
+ INIT_NAME;
+
+ /* Handle display name, opening the display */
+ Setup_Display_And_Screen(&argc, argv);
+
+ /* Handle selecting the window to display properties for */
+ target_win = Select_Window_Args(&argc, argv);
+
+ /* Set up default atom to format, dformat mapping */
+ XpropMode = XpropWindowProperties;
+ for (n=argc, nargv=argv; n; nargv++, n--)
+ if (! strcmp(nargv[0], "-font")) {
+ XpropMode = XpropFontProperties;
+ break;
+ }
+ Setup_Mapping();
+ if ((name = getenv("XPROPFORMATS"))) {
+ if (!(stream=fopen(name, "r")))
+ Fatal_Error("unable to open file %s for reading.", name);
+ Read_Mappings(stream);
+ fclose(stream);
+ }
+
+ /* Handle '-' options to setup xprop, select window to work on */
+ while (argv++, --argc>0 && **argv=='-') {
+ if (!strcmp(argv[0], "-"))
+ continue;
+ if (!strcmp(argv[0], "-grammar")) {
+ grammar ();
+ /* NOTREACHED */
+ }
+ if (!strcmp(argv[0], "-notype")) {
+ notype=1;
+ continue;
+ }
+ if (!strcmp(argv[0], "-spy")) {
+ spy=1;
+ continue;
+ }
+ if (!strcmp(argv[0], "-len")) {
+ if (++argv, --argc==0) usage();
+ max_len = atoi(argv[0]);
+ continue;
+ }
+ if (!strcmp(argv[0], "-formats") || !strcmp(argv[0], "-fs")) {
+ if (++argv, --argc==0) usage();
+ if (!(stream=fopen(argv[0], "r")))
+ Fatal_Error("unable to open file %s for reading.", argv[0]);
+ Read_Mappings(stream);
+ fclose(stream);
+ continue;
+ }
+ if (!strcmp(argv[0], "-font")) {
+ if (++argv, --argc==0) usage();
+ font = Open_Font(argv[0]);
+ target_win = -1;
+ continue;
+ }
+ if (!strcmp(argv[0], "-remove")) {
+ if (++argv, --argc==0) usage();
+ remove_propname = argv[0];
+ continue;
+ }
+ if (!strcmp(argv[0], "-frame")) {
+ frame_only = True;
+ continue;
+ }
+ if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "-format")) {
+ Parse_Format_Mapping(&argc, &argv);
+ continue;
+ }
+ usage();
+ }
+
+ if (target_win == None) {
+ target_win = Select_Window(dpy);
+ if (target_win != None && !frame_only) {
+ Window root;
+ int dummyi;
+ unsigned int dummy;
+
+ if (XGetGeometry (dpy, target_win, &root, &dummyi, &dummyi,
+ &dummy, &dummy, &dummy, &dummy) &&
+ target_win != root)
+ target_win = XmuClientWindow (dpy, target_win);
+ }
+ }
+
+ if (remove_propname) {
+ remove_property (dpy, target_win, remove_propname);
+ XCloseDisplay (dpy);
+ exit (0);
+ }
+
+ props=Handle_Prop_Requests(argc, argv);
+
+ if (spy && target_win != -1) {
+ XEvent event;
+ char *format, *dformat;
+
+ XSelectInput(dpy, target_win, PropertyChangeMask);
+ for (;;) {
+ XNextEvent(dpy, &event);
+ format = dformat = NULL;
+ if (props) {
+ int i;
+ for (i=0; i<props->thunk_count; i++)
+ if (props[i].value == event.xproperty.atom)
+ break;
+ if (i>=props->thunk_count)
+ continue;
+ format = props[i].format;
+ dformat = props[i].dformat;
+ }
+ Show_Prop(format, dformat, Format_Atom(event.xproperty.atom));
+ }
+ }
+ exit (0);
+}
+
+/*
+ *
+ * Other Stuff (temp.):
+ *
+ */
+
+remove_property (dpy, w, propname)
+ Display *dpy;
+ Window w;
+ char *propname;
+{
+ Atom id = XInternAtom (dpy, propname, True);
+
+ if (id == None) {
+ fprintf (stderr, "%s: no such property \"%s\"\n",
+ program_name, propname);
+ return;
+ }
+ XDeleteProperty (dpy, w, id);
+ return;
+}
+
+thunk *Handle_Prop_Requests(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *format, *dformat, *prop;
+ thunk *thunks, t;
+
+ thunks = Create_Thunk_List();
+
+ /* if no prop referenced, by default list all properties for given window */
+ if (!argc) {
+ Show_All_Props();
+ return(NULL);
+ }
+
+ while (argc>0) {
+ format = 0;
+ dformat = 0;
+
+ /* Get overriding formats, if any */
+ if (Is_A_Format(argv[0])) {
+ format = argv++[0]; argc--;
+ if (!argc) usage();
+ }
+ if (Is_A_DFormat(argv[0])) {
+ dformat = argv++[0]; argc--;
+ if (!argc) usage();
+ }
+
+ /* Get property name */
+ prop = argv++[0]; argc--;
+
+ t.value = Parse_Atom(prop, True);
+ t.format = format;
+ t.dformat = dformat;
+ if (t.value)
+ thunks = Add_Thunk(thunks, t);
+ Show_Prop(format, dformat, prop);
+ }
+ return(thunks);
+}
+
+Show_All_Props()
+{
+ Atom *atoms, atom;
+ char *name;
+ int count, i;
+
+ if (target_win!=-1) {
+ atoms = XListProperties(dpy, target_win, &count);
+ for (i=0; i<count; i++) {
+ name = Format_Atom(atoms[i]);
+ Show_Prop(0, 0, name);
+ }
+ } else
+ for (i=0; i<font->n_properties; i++) {
+ atom = font->properties[i].name;
+ name = Format_Atom(atom);
+ Show_Prop(0, 0, name);
+ }
+}
+
+Set_Prop(format, dformat, prop, mode, value)
+ char *format, *dformat, *prop, *value;
+ char mode;
+{
+ outl("Seting prop %s(%s) using %s mode %c to %s",
+ prop, format, dformat, mode, value);
+}
+
+static unsigned long _font_prop;
+
+char *Get_Font_Property_Data_And_Type(atom, length, type, size)
+ Atom atom;
+ long *length;
+ Atom *type;
+ int *size;
+{
+ int i;
+
+ *type = 0;
+
+ for (i=0; i<font->n_properties; i++)
+ if (atom==font->properties[i].name) {
+ _font_prop=font->properties[i].card32;
+ *length=sizeof(long);
+ *size=32;
+ return((char *) &_font_prop);
+ }
+ return(0);
+}
+
+char *Get_Window_Property_Data_And_Type(atom, length, type, size)
+ Atom atom;
+ long *length;
+ Atom *type;
+ int *size;
+{
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems;
+ unsigned long nbytes;
+ unsigned long bytes_after;
+ unsigned char *prop;
+ int status;
+
+ status = XGetWindowProperty(dpy, target_win, atom, 0, (max_len+3)/4,
+ False, AnyPropertyType, &actual_type,
+ &actual_format, &nitems, &bytes_after,
+ &prop);
+ if (status==BadWindow)
+ Fatal_Error("window id # 0x%lx does not exists!", target_win);
+ if (status!=Success)
+ Fatal_Error("XGetWindowProperty failed!");
+
+ if (actual_format == 32)
+ nbytes = sizeof(long);
+ else if (actual_format == 16)
+ nbytes = sizeof(short);
+ else
+ nbytes = 1;
+ *length = min(nitems * nbytes, max_len);
+ *type = actual_type;
+ *size = actual_format;
+ return((char *)prop);
+}
+
+char *Get_Property_Data_And_Type(atom, length, type, size)
+ Atom atom;
+ long *length;
+ Atom *type;
+ int *size;
+{
+ if (target_win == -1)
+ return(Get_Font_Property_Data_And_Type(atom, length, type, size));
+ else
+ return(Get_Window_Property_Data_And_Type(atom, length, type, size));
+}
+
+Show_Prop(format, dformat, prop)
+ char *format, *dformat, *prop;
+{
+ char *data;
+ long length;
+ Atom atom, type;
+ thunk *thunks;
+ int size, fsize;
+
+ printf("%s", prop);
+ if (!(atom = Parse_Atom(prop, True))) {
+ printf(": no such atom on any window.\n");
+ return;
+ }
+
+ data = Get_Property_Data_And_Type(atom, &length, &type, &size);
+ if (!size) {
+ puts(": not found.");
+ return;
+ }
+
+ if (!notype && type)
+ printf("(%s)", Format_Atom(type));
+
+ Lookup_Formats(atom, &format, &dformat);
+ if (type)
+ Lookup_Formats(type, &format, &dformat);
+ Apply_Default_Formats(&format, &dformat);
+
+ fsize=Get_Format_Size(format);
+ if (fsize!=size && fsize!=0) {
+ printf(": Type mismatch: assumed size %d bits, actual size %d bits.\n",
+ fsize, size);
+ return;
+ }
+
+ thunks = Break_Down_Property(data, (int)length, format, size);
+
+ Display_Property(thunks, dformat, format);
+}