home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / clients / xprop / xprop.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-12  |  32.3 KB  |  1,499 lines

  1. /* $XConsortium: xprop.c,v 1.37 91/05/12 18:23:07 rws Exp $*/
  2. /*
  3.  * Copyright 1990 Massachusetts Institute of Technology
  4.  *
  5.  * Permission to use, copy, modify, distribute, and sell this software and its
  6.  * documentation for any purpose is hereby granted without fee, provided that
  7.  * the above copyright notice appear in all copies and that both that
  8.  * copyright notice and this permission notice appear in supporting
  9.  * documentation, and that the name of M.I.T. not be used in advertising or
  10.  * publicity pertaining to distribution of the software without specific,
  11.  * written prior permission.  M.I.T. makes no representations about the
  12.  * suitability of this software for any purpose.  It is provided "as is"
  13.  * without express or implied warranty.
  14.  *
  15.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  16.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  17.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  18.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  19.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  20.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21.  *
  22.  */
  23.     
  24. #include <X11/Xlib.h>
  25. #include <X11/Xos.h>
  26. #include <X11/Xfuncs.h>
  27. #include <X11/Xutil.h>
  28. #include <stdio.h>
  29. #include <ctype.h>
  30.  
  31. #include <X11/Xatom.h>
  32. #include <X11/Xmu/WinUtil.h>
  33.  
  34. #include "dsimple.h"
  35.  
  36. #ifndef X_NOT_STDC_ENV
  37. #include <stdlib.h>
  38. #else
  39. char *getenv();
  40. #endif
  41.  
  42. #define MAXSTR 10000
  43.  
  44. #define min(a,b)  ((a) < (b) ? (a) : (b))
  45.  
  46. /*
  47.  *
  48.  * The Thunk Manager - routines to create, add to, and free thunk lists
  49.  *
  50.  */
  51.  
  52. typedef struct {
  53.   int thunk_count;
  54.   long value;
  55.   char *extra_value;
  56.   char *format;
  57.   char *dformat;
  58. } thunk;
  59.  
  60. thunk *Create_Thunk_List()
  61. {
  62.   thunk *tptr;
  63.  
  64.   tptr = (thunk *) Malloc( sizeof(thunk) );
  65.  
  66.   tptr->thunk_count = 0;
  67.  
  68.   return(tptr);
  69. }
  70.  
  71. Free_Thunk_List(list)
  72. thunk *list;
  73. {
  74.   free(list);
  75. }
  76.  
  77. thunk *Add_Thunk(list, t)
  78. thunk *list;
  79. thunk t;
  80. {
  81.   int i;
  82.  
  83.   i = list->thunk_count;
  84.  
  85.   list = (thunk *) realloc(list, (i+1)*sizeof(thunk) );
  86.   if (!list)
  87.     Fatal_Error("Out of memory!");
  88.  
  89.   list[i++] = t;
  90.   list->thunk_count = i;
  91.  
  92.   return(list);
  93. }
  94.  
  95. /*
  96.  * Misc. routines
  97.  */
  98.  
  99. char *Copy_String(string)
  100.      char *string;
  101. {
  102.     char *new;
  103.     int length;
  104.  
  105.     length = strlen(string) + 1;
  106.  
  107.     new = (char *) Malloc(length);
  108.     bcopy(string, new, length);
  109.  
  110.     return(new);
  111. }
  112.  
  113. int Read_Char(stream)
  114.      FILE *stream;
  115. {
  116.     int c;
  117.  
  118.     c = getc(stream);
  119.     if (c==EOF)
  120.       Fatal_Error("Bad format file: Unexpected EOF.");
  121.     return(c);
  122. }
  123.  
  124. Read_White_Space(stream)
  125.      FILE *stream;
  126. {
  127.     int c;
  128.  
  129.     while ((c=getc(stream))==' ' || c=='\n' || c=='\t');
  130.     ungetc(c, stream);
  131. }
  132.  
  133. static char _large_buffer[MAXSTR+10];
  134.  
  135. char *Read_Quoted(stream)
  136.      FILE *stream;
  137. {
  138.     char *ptr;
  139.     int c, length;
  140.  
  141.     Read_White_Space(stream);
  142.     if (Read_Char(stream)!='\'')
  143.       Fatal_Error("Bad format file format: missing dformat.");
  144.  
  145.     ptr = _large_buffer; length=MAXSTR;
  146.     for (;;) {
  147.         if (length<0)
  148.           Fatal_Error("Bad format file format: dformat too long.");
  149.         c = Read_Char(stream);
  150.         if (c==(int) '\'')
  151.           break;
  152.         ptr++[0]=c; length--;
  153.         if (c== (int) '\\') {
  154.             c=Read_Char(stream);
  155.             if (c=='\n') {
  156.                 ptr--; length++;
  157.             } else
  158.               ptr++[0]=c; length--;
  159.         }
  160.     }
  161.     ptr++[0]='\0';
  162.  
  163.     return(Copy_String(_large_buffer));
  164. }
  165.  
  166. /*
  167.  *
  168.  * Atom to format, dformat mapping Manager
  169.  *
  170.  */
  171.  
  172. #define D_FORMAT "0x"              /* Default format for properties */
  173. #define D_DFORMAT " = $0+\n"       /* Default display pattern for properties */
  174.  
  175. static thunk *_property_formats = 0;   /* Holds mapping */
  176.  
  177. Apply_Default_Formats(format, dformat)
  178.      char **format;
  179.      char **dformat;
  180. {
  181.   if (!*format)
  182.     *format = D_FORMAT;
  183.   if (!*dformat)
  184.     *dformat = D_DFORMAT;
  185. }
  186.   
  187. Lookup_Formats(atom, format, dformat)
  188.      Atom atom;
  189.      char **format;
  190.      char **dformat;
  191. {
  192.   int i;
  193.  
  194.   if (_property_formats)
  195.     for (i=_property_formats->thunk_count-1; i>=0; i--)
  196.       if (_property_formats[i].value==atom) {
  197.     if (!*format)
  198.       *format = _property_formats[i].format;
  199.     if (!*dformat)
  200.       *dformat = _property_formats[i].dformat;
  201.     break;
  202.       }
  203. }
  204.  
  205. Add_Mapping(atom, format, dformat)
  206.      Atom atom;
  207.      char *format;
  208.      char *dformat;
  209. {
  210.   thunk t;
  211.  
  212.   if (!_property_formats)
  213.     _property_formats = Create_Thunk_List();
  214.  
  215.   t.value=atom;
  216.   t.format=format;
  217.   t.dformat=dformat;
  218.  
  219.   _property_formats = Add_Thunk(_property_formats, t);
  220. }
  221.  
  222. /*
  223.  *
  224.  * Setup_Mapping: Routine to setup default atom to format, dformat mapping:
  225.  * 
  226.  */
  227.  
  228. typedef struct _propertyRec {
  229.     char *    name;
  230.     Atom    atom;
  231.     char *    format;
  232.     char *    dformat;
  233. } propertyRec;
  234.  
  235. #define ARC_DFORMAT    ":\n\
  236. \t\tarc at $0, $1\n\
  237. \t\tsize: $2 by $3\n\
  238. \t\tfrom angle $4 to angle $5\n"
  239.  
  240. #define RECTANGLE_DFORMAT    ":\n\
  241. \t\tupper left corner: $0, $1\n\
  242. \t\tsize: $2 by $3\n"
  243.  
  244. #define RGB_COLOR_MAP_DFORMAT    ":\n\
  245. \t\tcolormap id #: $0\n\
  246. \t\tred-max: $1\n\
  247. \t\tred-mult: $2\n\
  248. \t\tgreen-max: $3\n\
  249. \t\tgreen-mult: $4\n\
  250. \t\tblue-max: $5\n\
  251. \t\tblue-mult: $6\n\
  252. \t\tbase-pixel: $7\n"
  253.  
  254. #define WM_HINTS_DFORMAT    ":\n\
  255. ?m0(\t\tClient accepts input or input focus: $1\n)\
  256. ?m1(\t\tInitial state is \
  257. ?$2=0(Don't Care State)\
  258. ?$2=1(Normal State)\
  259. ?$2=2(Zoomed State)\
  260. ?$2=3(Iconic State)\
  261. ?$2=4(Inactive State)\
  262. .\n)\
  263. ?m2(\t\tbitmap id # to use for icon: $3\n)\
  264. ?m5(\t\tbitmap id # of mask for icon: $7\n)\
  265. ?m3(\t\twindow id # to use for icon: $4\n)\
  266. ?m4(\t\tstarting position for icon: $5, $6\n)\
  267. ?m6(\t\twindow id # of group leader: $8\n)"
  268.  
  269. #define WM_ICON_SIZE_DFORMAT    ":\n\
  270. \t\tminimum icon size: $0 by $1\n\
  271. \t\tmaximum icon size: $2 by $3\n\
  272. \t\tincremental size change: $4 by $5\n"
  273.  
  274. #define WM_SIZE_HINTS_DFORMAT ":\n\
  275. ?m0(\t\tuser specified location: $1, $2\n)\
  276. ?m2(\t\tprogram specified location: $1, $2\n)\
  277. ?m1(\t\tuser specified size: $3 by $4\n)\
  278. ?m3(\t\tprogram specified size: $3 by $4\n)\
  279. ?m4(\t\tprogram specified minimum size: $5 by $6\n)\
  280. ?m5(\t\tprogram specified maximum size: $7 by $8\n)\
  281. ?m6(\t\tprogram specified resize increment: $9 by $10\n)\
  282. ?m7(\t\tprogram specified minimum aspect ratio: $11/$12\n\
  283. \t\tprogram specified maximum aspect ratio: $13/$14\n)\
  284. ?m8(\t\tprogram specified base size: $15 by $16\n)\
  285. ?m9(\t\twindow gravity: \
  286. ?$17=0(Forget)\
  287. ?$17=1(NorthWest)\
  288. ?$17=2(North)\
  289. ?$17=3(NorthEast)\
  290. ?$17=4(West)\
  291. ?$17=5(Center)\
  292. ?$17=6(East)\
  293. ?$17=7(SouthWest)\
  294. ?$17=8(South)\
  295. ?$17=9(SouthEast)\
  296. ?$17=10(Static)\
  297. \n)"
  298.  
  299. #define WM_STATE_DFORMAT     ":\n\
  300. \t\twindow state: ?$0=0(Withdrawn)?$0=1(Normal)?$0=3(Iconic)\n\
  301. \t\ticon window: $1\n"
  302.  
  303. propertyRec windowPropTable[] = {
  304.     {"ARC",        XA_ARC,        "16iiccii",   ARC_DFORMAT },
  305.     {"ATOM",        XA_ATOM,     "32a",          0 },
  306.     {"BITMAP",        XA_BITMAP,     "32x",          ": bitmap id # $0\n" },
  307.     {"CARDINAL",    XA_CARDINAL,     "0c",          0 },
  308.     {"COLORMAP",    XA_COLORMAP,     "32x",          ": colormap id # $0\n" },
  309.     {"CURSOR",        XA_CURSOR,     "32x",          ": cursor id # $0\n" },
  310.     {"DRAWABLE",    XA_DRAWABLE,     "32x",          ": drawable id # $0\n" },
  311.     {"FONT",        XA_FONT,     "32x",          ": font id # $0\n" },
  312.     {"INTEGER",        XA_INTEGER,     "0i",          0 },
  313.     {"PIXMAP",        XA_PIXMAP,     "32x",          ": pixmap id # $0\n" },
  314.     {"POINT",        XA_POINT,     "16ii",      " = $0, $1\n" },
  315.     {"RECTANGLE",    XA_RECTANGLE,     "16iicc",    RECTANGLE_DFORMAT },
  316.     {"RGB_COLOR_MAP",    XA_RGB_COLOR_MAP,"32xccccccc",RGB_COLOR_MAP_DFORMAT},
  317.     {"STRING",        XA_STRING,     "8s",          0 },
  318.     {"WINDOW",        XA_WINDOW,     "32x",          ": window id # $0\n" },
  319.     {"VISUALID",    XA_VISUALID,     "32x",          ": visual id # $0\n" },
  320.     {"WM_COLORMAP_WINDOWS",    0,     "32x",       ": window id # $0+\n"},
  321.     {"WM_COMMAND",    XA_WM_COMMAND,     "8s",          " = { $0+ }\n" },
  322.     {"WM_HINTS",    XA_WM_HINTS,     "32mbcxxiixx",    WM_HINTS_DFORMAT },
  323.     {"WM_ICON_SIZE",    XA_WM_ICON_SIZE, "32cccccc",    WM_ICON_SIZE_DFORMAT},
  324.     {"WM_PROTOCOLS",        0,     "32a",          ": protocols  $0+\n"},
  325.     {"WM_SIZE_HINTS",    XA_WM_SIZE_HINTS,"32mii",     WM_SIZE_HINTS_DFORMAT },
  326.     {"WM_STATE",        0,     "32cx",      WM_STATE_DFORMAT}
  327. };
  328. #undef ARC_DFORMAT
  329. #undef RECTANGLE_DFORMAT
  330. #undef RGB_COLOR_MAP_DFORMAT
  331. #undef WM_ICON_SIZE_DFORMAT
  332. #undef WM_HINTS_DFORMAT
  333. #undef WM_SIZE_HINTS_DFORMAT
  334. #undef WM_STATE_DFORMAT
  335.  
  336. /* 
  337.  * Font-specific mapping of property names to types:
  338.  */
  339. propertyRec fontPropTable[] = {
  340.  
  341.     /* XLFD name properties */
  342.  
  343.     "FOUNDRY",            0,              "32a",    0,
  344.     "FAMILY_NAME",        XA_FAMILY_NAME,        "32a",    0,
  345.     "WEIGHT_NAME",        0,            "32a",    0,
  346.     "SLANT",            0,            "32a",    0,
  347.     "SETWIDTH_NAME",        0,            "32a",    0,
  348.     "ADD_STYLE_NAME",        0,            "32a",    0,
  349.     "PIXEL_SIZE",        0,            "32c",    0,
  350.     "POINT_SIZE",        XA_POINT_SIZE,        "32c",    0,
  351.     "RESOLUTION_X",        0,            "32c",    0,
  352.     "RESOLUTION_Y",        0,            "32c",    0,
  353.     "SPACING",            0,            "32a",    0,
  354.     "AVERAGE_WIDTH",        0,            "32c",    0,
  355.     "CHARSET_REGISTRY",        0,            "32a",    0,
  356.     "CHARSET_ENCODING",        0,            "32a",    0,
  357.  
  358.     /* other font properties referenced in the XLFD */
  359.  
  360.     "QUAD_WIDTH",        XA_QUAD_WIDTH,        "32i",    0,
  361.     "RESOLUTION",        XA_RESOLUTION,        "32c",    0,
  362.     "MIN_SPACE",        XA_MIN_SPACE,        "32c",    0,
  363.     "NORM_SPACE",        XA_NORM_SPACE,        "32c",    0,
  364.     "MAX_SPACE",        XA_MAX_SPACE,        "32c",    0,
  365.     "END_SPACE",        XA_END_SPACE,        "32c",    0,
  366.     "SUPERSCRIPT_X",        XA_SUPERSCRIPT_X,    "32i",    0,
  367.     "SUPERSCRIPT_Y",        XA_SUPERSCRIPT_Y,    "32i",    0,
  368.     "SUBSCRIPT_X",        XA_SUBSCRIPT_X,        "32i",    0,
  369.     "SUBSCRIPT_Y",        XA_SUBSCRIPT_Y,        "32i",    0,
  370.     "UNDERLINE_POSITION",    XA_UNDERLINE_POSITION,    "32i",    0,
  371.     "UNDERLINE_THICKNESS",    XA_UNDERLINE_THICKNESS,    "32i",    0,
  372.     "STRIKEOUT_ASCENT",        XA_STRIKEOUT_ASCENT,    "32i",    0,
  373.     "STRIKEOUT_DESCENT",    XA_STRIKEOUT_DESCENT,    "32i",    0,
  374.     "ITALIC_ANGLE",        XA_ITALIC_ANGLE,    "32i",    0,
  375.     "X_HEIGHT",            XA_X_HEIGHT,        "32i",    0,
  376.     "WEIGHT",            XA_WEIGHT,        "32i",    0,
  377.     "FACE_NAME",        0,            "32a",    0,
  378.     "COPYRIGHT",        XA_COPYRIGHT,        "32a",    0,
  379.     "AVG_CAPITAL_WIDTH",    0,            "32i",    0,
  380.     "AVG_LOWERCASE_WIDTH",    0,            "32i",    0,
  381.     "RELATIVE_SETWIDTH",    0,            "32c",    0,
  382.     "RELATIVE_WEIGHT",        0,            "32c",    0,
  383.     "CAP_HEIGHT",        XA_CAP_HEIGHT,        "32c",    0,
  384.     "SUPERSCRIPT_SIZE",        0,            "32c",    0,
  385.     "FIGURE_WIDTH",        0,            "32i",    0,
  386.     "SUBSCRIPT_SIZE",        0,            "32c",    0,
  387.     "SMALL_CAP_SIZE",        0,            "32i",    0,
  388.     "NOTICE",            XA_NOTICE,        "32a",    0,
  389.     "DESTINATION",        0,            "32c",    0,
  390.  
  391.     /* other font properties */
  392.  
  393.     "FONT",            XA_FONT,        "32a",    0,
  394.     "FONT_NAME",        XA_FONT_NAME,        "32a",    0,
  395. };    
  396.  
  397. static int XpropMode;
  398. #define XpropWindowProperties 0
  399. #define XpropFontProperties   1
  400.  
  401. Setup_Mapping()
  402. {
  403.     int n;
  404.     propertyRec *p;
  405.     
  406.     if (XpropMode == XpropWindowProperties) {
  407.     n = sizeof(windowPropTable) / sizeof(propertyRec);
  408.     p = windowPropTable;
  409.     } else {
  410.     n = sizeof (fontPropTable) / sizeof (propertyRec);
  411.     p = fontPropTable;
  412.     }
  413.     for ( ; --n >= 0; p++) {
  414.     if (! p->atom) {
  415.         p->atom = XInternAtom(dpy, p->name, True);
  416.         if (p->atom == None)
  417.         continue;
  418.     }
  419.     Add_Mapping(p->atom, p->format, p->dformat);
  420.     }    
  421. }
  422.  
  423. char *GetAtomName(atom)
  424.     Atom atom;
  425. {
  426.     int n;
  427.     propertyRec *p;
  428.         
  429.     if (XpropMode == XpropWindowProperties) {
  430.     n = sizeof(windowPropTable) / sizeof(propertyRec);
  431.     p = windowPropTable;
  432.     } else {
  433.     n = sizeof (fontPropTable) / sizeof (propertyRec);
  434.     p = fontPropTable;
  435.     }
  436.     for ( ; --n >= 0; p++)
  437.     if (p->atom == atom)
  438.         return p->name;
  439.  
  440.     return (char *) NULL;
  441. }
  442.  
  443. /*
  444.  * Read_Mapping: routine to read in additional mappings from a stream
  445.  *               already open for reading.
  446.  */
  447.  
  448. Read_Mappings(stream)
  449.      FILE *stream;
  450. {
  451.     char format_buffer[100];
  452.     char name[1000], *dformat, *format;
  453.     int count, c;
  454.     Atom atom, Parse_Atom();
  455.  
  456.     while ((count=fscanf(stream," %990s %90s ",name,format_buffer))!=EOF) {
  457.         if (count != 2)
  458.           Fatal_Error("Bad format file format.");
  459.  
  460.         atom = Parse_Atom(name, False);
  461.         format = Copy_String(format_buffer);
  462.  
  463.         Read_White_Space(stream);
  464.         dformat = D_DFORMAT;
  465.         c = getc(stream);
  466.         ungetc(c, stream);
  467.         if (c==(int)'\'')
  468.           dformat = Read_Quoted(stream);
  469.  
  470.         Add_Mapping(atom, format, dformat);
  471.     }
  472. }
  473.  
  474. /*
  475.  *
  476.  * Formatting Routines: a group of routines to translate from various
  477.  *                      values to a static read-only string useful for output.
  478.  *
  479.  * Routines: Format_Hex, Format_Unsigned, Format_Signed, Format_Atom,
  480.  *           Format_Mask_Word, Format_Bool, Format_String, Format_Len_String.
  481.  *
  482.  * All of the above routines take a long except for Format_String and
  483.  * Format_Len_String.
  484.  *
  485.  */
  486. static char _formatting_buffer[MAXSTR+100];
  487. static char _formatting_buffer2[10];
  488.  
  489. char *Format_Hex(wrd)
  490.      long wrd;
  491. {
  492.   sprintf(_formatting_buffer2, "0x%lx", wrd);
  493.   return(_formatting_buffer2);
  494. }
  495.  
  496. char *Format_Unsigned(wrd)
  497.      long wrd;
  498. {
  499.   sprintf(_formatting_buffer2, "%lu", wrd);
  500.   return(_formatting_buffer2);
  501. }
  502.  
  503. char *Format_Signed(wrd)
  504.      long wrd;
  505. {
  506.   sprintf(_formatting_buffer2, "%ld", wrd);
  507.   return(_formatting_buffer2);
  508. }
  509.  
  510. /*ARGSUSED*/
  511. int ignore_errors (dpy, ev)
  512.     Display *dpy;
  513.     XErrorEvent *ev;
  514. {
  515.     return 0;
  516. }
  517.  
  518. char *Format_Atom(atom)
  519.      Atom atom;
  520. {
  521.   char *name;
  522.   int (*handler)();
  523.  
  524.   if (name = GetAtomName(atom)) {
  525.       strncpy(_formatting_buffer, name, MAXSTR);
  526.       return(_formatting_buffer);
  527.   }
  528.  
  529.   handler = XSetErrorHandler (ignore_errors);
  530.   name=XGetAtomName(dpy, atom);
  531.   XSetErrorHandler(handler);
  532.   if (! name)
  533.       sprintf(_formatting_buffer, "undefined atom # 0x%lx", atom);
  534.   else {
  535.       strncpy(_formatting_buffer, name, MAXSTR);
  536.       XFree(name);
  537.   }
  538.   return(_formatting_buffer);
  539. }
  540.  
  541. char *Format_Mask_Word(wrd)
  542.      long wrd;
  543. {
  544.   long bit_mask, bit;
  545.   int seen = 0;
  546.  
  547.   strcpy(_formatting_buffer, "{MASK: ");
  548.   for (bit=0, bit_mask=1; bit<=sizeof(long)*8; bit++, bit_mask<<=1) {
  549.     if (bit_mask & wrd) {
  550.       if (seen) {
  551.     strcat(_formatting_buffer, ", ");
  552.       }
  553.       seen=1;
  554.       strcat(_formatting_buffer, Format_Unsigned(bit));
  555.     }
  556.   }
  557.   strcat(_formatting_buffer, "}");
  558.  
  559.   return(_formatting_buffer);
  560. }
  561.  
  562. char *Format_Bool(value)
  563.      long value;
  564. {
  565.   if (!value)
  566.     return("False");
  567.  
  568.   return("True");
  569. }
  570.  
  571. static char *_buf_ptr;
  572. static int _buf_len;
  573.  
  574. _put_char(c)
  575.      char c;
  576. {
  577.     if (--_buf_len<0) {
  578.         _buf_ptr[0]='\0';
  579.         return;
  580.     }
  581.     _buf_ptr++[0] = c;
  582. }
  583.  
  584. _format_char(c)
  585.      char c;
  586. {
  587.     switch (c) {
  588.           case '\\':
  589.           case '\"':
  590.         _put_char('\\');
  591.         _put_char(c);
  592.         break;
  593.           case '\n':
  594.         _put_char('\\');
  595.         _put_char('n');
  596.         break;
  597.           case '\t':
  598.         _put_char('\\');
  599.         _put_char('t');
  600.         break;
  601.           default:
  602.         if (c<' ') {
  603.             _put_char('\\');
  604.             sprintf(_buf_ptr, "%o", (int) c);
  605.             _buf_ptr += strlen(_buf_ptr);
  606.             _buf_len -= strlen(_buf_ptr);
  607.         } else
  608.           _put_char(c);
  609.     }
  610. }
  611.  
  612. char *Format_String(string)
  613.      char *string;
  614. {
  615.     char c;
  616.  
  617.     _buf_ptr = _formatting_buffer;
  618.     _buf_len = MAXSTR;
  619.     _put_char('\"');
  620.  
  621.     while (c = string++[0])
  622.       _format_char(c);
  623.  
  624.     _buf_len += 3;
  625.     _put_char('\"');
  626.     _put_char('\0');
  627.     return(_formatting_buffer);
  628. }
  629.  
  630. char *Format_Len_String(string, len)
  631.      char *string;
  632.      int len;
  633. {
  634.   char *data, *result;
  635.  
  636.   data = (char *) Malloc(len+1);
  637.  
  638.   bcopy(string, data, len);
  639.   data[len]='\0';
  640.  
  641.   result = Format_String(data);
  642.   free(data);
  643.  
  644.   return(result);
  645. }  
  646.  
  647. /*
  648.  *
  649.  * Parsing Routines: a group of routines to parse strings into values
  650.  *
  651.  * Routines: Parse_Atom, Scan_Long, Skip_Past_Right_Paran, Scan_Octal
  652.  *
  653.  * Routines of the form Parse_XXX take a string which is parsed to a value.
  654.  * Routines of the form Scan_XXX take a string, parse the beginning to a value,
  655.  * and return the rest of the string.  The value is returned via. the last
  656.  * parameter.  All numeric values are longs!
  657.  *
  658.  */
  659.  
  660. char *Skip_Digits(string)
  661.      char *string;
  662. {
  663.     while (isdigit(string[0])) string++;
  664.     return(string);
  665. }
  666.  
  667. char *Scan_Long(string, value)
  668.      char *string;
  669.      long *value;
  670. {
  671.     if (!isdigit(*string))
  672.       Fatal_Error("Bad number: %s.", string);
  673.  
  674.     *value = atol(string);
  675.     return(Skip_Digits(string));
  676. }
  677.  
  678. char *Scan_Octal(string, value)
  679.      char *string;
  680.      long *value;
  681. {
  682.     if (sscanf(string, "%lo", value)!=1)
  683.       Fatal_Error("Bad octal number: %s.", string);
  684.     return(Skip_Digits(string));
  685. }
  686.  
  687. Atom Parse_Atom(name, only_if_exists)
  688.      char *name;
  689.      int only_if_exists;
  690. {
  691.     Atom atom;
  692.  
  693.     if ((atom = XInternAtom(dpy, name, only_if_exists))==None)
  694.       return(0);
  695.  
  696.     return(atom);
  697. }
  698.  
  699. char *Skip_Past_Right_Paran(string)
  700.      char *string;
  701. {
  702.     char c;
  703.     int nesting=0;
  704.  
  705.     while (c=string++[0], c!=')' || nesting)
  706.       switch (c) {
  707.         case '\0':
  708.           Fatal_Error("Missing ')'.");
  709.         case '(':
  710.           nesting++;
  711.           break;
  712.         case ')':
  713.           nesting--;
  714.           break;
  715.         case '\\':
  716.           string++;
  717.           break;
  718.       }
  719.     return(string);
  720. }
  721.  
  722. /*
  723.  *
  724.  * The Format Manager: a group of routines to manage "formats"
  725.  *
  726.  */
  727.  
  728. int Is_A_Format(string)
  729. char *string;
  730. {
  731.     return(isdigit(string[0]));
  732. }
  733.  
  734. int Get_Format_Size(format)
  735.   char *format;
  736. {
  737.   long size;
  738.  
  739.   Scan_Long(format, &size);
  740.  
  741.   /* Check for legal sizes */
  742.   if (size != 0 && size != 8 && size != 16 && size != 32)
  743.     Fatal_Error("bad format: %s", format);
  744.  
  745.   return((int) size);
  746. }
  747.  
  748. char Get_Format_Char(format, i)
  749.      char *format;
  750.      int i;
  751. {
  752.   long size;
  753.  
  754.   /* Remove # at front of format */
  755.   format = Scan_Long(format, &size);
  756.   if (!*format)
  757.     Fatal_Error("bad format: %s", format);
  758.  
  759.   /* Last character repeats forever... */
  760.   if (i >= (int)strlen(format))
  761.     i=strlen(format)-1;
  762.  
  763.   return(format[i]);
  764. }
  765.  
  766. char *Format_Thunk(t, format_char)
  767.      thunk t;
  768.      char format_char;
  769. {
  770.   long value;
  771.   value = t.value;
  772.  
  773.   switch (format_char) {
  774.   case 's':
  775.     return(Format_Len_String(t.extra_value, t.value));
  776.   case 'x':
  777.     return(Format_Hex(value));
  778.   case 'c':
  779.     return(Format_Unsigned(value));
  780.   case 'i':
  781.     return(Format_Signed(value));
  782.   case 'b':
  783.     return(Format_Bool(value));
  784.   case 'm':
  785.     return(Format_Mask_Word(value));
  786.   case 'a':
  787.     return(Format_Atom(value));
  788.   default:
  789.     Fatal_Error("bad format character: %c", format_char);
  790.   }
  791. }
  792.  
  793. char *Format_Thunk_I(thunks, format, i)
  794.      thunk *thunks;
  795.      char *format;
  796.      int i;
  797. {
  798.   if (i >= thunks->thunk_count)
  799.     return("<field not available>");
  800.  
  801.   return(Format_Thunk(thunks[i], Get_Format_Char(format, i)));
  802. }
  803.  
  804. long Mask_Word(thunks, format)
  805.      thunk *thunks;
  806.      char *format;
  807. {
  808.     int j;
  809.  
  810.     for (j=0; j<(int)strlen(format); j++)
  811.       if (Get_Format_Char(format, j) == 'm')
  812.         return(thunks[j].value);
  813.     return(0L);
  814. }
  815.  
  816. /*
  817.  *
  818.  * The Display Format Manager:
  819.  *
  820.  */
  821.  
  822. int Is_A_DFormat(string)
  823.      char *string;
  824. {
  825.   return( string[0] && string[0] != '-' &&
  826.      !(isalpha(string[0]) || string[0] == '_') );
  827. }
  828.  
  829. char *Handle_Backslash(dformat)
  830.      char *dformat;
  831. {
  832.     char c;
  833.     long i;
  834.  
  835.     if (!(c = *(dformat++)))
  836.       return(dformat);
  837.  
  838.     switch (c) {
  839.           case 'n':
  840.         putchar('\n');
  841.         break;
  842.           case 't':
  843.         putchar('\t');
  844.         break;
  845.           case '0':
  846.           case '1':
  847.           case '2':
  848.           case '3':
  849.           case '4':
  850.           case '5':
  851.           case '6':
  852.           case '7':
  853.         dformat = Scan_Octal(dformat, &i);
  854.         putchar((int) i);
  855.         break;
  856.           default:
  857.         putchar(c);
  858.         break;
  859.     }
  860.     return(dformat);
  861. }
  862.  
  863. char *Handle_Dollar_sign(dformat, thunks, format)
  864.      char *dformat;
  865.      thunk *thunks;
  866.      char *format;
  867. {
  868.     long i;
  869.  
  870.     dformat = Scan_Long(dformat, &i);
  871.  
  872.     if (dformat[0]=='+') {
  873.         int seen=0;
  874.         dformat++;
  875.         for (; i<thunks->thunk_count; i++) {
  876.             if (seen)
  877.               printf(", ");
  878.             seen = 1;
  879.             printf("%s", Format_Thunk_I(thunks, format, (int) i));
  880.         }
  881.     } else
  882.       printf("%s", Format_Thunk_I(thunks, format, (int) i));
  883.  
  884.     return(dformat);
  885. }
  886.  
  887. int Mask_Bit_I(thunks, format, i)
  888.      thunk *thunks;
  889.      char *format;
  890.      int i;
  891. {
  892.     long value;
  893.  
  894.     value = Mask_Word(thunks, format);
  895.  
  896.     value = value & (1L<<i);
  897.     if (value)
  898.       value=1;
  899.     return(value);
  900. }
  901.  
  902. char *Scan_Term(string, thunks, format, value)
  903.      thunk *thunks;
  904.      char *string, *format;
  905.      long *value;
  906. {
  907.     long i;
  908.  
  909.     *value=0;
  910.  
  911.     if (isdigit(*string))
  912.       string = Scan_Long(string, value);
  913.     else if (*string=='$') {
  914.         string = Scan_Long(++string, &i);
  915.         if (i>=thunks->thunk_count)
  916.           i=thunks->thunk_count;
  917.         *value = thunks[i].value;
  918.     } else if (*string=='m') {
  919.         string = Scan_Long(++string, &i);
  920.         *value = Mask_Bit_I(thunks, format, (int) i);
  921.     } else
  922.       Fatal_Error("Bad term: %s.", string);
  923.  
  924.     return(string);
  925. }
  926.  
  927. char *Scan_Exp(string, thunks, format, value)
  928.      thunk *thunks;
  929.      char *string, *format;
  930.      long *value;
  931. {
  932.     long temp;
  933.  
  934.     if (string[0]=='(') {
  935.         string = Scan_Exp(++string, thunks, format, value);
  936.         if (string[0]!=')')
  937.           Fatal_Error("Missing ')'");
  938.         return(++string);
  939.     }
  940.     if (string[0]=='!') {
  941.         string = Scan_Exp(++string, thunks, format, value);
  942.         *value = !*value;
  943.         return(string);
  944.     }
  945.  
  946.     string = Scan_Term(string, thunks, format, value);
  947.  
  948.     if (string[0]=='=') {
  949.         string = Scan_Exp(++string, thunks, format, &temp);
  950.         *value = *value == temp;
  951.     }
  952.  
  953.     return(string);
  954. }
  955.  
  956. char *Handle_Question_Mark(dformat, thunks, format)
  957.      thunk *thunks;
  958.      char *dformat, *format;
  959. {
  960.     long true;
  961.  
  962.     dformat = Scan_Exp(dformat, thunks, format, &true);
  963.  
  964.     if (*dformat!='(')
  965.       Fatal_Error("Bad conditional: '(' expected: %s.", dformat);
  966.     ++dformat;
  967.  
  968.     if (!true)
  969.       dformat = Skip_Past_Right_Paran(dformat);
  970.  
  971.     return(dformat);
  972. }
  973.  
  974. Display_Property(thunks, dformat, format)
  975.      thunk *thunks;
  976.      char *dformat, *format;
  977. {
  978.   char c;
  979.  
  980.   while (c = *(dformat++))
  981.     switch (c) {
  982.       case ')':
  983.         continue;
  984.       case '\\':
  985.         dformat = Handle_Backslash(dformat);
  986.         continue;
  987.       case '$':
  988.         dformat = Handle_Dollar_sign(dformat, thunks, format);
  989.         continue;
  990.       case '?':
  991.         dformat = Handle_Question_Mark(dformat, thunks, format);
  992.         continue;
  993.       default:
  994.         putchar(c);
  995.         continue;
  996.     }
  997. }
  998.  
  999. /*
  1000.  *
  1001.  * Routines to convert property data to and from thunks
  1002.  *
  1003.  */
  1004.  
  1005. long Extract_Value(pointer, length, size, signedp)
  1006.      char **pointer;
  1007.      int *length;
  1008.      int size;
  1009. {
  1010.     long value, mask;
  1011.  
  1012.     switch (size) {
  1013.           case 8:
  1014.         value = (long) * (char *) *pointer;
  1015.         *pointer += 1;
  1016.         *length -= 1;
  1017.         mask = 0xff;
  1018.         break;
  1019.           case 16:
  1020.         value = (long) * (short *) *pointer;
  1021.         *pointer += 2;
  1022.         *length -= 2;
  1023.         mask = 0xffff;
  1024.         break;
  1025.           default:
  1026.         /* Error */
  1027.           case 32:
  1028.         value = (long) * (long *) *pointer;
  1029.         *pointer += 4;
  1030.         *length -= 4;
  1031.         mask = 0xffffffff;
  1032.         break;
  1033.     }
  1034.     if (!signedp)
  1035.       value &= mask;
  1036.     return(value);
  1037. }
  1038.  
  1039. long Extract_Len_String(pointer, length, size, string)
  1040.      char **pointer;
  1041.      int *length;
  1042.      int size;
  1043.      char **string;
  1044. {
  1045.     int len;
  1046.  
  1047.     if (size!=8)
  1048.      Fatal_Error("can't use format character 's' with any size except 8.");
  1049.     len=0; *string = *pointer;
  1050.     while ((len++, --*length, *((*pointer)++)) && *length>0);
  1051.  
  1052.     return(len);
  1053. }
  1054.  
  1055. thunk *Break_Down_Property(pointer, length, format, size)
  1056.      char *pointer, *format;
  1057.      int length, size;
  1058. {
  1059.     thunk *thunks;
  1060.     thunk t;
  1061.     int i;
  1062.     char format_char;
  1063.  
  1064.     thunks = Create_Thunk_List();
  1065.     i=0;
  1066.  
  1067.     while (length>=(size/8)) {
  1068.         format_char = Get_Format_Char(format, i);
  1069.         if (format_char=='s')
  1070.           t.value=Extract_Len_String(&pointer,&length,size,&t.extra_value);
  1071.         else
  1072.           t.value=Extract_Value(&pointer,&length,size,format_char=='i');
  1073.         thunks = Add_Thunk(thunks, t);
  1074.         i++;
  1075.         }
  1076.  
  1077.     return(thunks);
  1078. }
  1079.  
  1080. /*
  1081.  * 
  1082.  * Routines for parsing command line:
  1083.  *
  1084.  */
  1085.  
  1086. usage()
  1087. {
  1088.     char **cpp;
  1089.     static char *help_message[] = {
  1090. "where options include:",
  1091. "    -grammar                       print out full grammar for command line",
  1092. "    -display host:dpy              the X server to contact",
  1093. "    -id id                         resource id of window to examine",
  1094. "    -name name                     name of window to examine",
  1095. "    -font name                     name of font to examine",
  1096. "    -remove propname               name of property to remove",
  1097. "    -root                          examine the root window",
  1098. "    -len n                         display at most n bytes of any property",
  1099. "    -notype                        do not display the type field",
  1100. "    -fs filename                   where to look for formats for properties",
  1101. "    -frame                         don't ignore window manager frames",
  1102. "    -f propname format [dformat]   formats to use for property of given name",
  1103. "    -spy                           examine window properties forever",
  1104. NULL};
  1105.  
  1106.     fflush (stdout);
  1107.     fprintf (stderr, "usage:  %s [-options ...] [[format [dformat]] atom]\n\n", 
  1108.          program_name);
  1109.     for (cpp = help_message; *cpp; cpp++) {
  1110.     fprintf (stderr, "%s\n", *cpp);
  1111.     }
  1112.     fprintf (stderr, "\n");
  1113.     exit (1);
  1114. }
  1115.  
  1116. grammar ()
  1117. {
  1118.     printf ("Grammar for xprop:\n\n");
  1119.     printf("\t%s [<disp>] [<select option>] <option>* <mapping>* <spec>*",
  1120.          program_name);
  1121.     printf("\n\n\tdisp ::= -display host:dpy\
  1122. \n\tselect option ::= -root | -id <id> | -font <font> | -name <name>\
  1123. \n\toption ::= -len <n> | -notype | -spy | {-formats|-fs} <format file>\
  1124. \n\tmapping ::= {-f|-format} <atom> <format> [<dformat>] | -remove <propname>\
  1125. \n\tspec ::= [<format> [<dformat>]] <atom>\
  1126. \n\tformat ::= {0|8|16|32}{a|b|c|i|m|s|x}*\
  1127. \n\tdformat ::= <unit><unit>*             (can't start with a letter or '-')\
  1128. \n\tunit ::= ?<exp>(<unit>*) | $<n> | <display char>\
  1129. \n\texp ::= <term> | <term>=<exp> | !<exp>\
  1130. \n\tterm ::= <n> | $<n> | m<n>\
  1131. \n\tdisplay char ::= <normal char> | \\<non digit char> | \\<octal number>\
  1132. \n\tnormal char ::= <any char except a digit, $, ?, \\, or )>\
  1133. \n\n");
  1134.     exit(0);
  1135. }
  1136.  
  1137. Parse_Format_Mapping(argc, argv)
  1138.      int *argc;
  1139.      char ***argv;
  1140. #define ARGC (*argc)
  1141. #define ARGV (*argv)
  1142. #define OPTION ARGV[0]
  1143. #define NXTOPT if (++ARGV, --ARGC==0) usage()
  1144. {
  1145.   char *type_name, *format, *dformat;
  1146.   
  1147.   NXTOPT; type_name = OPTION;
  1148.  
  1149.   NXTOPT; format = OPTION;
  1150.   if (!Is_A_Format(format))
  1151.     Fatal_Error("Bad format: %s.", format);
  1152.  
  1153.   dformat=0;
  1154.   if (ARGC>0 && Is_A_DFormat(ARGV[1])) {
  1155.     ARGV++; ARGC--; dformat=OPTION;
  1156.   }
  1157.  
  1158.   Add_Mapping( Parse_Atom(type_name, False), format, dformat);
  1159. }
  1160.  
  1161. /*
  1162.  *
  1163.  * The Main Program:
  1164.  *
  1165.  */
  1166.  
  1167. Window target_win=0;
  1168. int notype=0;
  1169. int spy=0;
  1170. int max_len=MAXSTR;
  1171. XFontStruct *font;
  1172.  
  1173. main(argc, argv)
  1174. int argc;
  1175. char **argv;
  1176. {
  1177.   FILE *stream;
  1178.   char *name;
  1179.   thunk *props, *Handle_Prop_Requests();
  1180.   char *remove_propname = NULL;
  1181.   Bool frame_only = False;
  1182.   int n;
  1183.   char **nargv;
  1184.  
  1185.   INIT_NAME;
  1186.  
  1187.   /* Handle display name, opening the display */
  1188.   Setup_Display_And_Screen(&argc, argv);
  1189.  
  1190.   /* Handle selecting the window to display properties for */
  1191.   target_win = Select_Window_Args(&argc, argv);
  1192.  
  1193.   /* Set up default atom to format, dformat mapping */
  1194.   XpropMode = XpropWindowProperties;
  1195.   for (n=argc, nargv=argv; n; nargv++, n--)
  1196.       if (! strcmp(nargv[0], "-font")) {
  1197.       XpropMode = XpropFontProperties;
  1198.       break;
  1199.       }
  1200.   Setup_Mapping();
  1201.   if (name = getenv("XPROPFORMATS")) {
  1202.       if (!(stream=fopen(name, "r")))
  1203.         Fatal_Error("unable to open file %s for reading.", name);
  1204.       Read_Mappings(stream);
  1205.       fclose(stream);
  1206.   }
  1207.  
  1208.   /* Handle '-' options to setup xprop, select window to work on */
  1209.   while (argv++, --argc>0 && **argv=='-') {
  1210.     if (!strcmp(argv[0], "-"))
  1211.       continue;
  1212.     if (!strcmp(argv[0], "-grammar")) {
  1213.       grammar ();
  1214.       /* NOTREACHED */
  1215.     }
  1216.     if (!strcmp(argv[0], "-notype")) {
  1217.       notype=1;
  1218.       continue;
  1219.     }
  1220.     if (!strcmp(argv[0], "-spy")) {
  1221.         spy=1;
  1222.         continue;
  1223.     }
  1224.     if (!strcmp(argv[0], "-len")) {
  1225.         if (++argv, --argc==0) usage();
  1226.         max_len = atoi(argv[0]);
  1227.         continue;
  1228.     }
  1229.     if (!strcmp(argv[0], "-formats") || !strcmp(argv[0], "-fs")) {
  1230.         if (++argv, --argc==0) usage();
  1231.         if (!(stream=fopen(argv[0], "r")))
  1232.           Fatal_Error("unable to open file %s for reading.", argv[0]);
  1233.         Read_Mappings(stream);
  1234.         fclose(stream);
  1235.         continue;
  1236.     }
  1237.     if (!strcmp(argv[0], "-font")) {
  1238.         if (++argv, --argc==0) usage();
  1239.         font = Open_Font(argv[0]);
  1240.         target_win = -1;
  1241.         continue;
  1242.     }
  1243.     if (!strcmp(argv[0], "-remove")) {
  1244.         if (++argv, --argc==0) usage();
  1245.         remove_propname = argv[0];
  1246.         continue;
  1247.     }
  1248.     if (!strcmp(argv[0], "-frame")) {
  1249.         frame_only = True;
  1250.         continue;
  1251.     }
  1252.     if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "-format")) {
  1253.       Parse_Format_Mapping(&argc, &argv);
  1254.       continue;
  1255.     }
  1256.     usage();
  1257.   }
  1258.  
  1259.   if (target_win == None) {
  1260.       target_win = Select_Window(dpy);
  1261.       if (target_win != None && !frame_only) {
  1262.     Window root;
  1263.     int dummyi;
  1264.     unsigned int dummy;
  1265.  
  1266.     if (XGetGeometry (dpy, target_win, &root, &dummyi, &dummyi,
  1267.               &dummy, &dummy, &dummy, &dummy) &&
  1268.         target_win != root)
  1269.       target_win = XmuClientWindow (dpy, target_win);
  1270.       }
  1271.   }
  1272.  
  1273.   if (remove_propname) {
  1274.     remove_property (dpy, target_win, remove_propname);
  1275.     XCloseDisplay (dpy);
  1276.     exit (0);
  1277.   }
  1278.  
  1279.   props=Handle_Prop_Requests(argc, argv);
  1280.  
  1281.   if (spy && target_win != -1) {
  1282.     XEvent event;
  1283.         char *format, *dformat;
  1284.     
  1285.     XSelectInput(dpy, target_win, PropertyChangeMask);
  1286.     for (;;) {
  1287.         XNextEvent(dpy, &event);
  1288.         format = dformat = NULL;
  1289.         if (props) {
  1290.             int i;
  1291.             for (i=0; i<props->thunk_count; i++)
  1292.               if (props[i].value == event.xproperty.atom)
  1293.                 break;
  1294.             if (i>=props->thunk_count)
  1295.               continue;
  1296.             format = props[i].format;
  1297.             dformat = props[i].dformat;
  1298.             }
  1299.         Show_Prop(format, dformat, Format_Atom(event.xproperty.atom));
  1300.         }
  1301.   }
  1302.   exit (0);
  1303. }
  1304.  
  1305. /*
  1306.  *
  1307.  * Other Stuff (temp.):
  1308.  *
  1309.  */
  1310.  
  1311. remove_property (dpy, w, propname)
  1312.     Display *dpy;
  1313.     Window w;
  1314.     char *propname;
  1315. {
  1316.     Atom id = XInternAtom (dpy, propname, True);
  1317.  
  1318.     if (id == None) {
  1319.     fprintf (stderr, "%s:  no such property \"%s\"\n",
  1320.          program_name, propname);
  1321.     return;
  1322.     }
  1323.     XDeleteProperty (dpy, w, id);
  1324.     return;
  1325. }
  1326.  
  1327. thunk *Handle_Prop_Requests(argc, argv)
  1328.      int argc;
  1329.      char **argv;
  1330. {
  1331.   char *format, *dformat, *prop;
  1332.   thunk *thunks, t;
  1333.  
  1334.   thunks = Create_Thunk_List();
  1335.  
  1336.   /* if no prop referenced, by default list all properties for given window */
  1337.   if (!argc) {
  1338.     Show_All_Props();
  1339.     return(NULL);
  1340.   }
  1341.  
  1342.   while (argc>0) {
  1343.     format = 0;
  1344.     dformat = 0;
  1345.  
  1346.     /* Get overriding formats, if any */
  1347.     if (Is_A_Format(argv[0])) {
  1348.       format = argv++[0]; argc--;
  1349.       if (!argc) usage();
  1350.     }
  1351.     if (Is_A_DFormat(argv[0])) {
  1352.       dformat = argv++[0]; argc--;
  1353.       if (!argc) usage();
  1354.     }
  1355.  
  1356.     /* Get property name */
  1357.     prop = argv++[0]; argc--;
  1358.  
  1359.     t.value = Parse_Atom(prop, True);
  1360.     t.format = format;
  1361.     t.dformat = dformat;
  1362.     if (t.value)
  1363.       thunks = Add_Thunk(thunks, t);
  1364.     Show_Prop(format, dformat, prop);
  1365.   }
  1366.   return(thunks);
  1367. }
  1368.  
  1369. Show_All_Props()
  1370. {
  1371.   Atom *atoms, atom;
  1372.   char *name;
  1373.   int count, i;
  1374.  
  1375.   if (target_win!=-1) {
  1376.       atoms = XListProperties(dpy, target_win, &count);
  1377.       for (i=0; i<count; i++) {
  1378.           name = Format_Atom(atoms[i]);
  1379.           Show_Prop(0, 0, name);
  1380.       }
  1381.   } else
  1382.     for (i=0; i<font->n_properties; i++) {
  1383.         atom = font->properties[i].name;
  1384.         name = Format_Atom(atom);
  1385.         Show_Prop(0, 0, name);
  1386.     }
  1387. }
  1388.  
  1389. Set_Prop(format, dformat, prop, mode, value)
  1390.      char *format, *dformat, *prop, *value;
  1391.      char mode;
  1392. {
  1393.   outl("Seting prop %s(%s) using %s mode %c to %s",
  1394.        prop, format, dformat, mode, value);
  1395. }
  1396.  
  1397. static unsigned long _font_prop;
  1398.  
  1399. char *Get_Font_Property_Data_And_Type(atom, length, type, size)
  1400.      Atom atom;
  1401.      long *length;
  1402.      Atom *type;
  1403.      int *size;
  1404. {
  1405.     int i;
  1406.     
  1407.     *type = 0;
  1408.     
  1409.     for (i=0; i<font->n_properties; i++)
  1410.       if (atom==font->properties[i].name) {
  1411.           _font_prop=font->properties[i].card32;
  1412.           *length=4;
  1413.           *size=32;
  1414.           return((char *) &_font_prop);
  1415.       }
  1416.     return(0);
  1417. }
  1418.  
  1419. char *Get_Window_Property_Data_And_Type(atom, length, type, size)
  1420.      Atom atom;
  1421.      long *length;
  1422.      Atom *type;
  1423.      int *size;
  1424. {
  1425.     Atom actual_type;
  1426.     int actual_format;
  1427.     unsigned long nitems;
  1428.     unsigned long bytes_after;
  1429.     unsigned char *prop;
  1430.     int status;
  1431.     
  1432.     status = XGetWindowProperty(dpy, target_win, atom, 0, (max_len+3)/4,
  1433.                     False, AnyPropertyType, &actual_type,
  1434.                     &actual_format, &nitems, &bytes_after,
  1435.                     &prop);
  1436.     if (status==BadWindow)
  1437.       Fatal_Error("window id # 0x%lx does not exists!", target_win);
  1438.     if (status!=Success)
  1439.       Fatal_Error("XGetWindowProperty failed!");
  1440.     
  1441.     *length = min(nitems * actual_format/8, max_len);
  1442.     *type = actual_type;
  1443.     *size = actual_format;
  1444.     return((char *)prop);
  1445. }
  1446.  
  1447. char *Get_Property_Data_And_Type(atom, length, type, size)
  1448.      Atom atom;
  1449.      long *length;
  1450.      Atom *type;
  1451.      int *size;
  1452. {
  1453.     if (target_win == -1)
  1454.       return(Get_Font_Property_Data_And_Type(atom, length, type, size));
  1455.     else
  1456.       return(Get_Window_Property_Data_And_Type(atom, length, type, size));
  1457. }
  1458.  
  1459. Show_Prop(format, dformat, prop)
  1460.      char *format, *dformat, *prop;
  1461. {
  1462.   char *data;
  1463.   long length;
  1464.   Atom atom, type;
  1465.   thunk *thunks;
  1466.   int size, fsize;
  1467.  
  1468.   printf("%s", prop);
  1469.   if (!(atom = Parse_Atom(prop, True))) {
  1470.       printf(":  no such atom on any window.\n");
  1471.       return;
  1472.   }
  1473.  
  1474.   data = Get_Property_Data_And_Type(atom, &length, &type, &size);
  1475.   if (!size) {
  1476.           puts(":  not found.");
  1477.       return;
  1478.   }
  1479.  
  1480.   if (!notype && type)
  1481.     printf("(%s)", Format_Atom(type));
  1482.  
  1483.   Lookup_Formats(atom, &format, &dformat);
  1484.   if (type)
  1485.     Lookup_Formats(type, &format, &dformat);
  1486.   Apply_Default_Formats(&format, &dformat);
  1487.  
  1488.   fsize=Get_Format_Size(format);
  1489.   if (fsize!=size && fsize!=0) {
  1490.     printf(": Type mismatch: assumed size %d bits, actual size %d bits.\n",
  1491.      fsize, size);
  1492.       return;
  1493.   }
  1494.  
  1495.   thunks = Break_Down_Property(data, length, format, size);
  1496.  
  1497.   Display_Property(thunks, dformat, format);
  1498. }
  1499.