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 39e2515bd3Smrg#ifdef HAVE_BSD_STDLIB_H 40e2515bd3Smrg#include <bsd/stdlib.h> 41e2515bd3Smrg#endif 42e2515bd3Smrg 43e2515bd3Smrg#ifndef HAVE_REALLOCARRAY 44e2515bd3Smrg#define reallocarray(old, num, size) realloc(old, (num) * (size)) 45e2515bd3Smrg#endif 46e2515bd3Smrg 478ae5c7d9Smrg#define N_START INT_MAX /* Maximum # of fonts to start with (should 488ae5c7d9Smrg * always be be > 10000 as modern OSes like 498ae5c7d9Smrg * Solaris 8 already have more than 9000 XLFD 508ae5c7d9Smrg * fonts available) */ 51e6232409Smrg 52e6232409Smrg#define L_SHORT 0 53e6232409Smrg#define L_MEDIUM 1 54e6232409Smrg#define L_LONG 2 55e6232409Smrg#define L_VERYLONG 3 56e6232409Smrg 57e6232409Smrgstatic int max_output_line_width = 79; 58e6232409Smrgstatic int output_line_padding = 3; 59e6232409Smrgstatic int columns = 0; 60e6232409Smrg 61e6232409Smrgstatic Bool sort_output = True; 62e6232409Smrgstatic Bool open_instead_of_list = False; 63e6232409Smrgstatic int long_list = L_SHORT; 64e6232409Smrgstatic int nnames = N_START; 65e6232409Smrgstatic int font_cnt = 0; 66e6232409Smrgstatic int min_max; 67e6232409Smrg 68e6232409Smrgtypedef struct { 69e2515bd3Smrg const char *name; 708ae5c7d9Smrg XFontStruct *info; 71e6232409Smrg} FontList; 72e6232409Smrg 73e6232409Smrgstatic FontList *font_list = NULL; 74e6232409Smrg 75e6232409Smrg/* Local prototypes */ 7694a251fdSmrgstatic void get_list(const char *pattern); 77e6232409Smrgstatic int compare(const void *arg1, const void *arg2); 78e6232409Smrgstatic void show_fonts(void); 798ae5c7d9Smrgstatic void copy_number(char **pp1, char **pp2, int n1, int n2); 80e6232409Smrgstatic int IgnoreError(Display *disp, XErrorEvent *event); 81e6232409Smrgstatic void PrintProperty(XFontProp *prop); 82e6232409Smrgstatic void ComputeFontType(XFontStruct *fs); 83e6232409Smrgstatic void print_character_metrics(register XFontStruct *info); 84e2515bd3Smrgstatic void do_query_font(Display *dpy, const char *name); 85e6232409Smrg 868ae5c7d9Smrgvoid 878ae5c7d9Smrgusage(const char *errmsg) 88e6232409Smrg{ 896a45684fSmrg if (errmsg != NULL) 908ae5c7d9Smrg fprintf(stderr, "%s: %s\n\n", program_name, errmsg); 918ae5c7d9Smrg 928ae5c7d9Smrg fprintf(stderr, "usage: %s [-options] [-fn pattern]\n%s", program_name, 938ae5c7d9Smrg "where options include:\n" 948ae5c7d9Smrg " -l[l[l]] give long info about each font\n" 958ae5c7d9Smrg " -m give character min and max bounds\n" 968ae5c7d9Smrg " -C force columns\n" 978ae5c7d9Smrg " -1 force single column\n" 988ae5c7d9Smrg " -u keep output unsorted\n" 998ae5c7d9Smrg " -o use OpenFont/QueryFont instead of ListFonts\n" 1008ae5c7d9Smrg " -w width maximum width for multiple columns\n" 1018ae5c7d9Smrg " -n columns number of columns if multi column\n" 1028ae5c7d9Smrg " -display displayname X server to contact\n" 1038ae5c7d9Smrg " -d displayname (alias for -display displayname)\n" 1048ae5c7d9Smrg " -v print program version\n" 1058ae5c7d9Smrg "\n"); 106e6232409Smrg Close_Display(); 107e6232409Smrg exit(EXIT_FAILURE); 108e6232409Smrg} 109e6232409Smrg 1108ae5c7d9Smrgint 1118ae5c7d9Smrgmain(int argc, char **argv) 112e6232409Smrg{ 113e6232409Smrg int argcnt = 0, i; 114e6232409Smrg 115e6232409Smrg INIT_NAME; 116e6232409Smrg 117e6232409Smrg /* Handle command line arguments, open display */ 118e6232409Smrg Setup_Display_And_Screen(&argc, argv); 119e6232409Smrg 120e6232409Smrg for (argv++, argc--; argc; argv++, argc--) { 121e6232409Smrg if (argv[0][0] == '-') { 1226a45684fSmrg if (argcnt > 0) 1238ae5c7d9Smrg usage("options may not be specified after font names"); 1248ae5c7d9Smrg for (i = 1; argv[0][i]; i++) 1258ae5c7d9Smrg switch (argv[0][i]) { 126e6232409Smrg case 'l': 127e6232409Smrg long_list++; 128e6232409Smrg break; 129e6232409Smrg case 'm': 130e6232409Smrg min_max++; 131e6232409Smrg break; 132e6232409Smrg case 'C': 133e6232409Smrg columns = 0; 134e6232409Smrg break; 135e6232409Smrg case '1': 136e6232409Smrg columns = 1; 137e6232409Smrg break; 1388ae5c7d9Smrg case 'f': /* "-fn" */ 1398ae5c7d9Smrg if (argv[0][i + 1] != 'n') { 1408ae5c7d9Smrg fprintf(stderr, "%s: unrecognized argument %s\n\n", 1418ae5c7d9Smrg program_name, argv[0]); 1426a45684fSmrg usage(NULL); 1436a45684fSmrg } 1448ae5c7d9Smrg if (--argc <= 0) 1458ae5c7d9Smrg usage("-fn requires an argument"); 146e6232409Smrg argcnt++; 147e6232409Smrg argv++; 148e6232409Smrg get_list(argv[0]); 149e6232409Smrg goto next; 150e6232409Smrg case 'w': 1518ae5c7d9Smrg if (--argc <= 0) 1528ae5c7d9Smrg usage("-w requires an argument"); 153e6232409Smrg argv++; 154e6232409Smrg max_output_line_width = atoi(argv[0]); 155e6232409Smrg goto next; 156e6232409Smrg case 'n': 1578ae5c7d9Smrg if (--argc <= 0) 1588ae5c7d9Smrg usage("-n requires an argument"); 159e6232409Smrg argv++; 160e6232409Smrg columns = atoi(argv[0]); 161e6232409Smrg goto next; 162e6232409Smrg case 'o': 163e6232409Smrg open_instead_of_list = True; 164e6232409Smrg break; 165e6232409Smrg case 'u': 166e6232409Smrg sort_output = False; 167e6232409Smrg break; 1686a45684fSmrg case 'v': 1696a45684fSmrg puts(PACKAGE_STRING); 1706a45684fSmrg exit(0); 171e6232409Smrg default: 1728ae5c7d9Smrg fprintf(stderr, "%s: unrecognized argument -%c\n\n", 1738ae5c7d9Smrg program_name, argv[0][i]); 1746a45684fSmrg usage(NULL); 175e6232409Smrg break; 176e6232409Smrg } 1776a45684fSmrg if (i == 1) { 1788ae5c7d9Smrg fprintf(stderr, "%s: unrecognized argument %s\n\n", 1798ae5c7d9Smrg program_name, argv[0]); 1806a45684fSmrg usage(NULL); 1816a45684fSmrg } 1828ae5c7d9Smrg } 1838ae5c7d9Smrg else { 184e6232409Smrg argcnt++; 185e6232409Smrg get_list(argv[0]); 186e6232409Smrg } 1878ae5c7d9Smrg next: ; 188e6232409Smrg } 189e6232409Smrg 190e6232409Smrg if (argcnt == 0) 191e6232409Smrg get_list("*"); 192e6232409Smrg 193e6232409Smrg show_fonts(); 1948ae5c7d9Smrg 195e6232409Smrg Close_Display(); 196e6232409Smrg return EXIT_SUCCESS; 197e6232409Smrg} 198e6232409Smrg 1998ae5c7d9Smrgstatic void 2008ae5c7d9Smrgget_list(const char *pattern) 201e6232409Smrg{ 2028ae5c7d9Smrg XFontStruct *info; 203e6232409Smrg 204e2515bd3Smrg if (open_instead_of_list) { 205e2515bd3Smrg info = XLoadQueryFont(dpy, pattern); 206e6232409Smrg 207e2515bd3Smrg if (info == NULL) { 208e2515bd3Smrg fprintf(stderr, "%s: pattern \"%s\" unmatched\n", 209e2515bd3Smrg program_name, pattern); 210e2515bd3Smrg return; 211e6232409Smrg } 2128ae5c7d9Smrg 213e2515bd3Smrg font_list = reallocarray(font_list, (font_cnt + 1), sizeof(FontList)); 214e2515bd3Smrg if (font_list == NULL) 215e2515bd3Smrg Fatal_Error("Out of memory!"); 216e2515bd3Smrg font_list[font_cnt].name = pattern; 217e2515bd3Smrg if (long_list == L_MEDIUM) { 218e2515bd3Smrg font_list[font_cnt].info = info; 219e2515bd3Smrg XUnloadFont(dpy, info->fid); 220e2515bd3Smrg } 221e2515bd3Smrg else { 222e6232409Smrg font_list[font_cnt].info = NULL; 223e2515bd3Smrg XFreeFont(dpy, info); 224e2515bd3Smrg } 225e6232409Smrg font_cnt++; 226e6232409Smrg } 227e2515bd3Smrg else { 228e2515bd3Smrg /* Get list of fonts matching pattern */ 229e2515bd3Smrg int available = nnames + 1; 230e2515bd3Smrg char **fonts; 231e2515bd3Smrg 232e2515bd3Smrg for (;;) { 233e2515bd3Smrg if (long_list == L_MEDIUM) 234e2515bd3Smrg fonts = XListFontsWithInfo(dpy, pattern, nnames, &available, 235e2515bd3Smrg &info); 236e2515bd3Smrg else 237e2515bd3Smrg fonts = XListFonts(dpy, pattern, nnames, &available); 238e2515bd3Smrg if (fonts == NULL) { 239e2515bd3Smrg fprintf(stderr, "%s: pattern \"%s\" unmatched\n", 240e2515bd3Smrg program_name, pattern); 241e2515bd3Smrg return; 242e2515bd3Smrg } 243e2515bd3Smrg if (available < nnames) 244e2515bd3Smrg break; 245e2515bd3Smrg if (long_list == L_MEDIUM) 246e2515bd3Smrg XFreeFontInfo(fonts, info, available); 247e2515bd3Smrg else 248e2515bd3Smrg XFreeFontNames(fonts); 249e2515bd3Smrg nnames = available * 2; 250e2515bd3Smrg } 251e2515bd3Smrg 252e2515bd3Smrg font_list = reallocarray(font_list, 253e2515bd3Smrg (font_cnt + available), sizeof(FontList)); 254e2515bd3Smrg if (font_list == NULL) 255e2515bd3Smrg Fatal_Error("Out of memory!"); 256e2515bd3Smrg for (int i = 0; i < available; i++) { 257e2515bd3Smrg font_list[font_cnt].name = fonts[i]; 258e2515bd3Smrg if (long_list == L_MEDIUM) 259e2515bd3Smrg font_list[font_cnt].info = info + i; 260e2515bd3Smrg else 261e2515bd3Smrg font_list[font_cnt].info = NULL; 262e2515bd3Smrg 263e2515bd3Smrg font_cnt++; 264e2515bd3Smrg } 265e2515bd3Smrg } 266e6232409Smrg} 267e6232409Smrg 2688ae5c7d9Smrgstatic int 2698ae5c7d9Smrgcompare(const void *arg1, const void *arg2) 270e6232409Smrg{ 271e6232409Smrg const FontList *f1 = arg1; 272e6232409Smrg const FontList *f2 = arg2; 273e6232409Smrg const char *p1 = f1->name; 274e6232409Smrg const char *p2 = f2->name; 275e6232409Smrg 276e6232409Smrg while (*p1 && *p2 && *p1 == *p2) 2778ae5c7d9Smrg p1++, p2++; 2788ae5c7d9Smrg return (*p1 - *p2); 279e6232409Smrg} 280e6232409Smrg 2818ae5c7d9Smrgstatic void 2828ae5c7d9Smrgshow_fonts(void) 283e6232409Smrg{ 284e6232409Smrg int i; 285e6232409Smrg 286e6232409Smrg if (font_cnt == 0) 287e6232409Smrg return; 288e6232409Smrg 289e6232409Smrg /* first sort the output */ 2908ae5c7d9Smrg if (sort_output) 2918ae5c7d9Smrg qsort(font_list, font_cnt, sizeof(FontList), compare); 292e6232409Smrg 293e6232409Smrg if (long_list > L_MEDIUM) { 294e6232409Smrg for (i = 0; i < font_cnt; i++) { 2958ae5c7d9Smrg do_query_font(dpy, font_list[i].name); 296e6232409Smrg } 297e6232409Smrg return; 298e6232409Smrg } 299e6232409Smrg 300e6232409Smrg if (long_list == L_MEDIUM) { 301e6232409Smrg XFontStruct *pfi; 3028ae5c7d9Smrg 3038ae5c7d9Smrg const char *string; 304e6232409Smrg 305e6232409Smrg printf("DIR "); 306e6232409Smrg printf("MIN "); 307e6232409Smrg printf("MAX "); 308e6232409Smrg printf("EXIST "); 309e6232409Smrg printf("DFLT "); 310e6232409Smrg printf("PROP "); 311e6232409Smrg printf("ASC "); 312e6232409Smrg printf("DESC "); 313e6232409Smrg printf("NAME"); 314e6232409Smrg printf("\n"); 3158ae5c7d9Smrg for (i = 0; i < font_cnt; i++) { 316e6232409Smrg pfi = font_list[i].info; 317e6232409Smrg if (!pfi) { 318e6232409Smrg fprintf(stderr, "%s: no font information for font \"%s\".\n", 3198ae5c7d9Smrg program_name, 3208ae5c7d9Smrg font_list[i].name ? font_list[i].name : ""); 321e6232409Smrg continue; 322e6232409Smrg } 3238ae5c7d9Smrg switch (pfi->direction) { 3248ae5c7d9Smrg case FontLeftToRight: 3258ae5c7d9Smrg string = "-->"; 3268ae5c7d9Smrg break; 3278ae5c7d9Smrg case FontRightToLeft: 3288ae5c7d9Smrg string = "<--"; 3298ae5c7d9Smrg break; 3308ae5c7d9Smrg default: 3318ae5c7d9Smrg string = "???"; 3328ae5c7d9Smrg break; 333e6232409Smrg } 334e6232409Smrg printf("%-4s", string); 3358ae5c7d9Smrg if (pfi->min_byte1 == 0 && pfi->max_byte1 == 0) { 336e6232409Smrg printf(" %3d ", pfi->min_char_or_byte2); 337e6232409Smrg printf(" %3d ", pfi->max_char_or_byte2); 3388ae5c7d9Smrg } 3398ae5c7d9Smrg else { 340e6232409Smrg printf("*%3d ", pfi->min_byte1); 341e6232409Smrg printf("*%3d ", pfi->max_byte1); 342e6232409Smrg } 343e6232409Smrg printf("%5s ", pfi->all_chars_exist ? "all" : "some"); 344e6232409Smrg printf("%4d ", pfi->default_char); 345e6232409Smrg printf("%4d ", pfi->n_properties); 346e6232409Smrg printf("%3d ", pfi->ascent); 347e6232409Smrg printf("%4d ", pfi->descent); 348e6232409Smrg printf("%s\n", font_list[i].name); 349e6232409Smrg if (min_max) { 3508ae5c7d9Smrg char min[BUFSIZ], max[BUFSIZ]; 3518ae5c7d9Smrg 3528ae5c7d9Smrg char *pmax = max, *pmin = min; 353e6232409Smrg 354e6232409Smrg strcpy(pmin, " min(l,r,w,a,d) = ("); 355e6232409Smrg strcpy(pmax, " max(l,r,w,a,d) = ("); 356e6232409Smrg pmin += strlen(pmin); 357e6232409Smrg pmax += strlen(pmax); 358e6232409Smrg 359e6232409Smrg copy_number(&pmin, &pmax, 360e6232409Smrg pfi->min_bounds.lbearing, 361e6232409Smrg pfi->max_bounds.lbearing); 362e6232409Smrg *pmin++ = *pmax++ = ','; 363e6232409Smrg copy_number(&pmin, &pmax, 364e6232409Smrg pfi->min_bounds.rbearing, 365e6232409Smrg pfi->max_bounds.rbearing); 366e6232409Smrg *pmin++ = *pmax++ = ','; 367e6232409Smrg copy_number(&pmin, &pmax, 368e6232409Smrg pfi->min_bounds.width, 369e6232409Smrg pfi->max_bounds.width); 370e6232409Smrg *pmin++ = *pmax++ = ','; 371e6232409Smrg copy_number(&pmin, &pmax, 372e6232409Smrg pfi->min_bounds.ascent, 373e6232409Smrg pfi->max_bounds.ascent); 374e6232409Smrg *pmin++ = *pmax++ = ','; 375e6232409Smrg copy_number(&pmin, &pmax, 376e6232409Smrg pfi->min_bounds.descent, 377e6232409Smrg pfi->max_bounds.descent); 378e6232409Smrg *pmin++ = *pmax++ = ')'; 379e6232409Smrg *pmin = *pmax = '\0'; 380e6232409Smrg printf("%s\n", min); 381e6232409Smrg printf("%s\n", max); 382e6232409Smrg } 383e6232409Smrg } 384e6232409Smrg return; 385e6232409Smrg } 386e6232409Smrg 387e6232409Smrg if ((columns == 0 && isatty(1)) || columns > 1) { 3888ae5c7d9Smrg int width, max_width = 0, lines_per_column, j, index; 389e6232409Smrg 3908ae5c7d9Smrg for (i = 0; i < font_cnt; i++) { 391e6232409Smrg width = strlen(font_list[i].name); 392e6232409Smrg if (width > max_width) 393e6232409Smrg max_width = width; 394e6232409Smrg } 395e6232409Smrg if (max_width == 0) 396e6232409Smrg Fatal_Error("all %d fontnames listed are zero length", font_cnt); 397e6232409Smrg 398e6232409Smrg if (columns == 0) { 399e6232409Smrg if ((max_width * 2) + output_line_padding > 400e6232409Smrg max_output_line_width) { 401e6232409Smrg columns = 1; 4028ae5c7d9Smrg } 4038ae5c7d9Smrg else { 404e6232409Smrg max_width += output_line_padding; 405e6232409Smrg columns = ((max_output_line_width + 406e6232409Smrg output_line_padding) / max_width); 407e6232409Smrg } 4088ae5c7d9Smrg } 4098ae5c7d9Smrg else { 410e6232409Smrg max_width += output_line_padding; 411e6232409Smrg } 4128ae5c7d9Smrg if (columns <= 1) 4138ae5c7d9Smrg goto single_column; 414e6232409Smrg 415e6232409Smrg if (font_cnt < columns) 416e6232409Smrg columns = font_cnt; 417e6232409Smrg lines_per_column = (font_cnt + columns - 1) / columns; 418e6232409Smrg 4198ae5c7d9Smrg for (i = 0; i < lines_per_column; i++) { 4208ae5c7d9Smrg for (j = 0; j < columns; j++) { 421e6232409Smrg index = j * lines_per_column + i; 422e6232409Smrg if (index >= font_cnt) 423e6232409Smrg break; 4248ae5c7d9Smrg if (j + 1 == columns) 4258ae5c7d9Smrg printf("%s", font_list[index].name); 426e6232409Smrg else 4278ae5c7d9Smrg printf("%-*s", max_width, font_list[index].name); 428e6232409Smrg } 429e6232409Smrg printf("\n"); 430e6232409Smrg } 431e6232409Smrg return; 432e6232409Smrg } 433e6232409Smrg 4348ae5c7d9Smrg single_column: 4358ae5c7d9Smrg for (i = 0; i < font_cnt; i++) 436e6232409Smrg printf("%s\n", font_list[i].name); 437e6232409Smrg} 438e6232409Smrg 4398ae5c7d9Smrgstatic void 4408ae5c7d9Smrgcopy_number(char **pp1, char **pp2, int n1, int n2) 441e6232409Smrg{ 442e6232409Smrg char *p1 = *pp1; 443e6232409Smrg char *p2 = *pp2; 4448ae5c7d9Smrg int w; 445e6232409Smrg 446e6232409Smrg sprintf(p1, "%d", n1); 447e6232409Smrg sprintf(p2, "%d", n2); 448e6232409Smrg w = MAX(strlen(p1), strlen(p2)); 449e6232409Smrg sprintf(p1, "%*d", w, n1); 450e6232409Smrg sprintf(p2, "%*d", w, n2); 451e6232409Smrg p1 += strlen(p1); 452e6232409Smrg p2 += strlen(p2); 453e6232409Smrg *pp1 = p1; 454e6232409Smrg *pp2 = p2; 455e6232409Smrg} 456e6232409Smrg 457e6232409Smrg/* ARGSUSED */ 4588ae5c7d9Smrgstatic int 4598ae5c7d9SmrgIgnoreError(Display * disp, XErrorEvent *event) 460e6232409Smrg{ 461e6232409Smrg return 0; 462e6232409Smrg} 463e6232409Smrg 46494a251fdSmrgstatic const char *bounds_metrics_title = 4658ae5c7d9Smrg "width left right asc desc attr keysym\n"; 466e6232409Smrg 467e6232409Smrg#define PrintBounds(_what,_ptr) \ 468e6232409Smrg{ register XCharStruct *p = (_ptr); \ 4698fff3f40Smrg printf ("\t%3s\t\t%4d %4d %4d %4d %4d 0x%04x\n", \ 4708fff3f40Smrg (_what), p->width, p->lbearing, \ 471e6232409Smrg p->rbearing, p->ascent, p->descent, p->attributes); } 472e6232409Smrg 4738ae5c7d9Smrgstatic const char *stringValued[] = { /* values are atoms */ 474e6232409Smrg /* font name components (see section 3.2 of the XLFD) */ 475e6232409Smrg "FOUNDRY", 476e6232409Smrg "FAMILY_NAME", 477e6232409Smrg "WEIGHT_NAME", 478e6232409Smrg "SLANT", 479e6232409Smrg "SETWIDTH_NAME", 480e6232409Smrg "ADD_STYLE_NAME", 481e6232409Smrg "SPACING", 482e6232409Smrg "CHARSET_REGISTRY", 483e6232409Smrg "CHARSET_ENCODING", 484e6232409Smrg 485e6232409Smrg /* other standard X font properties (see section 3.2 of the XLFD) */ 486e6232409Smrg "FONT", 487e6232409Smrg "FACE_NAME", 4888ae5c7d9Smrg "FULL_NAME", /* deprecated */ 489e6232409Smrg "COPYRIGHT", 490e6232409Smrg "NOTICE", 491e6232409Smrg "FONT_TYPE", 492e6232409Smrg "FONT_VERSION", 493e6232409Smrg "RASTERIZER_NAME", 494e6232409Smrg "RASTERIZER_VERSION", 495e6232409Smrg 496e6232409Smrg /* other registered font properties (see the X.org Registry, sec. 15) */ 497e6232409Smrg "_ADOBE_POSTSCRIPT_FONTNAME", 4988ae5c7d9Smrg 499e6232409Smrg /* unregistered font properties */ 500e6232409Smrg "CHARSET_COLLECTIONS", 501e6232409Smrg "CLASSIFICATION", 502e6232409Smrg "DEVICE_FONT_NAME", 503e6232409Smrg "FONTNAME_REGISTRY", 504e6232409Smrg "MONOSPACED", 505e6232409Smrg "QUALITY", 506e6232409Smrg "RELATIVE_SET", 507e6232409Smrg "STYLE", 5088ae5c7d9Smrg NULL 5098ae5c7d9Smrg}; 510e6232409Smrg 5118ae5c7d9Smrgstatic void 5128ae5c7d9SmrgPrintProperty(XFontProp * prop) 513e6232409Smrg{ 514e6232409Smrg char *atom, *value; 515e6232409Smrg char nosuch[40]; 516e6232409Smrg int i; 517e6232409Smrg XErrorHandler oldhandler = XSetErrorHandler(IgnoreError); 518e6232409Smrg 519e6232409Smrg atom = XGetAtomName(dpy, prop->name); 520e6232409Smrg if (!atom) { 5218ae5c7d9Smrg snprintf(nosuch, sizeof(nosuch), "No such atom = %ld", prop->name); 522e6232409Smrg atom = nosuch; 523e6232409Smrg } 5248ae5c7d9Smrg printf(" %s", atom); 525e6232409Smrg 526e6232409Smrg /* Pad out to a column width of 22, but ensure there is always at 527e6232409Smrg least one space between property name & value. */ 5288ae5c7d9Smrg for (i = strlen(atom); i < 21; i++) 5298ae5c7d9Smrg putchar(' '); 530e6232409Smrg putchar(' '); 531e6232409Smrg 5328ae5c7d9Smrg for (i = 0;; i++) { 533e6232409Smrg if (stringValued[i] == NULL) { 5348ae5c7d9Smrg printf("%ld\n", prop->card32); 535e6232409Smrg break; 536e6232409Smrg } 537e6232409Smrg if (strcmp(stringValued[i], atom) == 0) { 538e6232409Smrg value = XGetAtomName(dpy, prop->card32); 539e6232409Smrg if (value == NULL) 5408ae5c7d9Smrg printf("%ld (expected string value)\n", prop->card32); 541e6232409Smrg else { 5428ae5c7d9Smrg printf("%s\n", value); 5438ae5c7d9Smrg XFree(value); 544e6232409Smrg } 545e6232409Smrg break; 546e6232409Smrg } 5478ae5c7d9Smrg } 5488ae5c7d9Smrg if (atom != nosuch) 5498ae5c7d9Smrg XFree(atom); 5508ae5c7d9Smrg XSetErrorHandler(oldhandler); 551e6232409Smrg} 552e6232409Smrg 553e6232409Smrgstatic void 554e6232409SmrgComputeFontType(XFontStruct *fs) 555e6232409Smrg{ 556e6232409Smrg Bool char_cell = True; 55794a251fdSmrg const char *reason = NULL; 558e6232409Smrg XCharStruct *cs; 5598ae5c7d9Smrg Atom awatom = XInternAtom(dpy, "AVERAGE_WIDTH", False); 560e6232409Smrg 5618ae5c7d9Smrg printf(" font type:\t\t"); 562e6232409Smrg if (fs->min_bounds.width != fs->max_bounds.width) { 5638ae5c7d9Smrg printf("Proportional (min and max widths not equal)\n"); 564e6232409Smrg return; 565e6232409Smrg } 566e6232409Smrg 567e6232409Smrg if (awatom) { 5688ae5c7d9Smrg for (int i = 0; i < fs->n_properties; i++) { 569e6232409Smrg if (fs->properties[i].name == awatom && 570e6232409Smrg (fs->max_bounds.width * 10) != fs->properties[i].card32) { 571e6232409Smrg char_cell = False; 572e6232409Smrg reason = "font width not equal to AVERAGE_WIDTH"; 573e6232409Smrg break; 574e6232409Smrg } 575e6232409Smrg } 576e6232409Smrg } 577e6232409Smrg 578e6232409Smrg if (fs->per_char) { 5798ae5c7d9Smrg unsigned int i; 580e6232409Smrg for (i = fs->min_char_or_byte2, cs = fs->per_char; 581e6232409Smrg i <= fs->max_char_or_byte2; i++, cs++) { 5828ae5c7d9Smrg if (cs->width == 0) 5838ae5c7d9Smrg continue; 584e6232409Smrg if (cs->width != fs->max_bounds.width) { 585e6232409Smrg /* this shouldn't happen since we checked above */ 5868ae5c7d9Smrg printf("Proportional (characters not all the same width)\n"); 587e6232409Smrg return; 588e6232409Smrg } 589e6232409Smrg if (char_cell) { 590e6232409Smrg if (cs->width < 0) { 591e6232409Smrg if (!(cs->width <= cs->lbearing && 592e6232409Smrg cs->lbearing <= cs->rbearing && 593e6232409Smrg cs->rbearing <= 0)) { 594e6232409Smrg char_cell = False; 595e6232409Smrg reason = "ink outside bounding box"; 596e6232409Smrg } 5978ae5c7d9Smrg } 5988ae5c7d9Smrg else { 599e6232409Smrg if (!(0 <= cs->lbearing && 600e6232409Smrg cs->lbearing <= cs->rbearing && 601e6232409Smrg cs->rbearing <= cs->width)) { 602e6232409Smrg char_cell = False; 603e6232409Smrg reason = "ink outside bounding box"; 604e6232409Smrg } 605e6232409Smrg } 606e6232409Smrg if (!(cs->ascent <= fs->ascent && 607e6232409Smrg cs->descent <= fs->descent)) { 6088ae5c7d9Smrg char_cell = False; 609e6232409Smrg reason = "characters not all same ascent or descent"; 610e6232409Smrg } 611e6232409Smrg } 612e6232409Smrg } 613e6232409Smrg } 614e6232409Smrg 6158ae5c7d9Smrg printf("%s", char_cell ? "Character Cell" : "Monospaced"); 6168ae5c7d9Smrg if (reason) 6178ae5c7d9Smrg printf(" (%s)", reason); 6188ae5c7d9Smrg printf("\n"); 6198ae5c7d9Smrg 620e6232409Smrg return; 621e6232409Smrg} 622e6232409Smrg 623e6232409Smrgstatic void 624e6232409Smrgprint_character_metrics(register XFontStruct *info) 625e6232409Smrg{ 626e6232409Smrg register XCharStruct *pc = info->per_char; 6278ae5c7d9Smrg unsigned int i, j; 628e6232409Smrg unsigned n, saven; 629e6232409Smrg 6308ae5c7d9Smrg printf(" character metrics:\n"); 631e6232409Smrg saven = ((info->min_byte1 << 8) | info->min_char_or_byte2); 632e6232409Smrg for (j = info->min_byte1; j <= info->max_byte1; j++) { 633e6232409Smrg n = saven; 634e6232409Smrg for (i = info->min_char_or_byte2; i <= info->max_char_or_byte2; i++) { 6358ae5c7d9Smrg char *s = XKeysymToString((KeySym) n); 6368ae5c7d9Smrg 6378ae5c7d9Smrg printf("\t0x%02x%02x (%u)\t%4d %4d %4d %4d %4d 0x%04x %s\n", 6388ae5c7d9Smrg j, i, n, pc->width, pc->lbearing, 6398ae5c7d9Smrg pc->rbearing, pc->ascent, pc->descent, pc->attributes, 6408ae5c7d9Smrg s ? s : "."); 641e6232409Smrg pc++; 642e6232409Smrg n++; 643e6232409Smrg } 644e6232409Smrg saven += 256; 645e6232409Smrg } 646e6232409Smrg} 647e6232409Smrg 6488ae5c7d9Smrgstatic void 649e2515bd3Smrgdo_query_font(Display *display, const char *name) 650e6232409Smrg{ 651e6232409Smrg register int i; 6528ae5c7d9Smrg register XFontStruct *info = XLoadQueryFont(display, name); 653e6232409Smrg 654e6232409Smrg if (!info) { 6558ae5c7d9Smrg fprintf(stderr, "%s: unable to get info about font \"%s\"\n", 6568ae5c7d9Smrg program_name, name); 657e6232409Smrg return; 658e6232409Smrg } 6598ae5c7d9Smrg printf("name: %s\n", name ? name : "(nil)"); 6608ae5c7d9Smrg printf(" direction:\t\t%s\n", ((info->direction == FontLeftToRight) 6618ae5c7d9Smrg ? "left to right" : "right to left")); 6628ae5c7d9Smrg printf(" indexing:\t\t%s\n", 6638ae5c7d9Smrg ((info->min_byte1 == 0 && info->max_byte1 == 0) 6648ae5c7d9Smrg ? "linear" : "matrix")); 6658ae5c7d9Smrg printf(" rows:\t\t\t0x%02x thru 0x%02x (%d thru %d)\n", 6668ae5c7d9Smrg info->min_byte1, info->max_byte1, 6678ae5c7d9Smrg info->min_byte1, info->max_byte1); 6688ae5c7d9Smrg printf(" columns:\t\t0x%02x thru 0x%02x (%d thru %d)\n", 6698ae5c7d9Smrg info->min_char_or_byte2, info->max_char_or_byte2, 6708ae5c7d9Smrg info->min_char_or_byte2, info->max_char_or_byte2); 6718ae5c7d9Smrg printf(" all chars exist:\t%s\n", 6728ae5c7d9Smrg (info->all_chars_exist) ? "yes" : "no"); 6738ae5c7d9Smrg printf(" default char:\t\t0x%04x (%d)\n", 6748ae5c7d9Smrg info->default_char, info->default_char); 6758ae5c7d9Smrg printf(" ascent:\t\t%d\n", info->ascent); 6768ae5c7d9Smrg printf(" descent:\t\t%d\n", info->descent); 6778ae5c7d9Smrg ComputeFontType(info); 6788ae5c7d9Smrg printf(" bounds:\t\t%s", bounds_metrics_title); 6798ae5c7d9Smrg PrintBounds("min", &info->min_bounds); 6808ae5c7d9Smrg PrintBounds("max", &info->max_bounds); 6818ae5c7d9Smrg if (info->per_char && long_list >= L_VERYLONG) 6828ae5c7d9Smrg print_character_metrics(info); 6838ae5c7d9Smrg printf(" properties:\t\t%d\n", info->n_properties); 684e6232409Smrg for (i = 0; i < info->n_properties; i++) 6858ae5c7d9Smrg PrintProperty(&info->properties[i]); 6868ae5c7d9Smrg printf("\n"); 687e6232409Smrg 6888ae5c7d9Smrg XFreeFontInfo(NULL, info, 1); 689e6232409Smrg} 690