xlsfonts.c revision 94a251fd
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 */
6694a251fdSmrgstatic void get_list(const 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{
7894a251fdSmrg    fprintf (stderr, "usage:  %s [-options] [-fn pattern]\n%s", program_name,
7994a251fdSmrg    "where options include:\n"
8094a251fdSmrg    "    -l[l[l]]                 give long info about each font\n"
8194a251fdSmrg    "    -m                       give character min and max bounds\n"
8294a251fdSmrg    "    -C                       force columns\n"
8394a251fdSmrg    "    -1                       force single column\n"
8494a251fdSmrg    "    -u                       keep output unsorted\n"
8594a251fdSmrg    "    -o                       use OpenFont/QueryFont instead of ListFonts\n"
8694a251fdSmrg    "    -w width                 maximum width for multiple columns\n"
8794a251fdSmrg    "    -n columns               number of columns if multi column\n"
8894a251fdSmrg    "    -display displayname     X server to contact\n"
8994a251fdSmrg    "    -d displayname           (alias for -display displayname)\n"
9094a251fdSmrg    "\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
16894a251fdSmrgvoid get_list(const 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
20994a251fdSmrg    font_list = realloc(font_list, (font_cnt + available) * sizeof(FontList));
21094a251fdSmrg    if (font_list == NULL)
21194a251fdSmrg        Fatal_Error("Out of memory!");
212e6232409Smrg    for (i=0; i<available; i++) {
213e6232409Smrg        font_list[font_cnt].name = fonts[i];
214e6232409Smrg        if (long_list == L_MEDIUM)
215e6232409Smrg            font_list[font_cnt].info = info + i;
216e6232409Smrg        else
217e6232409Smrg            font_list[font_cnt].info = NULL;
218e6232409Smrg
219e6232409Smrg        font_cnt++;
220e6232409Smrg    }
221e6232409Smrg}
222e6232409Smrg
223e6232409Smrgstatic
224e6232409Smrgint compare(const void *arg1, const void *arg2)
225e6232409Smrg{
226e6232409Smrg    const FontList *f1 = arg1;
227e6232409Smrg    const FontList *f2 = arg2;
228e6232409Smrg    const char *p1 = f1->name;
229e6232409Smrg    const char *p2 = f2->name;
230e6232409Smrg
231e6232409Smrg    while (*p1 && *p2 && *p1 == *p2)
232e6232409Smrg            p1++, p2++;
233e6232409Smrg    return(*p1 - *p2);
234e6232409Smrg}
235e6232409Smrg
236e6232409Smrgstatic
237e6232409Smrgvoid show_fonts(void)
238e6232409Smrg{
239e6232409Smrg    int i;
240e6232409Smrg
241e6232409Smrg    if (font_cnt == 0)
242e6232409Smrg        return;
243e6232409Smrg
244e6232409Smrg    /* first sort the output */
245e6232409Smrg    if (sort_output) qsort(font_list, font_cnt, sizeof(FontList), compare);
246e6232409Smrg
247e6232409Smrg    if (long_list > L_MEDIUM) {
248e6232409Smrg        for (i = 0; i < font_cnt; i++) {
249e6232409Smrg            do_query_font (dpy, font_list[i].name);
250e6232409Smrg        }
251e6232409Smrg        return;
252e6232409Smrg    }
253e6232409Smrg
254e6232409Smrg    if (long_list == L_MEDIUM) {
255e6232409Smrg        XFontStruct *pfi;
25694a251fdSmrg        const char  *string;
257e6232409Smrg
258e6232409Smrg        printf("DIR  ");
259e6232409Smrg        printf("MIN  ");
260e6232409Smrg        printf("MAX ");
261e6232409Smrg        printf("EXIST ");
262e6232409Smrg        printf("DFLT ");
263e6232409Smrg        printf("PROP ");
264e6232409Smrg        printf("ASC ");
265e6232409Smrg        printf("DESC ");
266e6232409Smrg        printf("NAME");
267e6232409Smrg        printf("\n");
268e6232409Smrg        for (i=0; i<font_cnt; i++) {
269e6232409Smrg            pfi = font_list[i].info;
270e6232409Smrg            if (!pfi) {
271e6232409Smrg                fprintf(stderr, "%s:  no font information for font \"%s\".\n",
272e6232409Smrg                        program_name,
273e6232409Smrg                        font_list[i].name ?
274e6232409Smrg                        font_list[i].name : "");
275e6232409Smrg                continue;
276e6232409Smrg            }
277e6232409Smrg            switch(pfi->direction) {
278e6232409Smrg                case FontLeftToRight: string = "-->"; break;
279e6232409Smrg                case FontRightToLeft: string = "<--"; break;
280e6232409Smrg                default:              string = "???"; break;
281e6232409Smrg            }
282e6232409Smrg            printf("%-4s", string);
283e6232409Smrg            if (pfi->min_byte1 == 0 &&
284e6232409Smrg                pfi->max_byte1 == 0) {
285e6232409Smrg                printf(" %3d ", pfi->min_char_or_byte2);
286e6232409Smrg                printf(" %3d ", pfi->max_char_or_byte2);
287e6232409Smrg            } else {
288e6232409Smrg                printf("*%3d ", pfi->min_byte1);
289e6232409Smrg                printf("*%3d ", pfi->max_byte1);
290e6232409Smrg            }
291e6232409Smrg            printf("%5s ", pfi->all_chars_exist ? "all" : "some");
292e6232409Smrg            printf("%4d ", pfi->default_char);
293e6232409Smrg            printf("%4d ", pfi->n_properties);
294e6232409Smrg            printf("%3d ", pfi->ascent);
295e6232409Smrg            printf("%4d ", pfi->descent);
296e6232409Smrg            printf("%s\n", font_list[i].name);
297e6232409Smrg            if (min_max) {
298e6232409Smrg                char  min[ BUFSIZ ],
299e6232409Smrg                      max[ BUFSIZ ];
300e6232409Smrg                char *pmax = max,
301e6232409Smrg                     *pmin = min;
302e6232409Smrg
303e6232409Smrg                strcpy(pmin, "     min(l,r,w,a,d) = (");
304e6232409Smrg                strcpy(pmax, "     max(l,r,w,a,d) = (");
305e6232409Smrg                pmin += strlen(pmin);
306e6232409Smrg                pmax += strlen(pmax);
307e6232409Smrg
308e6232409Smrg                copy_number(&pmin, &pmax,
309e6232409Smrg                            pfi->min_bounds.lbearing,
310e6232409Smrg                            pfi->max_bounds.lbearing);
311e6232409Smrg                *pmin++ = *pmax++ = ',';
312e6232409Smrg                copy_number(&pmin, &pmax,
313e6232409Smrg                            pfi->min_bounds.rbearing,
314e6232409Smrg                            pfi->max_bounds.rbearing);
315e6232409Smrg                *pmin++ = *pmax++ = ',';
316e6232409Smrg                copy_number(&pmin, &pmax,
317e6232409Smrg                            pfi->min_bounds.width,
318e6232409Smrg                            pfi->max_bounds.width);
319e6232409Smrg                *pmin++ = *pmax++ = ',';
320e6232409Smrg                copy_number(&pmin, &pmax,
321e6232409Smrg                            pfi->min_bounds.ascent,
322e6232409Smrg                            pfi->max_bounds.ascent);
323e6232409Smrg                *pmin++ = *pmax++ = ',';
324e6232409Smrg                copy_number(&pmin, &pmax,
325e6232409Smrg                            pfi->min_bounds.descent,
326e6232409Smrg                            pfi->max_bounds.descent);
327e6232409Smrg                *pmin++ = *pmax++ = ')';
328e6232409Smrg                *pmin = *pmax = '\0';
329e6232409Smrg                printf("%s\n", min);
330e6232409Smrg                printf("%s\n", max);
331e6232409Smrg            }
332e6232409Smrg        }
333e6232409Smrg        return;
334e6232409Smrg    }
335e6232409Smrg
336e6232409Smrg    if ((columns == 0 && isatty(1)) || columns > 1) {
337e6232409Smrg        int width,
338e6232409Smrg            max_width = 0,
339e6232409Smrg            lines_per_column,
340e6232409Smrg            j,
341e6232409Smrg            index;
342e6232409Smrg
343e6232409Smrg        for (i=0; i<font_cnt; i++) {
344e6232409Smrg            width = strlen(font_list[i].name);
345e6232409Smrg            if (width > max_width)
346e6232409Smrg                max_width = width;
347e6232409Smrg        }
348e6232409Smrg        if (max_width == 0)
349e6232409Smrg            Fatal_Error("all %d fontnames listed are zero length", font_cnt);
350e6232409Smrg
351e6232409Smrg        if (columns == 0) {
352e6232409Smrg            if ((max_width * 2) + output_line_padding >
353e6232409Smrg                max_output_line_width) {
354e6232409Smrg                columns = 1;
355e6232409Smrg            } else {
356e6232409Smrg                max_width += output_line_padding;
357e6232409Smrg                columns = ((max_output_line_width +
358e6232409Smrg                            output_line_padding) / max_width);
359e6232409Smrg            }
360e6232409Smrg        } else {
361e6232409Smrg            max_width += output_line_padding;
362e6232409Smrg        }
363e6232409Smrg        if (columns <= 1) goto single_column;
364e6232409Smrg
365e6232409Smrg        if (font_cnt < columns)
366e6232409Smrg            columns = font_cnt;
367e6232409Smrg        lines_per_column = (font_cnt + columns - 1) / columns;
368e6232409Smrg
369e6232409Smrg        for (i=0; i<lines_per_column; i++) {
370e6232409Smrg            for (j=0; j<columns; j++) {
371e6232409Smrg                index = j * lines_per_column + i;
372e6232409Smrg                if (index >= font_cnt)
373e6232409Smrg                    break;
374e6232409Smrg                if (j+1 == columns)
375e6232409Smrg                    printf("%s", font_list[ index ].name);
376e6232409Smrg                else
377e6232409Smrg                    printf("%-*s",
378e6232409Smrg                           max_width,
379e6232409Smrg                           font_list[ index ].name);
380e6232409Smrg            }
381e6232409Smrg            printf("\n");
382e6232409Smrg        }
383e6232409Smrg        return;
384e6232409Smrg    }
385e6232409Smrg
386e6232409Smrg  single_column:
387e6232409Smrg    for (i=0; i<font_cnt; i++)
388e6232409Smrg        printf("%s\n", font_list[i].name);
389e6232409Smrg}
390e6232409Smrg
391e6232409Smrgstatic
392e6232409Smrgvoid copy_number(char **pp1, char**pp2, int n1, int n2)
393e6232409Smrg{
394e6232409Smrg    char *p1 = *pp1;
395e6232409Smrg    char *p2 = *pp2;
396e6232409Smrg    int   w;
397e6232409Smrg
398e6232409Smrg    sprintf(p1, "%d", n1);
399e6232409Smrg    sprintf(p2, "%d", n2);
400e6232409Smrg    w = MAX(strlen(p1), strlen(p2));
401e6232409Smrg    sprintf(p1, "%*d", w, n1);
402e6232409Smrg    sprintf(p2, "%*d", w, n2);
403e6232409Smrg    p1 += strlen(p1);
404e6232409Smrg    p2 += strlen(p2);
405e6232409Smrg    *pp1 = p1;
406e6232409Smrg    *pp2 = p2;
407e6232409Smrg}
408e6232409Smrg
409e6232409Smrg
410e6232409Smrg
411e6232409Smrg/* ARGSUSED */
412e6232409Smrgstatic
413e6232409Smrgint IgnoreError(Display *disp, XErrorEvent *event)
414e6232409Smrg{
415e6232409Smrg    return 0;
416e6232409Smrg}
417e6232409Smrg
41894a251fdSmrgstatic const char *bounds_metrics_title =
419e6232409Smrg                      "width left  right  asc  desc   attr   keysym\n";
420e6232409Smrg
421e6232409Smrg#define PrintBounds(_what,_ptr) \
422e6232409Smrg{   register XCharStruct *p = (_ptr); \
4238fff3f40Smrg    printf ("\t%3s\t\t%4d  %4d  %4d  %4d  %4d  0x%04x\n", \
4248fff3f40Smrg          (_what), p->width, p->lbearing, \
425e6232409Smrg          p->rbearing, p->ascent, p->descent, p->attributes); }
426e6232409Smrg
427e6232409Smrg
42894a251fdSmrgstatic const char* stringValued [] = { /* values are atoms */
429e6232409Smrg    /* font name components (see section 3.2 of the XLFD) */
430e6232409Smrg    "FOUNDRY",
431e6232409Smrg    "FAMILY_NAME",
432e6232409Smrg    "WEIGHT_NAME",
433e6232409Smrg    "SLANT",
434e6232409Smrg    "SETWIDTH_NAME",
435e6232409Smrg    "ADD_STYLE_NAME",
436e6232409Smrg    "SPACING",
437e6232409Smrg    "CHARSET_REGISTRY",
438e6232409Smrg    "CHARSET_ENCODING",
439e6232409Smrg
440e6232409Smrg    /* other standard X font properties (see section 3.2 of the XLFD) */
441e6232409Smrg    "FONT",
442e6232409Smrg    "FACE_NAME",
443e6232409Smrg    "FULL_NAME",              /* deprecated */
444e6232409Smrg    "COPYRIGHT",
445e6232409Smrg    "NOTICE",
446e6232409Smrg    "FONT_TYPE",
447e6232409Smrg    "FONT_VERSION",
448e6232409Smrg    "RASTERIZER_NAME",
449e6232409Smrg    "RASTERIZER_VERSION",
450e6232409Smrg
451e6232409Smrg    /* other registered font properties (see the X.org Registry, sec. 15) */
452e6232409Smrg    "_ADOBE_POSTSCRIPT_FONTNAME",
453e6232409Smrg
454e6232409Smrg    /* unregistered font properties */
455e6232409Smrg    "CHARSET_COLLECTIONS",
456e6232409Smrg    "CLASSIFICATION",
457e6232409Smrg    "DEVICE_FONT_NAME",
458e6232409Smrg    "FONTNAME_REGISTRY",
459e6232409Smrg    "MONOSPACED",
460e6232409Smrg    "QUALITY",
461e6232409Smrg    "RELATIVE_SET",
462e6232409Smrg    "STYLE",
463e6232409Smrg     NULL
464e6232409Smrg    };
465e6232409Smrg
466e6232409Smrgstatic
467e6232409Smrgvoid PrintProperty(XFontProp *prop)
468e6232409Smrg{
469e6232409Smrg    char *atom, *value;
470e6232409Smrg    char nosuch[40];
471e6232409Smrg    int i;
472e6232409Smrg    XErrorHandler oldhandler = XSetErrorHandler(IgnoreError);
473e6232409Smrg
474e6232409Smrg    atom = XGetAtomName(dpy, prop->name);
475e6232409Smrg    if (!atom) {
476e6232409Smrg        atom = nosuch;
477e6232409Smrg        nosuch[0] = '\0';
478e6232409Smrg        (void)sprintf (atom, "No such atom = %ld", prop->name);
479e6232409Smrg    }
480e6232409Smrg    printf ("      %s", atom);
481e6232409Smrg
482e6232409Smrg    /* Pad out to a column width of 22, but ensure there is always at
483e6232409Smrg       least one space between property name & value. */
484e6232409Smrg    for (i = strlen(atom); i < 21; i++) putchar (' ');
485e6232409Smrg    putchar(' ');
486e6232409Smrg
487e6232409Smrg    for (i = 0; ; i++) {
488e6232409Smrg        if (stringValued[i] == NULL) {
489e6232409Smrg            printf ("%ld\n", prop->card32);
490e6232409Smrg            break;
491e6232409Smrg        }
492e6232409Smrg        if (strcmp(stringValued[i], atom) == 0) {
493e6232409Smrg            value = XGetAtomName(dpy, prop->card32);
494e6232409Smrg            if (value == NULL)
495e6232409Smrg                printf ("%ld (expected string value)\n", prop->card32);
496e6232409Smrg            else {
497e6232409Smrg                printf ("%s\n", value);
498e6232409Smrg                XFree (value);
499e6232409Smrg            }
500e6232409Smrg            break;
501e6232409Smrg        }
502e6232409Smrg    }
503e6232409Smrg    if (atom != nosuch) XFree (atom);
504e6232409Smrg    XSetErrorHandler (oldhandler);
505e6232409Smrg}
506e6232409Smrg
507e6232409Smrg
508e6232409Smrgstatic void
509e6232409SmrgComputeFontType(XFontStruct *fs)
510e6232409Smrg{
511e6232409Smrg    int i;
512e6232409Smrg    Bool char_cell = True;
51394a251fdSmrg    const char *reason = NULL;
514e6232409Smrg    XCharStruct *cs;
515e6232409Smrg    Atom awatom = XInternAtom (dpy, "AVERAGE_WIDTH", False);
516e6232409Smrg
517e6232409Smrg    printf ("  font type:\t\t");
518e6232409Smrg    if (fs->min_bounds.width != fs->max_bounds.width) {
519e6232409Smrg        printf ("Proportional (min and max widths not equal)\n");
520e6232409Smrg        return;
521e6232409Smrg    }
522e6232409Smrg
523e6232409Smrg    if (awatom) {
524e6232409Smrg        for (i = 0; i < fs->n_properties; i++) {
525e6232409Smrg            if (fs->properties[i].name == awatom &&
526e6232409Smrg                (fs->max_bounds.width * 10) != fs->properties[i].card32) {
527e6232409Smrg                char_cell = False;
528e6232409Smrg                reason = "font width not equal to AVERAGE_WIDTH";
529e6232409Smrg                break;
530e6232409Smrg            }
531e6232409Smrg        }
532e6232409Smrg    }
533e6232409Smrg
534e6232409Smrg    if (fs->per_char) {
535e6232409Smrg        for (i = fs->min_char_or_byte2, cs = fs->per_char;
536e6232409Smrg             i <= fs->max_char_or_byte2; i++, cs++) {
537e6232409Smrg            if (cs->width == 0) continue;
538e6232409Smrg            if (cs->width != fs->max_bounds.width) {
539e6232409Smrg                /* this shouldn't happen since we checked above */
540e6232409Smrg                printf ("Proportional (characters not all the same width)\n");
541e6232409Smrg                return;
542e6232409Smrg            }
543e6232409Smrg            if (char_cell) {
544e6232409Smrg                if (cs->width < 0) {
545e6232409Smrg                    if (!(cs->width <= cs->lbearing &&
546e6232409Smrg                          cs->lbearing <= cs->rbearing &&
547e6232409Smrg                          cs->rbearing <= 0)) {
548e6232409Smrg                        char_cell = False;
549e6232409Smrg                        reason = "ink outside bounding box";
550e6232409Smrg                    }
551e6232409Smrg                } else {
552e6232409Smrg                    if (!(0 <= cs->lbearing &&
553e6232409Smrg                          cs->lbearing <= cs->rbearing &&
554e6232409Smrg                          cs->rbearing <= cs->width)) {
555e6232409Smrg                        char_cell = False;
556e6232409Smrg                        reason = "ink outside bounding box";
557e6232409Smrg                    }
558e6232409Smrg                }
559e6232409Smrg                if (!(cs->ascent <= fs->ascent &&
560e6232409Smrg                      cs->descent <= fs->descent)) {
561e6232409Smrg                    char_cell  = False;
562e6232409Smrg                    reason = "characters not all same ascent or descent";
563e6232409Smrg                }
564e6232409Smrg            }
565e6232409Smrg        }
566e6232409Smrg    }
567e6232409Smrg
568e6232409Smrg    printf ("%s", char_cell ? "Character Cell" : "Monospaced");
569e6232409Smrg    if (reason) printf (" (%s)", reason);
570e6232409Smrg    printf ("\n");
571e6232409Smrg
572e6232409Smrg    return;
573e6232409Smrg}
574e6232409Smrg
575e6232409Smrg
576e6232409Smrgstatic void
577e6232409Smrgprint_character_metrics(register XFontStruct *info)
578e6232409Smrg{
579e6232409Smrg    register XCharStruct *pc = info->per_char;
580e6232409Smrg    register int i, j;
581e6232409Smrg    unsigned n, saven;
582e6232409Smrg
583e6232409Smrg    printf ("  character metrics:\n");
584e6232409Smrg    saven = ((info->min_byte1 << 8) | info->min_char_or_byte2);
585e6232409Smrg    for (j = info->min_byte1; j <= info->max_byte1; j++) {
586e6232409Smrg        n = saven;
587e6232409Smrg        for (i = info->min_char_or_byte2; i <= info->max_char_or_byte2; i++) {
588e6232409Smrg            char *s = XKeysymToString ((KeySym) n);
5898fff3f40Smrg            printf ("\t0x%02x%02x (%u)\t%4d  %4d  %4d  %4d  %4d  0x%04x  %s\n",
5908fff3f40Smrg                    j, i, n, pc->width, pc->lbearing,
591e6232409Smrg                    pc->rbearing, pc->ascent, pc->descent, pc->attributes,
592e6232409Smrg                    s ? s : ".");
593e6232409Smrg            pc++;
594e6232409Smrg            n++;
595e6232409Smrg        }
596e6232409Smrg        saven += 256;
597e6232409Smrg    }
598e6232409Smrg}
599e6232409Smrg
600e6232409Smrgstatic
601e6232409Smrgvoid do_query_font (Display *dpy, char *name)
602e6232409Smrg{
603e6232409Smrg    register int i;
604e6232409Smrg    register XFontStruct *info = XLoadQueryFont (dpy, name);
605e6232409Smrg
606e6232409Smrg    if (!info) {
607e6232409Smrg        fprintf (stderr, "%s:  unable to get info about font \"%s\"\n",
608e6232409Smrg                 program_name, name);
609e6232409Smrg        return;
610e6232409Smrg    }
611e6232409Smrg    printf ("name:  %s\n", name ? name : "(nil)");
612e6232409Smrg    printf ("  direction:\t\t%s\n", ((info->direction == FontLeftToRight)
613e6232409Smrg                                     ? "left to right" : "right to left"));
614e6232409Smrg    printf ("  indexing:\t\t%s\n",
615e6232409Smrg            ((info->min_byte1 == 0 && info->max_byte1 == 0) ? "linear" :
616e6232409Smrg             "matrix"));
617e6232409Smrg    printf ("  rows:\t\t\t0x%02x thru 0x%02x (%d thru %d)\n",
618e6232409Smrg            info->min_byte1, info->max_byte1,
619e6232409Smrg            info->min_byte1, info->max_byte1);
620e6232409Smrg    printf ("  columns:\t\t0x%02x thru 0x%02x (%d thru %d)\n",
621e6232409Smrg            info->min_char_or_byte2, info->max_char_or_byte2,
622e6232409Smrg            info->min_char_or_byte2, info->max_char_or_byte2);
623e6232409Smrg    printf ("  all chars exist:\t%s\n",
624e6232409Smrg        (info->all_chars_exist) ? "yes" : "no");
625e6232409Smrg    printf ("  default char:\t\t0x%04x (%d)\n",
626e6232409Smrg            info->default_char, info->default_char);
627e6232409Smrg    printf ("  ascent:\t\t%d\n", info->ascent);
628e6232409Smrg    printf ("  descent:\t\t%d\n", info->descent);
629e6232409Smrg    ComputeFontType (info);
630e6232409Smrg    printf ("  bounds:\t\t%s", bounds_metrics_title);
631e6232409Smrg    PrintBounds ("min", &info->min_bounds);
632e6232409Smrg    PrintBounds ("max", &info->max_bounds);
633e6232409Smrg    if (info->per_char && long_list >= L_VERYLONG)
634e6232409Smrg        print_character_metrics (info);
635e6232409Smrg    printf ("  properties:\t\t%d\n", info->n_properties);
636e6232409Smrg    for (i = 0; i < info->n_properties; i++)
637e6232409Smrg        PrintProperty (&info->properties[i]);
638e6232409Smrg    printf ("\n");
639e6232409Smrg
640e6232409Smrg    XFreeFontInfo (NULL, info, 1);
641e6232409Smrg}
642e6232409Smrg
643e6232409Smrg
644