xlsfonts.c revision 8fff3f40
1e6232409Smrg/*
2e6232409Smrg * $Xorg: xlsfonts.c,v 1.4 2001/02/09 02:05:54 xorgcvs Exp $
3e6232409Smrg *
4e6232409Smrg *
5e6232409SmrgCopyright 1989, 1998  The Open Group
6e6232409Smrg
7e6232409SmrgPermission to use, copy, modify, distribute, and sell this software and its
8e6232409Smrgdocumentation for any purpose is hereby granted without fee, provided that
9e6232409Smrgthe above copyright notice appear in all copies and that both that
10e6232409Smrgcopyright notice and this permission notice appear in supporting
11e6232409Smrgdocumentation.
12e6232409Smrg
13e6232409SmrgThe above copyright notice and this permission notice shall be included in
14e6232409Smrgall copies or substantial portions of the Software.
15e6232409Smrg
16e6232409SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17e6232409SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18e6232409SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19e6232409SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20e6232409SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21e6232409SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22e6232409Smrg
23e6232409SmrgExcept as contained in this notice, the name of The Open Group shall not be
24e6232409Smrgused in advertising or otherwise to promote the sale, use or other dealings
25e6232409Smrgin this Software without prior written authorization from The Open Group.
26e6232409Smrg * */
27e6232409Smrg/* $XFree86: xc/programs/xlsfonts/xlsfonts.c,v 1.9 2003/09/08 14:25:33 eich Exp $ */
28e6232409Smrg
29e6232409Smrg#include <X11/Xlib.h>
30e6232409Smrg#include <X11/Xutil.h>
31e6232409Smrg#include <X11/Xos.h>
32e6232409Smrg#include <stdio.h>
33e6232409Smrg#include <stdlib.h>
34e6232409Smrg#include <limits.h>
35e6232409Smrg#include "dsimple.h"
36e6232409Smrg
37e6232409Smrg#define N_START INT_MAX  /* Maximum # of fonts to start with (should
38e6232409Smrg                          * always be be > 10000 as modern OSes like
39e6232409Smrg                          * Solaris 8 already have more than 9000 XLFD
40e6232409Smrg                          * fonts available) */
41e6232409Smrg
42e6232409Smrg#define L_SHORT    0
43e6232409Smrg#define L_MEDIUM   1
44e6232409Smrg#define L_LONG     2
45e6232409Smrg#define L_VERYLONG 3
46e6232409Smrg
47e6232409Smrgstatic int  max_output_line_width     = 79;
48e6232409Smrgstatic int  output_line_padding       = 3;
49e6232409Smrgstatic int  columns                   = 0;
50e6232409Smrg
51e6232409Smrgstatic Bool sort_output               = True;
52e6232409Smrgstatic Bool open_instead_of_list      = False;
53e6232409Smrgstatic int  long_list                 = L_SHORT;
54e6232409Smrgstatic int  nnames                    = N_START;
55e6232409Smrgstatic int  font_cnt                  = 0;
56e6232409Smrgstatic int  min_max;
57e6232409Smrg
58e6232409Smrgtypedef struct {
59e6232409Smrg  char           *name;
60e6232409Smrg  XFontStruct    *info;
61e6232409Smrg} FontList;
62e6232409Smrg
63e6232409Smrgstatic FontList *font_list = NULL;
64e6232409Smrg
65e6232409Smrg/* Local prototypes */
66e6232409Smrgstatic void get_list(char *pattern);
67e6232409Smrgstatic int  compare(const void *arg1, const void *arg2);
68e6232409Smrgstatic void show_fonts(void);
69e6232409Smrgstatic void copy_number(char **pp1, char**pp2, int n1, int n2);
70e6232409Smrgstatic int  IgnoreError(Display *disp, XErrorEvent *event);
71e6232409Smrgstatic void PrintProperty(XFontProp *prop);
72e6232409Smrgstatic void ComputeFontType(XFontStruct *fs);
73e6232409Smrgstatic void print_character_metrics(register XFontStruct *info);
74e6232409Smrgstatic void do_query_font (Display *dpy, char *name);
75e6232409Smrg
76e6232409Smrgvoid usage(void)
77e6232409Smrg{
78e6232409Smrg    fprintf (stderr, "usage:  %s [-options] [-fn pattern]\n", program_name);
79e6232409Smrg    fprintf (stderr, "where options include:\n");
80e6232409Smrg    fprintf (stderr, "    -l[l[l]]                 give long info about each font\n");
81e6232409Smrg    fprintf (stderr, "    -m                       give character min and max bounds\n");
82e6232409Smrg    fprintf (stderr, "    -C                       force columns\n");
83e6232409Smrg    fprintf (stderr, "    -1                       force single column\n");
84e6232409Smrg    fprintf (stderr, "    -u                       keep output unsorted\n");
85e6232409Smrg    fprintf (stderr, "    -o                       use OpenFont/QueryFont instead of ListFonts\n");
86e6232409Smrg    fprintf (stderr, "    -w width                 maximum width for multiple columns\n");
87e6232409Smrg    fprintf (stderr, "    -n columns               number of columns if multi column\n");
88e6232409Smrg    fprintf (stderr, "    -display displayname     X server to contact\n");
89e6232409Smrg    fprintf (stderr, "    -d displayname           (alias for -display displayname)\n");
90e6232409Smrg    fprintf (stderr, "\n");
91e6232409Smrg    Close_Display();
92e6232409Smrg    exit(EXIT_FAILURE);
93e6232409Smrg}
94e6232409Smrg
95e6232409Smrgint main(int argc, char **argv)
96e6232409Smrg{
97e6232409Smrg    int argcnt = 0, i;
98e6232409Smrg
99e6232409Smrg    INIT_NAME;
100e6232409Smrg
101e6232409Smrg    /* Handle command line arguments, open display */
102e6232409Smrg    Setup_Display_And_Screen(&argc, argv);
103e6232409Smrg
104e6232409Smrg    for (argv++, argc--; argc; argv++, argc--) {
105e6232409Smrg        if (argv[0][0] == '-') {
106e6232409Smrg            if (argcnt > 0) usage ();
107e6232409Smrg            for (i=1; argv[0][i]; i++)
108e6232409Smrg                switch(argv[0][i]) {
109e6232409Smrg                case 'l':
110e6232409Smrg                    long_list++;
111e6232409Smrg                    break;
112e6232409Smrg                case 'm':
113e6232409Smrg                    min_max++;
114e6232409Smrg                    break;
115e6232409Smrg                case 'C':
116e6232409Smrg                    columns = 0;
117e6232409Smrg                    break;
118e6232409Smrg                case '1':
119e6232409Smrg                    columns = 1;
120e6232409Smrg                    break;
121e6232409Smrg                case 'f': /* "-fn" */
122e6232409Smrg                    if (--argc <= 0) usage ();
123e6232409Smrg                    if (argv[0][i+1] != 'n') usage ();
124e6232409Smrg                    argcnt++;
125e6232409Smrg                    argv++;
126e6232409Smrg                    get_list(argv[0]);
127e6232409Smrg                    goto next;
128e6232409Smrg                case 'w':
129e6232409Smrg                    if (--argc <= 0) usage ();
130e6232409Smrg                    argv++;
131e6232409Smrg                    max_output_line_width = atoi(argv[0]);
132e6232409Smrg                    goto next;
133e6232409Smrg                case 'n':
134e6232409Smrg                    if (--argc <= 0) usage ();
135e6232409Smrg                    argv++;
136e6232409Smrg                    columns = atoi(argv[0]);
137e6232409Smrg                    goto next;
138e6232409Smrg                case 'o':
139e6232409Smrg                    open_instead_of_list = True;
140e6232409Smrg                    break;
141e6232409Smrg                case 'u':
142e6232409Smrg                    sort_output = False;
143e6232409Smrg                    break;
144e6232409Smrg                default:
145e6232409Smrg                    usage();
146e6232409Smrg                    break;
147e6232409Smrg                }
148e6232409Smrg            if (i == 1)
149e6232409Smrg                usage();
150e6232409Smrg        } else {
151e6232409Smrg            argcnt++;
152e6232409Smrg            get_list(argv[0]);
153e6232409Smrg        }
154e6232409Smrg      next: ;
155e6232409Smrg    }
156e6232409Smrg
157e6232409Smrg    if (argcnt == 0)
158e6232409Smrg        get_list("*");
159e6232409Smrg
160e6232409Smrg    show_fonts();
161e6232409Smrg
162e6232409Smrg    Close_Display();
163e6232409Smrg    return EXIT_SUCCESS;
164e6232409Smrg}
165e6232409Smrg
166e6232409Smrg
167e6232409Smrgstatic
168e6232409Smrgvoid get_list(char *pattern)
169e6232409Smrg{
170e6232409Smrg    int           available = nnames+1,
171e6232409Smrg                  i;
172e6232409Smrg    char        **fonts;
173e6232409Smrg    XFontStruct  *info;
174e6232409Smrg
175e6232409Smrg    /* Get list of fonts matching pattern */
176e6232409Smrg    for (;;) {
177e6232409Smrg        if (open_instead_of_list) {
178e6232409Smrg            info = XLoadQueryFont (dpy, pattern);
179e6232409Smrg
180e6232409Smrg            if (info) {
181e6232409Smrg                fonts = &pattern;
182e6232409Smrg                available = 1;
183e6232409Smrg                XUnloadFont (dpy, info->fid);
184e6232409Smrg            } else {
185e6232409Smrg                fonts = NULL;
186e6232409Smrg            }
187e6232409Smrg            break;
188e6232409Smrg        }
189e6232409Smrg
190e6232409Smrg        if (long_list == L_MEDIUM)
191e6232409Smrg            fonts = XListFontsWithInfo(dpy, pattern, nnames, &available, &info);
192e6232409Smrg        else
193e6232409Smrg            fonts = XListFonts(dpy, pattern, nnames, &available);
194e6232409Smrg        if (fonts == NULL || available < nnames)
195e6232409Smrg            break;
196e6232409Smrg        if (long_list == L_MEDIUM)
197e6232409Smrg            XFreeFontInfo(fonts, info, available);
198e6232409Smrg        else
199e6232409Smrg            XFreeFontNames(fonts);
200e6232409Smrg        nnames = available * 2;
201e6232409Smrg    }
202e6232409Smrg
203e6232409Smrg    if (fonts == NULL) {
204e6232409Smrg        fprintf(stderr, "%s: pattern \"%s\" unmatched\n",
205e6232409Smrg                program_name, pattern);
206e6232409Smrg        return;
207e6232409Smrg    }
208e6232409Smrg
209e6232409Smrg    font_list = (FontList *)Realloc((char *)font_list,
210e6232409Smrg            (font_cnt + available) * sizeof(FontList));
211e6232409Smrg    for (i=0; i<available; i++) {
212e6232409Smrg        font_list[font_cnt].name = fonts[i];
213e6232409Smrg        if (long_list == L_MEDIUM)
214e6232409Smrg            font_list[font_cnt].info = info + i;
215e6232409Smrg        else
216e6232409Smrg            font_list[font_cnt].info = NULL;
217e6232409Smrg
218e6232409Smrg        font_cnt++;
219e6232409Smrg    }
220e6232409Smrg}
221e6232409Smrg
222e6232409Smrgstatic
223e6232409Smrgint compare(const void *arg1, const void *arg2)
224e6232409Smrg{
225e6232409Smrg    const FontList *f1 = arg1;
226e6232409Smrg    const FontList *f2 = arg2;
227e6232409Smrg    const char *p1 = f1->name;
228e6232409Smrg    const char *p2 = f2->name;
229e6232409Smrg
230e6232409Smrg    while (*p1 && *p2 && *p1 == *p2)
231e6232409Smrg            p1++, p2++;
232e6232409Smrg    return(*p1 - *p2);
233e6232409Smrg}
234e6232409Smrg
235e6232409Smrgstatic
236e6232409Smrgvoid show_fonts(void)
237e6232409Smrg{
238e6232409Smrg    int i;
239e6232409Smrg
240e6232409Smrg    if (font_cnt == 0)
241e6232409Smrg        return;
242e6232409Smrg
243e6232409Smrg    /* first sort the output */
244e6232409Smrg    if (sort_output) qsort(font_list, font_cnt, sizeof(FontList), compare);
245e6232409Smrg
246e6232409Smrg    if (long_list > L_MEDIUM) {
247e6232409Smrg        for (i = 0; i < font_cnt; i++) {
248e6232409Smrg            do_query_font (dpy, font_list[i].name);
249e6232409Smrg        }
250e6232409Smrg        return;
251e6232409Smrg    }
252e6232409Smrg
253e6232409Smrg    if (long_list == L_MEDIUM) {
254e6232409Smrg        XFontStruct *pfi;
255e6232409Smrg        char        *string;
256e6232409Smrg
257e6232409Smrg        printf("DIR  ");
258e6232409Smrg        printf("MIN  ");
259e6232409Smrg        printf("MAX ");
260e6232409Smrg        printf("EXIST ");
261e6232409Smrg        printf("DFLT ");
262e6232409Smrg        printf("PROP ");
263e6232409Smrg        printf("ASC ");
264e6232409Smrg        printf("DESC ");
265e6232409Smrg        printf("NAME");
266e6232409Smrg        printf("\n");
267e6232409Smrg        for (i=0; i<font_cnt; i++) {
268e6232409Smrg            pfi = font_list[i].info;
269e6232409Smrg            if (!pfi) {
270e6232409Smrg                fprintf(stderr, "%s:  no font information for font \"%s\".\n",
271e6232409Smrg                        program_name,
272e6232409Smrg                        font_list[i].name ?
273e6232409Smrg                        font_list[i].name : "");
274e6232409Smrg                continue;
275e6232409Smrg            }
276e6232409Smrg            switch(pfi->direction) {
277e6232409Smrg                case FontLeftToRight: string = "-->"; break;
278e6232409Smrg                case FontRightToLeft: string = "<--"; break;
279e6232409Smrg                default:              string = "???"; break;
280e6232409Smrg            }
281e6232409Smrg            printf("%-4s", string);
282e6232409Smrg            if (pfi->min_byte1 == 0 &&
283e6232409Smrg                pfi->max_byte1 == 0) {
284e6232409Smrg                printf(" %3d ", pfi->min_char_or_byte2);
285e6232409Smrg                printf(" %3d ", pfi->max_char_or_byte2);
286e6232409Smrg            } else {
287e6232409Smrg                printf("*%3d ", pfi->min_byte1);
288e6232409Smrg                printf("*%3d ", pfi->max_byte1);
289e6232409Smrg            }
290e6232409Smrg            printf("%5s ", pfi->all_chars_exist ? "all" : "some");
291e6232409Smrg            printf("%4d ", pfi->default_char);
292e6232409Smrg            printf("%4d ", pfi->n_properties);
293e6232409Smrg            printf("%3d ", pfi->ascent);
294e6232409Smrg            printf("%4d ", pfi->descent);
295e6232409Smrg            printf("%s\n", font_list[i].name);
296e6232409Smrg            if (min_max) {
297e6232409Smrg                char  min[ BUFSIZ ],
298e6232409Smrg                      max[ BUFSIZ ];
299e6232409Smrg                char *pmax = max,
300e6232409Smrg                     *pmin = min;
301e6232409Smrg
302e6232409Smrg                strcpy(pmin, "     min(l,r,w,a,d) = (");
303e6232409Smrg                strcpy(pmax, "     max(l,r,w,a,d) = (");
304e6232409Smrg                pmin += strlen(pmin);
305e6232409Smrg                pmax += strlen(pmax);
306e6232409Smrg
307e6232409Smrg                copy_number(&pmin, &pmax,
308e6232409Smrg                            pfi->min_bounds.lbearing,
309e6232409Smrg                            pfi->max_bounds.lbearing);
310e6232409Smrg                *pmin++ = *pmax++ = ',';
311e6232409Smrg                copy_number(&pmin, &pmax,
312e6232409Smrg                            pfi->min_bounds.rbearing,
313e6232409Smrg                            pfi->max_bounds.rbearing);
314e6232409Smrg                *pmin++ = *pmax++ = ',';
315e6232409Smrg                copy_number(&pmin, &pmax,
316e6232409Smrg                            pfi->min_bounds.width,
317e6232409Smrg                            pfi->max_bounds.width);
318e6232409Smrg                *pmin++ = *pmax++ = ',';
319e6232409Smrg                copy_number(&pmin, &pmax,
320e6232409Smrg                            pfi->min_bounds.ascent,
321e6232409Smrg                            pfi->max_bounds.ascent);
322e6232409Smrg                *pmin++ = *pmax++ = ',';
323e6232409Smrg                copy_number(&pmin, &pmax,
324e6232409Smrg                            pfi->min_bounds.descent,
325e6232409Smrg                            pfi->max_bounds.descent);
326e6232409Smrg                *pmin++ = *pmax++ = ')';
327e6232409Smrg                *pmin = *pmax = '\0';
328e6232409Smrg                printf("%s\n", min);
329e6232409Smrg                printf("%s\n", max);
330e6232409Smrg            }
331e6232409Smrg        }
332e6232409Smrg        return;
333e6232409Smrg    }
334e6232409Smrg
335e6232409Smrg    if ((columns == 0 && isatty(1)) || columns > 1) {
336e6232409Smrg        int width,
337e6232409Smrg            max_width = 0,
338e6232409Smrg            lines_per_column,
339e6232409Smrg            j,
340e6232409Smrg            index;
341e6232409Smrg
342e6232409Smrg        for (i=0; i<font_cnt; i++) {
343e6232409Smrg            width = strlen(font_list[i].name);
344e6232409Smrg            if (width > max_width)
345e6232409Smrg                max_width = width;
346e6232409Smrg        }
347e6232409Smrg        if (max_width == 0)
348e6232409Smrg            Fatal_Error("all %d fontnames listed are zero length", font_cnt);
349e6232409Smrg
350e6232409Smrg        if (columns == 0) {
351e6232409Smrg            if ((max_width * 2) + output_line_padding >
352e6232409Smrg                max_output_line_width) {
353e6232409Smrg                columns = 1;
354e6232409Smrg            } else {
355e6232409Smrg                max_width += output_line_padding;
356e6232409Smrg                columns = ((max_output_line_width +
357e6232409Smrg                            output_line_padding) / max_width);
358e6232409Smrg            }
359e6232409Smrg        } else {
360e6232409Smrg            max_width += output_line_padding;
361e6232409Smrg        }
362e6232409Smrg        if (columns <= 1) goto single_column;
363e6232409Smrg
364e6232409Smrg        if (font_cnt < columns)
365e6232409Smrg            columns = font_cnt;
366e6232409Smrg        lines_per_column = (font_cnt + columns - 1) / columns;
367e6232409Smrg
368e6232409Smrg        for (i=0; i<lines_per_column; i++) {
369e6232409Smrg            for (j=0; j<columns; j++) {
370e6232409Smrg                index = j * lines_per_column + i;
371e6232409Smrg                if (index >= font_cnt)
372e6232409Smrg                    break;
373e6232409Smrg                if (j+1 == columns)
374e6232409Smrg                    printf("%s", font_list[ index ].name);
375e6232409Smrg                else
376e6232409Smrg                    printf("%-*s",
377e6232409Smrg                           max_width,
378e6232409Smrg                           font_list[ index ].name);
379e6232409Smrg            }
380e6232409Smrg            printf("\n");
381e6232409Smrg        }
382e6232409Smrg        return;
383e6232409Smrg    }
384e6232409Smrg
385e6232409Smrg  single_column:
386e6232409Smrg    for (i=0; i<font_cnt; i++)
387e6232409Smrg        printf("%s\n", font_list[i].name);
388e6232409Smrg}
389e6232409Smrg
390e6232409Smrgstatic
391e6232409Smrgvoid copy_number(char **pp1, char**pp2, int n1, int n2)
392e6232409Smrg{
393e6232409Smrg    char *p1 = *pp1;
394e6232409Smrg    char *p2 = *pp2;
395e6232409Smrg    int   w;
396e6232409Smrg
397e6232409Smrg    sprintf(p1, "%d", n1);
398e6232409Smrg    sprintf(p2, "%d", n2);
399e6232409Smrg    w = MAX(strlen(p1), strlen(p2));
400e6232409Smrg    sprintf(p1, "%*d", w, n1);
401e6232409Smrg    sprintf(p2, "%*d", w, n2);
402e6232409Smrg    p1 += strlen(p1);
403e6232409Smrg    p2 += strlen(p2);
404e6232409Smrg    *pp1 = p1;
405e6232409Smrg    *pp2 = p2;
406e6232409Smrg}
407e6232409Smrg
408e6232409Smrg
409e6232409Smrg
410e6232409Smrg/* ARGSUSED */
411e6232409Smrgstatic
412e6232409Smrgint IgnoreError(Display *disp, XErrorEvent *event)
413e6232409Smrg{
414e6232409Smrg    return 0;
415e6232409Smrg}
416e6232409Smrg
417e6232409Smrgstatic char *bounds_metrics_title =
418e6232409Smrg                      "width left  right  asc  desc   attr   keysym\n";
419e6232409Smrg
420e6232409Smrg#define PrintBounds(_what,_ptr) \
421e6232409Smrg{   register XCharStruct *p = (_ptr); \
4228fff3f40Smrg    printf ("\t%3s\t\t%4d  %4d  %4d  %4d  %4d  0x%04x\n", \
4238fff3f40Smrg          (_what), p->width, p->lbearing, \
424e6232409Smrg          p->rbearing, p->ascent, p->descent, p->attributes); }
425e6232409Smrg
426e6232409Smrg
427e6232409Smrgstatic char* stringValued [] = { /* values are atoms */
428e6232409Smrg    /* font name components (see section 3.2 of the XLFD) */
429e6232409Smrg    "FOUNDRY",
430e6232409Smrg    "FAMILY_NAME",
431e6232409Smrg    "WEIGHT_NAME",
432e6232409Smrg    "SLANT",
433e6232409Smrg    "SETWIDTH_NAME",
434e6232409Smrg    "ADD_STYLE_NAME",
435e6232409Smrg    "SPACING",
436e6232409Smrg    "CHARSET_REGISTRY",
437e6232409Smrg    "CHARSET_ENCODING",
438e6232409Smrg
439e6232409Smrg    /* other standard X font properties (see section 3.2 of the XLFD) */
440e6232409Smrg    "FONT",
441e6232409Smrg    "FACE_NAME",
442e6232409Smrg    "FULL_NAME",              /* deprecated */
443e6232409Smrg    "COPYRIGHT",
444e6232409Smrg    "NOTICE",
445e6232409Smrg    "FONT_TYPE",
446e6232409Smrg    "FONT_VERSION",
447e6232409Smrg    "RASTERIZER_NAME",
448e6232409Smrg    "RASTERIZER_VERSION",
449e6232409Smrg
450e6232409Smrg    /* other registered font properties (see the X.org Registry, sec. 15) */
451e6232409Smrg    "_ADOBE_POSTSCRIPT_FONTNAME",
452e6232409Smrg
453e6232409Smrg    /* unregistered font properties */
454e6232409Smrg    "CHARSET_COLLECTIONS",
455e6232409Smrg    "CLASSIFICATION",
456e6232409Smrg    "DEVICE_FONT_NAME",
457e6232409Smrg    "FONTNAME_REGISTRY",
458e6232409Smrg    "MONOSPACED",
459e6232409Smrg    "QUALITY",
460e6232409Smrg    "RELATIVE_SET",
461e6232409Smrg    "STYLE",
462e6232409Smrg     NULL
463e6232409Smrg    };
464e6232409Smrg
465e6232409Smrgstatic
466e6232409Smrgvoid PrintProperty(XFontProp *prop)
467e6232409Smrg{
468e6232409Smrg    char *atom, *value;
469e6232409Smrg    char nosuch[40];
470e6232409Smrg    int i;
471e6232409Smrg    XErrorHandler oldhandler = XSetErrorHandler(IgnoreError);
472e6232409Smrg
473e6232409Smrg    atom = XGetAtomName(dpy, prop->name);
474e6232409Smrg    if (!atom) {
475e6232409Smrg        atom = nosuch;
476e6232409Smrg        nosuch[0] = '\0';
477e6232409Smrg        (void)sprintf (atom, "No such atom = %ld", prop->name);
478e6232409Smrg    }
479e6232409Smrg    printf ("      %s", atom);
480e6232409Smrg
481e6232409Smrg    /* Pad out to a column width of 22, but ensure there is always at
482e6232409Smrg       least one space between property name & value. */
483e6232409Smrg    for (i = strlen(atom); i < 21; i++) putchar (' ');
484e6232409Smrg    putchar(' ');
485e6232409Smrg
486e6232409Smrg    for (i = 0; ; i++) {
487e6232409Smrg        if (stringValued[i] == NULL) {
488e6232409Smrg            printf ("%ld\n", prop->card32);
489e6232409Smrg            break;
490e6232409Smrg        }
491e6232409Smrg        if (strcmp(stringValued[i], atom) == 0) {
492e6232409Smrg            value = XGetAtomName(dpy, prop->card32);
493e6232409Smrg            if (value == NULL)
494e6232409Smrg                printf ("%ld (expected string value)\n", prop->card32);
495e6232409Smrg            else {
496e6232409Smrg                printf ("%s\n", value);
497e6232409Smrg                XFree (value);
498e6232409Smrg            }
499e6232409Smrg            break;
500e6232409Smrg        }
501e6232409Smrg    }
502e6232409Smrg    if (atom != nosuch) XFree (atom);
503e6232409Smrg    XSetErrorHandler (oldhandler);
504e6232409Smrg}
505e6232409Smrg
506e6232409Smrg
507e6232409Smrgstatic void
508e6232409SmrgComputeFontType(XFontStruct *fs)
509e6232409Smrg{
510e6232409Smrg    int i;
511e6232409Smrg    Bool char_cell = True;
512e6232409Smrg    char *reason = NULL;
513e6232409Smrg    XCharStruct *cs;
514e6232409Smrg    Atom awatom = XInternAtom (dpy, "AVERAGE_WIDTH", False);
515e6232409Smrg
516e6232409Smrg    printf ("  font type:\t\t");
517e6232409Smrg    if (fs->min_bounds.width != fs->max_bounds.width) {
518e6232409Smrg        printf ("Proportional (min and max widths not equal)\n");
519e6232409Smrg        return;
520e6232409Smrg    }
521e6232409Smrg
522e6232409Smrg    if (awatom) {
523e6232409Smrg        for (i = 0; i < fs->n_properties; i++) {
524e6232409Smrg            if (fs->properties[i].name == awatom &&
525e6232409Smrg                (fs->max_bounds.width * 10) != fs->properties[i].card32) {
526e6232409Smrg                char_cell = False;
527e6232409Smrg                reason = "font width not equal to AVERAGE_WIDTH";
528e6232409Smrg                break;
529e6232409Smrg            }
530e6232409Smrg        }
531e6232409Smrg    }
532e6232409Smrg
533e6232409Smrg    if (fs->per_char) {
534e6232409Smrg        for (i = fs->min_char_or_byte2, cs = fs->per_char;
535e6232409Smrg             i <= fs->max_char_or_byte2; i++, cs++) {
536e6232409Smrg            if (cs->width == 0) continue;
537e6232409Smrg            if (cs->width != fs->max_bounds.width) {
538e6232409Smrg                /* this shouldn't happen since we checked above */
539e6232409Smrg                printf ("Proportional (characters not all the same width)\n");
540e6232409Smrg                return;
541e6232409Smrg            }
542e6232409Smrg            if (char_cell) {
543e6232409Smrg                if (cs->width < 0) {
544e6232409Smrg                    if (!(cs->width <= cs->lbearing &&
545e6232409Smrg                          cs->lbearing <= cs->rbearing &&
546e6232409Smrg                          cs->rbearing <= 0)) {
547e6232409Smrg                        char_cell = False;
548e6232409Smrg                        reason = "ink outside bounding box";
549e6232409Smrg                    }
550e6232409Smrg                } else {
551e6232409Smrg                    if (!(0 <= cs->lbearing &&
552e6232409Smrg                          cs->lbearing <= cs->rbearing &&
553e6232409Smrg                          cs->rbearing <= cs->width)) {
554e6232409Smrg                        char_cell = False;
555e6232409Smrg                        reason = "ink outside bounding box";
556e6232409Smrg                    }
557e6232409Smrg                }
558e6232409Smrg                if (!(cs->ascent <= fs->ascent &&
559e6232409Smrg                      cs->descent <= fs->descent)) {
560e6232409Smrg                    char_cell  = False;
561e6232409Smrg                    reason = "characters not all same ascent or descent";
562e6232409Smrg                }
563e6232409Smrg            }
564e6232409Smrg        }
565e6232409Smrg    }
566e6232409Smrg
567e6232409Smrg    printf ("%s", char_cell ? "Character Cell" : "Monospaced");
568e6232409Smrg    if (reason) printf (" (%s)", reason);
569e6232409Smrg    printf ("\n");
570e6232409Smrg
571e6232409Smrg    return;
572e6232409Smrg}
573e6232409Smrg
574e6232409Smrg
575e6232409Smrgstatic void
576e6232409Smrgprint_character_metrics(register XFontStruct *info)
577e6232409Smrg{
578e6232409Smrg    register XCharStruct *pc = info->per_char;
579e6232409Smrg    register int i, j;
580e6232409Smrg    unsigned n, saven;
581e6232409Smrg
582e6232409Smrg    printf ("  character metrics:\n");
583e6232409Smrg    saven = ((info->min_byte1 << 8) | info->min_char_or_byte2);
584e6232409Smrg    for (j = info->min_byte1; j <= info->max_byte1; j++) {
585e6232409Smrg        n = saven;
586e6232409Smrg        for (i = info->min_char_or_byte2; i <= info->max_char_or_byte2; i++) {
587e6232409Smrg            char *s = XKeysymToString ((KeySym) n);
5888fff3f40Smrg            printf ("\t0x%02x%02x (%u)\t%4d  %4d  %4d  %4d  %4d  0x%04x  %s\n",
5898fff3f40Smrg                    j, i, n, pc->width, pc->lbearing,
590e6232409Smrg                    pc->rbearing, pc->ascent, pc->descent, pc->attributes,
591e6232409Smrg                    s ? s : ".");
592e6232409Smrg            pc++;
593e6232409Smrg            n++;
594e6232409Smrg        }
595e6232409Smrg        saven += 256;
596e6232409Smrg    }
597e6232409Smrg}
598e6232409Smrg
599e6232409Smrgstatic
600e6232409Smrgvoid do_query_font (Display *dpy, char *name)
601e6232409Smrg{
602e6232409Smrg    register int i;
603e6232409Smrg    register XFontStruct *info = XLoadQueryFont (dpy, name);
604e6232409Smrg
605e6232409Smrg    if (!info) {
606e6232409Smrg        fprintf (stderr, "%s:  unable to get info about font \"%s\"\n",
607e6232409Smrg                 program_name, name);
608e6232409Smrg        return;
609e6232409Smrg    }
610e6232409Smrg    printf ("name:  %s\n", name ? name : "(nil)");
611e6232409Smrg    printf ("  direction:\t\t%s\n", ((info->direction == FontLeftToRight)
612e6232409Smrg                                     ? "left to right" : "right to left"));
613e6232409Smrg    printf ("  indexing:\t\t%s\n",
614e6232409Smrg            ((info->min_byte1 == 0 && info->max_byte1 == 0) ? "linear" :
615e6232409Smrg             "matrix"));
616e6232409Smrg    printf ("  rows:\t\t\t0x%02x thru 0x%02x (%d thru %d)\n",
617e6232409Smrg            info->min_byte1, info->max_byte1,
618e6232409Smrg            info->min_byte1, info->max_byte1);
619e6232409Smrg    printf ("  columns:\t\t0x%02x thru 0x%02x (%d thru %d)\n",
620e6232409Smrg            info->min_char_or_byte2, info->max_char_or_byte2,
621e6232409Smrg            info->min_char_or_byte2, info->max_char_or_byte2);
622e6232409Smrg    printf ("  all chars exist:\t%s\n",
623e6232409Smrg        (info->all_chars_exist) ? "yes" : "no");
624e6232409Smrg    printf ("  default char:\t\t0x%04x (%d)\n",
625e6232409Smrg            info->default_char, info->default_char);
626e6232409Smrg    printf ("  ascent:\t\t%d\n", info->ascent);
627e6232409Smrg    printf ("  descent:\t\t%d\n", info->descent);
628e6232409Smrg    ComputeFontType (info);
629e6232409Smrg    printf ("  bounds:\t\t%s", bounds_metrics_title);
630e6232409Smrg    PrintBounds ("min", &info->min_bounds);
631e6232409Smrg    PrintBounds ("max", &info->max_bounds);
632e6232409Smrg    if (info->per_char && long_list >= L_VERYLONG)
633e6232409Smrg        print_character_metrics (info);
634e6232409Smrg    printf ("  properties:\t\t%d\n", info->n_properties);
635e6232409Smrg    for (i = 0; i < info->n_properties; i++)
636e6232409Smrg        PrintProperty (&info->properties[i]);
637e6232409Smrg    printf ("\n");
638e6232409Smrg
639e6232409Smrg    XFreeFontInfo (NULL, info, 1);
640e6232409Smrg}
641e6232409Smrg
642e6232409Smrg
643