fslsfonts.c revision 69ef5f27
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 55#ifndef N_START 56#define N_START 1000 /* Maximum # of fonts to start with */ 57#endif 58 59static unsigned int max_output_line_width = 79; 60static unsigned int output_line_padding = 3; 61static unsigned int columns = 0; 62 63#define L_SHORT 0 64#define L_MEDIUM 1 65#define L_LONG 2 66#define L_VERYLONG 3 67 68static Bool sort_output = True; 69static int long_list = L_SHORT; 70static int nnames = N_START; 71static unsigned int font_cnt; 72static int min_max; 73typedef struct { 74 char *name; 75 FSXFontInfoHeader *info; 76 FSPropInfo *pi; 77 FSPropOffset *po; 78 unsigned char *pd; 79} FontList; 80static FontList *font_list; 81 82static FSServer *svr; 83 84static char *program_name; 85 86static void usage (const char *msg) _X_NORETURN _X_COLD; 87static void get_list ( const char *pattern ); 88static int compare ( const void *f1, const void *f2 ); 89static void show_fonts ( void ); 90static void print_font_header ( void ); 91static void show_font_header ( FontList *list ); 92static void copy_number ( char **pp1, char **pp2, int n1, int n2 ); 93static void show_font_props ( FontList *list ); 94 95static void _X_NORETURN _X_COLD 96missing_arg (const char *option) 97{ 98 char msg[32]; 99 100 snprintf(msg, sizeof(msg), "%s requires an argument", option); 101 usage(msg); 102} 103 104static void 105usage(const char *msg) 106{ 107 if (msg) 108 fprintf(stderr, "%s: %s\n", program_name, msg); 109 fprintf(stderr, "usage: %s [-options] [-fn pattern]\n", program_name); 110 fprintf(stderr, "%s", "where options include:\n" 111 " -l[l[l]] give long info about each font\n" 112 " -m give character min and max bounds\n" 113 " -C force columns\n" 114 " -1 force single column\n" 115 " -u keep output unsorted\n" 116 " -w width maximum width for multiple columns\n" 117 " -n columns number of columns if multi column\n" 118 " -server servername font server to contact\n" 119 " -version print command version and exit\n" 120 "\n"); 121 exit(1); 122} 123 124int 125main(int argc, char *argv[]) 126{ 127 int argcnt = 0, 128 i; 129 char *servername = NULL; 130 131 program_name = argv[0]; 132 133 for (i = 1; i < argc; i++) { 134 if (strncmp(argv[i], "-s", 2) == 0) { 135 if (++i >= argc) 136 missing_arg("-server"); 137 servername = argv[i]; 138 } 139 else if (strcmp(argv[i], "-version") == 0) { 140 printf("%s\n", PACKAGE_STRING); 141 exit(0); 142 } 143 } 144 145 if ((svr = FSOpenServer(servername)) == NULL) { 146 if (FSServerName(servername) == NULL) { 147 usage("no font server defined"); 148 } 149 fprintf(stderr, "%s: unable to open server \"%s\"\n", 150 program_name, FSServerName(servername)); 151 exit(0); 152 } 153 /* Handle command line arguments, open display */ 154 for (argv++, argc--; argc; argv++, argc--) { 155 if (argv[0][0] == '-') { 156 if (argcnt > 0) 157 usage(NULL); 158 for (i = 1; argv[0][i]; i++) 159 switch (argv[0][i]) { 160 case 'l': 161 long_list++; 162 break; 163 case 'm': 164 min_max++; 165 break; 166 case 'C': 167 columns = 0; 168 break; 169 case '1': 170 columns = 1; 171 break; 172 case 'f': 173 if (--argc <= 0) 174 missing_arg("-fn"); 175 argcnt++; 176 argv++; 177 get_list(argv[0]); 178 goto next; 179 case 'w': 180 if (--argc <= 0) 181 missing_arg("-w"); 182 argv++; 183 max_output_line_width = (unsigned int) atoi(argv[0]); 184 goto next; 185 case 'n': 186 if (--argc <= 0) 187 missing_arg("-n"); 188 argv++; 189 columns = (unsigned int) atoi(argv[0]); 190 goto next; 191 case 'u': 192 sort_output = False; 193 break; 194 case 's': /* eat -s */ 195 if (--argc <= 0) 196 missing_arg("-server"); 197 argv++; 198 goto next; 199 default: 200 fprintf(stderr, "%s: unrecognized option '%s'\n", 201 program_name, argv[0]); 202 usage(NULL); 203 } 204 if (i == 1) 205 usage(NULL); 206 } else { 207 argcnt++; 208 get_list(argv[0]); 209 } 210next: ; 211 } 212 if (argcnt == 0) 213 get_list("*"); 214 FSCloseServer(svr); 215 show_fonts(); 216 exit(0); 217} 218 219static void 220get_list(const char *pattern) 221{ 222 int available = nnames + 1, 223 i; 224 char **fonts; 225 FSXFontInfoHeader **info; 226 FSPropInfo **props; 227 FSPropOffset **offsets; 228 unsigned char **pdata; 229 230 /* Get list of fonts matching pattern */ 231 for (;;) { 232 233 if (long_list >= L_MEDIUM) 234 fonts = FSListFontsWithXInfo(svr, 235 pattern, nnames, &available, &info, &props, &offsets, &pdata); 236 else 237 fonts = FSListFonts(svr, pattern, nnames, &available); 238 if (fonts == NULL || available < nnames) 239 break; 240 241 if (long_list >= L_MEDIUM) { 242 for (i = 0; i < available; i++) { 243 FSFree((char *) fonts[i]); 244 FSFree((char *) info[i]); 245 FSFree((char *) props[i]); 246 FSFree((char *) offsets[i]); 247 FSFree((char *) pdata[i]); 248 } 249 FSFree((char *) fonts); 250 FSFree((char *) info); 251 FSFree((char *) props); 252 FSFree((char *) offsets); 253 FSFree((char *) pdata); 254 } else { 255 FSFreeFontNames(fonts); 256 } 257 nnames = available * 2; 258 } 259 260 if (fonts == NULL) { 261 fprintf(stderr, "%s: pattern \"%s\" unmatched\n", 262 program_name, pattern); 263 return; 264 } 265 if (font_list) 266 font_list = realloc(font_list, (font_cnt + (unsigned) available) 267 * sizeof(FontList)); 268 else 269 font_list = malloc((font_cnt + (unsigned) available) 270 * sizeof(FontList)); 271 if (font_list == NULL) { 272 fprintf(stderr, "%s: unable to allocate %zu bytes for font list\n", 273 program_name, 274 (font_cnt + (unsigned) available) * sizeof(FontList)); 275 exit(-1); 276 } 277 for (i = 0; i < available; i++) { 278 font_list[font_cnt].name = fonts[i]; 279 280 if (long_list >= L_MEDIUM) { 281 font_list[font_cnt].info = info[i]; 282 font_list[font_cnt].pi = props[i]; 283 font_list[font_cnt].po = offsets[i]; 284 font_list[font_cnt].pd = pdata[i]; 285 } else 286 font_list[font_cnt].info = NULL; 287 font_cnt++; 288 } 289} 290 291static int 292compare(const void *f1, const void *f2) 293{ 294 const char *p1 = ((const FontList *)f1)->name, 295 *p2 = ((const FontList *)f2)->name; 296 297 while (*p1 && *p2 && *p1 == *p2) 298 p1++, p2++; 299 return (*p1 - *p2); 300} 301 302static void 303show_fonts(void) 304{ 305 unsigned int i; 306 307 if (font_cnt == 0) 308 return; 309 310 /* first sort the output */ 311 if (sort_output) 312 qsort(font_list, font_cnt, sizeof(FontList), compare); 313 314 if (long_list > L_MEDIUM) { 315 print_font_header(); 316 for (i = 0; i < font_cnt; i++) { 317 show_font_header(&font_list[i]); 318 show_font_props(&font_list[i]); 319 } 320 return; 321 } 322 if (long_list == L_MEDIUM) { 323 print_font_header(); 324 325 for (i = 0; i < font_cnt; i++) { 326 show_font_header(&font_list[i]); 327 } 328 329 return; 330 } 331 if ((columns == 0 && isatty(1)) || columns > 1) { 332 unsigned int width, 333 max_width = 0, 334 lines_per_column, 335 j, 336 index; 337 338 for (i = 0; i < font_cnt; i++) { 339 width = (unsigned int) strlen(font_list[i].name); 340 if (width > max_width) 341 max_width = width; 342 } 343 if (max_width == 0) { 344 fprintf(stderr, "all %d fontnames listed are zero length", 345 font_cnt); 346 exit(-1); 347 } 348 if (columns == 0) { 349 if ((max_width * 2) + output_line_padding > 350 max_output_line_width) { 351 columns = 1; 352 } else { 353 max_width += output_line_padding; 354 columns = ((max_output_line_width + 355 output_line_padding) / max_width); 356 } 357 } else { 358 max_width += output_line_padding; 359 } 360 if (columns <= 1) 361 goto single_column; 362 363 if (font_cnt < columns) 364 columns = font_cnt; 365 lines_per_column = (font_cnt + columns - 1) / columns; 366 367 for (i = 0; i < lines_per_column; i++) { 368 for (j = 0; j < columns; j++) { 369 index = j * lines_per_column + i; 370 if (index >= font_cnt) 371 break; 372 if (j + 1 == columns) 373 printf("%s", font_list[index].name); 374 else 375 printf("%-*s", 376 max_width, 377 font_list[index].name); 378 } 379 printf("\n"); 380 } 381 return; 382 } 383single_column: 384 for (i = 0; i < font_cnt; i++) 385 printf("%s\n", font_list[i].name); 386} 387 388static void 389print_font_header(void) 390{ 391 printf("DIR "); 392 printf("MIN "); 393 printf("MAX "); 394 printf("EXIST "); 395 printf("DFLT "); 396 printf("ASC "); 397 printf("DESC "); 398 printf("NAME"); 399 printf("\n"); 400} 401 402static void 403show_font_header(FontList *list) 404{ 405 const char *string; 406 FSXFontInfoHeader *pfh; 407 408 pfh = list->info; 409 if (!pfh) { 410 fprintf(stderr, 411 "%s: no font information for font \"%s\".\n", 412 program_name, list->name ? list->name : ""); 413 return; 414 } 415 if (pfh->draw_direction == LeftToRightDrawDirection) 416 string = "-->"; 417 else 418 string = "<--"; 419 printf("%-4s", string); 420 if (pfh->char_range.min_char.high == 0 421 && pfh->char_range.max_char.high == 0) { 422 printf(" %3d ", pfh->char_range.min_char.low); 423 printf(" %3d ", pfh->char_range.max_char.low); 424 } else { 425 printf("*%3d ", pfh->char_range.min_char.high); 426 printf("*%3d ", pfh->char_range.max_char.high); 427 } 428 printf("%5s ", (pfh->flags & FontInfoAllCharsExist) ? "all" : "some"); 429 printf("%4d ", (pfh->default_char.high << 8) + pfh->default_char.low); 430 printf("%3d ", pfh->font_ascent); 431 printf("%4d ", pfh->font_descent); 432 printf("%s\n", list->name); 433 if (min_max) { 434 char min[BUFSIZ], 435 max[BUFSIZ]; 436 char *pmax = max, 437 *pmin = min; 438 439 strcpy(pmin, " min(l,r,w,a,d) = ("); 440 strcpy(pmax, " max(l,r,w,a,d) = ("); 441 pmin += strlen(pmin); 442 pmax += strlen(pmax); 443 444 copy_number(&pmin, &pmax, 445 pfh->min_bounds.left, 446 pfh->max_bounds.left); 447 *pmin++ = *pmax++ = ','; 448 copy_number(&pmin, &pmax, 449 pfh->min_bounds.right, 450 pfh->max_bounds.right); 451 *pmin++ = *pmax++ = ','; 452 copy_number(&pmin, &pmax, 453 pfh->min_bounds.width, 454 pfh->max_bounds.width); 455 *pmin++ = *pmax++ = ','; 456 copy_number(&pmin, &pmax, 457 pfh->min_bounds.ascent, 458 pfh->max_bounds.ascent); 459 *pmin++ = *pmax++ = ','; 460 copy_number(&pmin, &pmax, 461 pfh->min_bounds.descent, 462 pfh->max_bounds.descent); 463 *pmin++ = *pmax++ = ')'; 464 *pmin = *pmax = '\0'; 465 printf("%s\n", min); 466 printf("%s\n", max); 467 } 468} 469 470#ifndef max 471#define max(a, b) ((a) > (b) ? (a) : (b)) 472#endif 473 474static void 475copy_number(char **pp1, char **pp2, int n1, int n2) 476{ 477 char *p1 = *pp1; 478 char *p2 = *pp2; 479 int w; 480 481 sprintf(p1, "%d", n1); 482 sprintf(p2, "%d", n2); 483 w = (int) max(strlen(p1), strlen(p2)); 484 sprintf(p1, "%*d", w, n1); 485 sprintf(p2, "%*d", w, n2); 486 p1 += strlen(p1); 487 p2 += strlen(p2); 488 *pp1 = p1; 489 *pp2 = p2; 490} 491 492static void 493show_font_props(FontList *list) 494{ 495 unsigned int i; 496 char buf[1000]; 497 FSPropInfo *pi = list->pi; 498 FSPropOffset *po = list->po; 499 unsigned char *pd = list->pd; 500 unsigned int num_props; 501 502 num_props = pi->num_offsets; 503 for (i = 0; i < num_props; i++, po++) { 504 strncpy(buf, (char *) (pd + po->name.position), po->name.length); 505 buf[po->name.length] = '\0'; 506 printf("%s\t", buf); 507 switch (po->type) { 508 case PropTypeString: 509 strncpy(buf, (char *)pd + po->value.position, po->value.length); 510 buf[po->value.length] = '\0'; 511 printf("%s\n", buf); 512 break; 513 case PropTypeUnsigned: 514 printf("%lu\n", (unsigned long) po->value.position); 515 break; 516 case PropTypeSigned: 517 printf("%lu\n", (long) po->value.position); 518 break; 519 default: 520 fprintf(stderr, "bogus property\n"); 521 break; 522 } 523 524 } 525} 526