xlsfonts.c revision 8ae5c7d9
1e6232409Smrg/*
26a45684fSmrg
3e6232409SmrgCopyright 1989, 1998  The Open Group
4e6232409Smrg
5e6232409SmrgPermission to use, copy, modify, distribute, and sell this software and its
6e6232409Smrgdocumentation for any purpose is hereby granted without fee, provided that
7e6232409Smrgthe above copyright notice appear in all copies and that both that
8e6232409Smrgcopyright notice and this permission notice appear in supporting
9e6232409Smrgdocumentation.
10e6232409Smrg
11e6232409SmrgThe above copyright notice and this permission notice shall be included in
12e6232409Smrgall copies or substantial portions of the Software.
13e6232409Smrg
14e6232409SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15e6232409SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16e6232409SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17e6232409SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18e6232409SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19e6232409SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20e6232409Smrg
21e6232409SmrgExcept as contained in this notice, the name of The Open Group shall not be
22e6232409Smrgused in advertising or otherwise to promote the sale, use or other dealings
23e6232409Smrgin this Software without prior written authorization from The Open Group.
246a45684fSmrg
256a45684fSmrg */
266a45684fSmrg
276a45684fSmrg#ifdef HAVE_CONFIG_H
286a45684fSmrg# include "config.h"
296a45684fSmrg#endif
30e6232409Smrg
31e6232409Smrg#include <X11/Xlib.h>
32e6232409Smrg#include <X11/Xutil.h>
33e6232409Smrg#include <X11/Xos.h>
34e6232409Smrg#include <stdio.h>
35e6232409Smrg#include <stdlib.h>
36e6232409Smrg#include <limits.h>
37e6232409Smrg#include "dsimple.h"
38e6232409Smrg
398ae5c7d9Smrg#define N_START INT_MAX         /* Maximum # of fonts to start with (should
408ae5c7d9Smrg                                 * always be be > 10000 as modern OSes like
418ae5c7d9Smrg                                 * Solaris 8 already have more than 9000 XLFD
428ae5c7d9Smrg                                 * fonts available) */
43e6232409Smrg
44e6232409Smrg#define L_SHORT    0
45e6232409Smrg#define L_MEDIUM   1
46e6232409Smrg#define L_LONG     2
47e6232409Smrg#define L_VERYLONG 3
48e6232409Smrg
49e6232409Smrgstatic int  max_output_line_width     = 79;
50e6232409Smrgstatic int  output_line_padding       = 3;
51e6232409Smrgstatic int  columns                   = 0;
52e6232409Smrg
53e6232409Smrgstatic Bool sort_output               = True;
54e6232409Smrgstatic Bool open_instead_of_list      = False;
55e6232409Smrgstatic int  long_list                 = L_SHORT;
56e6232409Smrgstatic int  nnames                    = N_START;
57e6232409Smrgstatic int  font_cnt                  = 0;
58e6232409Smrgstatic int  min_max;
59e6232409Smrg
60e6232409Smrgtypedef struct {
618ae5c7d9Smrg    char *name;
628ae5c7d9Smrg    XFontStruct *info;
63e6232409Smrg} FontList;
64e6232409Smrg
65e6232409Smrgstatic FontList *font_list = NULL;
66e6232409Smrg
67e6232409Smrg/* Local prototypes */
6894a251fdSmrgstatic void get_list(const char *pattern);
69e6232409Smrgstatic int  compare(const void *arg1, const void *arg2);
70e6232409Smrgstatic void show_fonts(void);
718ae5c7d9Smrgstatic void copy_number(char **pp1, char **pp2, int n1, int n2);
72e6232409Smrgstatic int  IgnoreError(Display *disp, XErrorEvent *event);
73e6232409Smrgstatic void PrintProperty(XFontProp *prop);
74e6232409Smrgstatic void ComputeFontType(XFontStruct *fs);
75e6232409Smrgstatic void print_character_metrics(register XFontStruct *info);
768ae5c7d9Smrgstatic void do_query_font(Display *dpy, char *name);
77e6232409Smrg
788ae5c7d9Smrgvoid
798ae5c7d9Smrgusage(const char *errmsg)
80e6232409Smrg{
816a45684fSmrg    if (errmsg != NULL)
828ae5c7d9Smrg        fprintf(stderr, "%s: %s\n\n", program_name, errmsg);
838ae5c7d9Smrg
848ae5c7d9Smrg    fprintf(stderr, "usage:  %s [-options] [-fn pattern]\n%s", program_name,
858ae5c7d9Smrg            "where options include:\n"
868ae5c7d9Smrg            "    -l[l[l]]                 give long info about each font\n"
878ae5c7d9Smrg            "    -m                       give character min and max bounds\n"
888ae5c7d9Smrg            "    -C                       force columns\n"
898ae5c7d9Smrg            "    -1                       force single column\n"
908ae5c7d9Smrg            "    -u                       keep output unsorted\n"
918ae5c7d9Smrg            "    -o                       use OpenFont/QueryFont instead of ListFonts\n"
928ae5c7d9Smrg            "    -w width                 maximum width for multiple columns\n"
938ae5c7d9Smrg            "    -n columns               number of columns if multi column\n"
948ae5c7d9Smrg            "    -display displayname     X server to contact\n"
958ae5c7d9Smrg            "    -d displayname           (alias for -display displayname)\n"
968ae5c7d9Smrg            "    -v                       print program version\n"
978ae5c7d9Smrg            "\n");
98e6232409Smrg    Close_Display();
99e6232409Smrg    exit(EXIT_FAILURE);
100e6232409Smrg}
101e6232409Smrg
1028ae5c7d9Smrgint
1038ae5c7d9Smrgmain(int argc, char **argv)
104e6232409Smrg{
105e6232409Smrg    int argcnt = 0, i;
106e6232409Smrg
107e6232409Smrg    INIT_NAME;
108e6232409Smrg
109e6232409Smrg    /* Handle command line arguments, open display */
110e6232409Smrg    Setup_Display_And_Screen(&argc, argv);
111e6232409Smrg
112e6232409Smrg    for (argv++, argc--; argc; argv++, argc--) {
113e6232409Smrg        if (argv[0][0] == '-') {
1146a45684fSmrg            if (argcnt > 0)
1158ae5c7d9Smrg                usage("options may not be specified after font names");
1168ae5c7d9Smrg            for (i = 1; argv[0][i]; i++)
1178ae5c7d9Smrg                switch (argv[0][i]) {
118e6232409Smrg                case 'l':
119e6232409Smrg                    long_list++;
120e6232409Smrg                    break;
121e6232409Smrg                case 'm':
122e6232409Smrg                    min_max++;
123e6232409Smrg                    break;
124e6232409Smrg                case 'C':
125e6232409Smrg                    columns = 0;
126e6232409Smrg                    break;
127e6232409Smrg                case '1':
128e6232409Smrg                    columns = 1;
129e6232409Smrg                    break;
1308ae5c7d9Smrg                case 'f':      /* "-fn" */
1318ae5c7d9Smrg                    if (argv[0][i + 1] != 'n') {
1328ae5c7d9Smrg                        fprintf(stderr, "%s: unrecognized argument %s\n\n",
1338ae5c7d9Smrg                                program_name, argv[0]);
1346a45684fSmrg                        usage(NULL);
1356a45684fSmrg                    }
1368ae5c7d9Smrg                    if (--argc <= 0)
1378ae5c7d9Smrg                        usage("-fn requires an argument");
138e6232409Smrg                    argcnt++;
139e6232409Smrg                    argv++;
140e6232409Smrg                    get_list(argv[0]);
141e6232409Smrg                    goto next;
142e6232409Smrg                case 'w':
1438ae5c7d9Smrg                    if (--argc <= 0)
1448ae5c7d9Smrg                        usage("-w requires an argument");
145e6232409Smrg                    argv++;
146e6232409Smrg                    max_output_line_width = atoi(argv[0]);
147e6232409Smrg                    goto next;
148e6232409Smrg                case 'n':
1498ae5c7d9Smrg                    if (--argc <= 0)
1508ae5c7d9Smrg                        usage("-n requires an argument");
151e6232409Smrg                    argv++;
152e6232409Smrg                    columns = atoi(argv[0]);
153e6232409Smrg                    goto next;
154e6232409Smrg                case 'o':
155e6232409Smrg                    open_instead_of_list = True;
156e6232409Smrg                    break;
157e6232409Smrg                case 'u':
158e6232409Smrg                    sort_output = False;
159e6232409Smrg                    break;
1606a45684fSmrg                case 'v':
1616a45684fSmrg                    puts(PACKAGE_STRING);
1626a45684fSmrg                    exit(0);
163e6232409Smrg                default:
1648ae5c7d9Smrg                    fprintf(stderr, "%s: unrecognized argument -%c\n\n",
1658ae5c7d9Smrg                            program_name, argv[0][i]);
1666a45684fSmrg                    usage(NULL);
167e6232409Smrg                    break;
168e6232409Smrg                }
1696a45684fSmrg            if (i == 1) {
1708ae5c7d9Smrg                fprintf(stderr, "%s: unrecognized argument %s\n\n",
1718ae5c7d9Smrg                        program_name, argv[0]);
1726a45684fSmrg                usage(NULL);
1736a45684fSmrg            }
1748ae5c7d9Smrg        }
1758ae5c7d9Smrg        else {
176e6232409Smrg            argcnt++;
177e6232409Smrg            get_list(argv[0]);
178e6232409Smrg        }
1798ae5c7d9Smrg next: ;
180e6232409Smrg    }
181e6232409Smrg
182e6232409Smrg    if (argcnt == 0)
183e6232409Smrg        get_list("*");
184e6232409Smrg
185e6232409Smrg    show_fonts();
1868ae5c7d9Smrg
187e6232409Smrg    Close_Display();
188e6232409Smrg    return EXIT_SUCCESS;
189e6232409Smrg}
190e6232409Smrg
1918ae5c7d9Smrgstatic void
1928ae5c7d9Smrgget_list(const char *pattern)
193e6232409Smrg{
1948ae5c7d9Smrg    int available = nnames + 1, i;
1958ae5c7d9Smrg    char **fonts;
1968ae5c7d9Smrg    XFontStruct *info;
197e6232409Smrg
198e6232409Smrg    /* Get list of fonts matching pattern */
199e6232409Smrg    for (;;) {
200e6232409Smrg        if (open_instead_of_list) {
2018ae5c7d9Smrg            info = XLoadQueryFont(dpy, pattern);
202e6232409Smrg
203e6232409Smrg            if (info) {
2040790806fSchristos                fonts = __UNCONST(&pattern);
205e6232409Smrg                available = 1;
2068ae5c7d9Smrg                XUnloadFont(dpy, info->fid);
2078ae5c7d9Smrg            }
2088ae5c7d9Smrg            else {
209e6232409Smrg                fonts = NULL;
210e6232409Smrg            }
211e6232409Smrg            break;
212e6232409Smrg        }
2138ae5c7d9Smrg
214e6232409Smrg        if (long_list == L_MEDIUM)
215e6232409Smrg            fonts = XListFontsWithInfo(dpy, pattern, nnames, &available, &info);
216e6232409Smrg        else
217e6232409Smrg            fonts = XListFonts(dpy, pattern, nnames, &available);
218e6232409Smrg        if (fonts == NULL || available < nnames)
219e6232409Smrg            break;
220e6232409Smrg        if (long_list == L_MEDIUM)
221e6232409Smrg            XFreeFontInfo(fonts, info, available);
222e6232409Smrg        else
223e6232409Smrg            XFreeFontNames(fonts);
224e6232409Smrg        nnames = available * 2;
225e6232409Smrg    }
226e6232409Smrg
227e6232409Smrg    if (fonts == NULL) {
228e6232409Smrg        fprintf(stderr, "%s: pattern \"%s\" unmatched\n",
229e6232409Smrg                program_name, pattern);
230e6232409Smrg        return;
231e6232409Smrg    }
232e6232409Smrg
23394a251fdSmrg    font_list = realloc(font_list, (font_cnt + available) * sizeof(FontList));
23494a251fdSmrg    if (font_list == NULL)
23594a251fdSmrg        Fatal_Error("Out of memory!");
2368ae5c7d9Smrg    for (i = 0; i < available; i++) {
237e6232409Smrg        font_list[font_cnt].name = fonts[i];
238e6232409Smrg        if (long_list == L_MEDIUM)
239e6232409Smrg            font_list[font_cnt].info = info + i;
240e6232409Smrg        else
241e6232409Smrg            font_list[font_cnt].info = NULL;
2428ae5c7d9Smrg
243e6232409Smrg        font_cnt++;
244e6232409Smrg    }
245e6232409Smrg}
246e6232409Smrg
2478ae5c7d9Smrgstatic int
2488ae5c7d9Smrgcompare(const void *arg1, const void *arg2)
249e6232409Smrg{
250e6232409Smrg    const FontList *f1 = arg1;
251e6232409Smrg    const FontList *f2 = arg2;
252e6232409Smrg    const char *p1 = f1->name;
253e6232409Smrg    const char *p2 = f2->name;
254e6232409Smrg
255e6232409Smrg    while (*p1 && *p2 && *p1 == *p2)
2568ae5c7d9Smrg        p1++, p2++;
2578ae5c7d9Smrg    return (*p1 - *p2);
258e6232409Smrg}
259e6232409Smrg
2608ae5c7d9Smrgstatic void
2618ae5c7d9Smrgshow_fonts(void)
262e6232409Smrg{
263e6232409Smrg    int i;
264e6232409Smrg
265e6232409Smrg    if (font_cnt == 0)
266e6232409Smrg        return;
267e6232409Smrg
268e6232409Smrg    /* first sort the output */
2698ae5c7d9Smrg    if (sort_output)
2708ae5c7d9Smrg        qsort(font_list, font_cnt, sizeof(FontList), compare);
271e6232409Smrg
272e6232409Smrg    if (long_list > L_MEDIUM) {
273e6232409Smrg        for (i = 0; i < font_cnt; i++) {
2748ae5c7d9Smrg            do_query_font(dpy, font_list[i].name);
275e6232409Smrg        }
276e6232409Smrg        return;
277e6232409Smrg    }
278e6232409Smrg
279e6232409Smrg    if (long_list == L_MEDIUM) {
280e6232409Smrg        XFontStruct *pfi;
2818ae5c7d9Smrg
2828ae5c7d9Smrg        const char *string;
283e6232409Smrg
284e6232409Smrg        printf("DIR  ");
285e6232409Smrg        printf("MIN  ");
286e6232409Smrg        printf("MAX ");
287e6232409Smrg        printf("EXIST ");
288e6232409Smrg        printf("DFLT ");
289e6232409Smrg        printf("PROP ");
290e6232409Smrg        printf("ASC ");
291e6232409Smrg        printf("DESC ");
292e6232409Smrg        printf("NAME");
293e6232409Smrg        printf("\n");
2948ae5c7d9Smrg        for (i = 0; i < font_cnt; i++) {
295e6232409Smrg            pfi = font_list[i].info;
296e6232409Smrg            if (!pfi) {
297e6232409Smrg                fprintf(stderr, "%s:  no font information for font \"%s\".\n",
2988ae5c7d9Smrg                        program_name,
2998ae5c7d9Smrg                        font_list[i].name ? font_list[i].name : "");
300e6232409Smrg                continue;
301e6232409Smrg            }
3028ae5c7d9Smrg            switch (pfi->direction) {
3038ae5c7d9Smrg            case FontLeftToRight:
3048ae5c7d9Smrg                string = "-->";
3058ae5c7d9Smrg                break;
3068ae5c7d9Smrg            case FontRightToLeft:
3078ae5c7d9Smrg                string = "<--";
3088ae5c7d9Smrg                break;
3098ae5c7d9Smrg            default:
3108ae5c7d9Smrg                string = "???";
3118ae5c7d9Smrg                break;
312e6232409Smrg            }
313e6232409Smrg            printf("%-4s", string);
3148ae5c7d9Smrg            if (pfi->min_byte1 == 0 && pfi->max_byte1 == 0) {
315e6232409Smrg                printf(" %3d ", pfi->min_char_or_byte2);
316e6232409Smrg                printf(" %3d ", pfi->max_char_or_byte2);
3178ae5c7d9Smrg            }
3188ae5c7d9Smrg            else {
319e6232409Smrg                printf("*%3d ", pfi->min_byte1);
320e6232409Smrg                printf("*%3d ", pfi->max_byte1);
321e6232409Smrg            }
322e6232409Smrg            printf("%5s ", pfi->all_chars_exist ? "all" : "some");
323e6232409Smrg            printf("%4d ", pfi->default_char);
324e6232409Smrg            printf("%4d ", pfi->n_properties);
325e6232409Smrg            printf("%3d ", pfi->ascent);
326e6232409Smrg            printf("%4d ", pfi->descent);
327e6232409Smrg            printf("%s\n", font_list[i].name);
328e6232409Smrg            if (min_max) {
3298ae5c7d9Smrg                char min[BUFSIZ], max[BUFSIZ];
3308ae5c7d9Smrg
3318ae5c7d9Smrg                char *pmax = max, *pmin = min;
332e6232409Smrg
333e6232409Smrg                strcpy(pmin, "     min(l,r,w,a,d) = (");
334e6232409Smrg                strcpy(pmax, "     max(l,r,w,a,d) = (");
335e6232409Smrg                pmin += strlen(pmin);
336e6232409Smrg                pmax += strlen(pmax);
337e6232409Smrg
338e6232409Smrg                copy_number(&pmin, &pmax,
339e6232409Smrg                            pfi->min_bounds.lbearing,
340e6232409Smrg                            pfi->max_bounds.lbearing);
341e6232409Smrg                *pmin++ = *pmax++ = ',';
342e6232409Smrg                copy_number(&pmin, &pmax,
343e6232409Smrg                            pfi->min_bounds.rbearing,
344e6232409Smrg                            pfi->max_bounds.rbearing);
345e6232409Smrg                *pmin++ = *pmax++ = ',';
346e6232409Smrg                copy_number(&pmin, &pmax,
347e6232409Smrg                            pfi->min_bounds.width,
348e6232409Smrg                            pfi->max_bounds.width);
349e6232409Smrg                *pmin++ = *pmax++ = ',';
350e6232409Smrg                copy_number(&pmin, &pmax,
351e6232409Smrg                            pfi->min_bounds.ascent,
352e6232409Smrg                            pfi->max_bounds.ascent);
353e6232409Smrg                *pmin++ = *pmax++ = ',';
354e6232409Smrg                copy_number(&pmin, &pmax,
355e6232409Smrg                            pfi->min_bounds.descent,
356e6232409Smrg                            pfi->max_bounds.descent);
357e6232409Smrg                *pmin++ = *pmax++ = ')';
358e6232409Smrg                *pmin = *pmax = '\0';
359e6232409Smrg                printf("%s\n", min);
360e6232409Smrg                printf("%s\n", max);
361e6232409Smrg            }
362e6232409Smrg        }
363e6232409Smrg        return;
364e6232409Smrg    }
365e6232409Smrg
366e6232409Smrg    if ((columns == 0 && isatty(1)) || columns > 1) {
3678ae5c7d9Smrg        int width, max_width = 0, lines_per_column, j, index;
368e6232409Smrg
3698ae5c7d9Smrg        for (i = 0; i < font_cnt; i++) {
370e6232409Smrg            width = strlen(font_list[i].name);
371e6232409Smrg            if (width > max_width)
372e6232409Smrg                max_width = width;
373e6232409Smrg        }
374e6232409Smrg        if (max_width == 0)
375e6232409Smrg            Fatal_Error("all %d fontnames listed are zero length", font_cnt);
376e6232409Smrg
377e6232409Smrg        if (columns == 0) {
378e6232409Smrg            if ((max_width * 2) + output_line_padding >
379e6232409Smrg                max_output_line_width) {
380e6232409Smrg                columns = 1;
3818ae5c7d9Smrg            }
3828ae5c7d9Smrg            else {
383e6232409Smrg                max_width += output_line_padding;
384e6232409Smrg                columns = ((max_output_line_width +
385e6232409Smrg                            output_line_padding) / max_width);
386e6232409Smrg            }
3878ae5c7d9Smrg        }
3888ae5c7d9Smrg        else {
389e6232409Smrg            max_width += output_line_padding;
390e6232409Smrg        }
3918ae5c7d9Smrg        if (columns <= 1)
3928ae5c7d9Smrg            goto single_column;
393e6232409Smrg
394e6232409Smrg        if (font_cnt < columns)
395e6232409Smrg            columns = font_cnt;
396e6232409Smrg        lines_per_column = (font_cnt + columns - 1) / columns;
397e6232409Smrg
3988ae5c7d9Smrg        for (i = 0; i < lines_per_column; i++) {
3998ae5c7d9Smrg            for (j = 0; j < columns; j++) {
400e6232409Smrg                index = j * lines_per_column + i;
401e6232409Smrg                if (index >= font_cnt)
402e6232409Smrg                    break;
4038ae5c7d9Smrg                if (j + 1 == columns)
4048ae5c7d9Smrg                    printf("%s", font_list[index].name);
405e6232409Smrg                else
4068ae5c7d9Smrg                    printf("%-*s", max_width, font_list[index].name);
407e6232409Smrg            }
408e6232409Smrg            printf("\n");
409e6232409Smrg        }
410e6232409Smrg        return;
411e6232409Smrg    }
412e6232409Smrg
4138ae5c7d9Smrg single_column:
4148ae5c7d9Smrg    for (i = 0; i < font_cnt; i++)
415e6232409Smrg        printf("%s\n", font_list[i].name);
416e6232409Smrg}
417e6232409Smrg
4188ae5c7d9Smrgstatic void
4198ae5c7d9Smrgcopy_number(char **pp1, char **pp2, int n1, int n2)
420e6232409Smrg{
421e6232409Smrg    char *p1 = *pp1;
422e6232409Smrg    char *p2 = *pp2;
4238ae5c7d9Smrg    int w;
424e6232409Smrg
425e6232409Smrg    sprintf(p1, "%d", n1);
426e6232409Smrg    sprintf(p2, "%d", n2);
427e6232409Smrg    w = MAX(strlen(p1), strlen(p2));
428e6232409Smrg    sprintf(p1, "%*d", w, n1);
429e6232409Smrg    sprintf(p2, "%*d", w, n2);
430e6232409Smrg    p1 += strlen(p1);
431e6232409Smrg    p2 += strlen(p2);
432e6232409Smrg    *pp1 = p1;
433e6232409Smrg    *pp2 = p2;
434e6232409Smrg}
435e6232409Smrg
436e6232409Smrg/* ARGSUSED */
4378ae5c7d9Smrgstatic int
4388ae5c7d9SmrgIgnoreError(Display * disp, XErrorEvent *event)
439e6232409Smrg{
440e6232409Smrg    return 0;
441e6232409Smrg}
442e6232409Smrg
44394a251fdSmrgstatic const char *bounds_metrics_title =
4448ae5c7d9Smrg    "width left  right  asc  desc   attr   keysym\n";
445e6232409Smrg
446e6232409Smrg#define PrintBounds(_what,_ptr) \
447e6232409Smrg{   register XCharStruct *p = (_ptr); \
4488fff3f40Smrg    printf ("\t%3s\t\t%4d  %4d  %4d  %4d  %4d  0x%04x\n", \
4498fff3f40Smrg          (_what), p->width, p->lbearing, \
450e6232409Smrg          p->rbearing, p->ascent, p->descent, p->attributes); }
451e6232409Smrg
4528ae5c7d9Smrgstatic const char *stringValued[] = {   /* values are atoms */
453e6232409Smrg    /* font name components (see section 3.2 of the XLFD) */
454e6232409Smrg    "FOUNDRY",
455e6232409Smrg    "FAMILY_NAME",
456e6232409Smrg    "WEIGHT_NAME",
457e6232409Smrg    "SLANT",
458e6232409Smrg    "SETWIDTH_NAME",
459e6232409Smrg    "ADD_STYLE_NAME",
460e6232409Smrg    "SPACING",
461e6232409Smrg    "CHARSET_REGISTRY",
462e6232409Smrg    "CHARSET_ENCODING",
463e6232409Smrg
464e6232409Smrg    /* other standard X font properties (see section 3.2 of the XLFD) */
465e6232409Smrg    "FONT",
466e6232409Smrg    "FACE_NAME",
4678ae5c7d9Smrg    "FULL_NAME",                /* deprecated */
468e6232409Smrg    "COPYRIGHT",
469e6232409Smrg    "NOTICE",
470e6232409Smrg    "FONT_TYPE",
471e6232409Smrg    "FONT_VERSION",
472e6232409Smrg    "RASTERIZER_NAME",
473e6232409Smrg    "RASTERIZER_VERSION",
474e6232409Smrg
475e6232409Smrg    /* other registered font properties (see the X.org Registry, sec. 15) */
476e6232409Smrg    "_ADOBE_POSTSCRIPT_FONTNAME",
4778ae5c7d9Smrg
478e6232409Smrg    /* unregistered font properties */
479e6232409Smrg    "CHARSET_COLLECTIONS",
480e6232409Smrg    "CLASSIFICATION",
481e6232409Smrg    "DEVICE_FONT_NAME",
482e6232409Smrg    "FONTNAME_REGISTRY",
483e6232409Smrg    "MONOSPACED",
484e6232409Smrg    "QUALITY",
485e6232409Smrg    "RELATIVE_SET",
486e6232409Smrg    "STYLE",
4878ae5c7d9Smrg    NULL
4888ae5c7d9Smrg};
489e6232409Smrg
4908ae5c7d9Smrgstatic void
4918ae5c7d9SmrgPrintProperty(XFontProp * prop)
492e6232409Smrg{
493e6232409Smrg    char *atom, *value;
494e6232409Smrg    char nosuch[40];
495e6232409Smrg    int i;
496e6232409Smrg    XErrorHandler oldhandler = XSetErrorHandler(IgnoreError);
497e6232409Smrg
498e6232409Smrg    atom = XGetAtomName(dpy, prop->name);
499e6232409Smrg    if (!atom) {
5008ae5c7d9Smrg        snprintf(nosuch, sizeof(nosuch), "No such atom = %ld", prop->name);
501e6232409Smrg        atom = nosuch;
502e6232409Smrg    }
5038ae5c7d9Smrg    printf("      %s", atom);
504e6232409Smrg
505e6232409Smrg    /* Pad out to a column width of 22, but ensure there is always at
506e6232409Smrg       least one space between property name & value. */
5078ae5c7d9Smrg    for (i = strlen(atom); i < 21; i++)
5088ae5c7d9Smrg        putchar(' ');
509e6232409Smrg    putchar(' ');
510e6232409Smrg
5118ae5c7d9Smrg    for (i = 0;; i++) {
512e6232409Smrg        if (stringValued[i] == NULL) {
5138ae5c7d9Smrg            printf("%ld\n", prop->card32);
514e6232409Smrg            break;
515e6232409Smrg        }
516e6232409Smrg        if (strcmp(stringValued[i], atom) == 0) {
517e6232409Smrg            value = XGetAtomName(dpy, prop->card32);
518e6232409Smrg            if (value == NULL)
5198ae5c7d9Smrg                printf("%ld (expected string value)\n", prop->card32);
520e6232409Smrg            else {
5218ae5c7d9Smrg                printf("%s\n", value);
5228ae5c7d9Smrg                XFree(value);
523e6232409Smrg            }
524e6232409Smrg            break;
525e6232409Smrg        }
5268ae5c7d9Smrg    }
5278ae5c7d9Smrg    if (atom != nosuch)
5288ae5c7d9Smrg        XFree(atom);
5298ae5c7d9Smrg    XSetErrorHandler(oldhandler);
530e6232409Smrg}
531e6232409Smrg
532e6232409Smrgstatic void
533e6232409SmrgComputeFontType(XFontStruct *fs)
534e6232409Smrg{
535e6232409Smrg    Bool char_cell = True;
53694a251fdSmrg    const char *reason = NULL;
537e6232409Smrg    XCharStruct *cs;
5388ae5c7d9Smrg    Atom awatom = XInternAtom(dpy, "AVERAGE_WIDTH", False);
539e6232409Smrg
5408ae5c7d9Smrg    printf("  font type:\t\t");
541e6232409Smrg    if (fs->min_bounds.width != fs->max_bounds.width) {
5428ae5c7d9Smrg        printf("Proportional (min and max widths not equal)\n");
543e6232409Smrg        return;
544e6232409Smrg    }
545e6232409Smrg
546e6232409Smrg    if (awatom) {
5478ae5c7d9Smrg        for (int i = 0; i < fs->n_properties; i++) {
548e6232409Smrg            if (fs->properties[i].name == awatom &&
549e6232409Smrg                (fs->max_bounds.width * 10) != fs->properties[i].card32) {
550e6232409Smrg                char_cell = False;
551e6232409Smrg                reason = "font width not equal to AVERAGE_WIDTH";
552e6232409Smrg                break;
553e6232409Smrg            }
554e6232409Smrg        }
555e6232409Smrg    }
556e6232409Smrg
557e6232409Smrg    if (fs->per_char) {
5588ae5c7d9Smrg        unsigned int i;
559e6232409Smrg        for (i = fs->min_char_or_byte2, cs = fs->per_char;
560e6232409Smrg             i <= fs->max_char_or_byte2; i++, cs++) {
5618ae5c7d9Smrg            if (cs->width == 0)
5628ae5c7d9Smrg                continue;
563e6232409Smrg            if (cs->width != fs->max_bounds.width) {
564e6232409Smrg                /* this shouldn't happen since we checked above */
5658ae5c7d9Smrg                printf("Proportional (characters not all the same width)\n");
566e6232409Smrg                return;
567e6232409Smrg            }
568e6232409Smrg            if (char_cell) {
569e6232409Smrg                if (cs->width < 0) {
570e6232409Smrg                    if (!(cs->width <= cs->lbearing &&
571e6232409Smrg                          cs->lbearing <= cs->rbearing &&
572e6232409Smrg                          cs->rbearing <= 0)) {
573e6232409Smrg                        char_cell = False;
574e6232409Smrg                        reason = "ink outside bounding box";
575e6232409Smrg                    }
5768ae5c7d9Smrg                }
5778ae5c7d9Smrg                else {
578e6232409Smrg                    if (!(0 <= cs->lbearing &&
579e6232409Smrg                          cs->lbearing <= cs->rbearing &&
580e6232409Smrg                          cs->rbearing <= cs->width)) {
581e6232409Smrg                        char_cell = False;
582e6232409Smrg                        reason = "ink outside bounding box";
583e6232409Smrg                    }
584e6232409Smrg                }
585e6232409Smrg                if (!(cs->ascent <= fs->ascent &&
586e6232409Smrg                      cs->descent <= fs->descent)) {
5878ae5c7d9Smrg                    char_cell = False;
588e6232409Smrg                    reason = "characters not all same ascent or descent";
589e6232409Smrg                }
590e6232409Smrg            }
591e6232409Smrg        }
592e6232409Smrg    }
593e6232409Smrg
5948ae5c7d9Smrg    printf("%s", char_cell ? "Character Cell" : "Monospaced");
5958ae5c7d9Smrg    if (reason)
5968ae5c7d9Smrg        printf(" (%s)", reason);
5978ae5c7d9Smrg    printf("\n");
5988ae5c7d9Smrg
599e6232409Smrg    return;
600e6232409Smrg}
601e6232409Smrg
602e6232409Smrgstatic void
603e6232409Smrgprint_character_metrics(register XFontStruct *info)
604e6232409Smrg{
605e6232409Smrg    register XCharStruct *pc = info->per_char;
6068ae5c7d9Smrg    unsigned int i, j;
607e6232409Smrg    unsigned n, saven;
608e6232409Smrg
6098ae5c7d9Smrg    printf("  character metrics:\n");
610e6232409Smrg    saven = ((info->min_byte1 << 8) | info->min_char_or_byte2);
611e6232409Smrg    for (j = info->min_byte1; j <= info->max_byte1; j++) {
612e6232409Smrg        n = saven;
613e6232409Smrg        for (i = info->min_char_or_byte2; i <= info->max_char_or_byte2; i++) {
6148ae5c7d9Smrg            char *s = XKeysymToString((KeySym) n);
6158ae5c7d9Smrg
6168ae5c7d9Smrg            printf("\t0x%02x%02x (%u)\t%4d  %4d  %4d  %4d  %4d  0x%04x  %s\n",
6178ae5c7d9Smrg                   j, i, n, pc->width, pc->lbearing,
6188ae5c7d9Smrg                   pc->rbearing, pc->ascent, pc->descent, pc->attributes,
6198ae5c7d9Smrg                   s ? s : ".");
620e6232409Smrg            pc++;
621e6232409Smrg            n++;
622e6232409Smrg        }
623e6232409Smrg        saven += 256;
624e6232409Smrg    }
625e6232409Smrg}
626e6232409Smrg
6278ae5c7d9Smrgstatic void
6288ae5c7d9Smrgdo_query_font(Display *display, char *name)
629e6232409Smrg{
630e6232409Smrg    register int i;
6318ae5c7d9Smrg    register XFontStruct *info = XLoadQueryFont(display, name);
632e6232409Smrg
633e6232409Smrg    if (!info) {
6348ae5c7d9Smrg        fprintf(stderr, "%s:  unable to get info about font \"%s\"\n",
6358ae5c7d9Smrg                program_name, name);
636e6232409Smrg        return;
637e6232409Smrg    }
6388ae5c7d9Smrg    printf("name:  %s\n", name ? name : "(nil)");
6398ae5c7d9Smrg    printf("  direction:\t\t%s\n", ((info->direction == FontLeftToRight)
6408ae5c7d9Smrg                                    ? "left to right" : "right to left"));
6418ae5c7d9Smrg    printf("  indexing:\t\t%s\n",
6428ae5c7d9Smrg           ((info->min_byte1 == 0 && info->max_byte1 == 0)
6438ae5c7d9Smrg            ? "linear" : "matrix"));
6448ae5c7d9Smrg    printf("  rows:\t\t\t0x%02x thru 0x%02x (%d thru %d)\n",
6458ae5c7d9Smrg           info->min_byte1, info->max_byte1,
6468ae5c7d9Smrg           info->min_byte1, info->max_byte1);
6478ae5c7d9Smrg    printf("  columns:\t\t0x%02x thru 0x%02x (%d thru %d)\n",
6488ae5c7d9Smrg           info->min_char_or_byte2, info->max_char_or_byte2,
6498ae5c7d9Smrg           info->min_char_or_byte2, info->max_char_or_byte2);
6508ae5c7d9Smrg    printf("  all chars exist:\t%s\n",
6518ae5c7d9Smrg           (info->all_chars_exist) ? "yes" : "no");
6528ae5c7d9Smrg    printf("  default char:\t\t0x%04x (%d)\n",
6538ae5c7d9Smrg           info->default_char, info->default_char);
6548ae5c7d9Smrg    printf("  ascent:\t\t%d\n", info->ascent);
6558ae5c7d9Smrg    printf("  descent:\t\t%d\n", info->descent);
6568ae5c7d9Smrg    ComputeFontType(info);
6578ae5c7d9Smrg    printf("  bounds:\t\t%s", bounds_metrics_title);
6588ae5c7d9Smrg    PrintBounds("min", &info->min_bounds);
6598ae5c7d9Smrg    PrintBounds("max", &info->max_bounds);
6608ae5c7d9Smrg    if (info->per_char && long_list >= L_VERYLONG)
6618ae5c7d9Smrg        print_character_metrics(info);
6628ae5c7d9Smrg    printf("  properties:\t\t%d\n", info->n_properties);
663e6232409Smrg    for (i = 0; i < info->n_properties; i++)
6648ae5c7d9Smrg        PrintProperty(&info->properties[i]);
6658ae5c7d9Smrg    printf("\n");
666e6232409Smrg
6678ae5c7d9Smrg    XFreeFontInfo(NULL, info, 1);
668e6232409Smrg}
669