font-open.c (38928B)
1 /*========================================================================*\ 2 3 Copyright (c) 1990-2013 Paul Vojta 4 5 Permission is hereby granted, free of charge, to any person obtaining a copy 6 of this software and associated documentation files (the "Software"), to 7 deal in the Software without restriction, including without limitation the 8 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9 sell copies of the Software, and to permit persons to whom the Software is 10 furnished to do so, subject to the following conditions: 11 12 The above copyright notice and this permission notice shall be included in 13 all copies or substantial portions of the Software. 14 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF OR CONTRIBUTOR TO 19 THIS SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 IN THE SOFTWARE. 23 24 NOTE: 25 xdvi is based on prior work, as noted in the modification history 26 in xdvi.c. 27 28 \*========================================================================*/ 29 30 #include <err.h> 31 #include <errno.h> 32 #include <stdlib.h> /* free(), atoi() */ 33 34 #include "events.h" /* ev_flags */ 35 #include "font.h" /* struct avl_t1 */ 36 #include "filf-app.h" /* application-related defs, etc. */ 37 #include "filefind.h" 38 #include "font-open.h" 39 #include "util.h" /* xmalloc(), xmemdup(), avladd(), ... */ 40 41 42 /* 43 * If you think you have to change DEFAULT_TAIL, then you haven't read the 44 * documentation closely enough. 45 */ 46 47 #define PATH_SEP ':' 48 #define DEFAULT_TAIL "/%f.%d%p" 49 #define DEFAULT_VF_TAIL "/%f.vf" 50 51 #define DEFAULT_FONT_PATH ".:%S" /* font searching */ 52 #define DEFAULT_VF_PATH ".:%S" /* virtual-font searching */ 53 #define DEFAULT_DVIPS_CF_PATH ".:%S" /* dvips config file searching */ 54 #define DEFAULT_FONTMAP_PATH ".:%S" /* dvips-style fontmap searching */ 55 #define DEFAULT_ENC_PATH ".:%S" /* encoding file searching */ 56 #define DEFAULT_TYPE1_PATH ".:%S" /* Type 1 font file searching */ 57 58 /* 59 * gs -h | sed \ 60 * -e '1,/Search path:/d' \ 61 * -e '/For more information/,$d' \ 62 * -e '/Initialization files are compiled/d' \ 63 * -e 's/$/\/\/\//' \ 64 * -e 's/^ //' \ 65 * | tr '\n' '/' 66 */ 67 #define DEFAULT_GS_LIB_PATH "/usr/local/share/ghostscript/9.07/Resource/Init:/usr/local/share/ghostscript/9.07/lib:/usr/local/share/ghostscript/9.07/Resource/Font:/usr/local/share/fonts/ghostscript" 68 69 #ifndef DEFAULT_FONT_SIZES 70 /* default sizes for current dpi */ 71 #define DEFAULT_FONT_SIZES "m0:m0.5:m1:m2:m3:m4:m5" 72 #endif 73 74 /* 75 * Information on how to search for pk and gf files. 76 */ 77 78 static const char no_f_str_pkgf[] = DEFAULT_TAIL; 79 80 static struct findrec search_pkgf = { 81 /* path1 */ NULL, 82 /* path2 */ DEFAULT_FONT_PATH, 83 /* type */ "font", 84 /* fF_etc */ "fFdbpm", 85 /* x_var_char */ 'd', 86 /* n_var_opts */ 3, 87 /* no_f_str */ no_f_str_pkgf, 88 /* no_f_str_end */ no_f_str_pkgf + sizeof(no_f_str_pkgf) - 1, 89 /* abs_str */ "%f.%d%p", 90 /* pct_s_str */ "%qfonts/%p/%m//:%qfonts/%p/modeless//", 91 { 92 /* v.stephead */ NULL, 93 /* v.pct_s_head */ NULL, 94 /* v.pct_s_count */ 0, 95 /* v.pct_s_atom */ NULL, 96 /* v.rootp */ NULL, 97 } 98 }; 99 100 /* 101 * Information on how to search for vf files. 102 */ 103 104 static const char no_f_str_vf[] = DEFAULT_VF_TAIL; 105 106 static struct findrec search_vf = { 107 /* path1 */ NULL, 108 /* path2 */ DEFAULT_VF_PATH, 109 /* type */ "vf", 110 /* fF_etc */ "fF", 111 /* x_var_char */ 'f', /* i.e., none */ 112 /* n_var_opts */ 2, 113 /* no_f_str */ no_f_str_vf, 114 /* no_f_str_end */ no_f_str_vf + sizeof(no_f_str_vf) - 1, 115 /* abs_str */ "%f.vf", 116 /* pct_s_str */ "%qfonts/vf//", 117 { 118 /* v.stephead */ NULL, 119 /* v.pct_s_head */ NULL, 120 /* v.pct_s_count */ 0, 121 /* v.pct_s_atom */ NULL, 122 /* v.rootp */ NULL, 123 } 124 }; 125 126 static int *sizes, *sizend; 127 static char default_size_list[] = DEFAULT_FONT_SIZES; 128 129 static char bdpi_string[10]; 130 static char dpi_string[10]; 131 132 static double magsteps[10] = {1.0, 1.2, 1.44, 1.728, 2.0736, 133 2.48832, 2.985984, 3.5831808, 134 4.29981696, 5.159780352}; 135 136 137 /* 138 * Information on how to search for dvips configuration files. 139 */ 140 141 static const char no_f_str_dvips_cf[] = "/%f"; 142 143 static struct findrec search_dvips_cf = { 144 /* path1 */ NULL, 145 /* path2 */ DEFAULT_DVIPS_CF_PATH, 146 /* type */ "dvips config", 147 /* fF_etc */ "fF", 148 /* x_var_char */ 'f', /* i.e., none */ 149 /* n_var_opts */ 2, 150 /* no_f_str */ no_f_str_dvips_cf, 151 /* no_f_str_end */ no_f_str_dvips_cf + sizeof no_f_str_dvips_cf -1, 152 /* abs_str */ "%f", 153 /* pct_s_str */ "%qdvips//", 154 { 155 /* v.stephead */ NULL, 156 /* v.pct_s_head */ NULL, 157 /* v.pct_s_count */ 0, 158 /* v.pct_s_atom */ NULL, 159 /* v.rootp */ NULL, 160 } 161 }; 162 163 /* 164 * Information on how to search for (dvips-style) map files. 165 */ 166 167 static const char no_f_str_fontmap[] = "/%f"; 168 169 static struct findrec search_fontmap = { 170 /* path1 */ NULL, 171 /* path2 */ DEFAULT_FONTMAP_PATH, 172 /* type */ "font map", 173 /* fF_etc */ "fF", 174 /* x_var_char */ 'f', /* i.e., none */ 175 /* n_var_opts */ 2, 176 /* no_f_str */ no_f_str_fontmap, 177 /* no_f_str_end */ no_f_str_fontmap + sizeof no_f_str_fontmap -1, 178 /* abs_str */ "%f", 179 /* pct_s_str */ "%qfonts/map/{xdvi,dvips,pdftex}//:%qfonts/map//", 180 { 181 /* v.stephead */ NULL, 182 /* v.pct_s_head */ NULL, 183 /* v.pct_s_count */ 0, 184 /* v.pct_s_atom */ NULL, 185 /* v.rootp */ NULL, 186 } 187 }; 188 189 /* 190 * Information on how to search for font encoding files. 191 */ 192 193 static const char no_f_str_enc[] = "/%f"; 194 195 static struct findrec search_enc = { 196 /* path1 */ no_f_str_enc, /* flag value: uninitialized */ 197 /* path2 */ DEFAULT_ENC_PATH, 198 /* type */ "font encoding", 199 /* fF_etc */ "fF", 200 /* x_var_char */ 'f', /* i.e., none */ 201 /* n_var_opts */ 2, 202 /* no_f_str */ no_f_str_enc, 203 /* no_f_str_end */ no_f_str_enc + sizeof no_f_str_enc -1, 204 /* abs_str */ "%f", 205 /* pct_s_str */ "%qfonts/enc//", 206 { 207 /* v.stephead */ NULL, 208 /* v.pct_s_head */ NULL, 209 /* v.pct_s_count */ 0, 210 /* v.pct_s_atom */ NULL, 211 /* v.rootp */ NULL, 212 } 213 }; 214 215 /* 216 * Information on how to search for Type 1 fonts. 217 */ 218 219 static const char no_f_str_type1[] = "/%f"; 220 221 static struct findrec search_type1 = { 222 /* path1 */ no_f_str_type1, /* flag value: uninitialized */ 223 /* path2 */ DEFAULT_TYPE1_PATH, 224 /* type */ "Type 1 font", 225 /* fF_etc */ "fF", 226 /* x_var_char */ 'f', 227 /* n_var_opts */ 2, 228 /* no_f_str */ no_f_str_type1, 229 /* no_f_str_end */ no_f_str_type1 + sizeof(no_f_str_type1) - 1, 230 /* abs_str */ "%f", 231 /* pct_s_str */ "%qfonts/type1//", 232 { 233 /* v.stephead */ NULL, 234 /* v.pct_s_head */ NULL, 235 /* v.pct_s_count */ 0, 236 /* v.pct_s_atom */ NULL, 237 /* v.rootp */ NULL, 238 } 239 }; 240 241 242 243 static int 244 atosize(p) 245 const char *p; 246 { 247 const char *q; 248 Boolean minus; 249 double factor; 250 251 if (*p != 'm') 252 return atoi(p); 253 254 for (q = "agstep";; ++q) { 255 ++p; 256 if (*q == '\0' || *p != *q) break; 257 } 258 259 minus = False; 260 if (*p == '-') { 261 minus = True; 262 ++p; 263 } 264 265 if (*p < '0' || *p > '9') 266 return 0; 267 factor = magsteps[*p - '0']; 268 ++p; 269 270 if (*p == '.' && p[1] == '5') 271 factor *= 1.0954451150103321; /* sqrt(1.2) */ 272 273 return (int) 274 ((minus ? pixels_per_inch / factor : pixels_per_inch * factor) + 0.5); 275 } 276 277 static void 278 get_sizes(size_list, spp) 279 char *size_list; 280 int **spp; 281 { 282 if (*size_list == PATH_SEP) ++size_list; 283 for (;;) { 284 *(*spp)++ = atosize(size_list); 285 size_list = index(size_list, PATH_SEP); 286 if (size_list == NULL) return; 287 ++size_list; 288 } 289 } 290 291 292 293 /* 294 * The following code handles lookup of Type 1 fonts for use as FreeType 295 * fonts, and for use within MetaPost output. 296 * The system psfonts.map file is read into an AVL tree as needed (lazy 297 * evaluation), and searched for Type 1 fonts. 298 */ 299 300 struct p_list { /* list of map file names */ 301 struct p_list *next; 302 const char *value; 303 }; 304 305 /* Initialize this list to "psfonts.map". */ 306 307 static struct p_list psfonts_map = {NULL, "psfonts.map"}; 308 309 static struct p_list *p_head = &psfonts_map; 310 static struct p_list **p_tail = &psfonts_map.next; 311 312 static FILE *mapfile = NULL; 313 314 static Boolean 315 fgets_long(f) 316 FILE *f; 317 { 318 int len; 319 320 if (fgets(ffline, ffline_len, f) == NULL) 321 return False; 322 323 len = 0; 324 for (;;) { 325 len += strlen(ffline + len); 326 if (len > 0 && ffline[len - 1] == '\n') { 327 ffline[--len] = '\0'; 328 break; 329 } 330 if (len < ffline_len - 1) 331 break; 332 expandline(len); 333 fgets(ffline + len, ffline_len - len, f); 334 } 335 336 return True; 337 } 338 339 /* 340 * Get list of map files from dvips config file(s). 341 */ 342 343 static void 344 getdefaults(f) 345 FILE *f; 346 { 347 char *p, *q; 348 int len; 349 struct p_list *p_node; 350 351 while (fgets_long(f)) { 352 p = ffline; 353 while (*p == ' ' || *p == '\t') ++p; 354 if (*p == 'p') { 355 do ++p; 356 while (*p == ' ' || *p == '\t'); 357 358 if (*p == '+') 359 do ++p; 360 while (*p == ' ' || *p == '\t'); 361 else { /* discard old list */ 362 struct p_list *pl, *pl2; 363 364 *p_tail = NULL; 365 pl = p_head; 366 if (pl == &psfonts_map) pl = pl->next; 367 while (pl != NULL) { 368 free((char *) pl->value); 369 pl2 = pl->next; 370 free(pl); 371 pl = pl2; 372 } 373 p_tail = &p_head; 374 } 375 376 /* get white-delimited argument */ 377 len = strlen(p); 378 q = memchr(p, ' ', len); 379 if (q != NULL) len = q - p; 380 q = memchr(p, '\t', len); 381 if (q != NULL) len = q - p; 382 p[len] = '\0'; 383 384 p_node = xmalloc(sizeof *p_node); 385 p_node->value = xmemdup(p, len + 1); 386 *p_tail = p_node; 387 p_tail = &p_node->next; 388 } 389 } 390 391 fclose(f); 392 } 393 394 395 /* 396 * Information about Type 1 fonts is stored in an AVL tree. 397 */ 398 399 static struct avl_t1 *t1_head = NULL; 400 401 402 /* 403 * Parse line from psfonts.map file. 404 */ 405 406 static struct avl_t1 * 407 dvips_parse(line) 408 const char *line; 409 { 410 const char *w1p, *encp, *pfp, *qp; 411 size_t w1l, encl, pfl, ql; 412 const char *w2p; 413 size_t w2l; 414 const char *p, *p0; 415 const char *err; 416 struct avl_t1 *t1p; 417 char *q; 418 419 w2l = w1l = encl = pfl = ql = 0; 420 err = NULL; 421 p = line; 422 for (;;) { /* loop over words */ 423 while (*p == ' ' || *p == '\t') ++p; 424 if (*p == '\0') 425 break; 426 427 if (*p == '"') { /* quoted string */ 428 const char *p_end; 429 430 p0 = p + 1; 431 p_end = p0 + strlen(p0); 432 p = memchr(p0, '"', p_end - p0); 433 if (p == NULL) p = p_end; 434 qp = (ql == 0 ? p0 : NULL); 435 ql += p - p0 + 1; 436 if (*p == '"') ++p; 437 continue; 438 } 439 440 if (*p == '<') { /* encoding or pfa/b file */ 441 int wtype = 0; 442 443 ++p; 444 if (*p == '<') { 445 wtype = 1; /* font file */ 446 ++p; 447 } 448 else if (*p == '[') { 449 wtype = -1; /* encoding file */ 450 ++p; 451 } 452 453 /* find word */ 454 while (*p == ' ' || *p == '\t') ++p; 455 p0 = p; 456 while (*p != '\0' && *p != ' ' && *p != '\t') ++p; 457 458 if (wtype == 0 && p > p0 + 4 && p[-4] == '.') { 459 if (memcmp(p - 3, "enc", 3) == 0 460 || memcmp(p - 3, "ENC", 3) == 0) 461 wtype = -1; 462 else if (memcmp(p - 3, "pfa", 3) == 0 463 || memcmp(p - 3, "pfb", 3) == 0 464 || memcmp(p - 3, "PFA", 3) == 0 465 || memcmp(p - 3, "PFB", 3) == 0) 466 wtype = 1; 467 } 468 469 if (wtype > 0) { 470 if (pfl != 0) 471 err = "more than one font file given"; 472 else { 473 pfp = p0; 474 pfl = p - p0 + 1; 475 } 476 } 477 else if (wtype < 0) { 478 if (encl != 0) 479 err = "more than one encoding file given"; 480 else { 481 encp = p0; 482 encl = p - p0 + 1; 483 } 484 } 485 else 486 err = "cannot identify file type"; 487 } 488 else { /* if ordinary word */ 489 p0 = p; 490 while (*p != '\0' && *p != ' ' && *p != '\t') ++p; 491 if (w1l == 0) { 492 w1p = p0; 493 w1l = p - p0; 494 } 495 else if (w2l == 0) { 496 w2p = p0; 497 w2l = p - p0; 498 } 499 else 500 err = "more than two non-download words given"; 501 } 502 } /* end loop over words */ 503 504 if (w1l == 0) { 505 if (debug & DBG_OPEN) 506 warnx("map file '%s': line '%s' does not give a font name.", 507 p_head->value, line); 508 return NULL; 509 } 510 511 if (err != NULL) { 512 if (debug & DBG_OPEN) 513 warnx("map file '%s', font '%.*s': '%s'", p_head->value, 514 (int) w1l, w1p, err); 515 return NULL; 516 } 517 518 t1p = (struct avl_t1 *) avladd(w1p, w1l, (struct avl **) &t1_head, 519 sizeof(struct avl_t1)); 520 521 if (t1p->key != w1p) { /* if existing record */ 522 if (debug & DBG_OPEN) 523 warnx("map file '%s', font '%.*s': duplicate record; using first one", 524 p_head->value, (int) w1l, w1p); 525 return NULL; 526 } 527 528 t1p->key = q = xmalloc(w1l + w2l + 1 + pfl + encl + ql); 529 530 memcpy(q, w1p, w1l); 531 q += w1l; 532 t1p->psname = t1p->key; 533 if (w2l != 0) { 534 t1p->psname = q; 535 memcpy(q, w2p, w2l); 536 q += w2l; 537 } 538 *q++ = '\0'; 539 540 t1p->fontfile = NULL; 541 if (pfl != 0) { 542 t1p->fontfile = q; 543 memcpy(q, pfp, pfl - 1); 544 q += pfl; 545 q[-1] = '\0'; 546 } 547 548 t1p->encname = t1p->addinfo = NULL; 549 t1p->bad = False; 550 t1p->ft = NULL; 551 552 if (encl != 0) { 553 t1p->encname = q; 554 memcpy(q, encp, encl - 1); 555 q += encl; 556 q[-1] = '\0'; 557 } 558 559 if (ql != 0) { 560 t1p->addinfo = q; 561 if (qp != 0) { 562 memcpy(q, qp, ql - 1); 563 q += ql; 564 } 565 else { /* multiple quoted strings; rescan to get them */ 566 const char *p_end; 567 568 p = line; 569 p_end = p + strlen(p); 570 for (;;) { 571 while (*p == ' ' || *p == '\t') ++p; 572 if (*p == '\0') 573 break; 574 575 /* found a word */ 576 if (*p == '"') { 577 ++p; 578 p0 = p; 579 p = memchr(p0, '"', p_end - p0); 580 if (p == NULL) p = p_end; 581 memcpy(q, p0, p - p0); 582 q += p - p0; 583 *q++ = ' '; 584 if (*p == '\0') break; 585 ++p; 586 } 587 else /* skip unquoted word */ 588 while (*p != '\0' && *p != ' ' && *p != '\t') ++p; 589 } 590 } 591 q[-1] = '\0'; 592 } 593 594 return t1p; 595 } 596 597 /* 598 * Information on the Ghostscript font aliasing mechanism is kept in 599 * another AVL tree. Each identifier points to a list of strings, 600 * up to one from each Fontmap file. Within a Fontmap file, later entries 601 * for a given string override earlier ones. 602 */ 603 604 struct avl_gs { /* structure for gs font information */ 605 AVL_COMMON; 606 short fontmap_number; /* sequence of most recent entry */ 607 Boolean in_use; 608 struct gs_list *list; 609 }; 610 611 struct gs_list { /* list of Fontmap entries for this font name */ 612 struct gs_list *next; 613 const char value[0]; 614 }; 615 616 static struct avl_gs *gs_head = NULL; 617 618 typedef void (*gs_path_proc)(FILE *); 619 620 static const char *env_gs_lib; 621 622 static FILE * 623 gs_try_fopen(str, len, name) 624 const char *str; 625 unsigned int len; 626 const char *name; 627 { 628 unsigned int namelen = strlen(name) + 1; 629 FILE *f; 630 631 if (len + namelen + 1 > ffline_len) expandline(len + namelen + 1); 632 memcpy(ffline, str, len); 633 ffline[len] = '/'; 634 memcpy(ffline + len + 1, name, namelen); 635 636 f = xfopen(ffline, "r"); 637 638 if (debug & DBG_OPEN) 639 printf("gs_try_fopen: %s: %s\n", ffline, 640 f != NULL ? "file opened" : strerror(errno)); 641 642 return f; 643 } 644 645 static FILE * 646 gs_path_fopen(name, proc) 647 const char *name; 648 gs_path_proc proc; 649 { 650 const char *str1 = env_gs_lib; 651 const char *str2 = DEFAULT_GS_LIB_PATH; 652 const char *str1_end, *str2_end; 653 const char *p1, *p2; 654 FILE *f; 655 656 if (str1 == NULL) { 657 str1 = str2; 658 str2 = NULL; 659 } 660 661 str1_end = str1 + strlen(str1); 662 663 for (;;) { 664 p1 = memchr(str1, ':', str1_end - str1); 665 if (p1 == NULL) p1 = str1_end; 666 if (p1 == str1) { 667 if (str2 != NULL) { 668 str2_end = str2 + strlen(str2); 669 for (;;) { 670 p2 = memchr(str2, ':', str2_end - str2); 671 if (p2 == NULL) p2 = str2_end; 672 if (p2 > str2) { 673 f = gs_try_fopen(str2, p2 - str2, name); 674 if (f != NULL) { 675 if (proc != NULL) 676 proc(f); 677 else 678 return f; 679 } 680 } 681 if (*p2 == '\0') 682 break; 683 str2 = p2 + 1; 684 } 685 str2 = NULL; 686 } 687 } 688 else { 689 f = gs_try_fopen(str1, p1 - str1, name); 690 if (f != NULL) { 691 if (proc != NULL) 692 proc(f); 693 else 694 return f; 695 } 696 } 697 698 if (*p1 == '\0') 699 break; 700 str1 = p1 + 1; 701 } 702 703 return NULL; 704 } 705 706 707 static FILE * 708 lookup_gs_font(font, path_ret) 709 const char *font; 710 const char **path_ret; 711 { 712 struct avl_gs *gsfp; 713 int font_len; 714 int i; 715 716 font_len = strlen(font); 717 gsfp = gs_head; 718 for (;;) { 719 if (gsfp == NULL) /* if not found */ 720 return NULL; 721 722 i = font_len - gsfp->key_len; 723 if (i == 0) 724 i = memcmp(font, gsfp->key, font_len); 725 if (i == 0) { /* if found */ 726 struct gs_list *gl, *gl2, *gl3; 727 FILE *f; 728 729 if (gsfp->in_use) { 730 if (debug & DBG_OPEN) 731 printf("Alias loop for %s detected; ignoring.\n", font); 732 return NULL; 733 } 734 735 /* If we haven't done it yet, reverse the linked list */ 736 if (gsfp->fontmap_number != 0) { 737 gsfp->fontmap_number = 0; 738 gl = gsfp->list; 739 gl2 = NULL; 740 while (gl != NULL) { 741 gl3 = gl->next; 742 gl->next = gl2; 743 gl2 = gl; 744 gl = gl3; 745 } 746 gsfp->list = gl2; 747 } 748 gsfp->in_use = True; 749 f = NULL; 750 for (gl = gsfp->list; gl != NULL; gl = gl->next) { 751 if (gl->value[0] == '\0') { /* if alias */ 752 if (debug & DBG_OPEN) 753 printf("Found alias %s --> %s\n", font, 754 gl->value + 1); 755 f = lookup_gs_font(gl->value + 1, path_ret); 756 if (debug & DBG_OPEN) 757 if (f == NULL) 758 printf("Alias %s not found.\n", gl->value + 1); 759 if (f != NULL) break; 760 } 761 else { 762 if (debug & DBG_OPEN) 763 printf("Checking file %s\n", gl->value); 764 if (gl->value[0] == '/' || (gl->value[0] == '.' 765 && (gl->value[1] == '/' || (gl->value[1] == '.' 766 && gl->value[2] == '/')))) { 767 f = xfopen(gl->value, "r"); 768 if (f != NULL) { 769 *path_ret = xstrdup(gl->value); 770 break; 771 } 772 } 773 else { 774 f = gs_path_fopen(gl->value, NULL); 775 if (f != NULL) { 776 *path_ret = xstrdup(ffline); 777 break; 778 } 779 } 780 } 781 } 782 gsfp->in_use = False; 783 return f; 784 } 785 gsfp = (struct avl_gs *) (i < 0 ? gsfp->left : gsfp->right); 786 } 787 } 788 789 790 #define GS_BUF_SIZE 4096 791 792 struct gsfile { 793 FILE *f; 794 unsigned char *buffer; 795 const unsigned char *bufpos; 796 const unsigned char *buf_end; 797 }; 798 799 static Boolean 800 gs_fillbuf(gsf) 801 struct gsfile *gsf; 802 { 803 unsigned char *p; 804 unsigned int len; 805 806 if (gsf->buf_end < gsf->buffer + GS_BUF_SIZE) 807 return False; 808 809 gsf->bufpos = p = gsf->buffer; 810 for (;;) { 811 len = gsf->buf_end - p; 812 if (len <= 0) break; 813 len = fread(p, 1, len, gsf->f); 814 if (len <= 0) break; 815 p += len; 816 } 817 gsf->buf_end = p; 818 return (p > gsf->buffer); 819 } 820 821 static unsigned char gs_ctype[256]; 822 823 #define GS_EOF '\0' 824 #define GS_ERR '%' 825 #define LPAREN '(' 826 #define RPAREN ')' 827 828 static void 829 init_gs_ctype() 830 { 831 const char *p; 832 833 for (p = " \t\f\n\r";; ++p) { 834 gs_ctype[(unsigned char) *p] = 1; /* white space */ 835 if (*p == '\0') break; 836 } 837 gs_ctype['/'] = 2; /* literal token */ 838 gs_ctype['('] = 3; /* string */ 839 for (p = ")<>[]{}%"; *p != '\0'; ++p) 840 gs_ctype[(unsigned char) *p] = 4; /* delimiter */ 841 } 842 843 static unsigned char 844 get_gs_character(gsfp) 845 struct gsfile *gsfp; 846 { 847 unsigned char c; 848 849 for (;;) { 850 if (gsfp->bufpos >= gsfp->buf_end && !gs_fillbuf(gsfp)) 851 return '%'; 852 c = *gsfp->bufpos++; 853 854 /* Check for comments */ 855 if (c == '%') { 856 for (;;) { 857 const unsigned char *p1, *p2; 858 859 p1 = memchr(gsfp->bufpos, '\n', 860 gsfp->buf_end - gsfp->bufpos); 861 if (p1 == NULL) p1 = gsfp->buf_end; 862 p2 = memchr(gsfp->bufpos, '\r', p1 - gsfp->bufpos); 863 if (p2 != NULL) p1 = p2; 864 p2 = memchr(gsfp->bufpos, '\f', p1 - gsfp->bufpos); 865 if (p2 != NULL) p1 = p2; 866 if (p1 < gsfp->buf_end) { 867 gsfp->bufpos = p1 + 1; 868 break; 869 } 870 if (!gs_fillbuf(gsfp)) 871 return '%'; 872 } 873 continue; 874 } 875 876 if (gs_ctype[c] != 1) 877 break; 878 } 879 880 return c; 881 } 882 883 static unsigned char 884 get_gs_token(gsfp, pos, pos_ret, file_type) 885 struct gsfile *gsfp; 886 unsigned int pos; 887 unsigned int *pos_ret; 888 const char *file_type; 889 { 890 unsigned char gs_t_type; 891 unsigned char c; 892 const unsigned char *p0; 893 unsigned int pos0; 894 unsigned int depth; 895 896 gs_t_type = c = get_gs_character(gsfp); 897 if (c == '%') 898 return GS_EOF; 899 900 p0 = gsfp->bufpos; 901 switch (gs_ctype[c]) { 902 case 0: /* most characters */ 903 case 2: /* '/' */ 904 --p0; /* retain initial character */ 905 pos0 = pos; 906 for (;;) { 907 if (gsfp->bufpos >= gsfp->buf_end) { 908 unsigned int len = gsfp->bufpos - p0; 909 910 if (pos + len >= ffline_len) expandline(pos + len); 911 bcopy(p0, ffline + pos, len); 912 pos += len; 913 if (!gs_fillbuf(gsfp)) 914 break; 915 p0 = gsfp->buffer; 916 } 917 if (gs_ctype[*gsfp->bufpos] != 0) { 918 unsigned int len = gsfp->bufpos - p0; 919 920 if (pos + len >= ffline_len) expandline(pos + len); 921 bcopy(p0, ffline + pos, len); 922 pos += len; 923 break; 924 } 925 ++gsfp->bufpos; 926 } 927 /* Filter out DOS ^Z */ 928 if (pos == pos0 + 1 && ffline[pos0] == '\032') 929 return GS_EOF; 930 break; 931 932 case 3: /* left parenthesis */ 933 depth = 1; 934 for (;;) { 935 const unsigned char *p1, *p2, *p3; 936 937 if (gsfp->bufpos >= gsfp->buf_end) { 938 unsigned int len = gsfp->bufpos - p0; 939 940 if (pos + len >= ffline_len) expandline(pos + len); 941 bcopy(p0, ffline + pos, len); 942 pos += len; 943 if (!gs_fillbuf(gsfp)) { 944 warnx("unterminated string in '%s' file; giving up." , 945 file_type); 946 return GS_ERR; 947 } 948 p0 = gsfp->buffer; 949 } 950 p1 = memchr(gsfp->bufpos, RPAREN, 951 gsfp->buf_end - gsfp->bufpos); 952 if (p1 == NULL) p1 = gsfp->buf_end; 953 for (;;) { 954 p2 = memchr(gsfp->bufpos, LPAREN, p1 - gsfp->bufpos); 955 if (p2 == NULL) p2 = p1; 956 p3 = p2; 957 for (;;) { 958 if (p3 <= gsfp->bufpos) { 959 if (c == '\\') --p3; 960 break; 961 } 962 if (p3[-1] != '\\') break; 963 --p3; 964 } 965 c = '\\' - 1 + ((p2 - p3) & 1); 966 if (p2 >= p1) 967 break; 968 if (c != '\\') 969 ++depth; 970 gsfp->bufpos = p2 + 1; 971 c = '\0'; 972 } 973 if (p1 < gsfp->buf_end) { /* if left parenthesis at p1 */ 974 if (c != '\\') { 975 if (--depth == 0) { 976 unsigned int len = p1 - p0; 977 978 if (pos + len >= ffline_len) 979 expandline(pos + len); 980 bcopy(p0, ffline + pos, len); 981 pos += len; 982 gsfp->bufpos = p1 + 1; 983 break; 984 } 985 } 986 ++p1; 987 } 988 gsfp->bufpos = p1; 989 } 990 /* We could do backslash escaping here, but it's probably 991 unnecessary. */ 992 break; 993 994 default: 995 warnx("invalid character `%c' encountered in '%s' file; giving up.", 996 c, file_type); 997 return GS_ERR; 998 } 999 1000 *pos_ret = pos; 1001 return gs_t_type; 1002 } 1003 1004 1005 static short gs_fontmap_number = 0; 1006 1007 static void 1008 process_gs_fontmap(FILE *f) 1009 { 1010 struct gsfile gsf; 1011 unsigned char buffer[GS_BUF_SIZE]; 1012 unsigned char ttype; 1013 unsigned int pos1, pos2, pos3; 1014 1015 ++gs_fontmap_number; 1016 1017 gsf.f = f; 1018 gsf.buffer = buffer; 1019 gsf.bufpos = gsf.buf_end = buffer + GS_BUF_SIZE; 1020 1021 /* 1022 * Allow entries of the following types: 1023 * 1024 * (string) .runlibfile 1025 * /identifier (string) ; 1026 * /identifier /alias ; 1027 */ 1028 1029 for (;;) { 1030 ttype = get_gs_token(&gsf, 0, &pos1, "Fontmap"); 1031 if (ttype == GS_EOF || ttype == GS_ERR) 1032 break; 1033 if (ttype == LPAREN) { 1034 FILE *f1; 1035 1036 ttype = get_gs_token(&gsf, pos1, &pos2, "Fontmap"); 1037 if (ttype == GS_ERR) 1038 break; 1039 if (ttype == GS_EOF) { 1040 warnx("unexpected end of Fontmap file; giving up."); 1041 break; 1042 } 1043 if (ttype != '.' || pos2 - pos1 != 11 1044 || memcmp(ffline + pos1, ".runlibfile", 11) != 0) { 1045 warnx("invalid token following '(%.*s)' in Fontmap file; giving up.", 1046 (int) pos1, ffline); 1047 break; 1048 } 1049 1050 ffline[pos1] = '\0'; 1051 if (ffline[0] == '/' || (ffline[0] == '.' && (ffline[1] == '/' 1052 || (ffline[1] == '.' && ffline[2] == '/')))) 1053 f1 = xfopen(ffline, "r"); 1054 else { 1055 char *q; 1056 1057 q = xmemdup(ffline, pos1 + 1); 1058 f1 = gs_path_fopen(q, NULL); 1059 free(q); 1060 } 1061 1062 if (f1 == NULL) 1063 warn("Fontmap .runlibfile: '%s'", ffline); 1064 else { 1065 --gs_fontmap_number; 1066 process_gs_fontmap(f1); 1067 } 1068 } 1069 else if (ttype == '/') { 1070 struct avl_gs *gsfp; 1071 struct gs_list *gslp; 1072 1073 ttype = get_gs_token(&gsf, pos1, &pos2, "Fontmap"); 1074 if (ttype == GS_ERR) 1075 break; 1076 if (ttype == GS_EOF) { 1077 warnx("unexpected end of Fontmap file; giving up."); 1078 break; 1079 } 1080 if ((ttype != '/' && ttype != LPAREN) 1081 || pos2 == pos1 /* empty string would mess things up */ 1082 || get_gs_token(&gsf, pos2, &pos3, "Fontmap") != ';' 1083 || pos3 != pos2 + 1) { 1084 warnx("invalid token following '%.*s' in Fontmap file; giving up.", 1085 (int) pos1, ffline); 1086 break; 1087 } 1088 if (ttype == '/') 1089 ffline[pos1] = '\0'; /* mark aliases by initial \0 */ 1090 ffline[pos2++] = '\0'; /* terminate string */ 1091 1092 /* Add to database */ 1093 gsfp = (struct avl_gs *) avladd(ffline + 1, pos1 - 1, 1094 (struct avl **) &gs_head, sizeof *gsfp); 1095 1096 if (gsfp->key == ffline + 1) { /* if new record */ 1097 gsfp->key = xmemdup(ffline + 1, pos1 - 1); 1098 gsfp->in_use = False; 1099 gsfp->list = NULL; 1100 } 1101 else { 1102 if (strlen(gsfp->list->value + 1) + 2 == pos2 - pos1 1103 && memcmp(gsfp->list->value, ffline + pos1, pos2 - pos1) 1104 == 0) 1105 continue; /* ignore duplicate entry */ 1106 if (gsfp->fontmap_number == gs_fontmap_number) { 1107 /* Later entries in a Fontmap file override earlier 1108 ones */ 1109 gslp = gsfp->list; 1110 gsfp->list = gslp->next; 1111 free(gslp); 1112 } 1113 } 1114 gslp = xmalloc(sizeof *gslp + pos2 - pos1); 1115 gslp->next = gsfp->list; 1116 gsfp->list = gslp; 1117 memcpy((char *) gslp->value, ffline + pos1, pos2 - pos1); 1118 1119 gsfp->fontmap_number = gs_fontmap_number; 1120 } 1121 else { 1122 warnx("invalid token '%s' in Fontmap file; giving up.", 1123 ffline); 1124 } 1125 } 1126 1127 fclose(f); 1128 } 1129 1130 /* 1131 * Read Ghostscript Fontmap files. These are used if the line in 1132 * psfonts.map does not contain a filename for the font. 1133 * 1134 * For example: 1135 * n019003l NimbusSanL-Regu 1136 */ 1137 1138 static void 1139 read_gs_fontmaps() 1140 { 1141 env_gs_lib = getenv("XDVI_GS_LIB"); 1142 if (env_gs_lib == NULL) 1143 env_gs_lib = getenv("GS_LIB"); 1144 1145 if (gs_ctype[0] == 0) 1146 init_gs_ctype(); 1147 1148 (void) gs_path_fopen("Fontmap", process_gs_fontmap); 1149 } 1150 1151 1152 /* 1153 * pre_lookup_t1_font - Find a Type 1 font (or return NULL). 1154 */ 1155 1156 static struct avl_t1 * 1157 pre_lookup_t1_font(fontname) 1158 const char *fontname; 1159 { 1160 struct avl_t1 *t1p; 1161 size_t len; 1162 int i; 1163 1164 /* first, search for the font */ 1165 1166 len = strlen(fontname); 1167 t1p = t1_head; 1168 while (t1p != NULL) { 1169 i = len - t1p->key_len; 1170 if (i == 0) 1171 i = memcmp(fontname, t1p->key, len); 1172 if (i == 0) 1173 return t1p; /* found it */ 1174 t1p = (struct avl_t1 *) (i < 0 ? t1p->left : t1p->right); 1175 } 1176 1177 /* next, read in more records in hopes of finding the font */ 1178 1179 if (p_head != NULL) 1180 for (;;) { 1181 if (!fgets_long(mapfile)) { /* if end of file */ 1182 fclose(mapfile); 1183 for (;;) { 1184 p_head = p_head->next; 1185 if (p_head == NULL) 1186 return NULL; 1187 mapfile = filefind(p_head->value, &search_fontmap, 1188 NULL); 1189 if (mapfile != NULL) { 1190 if (debug & DBG_OPEN) 1191 printf("Map file: %s\n", p_head->value); 1192 break; 1193 } 1194 warnx("cannot open map file '%s'", p_head->value); 1195 } 1196 continue; 1197 } 1198 1199 if (*ffline < ' ' || *ffline == '*' || *ffline == '#' 1200 || *ffline == ';' || *ffline == '%') 1201 continue; 1202 1203 t1p = dvips_parse(ffline); 1204 1205 if (t1p != NULL && t1p->key_len == len 1206 && memcmp(t1p->key, fontname, len) == 0) 1207 return t1p; /* found it */ 1208 } 1209 1210 return NULL; 1211 } 1212 1213 /* 1214 * lookup_t1_font - Find a Type 1 font (or return NULL). 1215 */ 1216 1217 1218 static struct avl_t1 * 1219 lookup_t1_font(fontp) 1220 struct font *fontp; 1221 { 1222 struct avl_t1 *t1p; 1223 struct ftfont *ftp; 1224 1225 t1p = pre_lookup_t1_font(fontp->fontname); 1226 1227 if (t1p == NULL) 1228 return NULL; 1229 1230 if (t1p->bad) { 1231 if (debug & DBG_OPEN) 1232 printf("Font %s is marked as bad: skipping scalable version\n", 1233 fontp->fontname); 1234 return NULL; 1235 } 1236 1237 ftp = t1p->ft; 1238 if (ftp != NULL) { /* if it's is already in use at another size */ 1239 struct font *first_size; 1240 1241 /* The first node in the linked list of sizes contains the file */ 1242 /* reference, so we link in the new node after the first node */ 1243 first_size = ftp->first_size; 1244 fontp->next_size = first_size->next_size; 1245 first_size->next_size = fontp; 1246 } 1247 else { /* first use at this size */ 1248 t1p->ft = ftp = xmalloc(sizeof *ftp); 1249 ftp->face = NULL; 1250 ftp->t1 = t1p; 1251 ftp->first_size = fontp; 1252 fontp->next_size = NULL; 1253 } 1254 fontp->ft = ftp; 1255 fontp->size = NULL; 1256 1257 return t1p; 1258 } 1259 1260 1261 FILE * 1262 open_t1_font(t1p, path_ret) 1263 struct avl_t1 *t1p; 1264 const char **path_ret; 1265 { 1266 FILE *f; 1267 1268 /* 1269 * Set up the search paths, if necessary. 1270 */ 1271 1272 if (search_type1.path1 == no_f_str_type1) { /* if uninitialized */ 1273 if ((search_type1.path1 = getenv("XDVIT1FONTS")) == NULL 1274 && (search_type1.path1 = getenv("T1FONTS")) == NULL 1275 && (search_type1.path1 = getenv("T1INPUTS")) == NULL 1276 && (search_type1.path1 = getenv("TEXFONTS")) == NULL 1277 && (search_type1.path1 = getenv("XDVIHEADERS")) == NULL 1278 && (search_type1.path1 = getenv("TEXPSHEADERS")) == NULL 1279 && (search_type1.path1 = getenv("PSHEADERS")) == NULL) { 1280 search_type1.path1 = search_type1.path2; 1281 search_type1.path2 = NULL; 1282 } 1283 } 1284 1285 if (t1p->fontfile == NULL) { /* look up in GS Fontmap */ 1286 static Boolean gs_fontmap_initialized = False; 1287 1288 if (!gs_fontmap_initialized) { 1289 read_gs_fontmaps(); 1290 gs_fontmap_initialized = True; 1291 } 1292 1293 if (debug & DBG_OPEN) 1294 printf( 1295 "Looking for font %.*s using gs method (PS name %s) --\n", 1296 t1p->key_len, t1p->key, t1p->psname); 1297 f = lookup_gs_font(t1p->psname, path_ret); 1298 1299 if (f == NULL) { 1300 warnx("cannot find Type 1 font '%s'", t1p->psname); 1301 return NULL; 1302 } 1303 1304 if (debug & DBG_OPEN) 1305 printf("Found file %s\n", *path_ret); 1306 } 1307 else { 1308 f = filefind(t1p->fontfile, &search_type1, path_ret); 1309 1310 if (f == NULL) { 1311 warnx("cannot find Type 1 font file '%s' (will try PK version instead)", 1312 t1p->fontfile); 1313 return NULL; 1314 } 1315 } 1316 1317 return f; 1318 } 1319 1320 1321 /* 1322 * Read the encoding vector file. This assumes the same format as afm2tfm. 1323 */ 1324 1325 void 1326 read_encoding(encp) 1327 struct avl_enc *encp; 1328 { 1329 FILE *f; 1330 struct gsfile gsf; 1331 unsigned char buffer[GS_BUF_SIZE]; 1332 jmp_buf err_env; 1333 unsigned char ttype; 1334 unsigned int pos1, pos2; 1335 unsigned int identindex[256]; 1336 const char *str; 1337 unsigned int i; 1338 1339 if (debug & DBG_OPEN) 1340 printf("Reading encoding file %s\n", encp->key); 1341 1342 encp->valid = False; 1343 1344 /* 1345 * Set up the search paths, if necessary. 1346 */ 1347 1348 if (search_enc.path1 == no_f_str_enc) { /* if uninitialized */ 1349 if ((search_enc.path1 = getenv("XDVIENCS")) == NULL 1350 && (search_enc.path1 = getenv("ENCFONTS")) == NULL 1351 && (search_enc.path1 = getenv("TEXFONTS")) == NULL) { 1352 search_enc.path1 = search_enc.path2; 1353 search_enc.path2 = NULL; 1354 } 1355 } 1356 1357 f = filefind(encp->key, &search_enc, NULL); 1358 if (f == NULL) { 1359 warnx("cannot find encoding file '%s'; ignoring encoding", 1360 encp->key); 1361 return; 1362 } 1363 1364 if (gs_ctype[0] == 0) 1365 init_gs_ctype(); 1366 1367 gsf.f = f; 1368 gsf.buffer = buffer; 1369 gsf.bufpos = gsf.buf_end = buffer + GS_BUF_SIZE; 1370 1371 if (!setjmp(err_env)) { 1372 if (get_gs_token(&gsf, 0, &pos1, "encoding") != '/' 1373 || get_gs_character(&gsf) != '[') 1374 longjmp(err_env, 1); 1375 1376 pos1 = 0; 1377 for (i = 0; i < 256; ++i) { 1378 if (get_gs_token(&gsf, pos1, &pos2, "encoding") != '/') 1379 longjmp(err_env, 1); 1380 if (pos2 == pos1 + 8 1381 && memcmp(ffline + pos1, "/.notdef", 8) == 0) 1382 identindex[i] = 0; 1383 else { 1384 ffline[pos1] = '\0'; 1385 identindex[i] = pos1 + 1; 1386 pos1 = pos2; 1387 } 1388 } 1389 1390 if (get_gs_character(&gsf) != ']') 1391 longjmp(err_env, 1); 1392 1393 ttype = get_gs_token(&gsf, pos1, &pos2, "encoding"); 1394 if (!(ttype == GS_EOF 1395 || (ttype == 'd' && pos2 == pos1 + 3 1396 && memcmp(ffline + pos1, "def", 3) == 0 1397 && get_gs_token(&gsf, pos2, &pos2, "encoding") == GS_EOF))) 1398 longjmp(err_env, 1); 1399 1400 if (pos1 >= ffline_len) expandline(pos1 + 1); 1401 ffline[pos1] = '\0'; 1402 str = xmemdup(ffline + 1, pos1); 1403 for (i = 0; i < 256; ++i) 1404 encp->vec[i] = 1405 (identindex[i] != 0 ? str + identindex[i] - 1 : NULL); 1406 1407 encp->valid = True; 1408 } 1409 else /* if error */ 1410 warnx("invalid format in encoding file '%s'; giving up.", 1411 encp->key); 1412 1413 fclose(f); 1414 } 1415 1416 1417 1418 void 1419 init_font_open() 1420 { 1421 char *size_list; 1422 int *sp, *sp1; 1423 unsigned int n; 1424 char *p; 1425 FILE *f; 1426 const char *dvipsrc; 1427 1428 sprintf(bdpi_string, "%d", pixels_per_inch); 1429 1430 if ((search_pkgf.path1 = getenv("XDVIFONTS")) == NULL 1431 #ifndef XDVIFONTS_ONLY 1432 && (search_pkgf.path1 = getenv("PKFONTS")) == NULL 1433 && (search_pkgf.path1 = getenv("TEXPKS")) == NULL 1434 && (search_pkgf.path1 = getenv("TEXFONTS")) == NULL 1435 #endif 1436 ) { 1437 search_pkgf.path1 = search_pkgf.path2; 1438 search_pkgf.path2 = NULL; 1439 } 1440 1441 /* 1442 * pk/gf searching is the only kind that uses more than three 1443 * characters in fF_etc, so these can be initialized once and then 1444 * forgotten. 1445 */ 1446 1447 fF_values[2] = dpi_string; 1448 fF_values[3] = bdpi_string; 1449 fF_values[4] = "pk"; 1450 fF_values[5] = resource.mfmode; 1451 1452 if ((search_vf.path1 = getenv("XDVIVFS")) == NULL 1453 #ifndef XDVIFONTS_ONLY 1454 && (search_vf.path1 = getenv("VFFONTS")) == NULL 1455 #endif 1456 ) { 1457 search_vf.path1 = search_vf.path2; 1458 search_vf.path2 = NULL; 1459 } 1460 1461 size_list = getenv("XDVISIZES"); 1462 n = 1; /* count number of sizes */ 1463 if (size_list == NULL || *size_list == '\0' || *size_list == PATH_SEP) 1464 for (p = default_size_list; (p = index(p, PATH_SEP)) != NULL; ++p) 1465 ++n; 1466 if (size_list != NULL) 1467 for (p = size_list; (p = index(p, PATH_SEP)) != NULL; ++p) ++n; 1468 sizes = xmalloc(n * sizeof(int)); 1469 sizend = sizes; /* get the actual sizes */ 1470 if (size_list == NULL || *size_list == '\0' || *size_list == PATH_SEP) 1471 get_sizes(default_size_list, &sizend); 1472 if (size_list != NULL && *size_list != '\0') 1473 get_sizes(size_list, &sizend); 1474 1475 /* sort the sizes (insertion sort) */ 1476 for (sp = sizes + 1; sp < sizend; ++sp) 1477 if (*sp < sp[-1]) { 1478 int i = *sp; 1479 1480 sp1 = sp; 1481 do 1482 *sp1 = sp1[-1]; 1483 while (--sp1 > sizes && i < sp1[-1]); 1484 *sp1 = i; 1485 } 1486 1487 /* eliminate duplicates and erroneous values */ 1488 n = 0; /* previous value */ 1489 for (sp = sp1 = sizes; sp < sizend; ++sp) 1490 if (*sp != n) 1491 n = *sp1++ = *sp; 1492 sizend = sp1; 1493 1494 /* 1495 * Initialize reading of Type 1 fonts and map files 1496 * (PS uses T1 fonts for MetaPost figures). 1497 */ 1498 1499 if ((search_dvips_cf.path1 = getenv("XDVITYPE1CONFIG")) == NULL 1500 && (search_dvips_cf.path1 = getenv("TEXCONFIG")) == NULL) { 1501 search_dvips_cf.path1 = search_dvips_cf.path2; 1502 search_dvips_cf.path2 = NULL; 1503 } 1504 1505 if ((search_fontmap.path1 = getenv("XDVIFONTMAPS")) == NULL 1506 && (search_fontmap.path1 = getenv("TEXFONTMAPS")) == NULL 1507 && (search_fontmap.path1 = getenv("TEXFONTS")) == NULL) { 1508 search_fontmap.path1 = search_fontmap.path2; 1509 search_fontmap.path2 = NULL; 1510 } 1511 1512 if (ffline == NULL) expandline(80); 1513 1514 f = filefind("config.ps", &search_dvips_cf, NULL); 1515 if (f != NULL) 1516 getdefaults(f); 1517 1518 dvipsrc = getenv("DVIPSRC"); 1519 if (dvipsrc == NULL) { 1520 dvipsrc = getenv("HOME"); 1521 if (dvipsrc != NULL) { 1522 n = strlen(dvipsrc); 1523 if (n + 10 > ffline_len) expandline(n + 10); 1524 memcpy(ffline, dvipsrc, n); 1525 memcpy(ffline + n, "/.dvipsrc", 10); 1526 dvipsrc = ffline; 1527 } 1528 } 1529 if (dvipsrc != NULL) { 1530 f = xfopen(dvipsrc, "r"); 1531 if (f != NULL) 1532 getdefaults(f); 1533 } 1534 1535 f = filefind("config.xdvi", &search_dvips_cf, NULL); 1536 if (f != NULL) 1537 getdefaults(f); 1538 1539 *p_tail = NULL; 1540 1541 /* 1542 * Look for the first (openable) map file. Others will be read later 1543 * as needed. 1544 */ 1545 1546 while (p_head != NULL) { 1547 mapfile = filefind(p_head->value, &search_fontmap, NULL); 1548 if (mapfile != NULL) { 1549 if (debug & DBG_OPEN) 1550 printf("Map file: %s\n", p_head->value); 1551 break; 1552 } 1553 warnx("Cannot open map file '%s'", p_head->value); 1554 p_head = p_head->next; 1555 } 1556 } 1557 1558 /* 1559 * Try a given size. 1560 */ 1561 1562 static FILE * 1563 try_size(font, dpi, ret_path) 1564 const char *font; 1565 int dpi; 1566 const char **ret_path; 1567 { 1568 sprintf(dpi_string, "%d", dpi); 1569 1570 return filefind(font, &search_pkgf, ret_path); 1571 } 1572 1573 1574 /* 1575 * Try a given font name 1576 */ 1577 1578 static Boolean 1579 pre_font_open(struct font *fontp, const char *fontname, double fdpi, 1580 const char **name_ret, int *dpi_ret) 1581 { 1582 FILE *f; 1583 int *p1, *p2; 1584 int dpi; 1585 int tempdpi; 1586 1587 *dpi_ret = dpi = fdpi + 0.5; 1588 1589 /* 1590 * First look for a scalable font. 1591 */ 1592 1593 struct avl_t1 *t1p = lookup_t1_font(fontp); 1594 1595 if (t1p != NULL) { /* if font found */ 1596 if (debug & DBG_OPEN) 1597 printf("lookup_t1_font(%s) --> found %s\n", 1598 fontp->fontname, t1p->fontfile != NULL ? 1599 t1p->fontfile : t1p->psname); 1600 1601 return True; 1602 } 1603 1604 if (debug & DBG_OPEN) 1605 printf("lookup_t1_font(%s) --> not found\n", fontp->fontname); 1606 1607 /* 1608 * Loop over sizes. Try actual size first, then closest sizes. 1609 * If the pathname is absolutely or explicitly relative, don't 1610 * use the usual paths to search for it; just look for it in the 1611 * directory specified. 1612 */ 1613 1614 f = try_size(fontname, dpi, name_ret); 1615 if (f != NULL) { 1616 fontp->file = f; 1617 return True; 1618 } 1619 1620 /* Try at one away from the size we just tried, to account 1621 for rounding error. */ 1622 tempdpi = dpi + (dpi < fdpi ? 1 : -1); 1623 f = try_size(fontname, tempdpi, name_ret); 1624 if (f != NULL) { 1625 fontp->file = f; 1626 *dpi_ret = tempdpi; 1627 return True; 1628 } 1629 1630 /* Try a virtual font. */ 1631 f = filefind(fontname, &search_vf, name_ret); 1632 if (f != NULL) { 1633 fontp->file = f; 1634 return True; 1635 } 1636 1637 /* Now try at all the sizes. */ 1638 for (p2 = sizes; p2 < sizend; ++p2) if (*p2 >= dpi) break; 1639 p1 = p2; 1640 for (;;) { 1641 /* find another resolution */ 1642 if (p1 <= sizes) 1643 if (p2 >= sizend) return False; 1644 else tempdpi = *p2++; 1645 else if (p2 >= sizend || (long) dpi * dpi <= (long) p1[-1] * *p2) 1646 tempdpi = *--p1; 1647 else tempdpi = *p2++; 1648 f = try_size(fontname, *dpi_ret = tempdpi, name_ret); 1649 if (f != NULL) { 1650 fontp->file = f; 1651 return True; 1652 } 1653 } 1654 } 1655 1656 /* 1657 * font_open() 1658 * 1659 * This is the publicly accessible routine. It uses the following fields 1660 * in the font structure: 1661 * fontname 1662 * magstepval 1663 * fsize 1664 * filename 1665 * ft 1666 * next_size 1667 * size 1668 */ 1669 1670 Boolean 1671 font_open(fontp, font_ret, dpi_ret) 1672 struct font *fontp; 1673 char **font_ret; 1674 int *dpi_ret; 1675 { 1676 Boolean val; 1677 int actual_pt, low_pt, high_pt, trial_pt; 1678 char *fn, *fnend; 1679 1680 val = pre_font_open(fontp, fontp->fontname, fontp->fsize, 1681 &fontp->filename, dpi_ret); 1682 if (val || ev_flags & EV_GE_NEWDOC) { 1683 *font_ret = NULL; 1684 return val; 1685 } 1686 1687 fn = xmalloc(strlen(fontp->fontname) + 2); 1688 strcpy(fn, fontp->fontname); 1689 fnend = fn + strlen(fn); 1690 while (fnend > fn && fnend[-1] >= '0' && fnend[-1] <= '9') --fnend; 1691 actual_pt = low_pt = high_pt = atoi(fnend); 1692 if (actual_pt) { 1693 low_pt = actual_pt - 1; 1694 high_pt = actual_pt + 1; 1695 for (;;) { 1696 if (2 * low_pt >= actual_pt && 1697 (low_pt * high_pt > actual_pt * actual_pt || 1698 high_pt > actual_pt + 5)) 1699 trial_pt = low_pt--; 1700 else if (high_pt > actual_pt + 5) break; 1701 else trial_pt = high_pt++; 1702 sprintf(fnend, "%d", trial_pt); 1703 if (pre_font_open(fontp, fn, 1704 fontp->fsize * actual_pt / trial_pt, 1705 &fontp->filename, dpi_ret)) { 1706 *font_ret = fn; 1707 return True; 1708 } 1709 } 1710 } 1711 free(fn); 1712 1713 if (resource._alt_font != NULL) { 1714 if (pre_font_open(fontp, resource._alt_font, fontp->fsize, 1715 &fontp->filename, dpi_ret)) { 1716 *font_ret = xstrdup(resource._alt_font); 1717 return True; 1718 } 1719 } 1720 return False; 1721 }