fslsfonts.c revision d04472e1
1/* 2 3Copyright 1990, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25 * Copyright 1990 Network Computing Devices; 26 * Portions Copyright 1987 by Digital Equipment Corporation 27 * 28 * Permission to use, copy, modify, distribute, and sell this software and 29 * its documentation for any purpose is hereby granted without fee, provided 30 * that the above copyright notice appear in all copies and that both that 31 * copyright notice and this permission notice appear in supporting 32 * documentation, and that the names of Network Computing Devices, or Digital 33 * not be used in advertising or publicity pertaining to distribution 34 * of the software without specific, written prior permission. 35 * 36 * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH 37 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF 38 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES, 39 * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 40 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 41 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 42 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 43 * THIS SOFTWARE. 44 */ 45 46#ifdef HAVE_CONFIG_H 47# include "config.h" 48#endif 49 50#include <X11/fonts/FSlib.h> 51#include <stdio.h> 52#include <X11/Xos.h> 53#include <stdlib.h> 54#include <assert.h> 55 56#ifdef HAVE_BSD_STDLIB_H 57#include <bsd/stdlib.h> 58#endif 59 60#ifndef HAVE_REALLOCARRAY 61#define reallocarray(old, num, size) realloc(old, (num) * (size)) 62#endif 63 64#ifndef N_START 65#define N_START 1000 /* Maximum # of fonts to start with */ 66#endif 67 68static unsigned int max_output_line_width = 79; 69static unsigned int output_line_padding = 3; 70static unsigned int columns = 0; 71 72#define L_SHORT 0 73#define L_MEDIUM 1 74#define L_LONG 2 75#define L_VERYLONG 3 76 77static Bool sort_output = True; 78static int long_list = L_SHORT; 79static int nnames = N_START; 80static unsigned int font_cnt; 81static int min_max; 82typedef struct { 83 char *name; 84 FSXFontInfoHeader *info; 85 FSPropInfo *pi; 86 FSPropOffset *po; 87 unsigned char *pd; 88} FontList; 89static FontList *font_list; 90 91static FSServer *svr; 92 93static char *program_name; 94 95static void usage (const char *msg) _X_NORETURN _X_COLD; 96static void get_list ( const char *pattern ); 97static int compare ( const void *f1, const void *f2 ); 98static void show_fonts ( void ); 99static void print_font_header ( void ); 100static void show_font_header ( FontList *list ); 101static void copy_number ( char **pp1, char **pp2, char **ep1, char **ep2, 102 int n1, int n2, char suffix ); 103static void show_font_props ( FontList *list ); 104 105static void _X_NORETURN _X_COLD 106missing_arg (const char *option) 107{ 108 char msg[32]; 109 110 snprintf(msg, sizeof(msg), "%s requires an argument", option); 111 usage(msg); 112} 113 114static void 115usage(const char *msg) 116{ 117 if (msg) 118 fprintf(stderr, "%s: %s\n", program_name, msg); 119 fprintf(stderr, "usage: %s [-options] [-fn pattern]\n", program_name); 120 fprintf(stderr, "%s", "where options include:\n" 121 " -l[l[l]] give long info about each font\n" 122 " -m give character min and max bounds\n" 123 " -C force columns\n" 124 " -1 force single column\n" 125 " -u keep output unsorted\n" 126 " -w width maximum width for multiple columns\n" 127 " -n columns number of columns if multi column\n" 128 " -server servername font server to contact\n" 129 " -version print command version and exit\n" 130 "\n"); 131 exit(1); 132} 133 134int 135main(int argc, char *argv[]) 136{ 137 int argcnt = 0, 138 i; 139 char *servername = NULL; 140 141 program_name = argv[0]; 142 143 for (i = 1; i < argc; i++) { 144 if (strncmp(argv[i], "-s", 2) == 0) { 145 if (++i >= argc) 146 missing_arg("-server"); 147 servername = argv[i]; 148 } 149 else if (strcmp(argv[i], "-version") == 0) { 150 printf("%s\n", PACKAGE_STRING); 151 exit(0); 152 } 153 } 154 155 if ((svr = FSOpenServer(servername)) == NULL) { 156 if (FSServerName(servername) == NULL) { 157 usage("no font server defined"); 158 } 159 fprintf(stderr, "%s: unable to open server \"%s\"\n", 160 program_name, FSServerName(servername)); 161 exit(0); 162 } 163 /* Handle command line arguments, open display */ 164 for (argv++, argc--; argc; argv++, argc--) { 165 if (argv[0][0] == '-') { 166 if (argcnt > 0) 167 usage(NULL); 168 for (i = 1; argv[0][i]; i++) 169 switch (argv[0][i]) { 170 case 'l': 171 long_list++; 172 break; 173 case 'm': 174 min_max++; 175 break; 176 case 'C': 177 columns = 0; 178 break; 179 case '1': 180 columns = 1; 181 break; 182 case 'f': 183 if (--argc <= 0) 184 missing_arg("-fn"); 185 argcnt++; 186 argv++; 187 get_list(argv[0]); 188 goto next; 189 case 'w': 190 if (--argc <= 0) 191 missing_arg("-w"); 192 argv++; 193 max_output_line_width = (unsigned int) atoi(argv[0]); 194 goto next; 195 case 'n': 196 if (--argc <= 0) 197 missing_arg("-n"); 198 argv++; 199 columns = (unsigned int) atoi(argv[0]); 200 goto next; 201 case 'u': 202 sort_output = False; 203 break; 204 case 's': /* eat -s */ 205 if (--argc <= 0) 206 missing_arg("-server"); 207 argv++; 208 goto next; 209 default: 210 fprintf(stderr, "%s: unrecognized option '%s'\n", 211 program_name, argv[0]); 212 usage(NULL); 213 } 214 if (i == 1) 215 usage(NULL); 216 } else { 217 argcnt++; 218 get_list(argv[0]); 219 } 220next: ; 221 } 222 if (argcnt == 0) 223 get_list("*"); 224 FSCloseServer(svr); 225 show_fonts(); 226 exit(0); 227} 228 229static void 230get_list(const char *pattern) 231{ 232 int available = nnames + 1, 233 i; 234 char **fonts; 235 FSXFontInfoHeader **info; 236 FSPropInfo **props; 237 FSPropOffset **offsets; 238 unsigned char **pdata; 239 240 /* Get list of fonts matching pattern */ 241 for (;;) { 242 243 if (long_list >= L_MEDIUM) 244 fonts = FSListFontsWithXInfo(svr, 245 pattern, nnames, &available, &info, &props, &offsets, &pdata); 246 else 247 fonts = FSListFonts(svr, pattern, nnames, &available); 248 if (fonts == NULL || available < nnames) 249 break; 250 251 if (long_list >= L_MEDIUM) { 252 for (i = 0; i < available; i++) { 253 FSFree((char *) fonts[i]); 254 FSFree((char *) info[i]); 255 FSFree((char *) props[i]); 256 FSFree((char *) offsets[i]); 257 FSFree((char *) pdata[i]); 258 } 259 FSFree((char *) fonts); 260 FSFree((char *) info); 261 FSFree((char *) props); 262 FSFree((char *) offsets); 263 FSFree((char *) pdata); 264 } else { 265 FSFreeFontNames(fonts); 266 } 267 nnames = available * 2; 268 } 269 270 if (fonts == NULL) { 271 fprintf(stderr, "%s: pattern \"%s\" unmatched\n", 272 program_name, pattern); 273 return; 274 } 275 else { 276 FontList *old_list = font_list; 277 278 font_list = reallocarray(old_list, (font_cnt + (unsigned) available), 279 sizeof(FontList)); 280 281 if (font_list == NULL) { 282 free(old_list); 283 fprintf(stderr, "%s: unable to allocate %zu bytes for font list\n", 284 program_name, 285 (font_cnt + (unsigned) available) * sizeof(FontList)); 286 exit(-1); 287 } 288 } 289 for (i = 0; i < available; i++) { 290 font_list[font_cnt].name = fonts[i]; 291 292 if (long_list >= L_MEDIUM) { 293 font_list[font_cnt].info = info[i]; 294 font_list[font_cnt].pi = props[i]; 295 font_list[font_cnt].po = offsets[i]; 296 font_list[font_cnt].pd = pdata[i]; 297 } else 298 font_list[font_cnt].info = NULL; 299 font_cnt++; 300 } 301} 302 303static int 304compare(const void *f1, const void *f2) 305{ 306 const char *p1 = ((const FontList *)f1)->name, 307 *p2 = ((const FontList *)f2)->name; 308 309 while (*p1 && *p2 && *p1 == *p2) 310 p1++, p2++; 311 return (*p1 - *p2); 312} 313 314static void 315show_fonts(void) 316{ 317 unsigned int i; 318 319 if (font_cnt == 0) 320 return; 321 322 /* first sort the output */ 323 if (sort_output) 324 qsort(font_list, font_cnt, sizeof(FontList), compare); 325 326 if (long_list > L_MEDIUM) { 327 print_font_header(); 328 for (i = 0; i < font_cnt; i++) { 329 show_font_header(&font_list[i]); 330 show_font_props(&font_list[i]); 331 } 332 return; 333 } 334 if (long_list == L_MEDIUM) { 335 print_font_header(); 336 337 for (i = 0; i < font_cnt; i++) { 338 show_font_header(&font_list[i]); 339 } 340 341 return; 342 } 343 if ((columns == 0 && isatty(1)) || columns > 1) { 344 unsigned int width, 345 max_width = 0, 346 lines_per_column, 347 j, 348 index; 349 350 for (i = 0; i < font_cnt; i++) { 351 width = (unsigned int) strlen(font_list[i].name); 352 if (width > max_width) 353 max_width = width; 354 } 355 if (max_width == 0) { 356 fprintf(stderr, "all %d fontnames listed are zero length", 357 font_cnt); 358 exit(-1); 359 } 360 if (columns == 0) { 361 if ((max_width * 2) + output_line_padding > 362 max_output_line_width) { 363 columns = 1; 364 } else { 365 max_width += output_line_padding; 366 columns = ((max_output_line_width + 367 output_line_padding) / max_width); 368 } 369 } else { 370 max_width += output_line_padding; 371 } 372 if (columns <= 1) 373 goto single_column; 374 375 if (font_cnt < columns) 376 columns = font_cnt; 377 lines_per_column = (font_cnt + columns - 1) / columns; 378 379 for (i = 0; i < lines_per_column; i++) { 380 for (j = 0; j < columns; j++) { 381 index = j * lines_per_column + i; 382 if (index >= font_cnt) 383 break; 384 if (j + 1 == columns) 385 printf("%s", font_list[index].name); 386 else 387 printf("%-*s", 388 max_width, 389 font_list[index].name); 390 } 391 printf("\n"); 392 } 393 return; 394 } 395single_column: 396 for (i = 0; i < font_cnt; i++) 397 printf("%s\n", font_list[i].name); 398} 399 400static void 401print_font_header(void) 402{ 403 printf("DIR "); 404 printf("MIN "); 405 printf("MAX "); 406 printf("EXIST "); 407 printf("DFLT "); 408 printf("ASC "); 409 printf("DESC "); 410 printf("NAME"); 411 printf("\n"); 412} 413 414static void 415show_font_header(FontList *list) 416{ 417 const char *string; 418 FSXFontInfoHeader *pfh; 419 420 pfh = list->info; 421 if (!pfh) { 422 fprintf(stderr, 423 "%s: no font information for font \"%s\".\n", 424 program_name, list->name ? list->name : ""); 425 return; 426 } 427 if (pfh->draw_direction == LeftToRightDrawDirection) 428 string = "-->"; 429 else 430 string = "<--"; 431 printf("%-4s", string); 432 if (pfh->char_range.min_char.high == 0 433 && pfh->char_range.max_char.high == 0) { 434 printf(" %3d ", pfh->char_range.min_char.low); 435 printf(" %3d ", pfh->char_range.max_char.low); 436 } else { 437 printf("*%3d ", pfh->char_range.min_char.high); 438 printf("*%3d ", pfh->char_range.max_char.high); 439 } 440 printf("%5s ", (pfh->flags & FontInfoAllCharsExist) ? "all" : "some"); 441 printf("%4d ", (pfh->default_char.high << 8) + pfh->default_char.low); 442 printf("%3d ", pfh->font_ascent); 443 printf("%4d ", pfh->font_descent); 444 printf("%s\n", list->name); 445 if (min_max) { 446 char min[BUFSIZ], 447 max[BUFSIZ]; 448 char *pmax = max, 449 *pmin = min; 450 char *emin = min + sizeof(min), 451 *emax = max + sizeof(max); 452 453 copy_number(&pmin, &pmax, &emin, &emax, 454 pfh->min_bounds.left, 455 pfh->max_bounds.left, ','); 456 copy_number(&pmin, &pmax, &emin, &emax, 457 pfh->min_bounds.right, 458 pfh->max_bounds.right, ','); 459 copy_number(&pmin, &pmax, &emin, &emax, 460 pfh->min_bounds.width, 461 pfh->max_bounds.width, ','); 462 copy_number(&pmin, &pmax, &emin, &emax, 463 pfh->min_bounds.ascent, 464 pfh->max_bounds.ascent, ','); 465 copy_number(&pmin, &pmax, &emin, &emax, 466 pfh->min_bounds.descent, 467 pfh->max_bounds.descent, '\0'); 468 printf(" min(l,r,w,a,d) = (%s)\n", min); 469 printf(" max(l,r,w,a,d) = (%s)\n", max); 470 } 471} 472 473#ifndef max 474#define max(a, b) ((a) > (b) ? (a) : (b)) 475#endif 476 477/* 478 * Append string representations of n1 to pp1 and n2 to pp2, 479 * followed by the given suffix character, 480 * but not writing into or past ep1 & ep2, respectively. 481 * The string representations will be padded to the same width. 482 */ 483static void 484copy_number(char **pp1, char **pp2, char **ep1, char **ep2, int n1, int n2, 485 char suffix) 486{ 487 char *p1 = *pp1; 488 char *p2 = *pp2; 489 int w, w1, w2; 490 491 w1 = snprintf(NULL, 0, "%d", n1); 492 w2 = snprintf(NULL, 0, "%d", n2); 493 w = (int) max(w1, w2); 494 assert(w > 0); 495 snprintf(p1, *ep1 - p1, "%*d%c", w, n1, suffix); 496 snprintf(p2, *ep2 - p2, "%*d%c", w, n2, suffix); 497 *pp1 = p1 + strlen(p1); 498 assert(*pp1 < *ep1); 499 *pp2 = p2 + strlen(p2); 500 assert(*pp2 < *ep2); 501} 502 503static void 504show_font_props(FontList *list) 505{ 506 unsigned int i; 507 FSPropInfo *pi = list->pi; 508 FSPropOffset *po = list->po; 509 unsigned char *pd = list->pd; 510 unsigned int num_props; 511 512 num_props = pi->num_offsets; 513 for (i = 0; i < num_props; i++, po++) { 514 fwrite(pd + po->name.position, 1, po->name.length, stdout); 515 putc('\t', stdout); 516 switch (po->type) { 517 case PropTypeString: 518 fwrite(pd + po->value.position, 1, po->value.length, stdout); 519 putc('\n', stdout); 520 break; 521 case PropTypeUnsigned: 522 printf("%lu\n", (unsigned long) po->value.position); 523 break; 524 case PropTypeSigned: 525 printf("%lu\n", (long) po->value.position); 526 break; 527 default: 528 fprintf(stderr, "bogus property\n"); 529 break; 530 } 531 532 } 533} 534