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