1 /*
2 font-open.c: find font files. The routine font_open() itself bears
3 no relation (except for the interface) to the original font_open().
4
5 Copyright (c) 1999-2013 The texk project
6
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to
9 deal in the Software without restriction, including without limitation the
10 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11 sell copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE
21 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25 */
26
27 #include "xdvi-config.h"
28 #include "xdvi.h"
29 #include "dvi-draw.h"
30 #ifdef PTEX
31 #include "ptexmap.h"
32 #endif
33 #include "util.h"
34 #include "events.h"
35 #include "dvi-init.h"
36 #include "my-snprintf.h"
37 #include "print-log.h"
38
39 #include "statusline.h"
40 #include "message-window.h"
41 #include "font-open.h"
42
43 #include "kpathsea/c-fopen.h"
44 #include "kpathsea/tex-glyph.h"
45
46 #include <stdlib.h>
47 #include <ctype.h>
48
49 #if HAVE_SYS_WAIT_H
50 # include <sys/wait.h>
51 #endif
52 #ifndef WIFEXITED
53 # define WIFEXITED(status) (((status) & 255) == 0)
54 #endif
55 #ifndef WEXITSTATUS
56 # define WEXITSTATUS(status) ((unsigned)(status) >> 8)
57 #endif
58 #ifndef WIFSIGNALED
59 # ifndef WIFSTOPPED
60 # define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
61 # endif
62 # define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))
63 #endif
64 #ifndef WTERMSIG
65 # define WTERMSIG(status) ((status) & 0x7f)
66 #endif
67
68 /* if POSIX O_NONBLOCK is not available, use O_NDELAY */
69 #if !defined(O_NONBLOCK) && defined(O_NDELAY)
70 # define O_NONBLOCK O_NDELAY
71 #endif
72
73 #ifdef EWOULDBLOCK
74 # ifdef EAGAIN
75 # define AGAIN_CONDITION (errno == EWOULDBLOCK || errno == EAGAIN)
76 # else
77 # define AGAIN_CONDITION (errno == EWOULDBLOCK)
78 # endif
79 #else /* EWOULDBLOCK */
80 # ifdef EAGAIN
81 # define AGAIN_CONDITION (errno == EAGAIN)
82 # endif
83 #endif /* EWOULDBLOCK */
84
85 #if HAVE_POLL
86 # include <poll.h>
87 # define XIO_IN POLLIN
88 # define XIO_OUT POLLOUT
89 #else
90 # define XIO_IN 1
91 # define XIO_OUT 2
92 #endif /* HAVE_POLL */
93
94
95 /* see just above the second init_t1_lookup for why this was chosen */
96 #define DVIPS_SETUP 1
97
98 #if FREETYPE || PS
99
100 /*
101 * The following code handles lookup of Type 1 fonts for use as FreeType
102 * fonts, and for use within MetaPost output.
103 * The system psfonts.map file is read into an AVL tree as needed (lazy
104 * evaluation), and searched for Type 1 fonts.
105 */
106
107 struct p_list { /* list of map file names */
108 struct p_list *next;
109 const char *value;
110 };
111
112 /* Initialize this list to "psfonts.map". */
113
114 static struct p_list psfonts_map = {NULL, "psfonts.map"};
115
116 static struct p_list *p_head = &psfonts_map;
117 static struct p_list **p_tail = &psfonts_map.next;
118
119 static FILE *mapfile = NULL;
120
121 static char *ffline = NULL; /* an array used to store */
122 /* the file name being formed. */
123 /* It expands as needed. */
124 /* Also used elsewhere. */
125 static size_t ffline_len = 0; /* current length of ffline[] */
126
127 /*
128 * Expand ffline[] to at least the given size.
129 */
130
131 static void
expandline(int n)132 expandline(int n)
133 {
134 int newlen = n + 128;
135
136 ffline = (ffline == NULL) ? xmalloc(newlen) : xrealloc(ffline, newlen);
137 ffline_len = newlen;
138 }
139
140
141 /*
142 * Like fgets(), but read an arbitrarily long line into ffline[].
143 */
144
145 static Boolean
fgets_long(FILE * f)146 fgets_long(FILE *f)
147 {
148 int len;
149
150 if (fgets(ffline, ffline_len, f) == NULL)
151 return False;
152
153 len = 0;
154 for (;;) {
155 len += strlen(ffline + len);
156 if (len > 0 && ffline[len - 1] == '\n') {
157 ffline[--len] = '\0';
158 break;
159 }
160 if (len < ffline_len - 1)
161 break;
162 expandline(len);
163 fgets(ffline + len, ffline_len - len, f);
164 }
165
166 return True;
167 }
168
169 # if DVIPS_SETUP
170
171 /*
172 * Get list of map files from dvips config file(s).
173 */
174
175 static void
getdefaults(FILE * f)176 getdefaults(FILE *f)
177 {
178 char *p, *q;
179 int len;
180 struct p_list *p_node;
181
182 while (fgets_long(f)) {
183 p = ffline;
184 while (*p == ' ' || *p == '\t') ++p;
185 if (*p == 'p') {
186 do ++p;
187 while (*p == ' ' || *p == '\t');
188
189 if (*p == '+')
190 do ++p;
191 while (*p == ' ' || *p == '\t');
192 else { /* discard old list */
193 struct p_list *pl, *pl2;
194
195 *p_tail = NULL;
196 pl = p_head;
197 if (pl == &psfonts_map) pl = pl->next;
198 while (pl != NULL) {
199 free((char *) pl->value);
200 pl2 = pl->next;
201 free(pl);
202 pl = pl2;
203 }
204 p_tail = &p_head;
205 }
206
207 /* get white-delimited argument */
208 len = strlen(p);
209 q = memchr(p, ' ', len);
210 if (q != NULL) len = q - p;
211 q = memchr(p, '\t', len);
212 if (q != NULL) len = q - p;
213 p[len] = '\0';
214
215 p_node = xmalloc(sizeof *p_node);
216 p_node->value = xmemdup(p, len + 1);
217 *p_tail = p_node;
218 p_tail = &p_node->next;
219 } else if (*p == 'x') {
220 char *name;
221
222 name = NULL;
223 do ++p;
224 while (*p == ' ' || *p == '\t');
225
226 if (*p == '+')
227 do ++p;
228 while (*p == ' ' || *p == '\t');
229
230 name = strtok(p, " \t");
231 if (name == NULL) {
232 XDVI_WARNING((stderr, "Syntax error in entry \"%s\" "
233 "(ignored)", ffline));
234 continue;
235 }
236 read_ptexmap_file(name);
237 } else if (*p == 'r') {
238 char *name, *ptr;
239
240 name = ptr = NULL;
241 do ++p;
242 while (*p == ' ' || *p == '\t');
243 name = strtok(p, " \t");
244 if ((name == NULL) ||
245 (ptr = strtok(NULL, " \t")) == NULL) {
246 XDVI_WARNING((stderr, "Syntax error in entry \"%s\" "
247 "(ignored)", ffline));
248 continue;
249 }
250 add_replace_dictionary(name, ptr);
251 }
252 }
253
254 fclose(f);
255 }
256
257 # endif /* DVIPS_SETUP */
258
259 /*
260 * Open the next (available) map file.
261 */
262
263 static Boolean
open_next_mapfile(void)264 open_next_mapfile(void)
265 {
266 char *filename;
267
268 /*
269 * Look for the first (openable) map file. Others will be read later
270 * as needed.
271 */
272
273 while (p_head != NULL) {
274 filename = kpse_find_file(p_head->value, kpse_program_text_format,
275 True);
276 if (filename == NULL)
277 filename = kpse_find_file(p_head->value, kpse_fontmap_format,
278 True);
279 if (filename == NULL) {
280 XDVI_WARNING((stderr,
281 "could not find dvips map file %s; skipping\n",
282 p_head->value));
283 }
284 else {
285 mapfile = XFOPEN(filename, OPEN_MODE);
286 if (mapfile == NULL) {
287 XDVI_WARNING((stderr,
288 "could not open dvips map file %s: %s\n",
289 filename, strerror(errno)));
290 free(filename);
291 }
292 else {
293 TRACE_FT((stderr, "Map file: %s\n", filename));
294 free(filename);
295 return True;
296 }
297 }
298 p_head = p_head->next;
299 }
300
301 return False;
302 }
303
304
305 /*
306 * Initialize these lookup routines.
307 */
308
309 # if DVIPS_SETUP
310
311 Boolean
init_t1_lookup(void)312 init_t1_lookup(void)
313 {
314 char *filename;
315 struct stat statbuf;
316 FILE *f;
317 char *dvipsrc;
318
319 if (ffline == NULL) expandline(80);
320
321 filename = find_file("config.ps", &statbuf, kpse_dvips_config_format);
322 if (filename == NULL) {
323 TRACE_FT((stderr, "could not find file config.ps; skipping"));
324 }
325 else {
326 f = XFOPEN(filename, OPEN_MODE);
327 if (f == NULL) {
328 TRACE_FT((stderr, "could not open file %s: %s",
329 filename, strerror(errno)));
330 }
331 else
332 getdefaults(f);
333 free(filename);
334 }
335
336 dvipsrc = getenv("DVIPSRC");
337 if (dvipsrc == NULL) {
338 dvipsrc = getenv("HOME");
339 if (dvipsrc != NULL) {
340 size_t n;
341
342 n = strlen(dvipsrc);
343 if (n + 10 > ffline_len) expandline(n + 10);
344 memcpy(ffline, dvipsrc, n);
345 memcpy(ffline + n, "/.dvipsrc", 10);
346 dvipsrc = ffline;
347 }
348 }
349 if (dvipsrc != NULL) {
350 f = XFOPEN(dvipsrc, OPEN_MODE);
351 if (f == NULL) {
352 TRACE_FT((stderr,
353 "could not open dvipsrc file %s: %s; skipping",
354 dvipsrc, strerror(errno)));
355 }
356 else
357 getdefaults(f);
358 }
359
360 filename = find_file("config.xdvi", &statbuf, kpse_dvips_config_format);
361 if (filename == NULL) {
362 TRACE_FT((stderr, "could not find file config.xdvi; skipping"));
363 }
364 else {
365 f = XFOPEN(filename, OPEN_MODE);
366 if (f == NULL) {
367 TRACE_FT((stderr, "could not open file %s: %s",
368 filename, strerror(errno)));
369 }
370 else
371 getdefaults(f);
372 free(filename);
373 }
374
375 *p_tail = NULL;
376
377 return open_next_mapfile();
378 }
379
380 # else /* !DVIPS_SETUP */
381
382 /*
383 * Under the earlier regime, T1 lookup was controlled by xdvi.cfg.
384 *
385 * This has been disabled, for the following reasons.
386 *
387 * It only supported "enc" and "dvipsmap" directives.
388 *
389 * The "enc" directives selected implicit encoding files for fonts ending
390 * in certain character strings (8r, 8c, 8y), unless the map file
391 * explicitly referenced a .enc file. However, among the dvips map files
392 * supplied with TeX Live 2012 (at least) there were no such fonts ending
393 * in 8r and 8y, and the encoding file for the 8c fonts was cork.enc,
394 * which is no longer included in TeX Live.
395 *
396 * As for the dvipsmap directives, it seemed better to use the dvips
397 * configuration method.
398 */
399
400 Boolean
init_t1_lookup(void)401 init_t1_lookup(void)
402 {
403 char *filename;
404 FILE *fp;
405 char *keyword;
406 char *ptr;
407 struct p_list *p_node;
408 char *enc;
409 char *name;
410 static const char delim[] = "\t \n\r";
411
412 if (ffline == NULL) expandline(80);
413
414 filename = kpse_find_file("xdvi.cfg", kpse_program_text_format, 1);
415 if (filename == NULL) {
416 statusline_error(STATUS_MEDIUM,
417 "Warning: Unable to find \"xdvi.cfg\"!");
418 return open_next_mapfile();
419 }
420
421 if ((fp = XFOPEN(filename, "r")) == NULL) {
422 XDVI_ERROR((stderr, "Cannot open config file `%s' for reading: %s",
423 filename, strerror(errno)));
424 free(filename);
425 return open_next_mapfile();
426 }
427
428 TRACE_FT((stderr, "Reading cfg file %s", filename));
429
430 while (fgets_long(fp)) {
431 keyword = ffline;
432
433 /* Skip leading whitespace */
434 while (*keyword == ' ' || *keyword == '\t')
435 keyword++;
436
437 /* % in first column is a correct comment */
438 if (*keyword == '%' || *keyword == '\0' || *keyword == '\n')
439 continue;
440
441 keyword = strtok(keyword, delim);
442
443 if (strcmp(keyword, "dvipsmap") == 0) {
444 if ((ptr = strtok(NULL, delim)) == NULL) {
445 XDVI_WARNING((stderr, "Syntax error in entry \"%s\"",
446 ffline));
447 continue;
448 }
449 TRACE_FT((stderr, "DVIPSMAP: '%s'", ptr));
450
451 /* Add it to the list for later reading */
452 p_node = xmalloc(sizeof *p_node);
453 p_node->value = xmemdup(ptr, strlen(ptr) + 1);
454 /* If we're still pointing to the default list, remove it */
455 if (p_tail == &psfonts_map.next)
456 p_tail = &p_head;
457 *p_tail = p_node;
458 p_tail = &p_node->next;
459 }
460 else if (strcmp(keyword, "encmap") == 0) {
461 popup_message(globals.widgets.top_level,
462 MSG_ERR,
463 "Your xdvi.cfg file is for a previous version "
464 "of xdvik. Please replace it with the xdvi.cfg file "
465 "in the current xdvik distribution.",
466 "The keyword \"encmap\" in xdvi.cfg is no longer "
467 "supported. Please update the config file %s.",
468 filename);
469 }
470 else if (strcmp(keyword, "enc") == 0) {
471 enc = strtok(NULL, delim);
472 name = strtok(NULL, delim);
473 if ((ptr = strtok(NULL, delim)) == NULL) {
474 XDVI_WARNING((stderr,
475 "Syntax error in entry \"%s\" (skipping line)",
476 ffline));
477 continue;
478 }
479 # if 0
480 i = new_encoding(enc, ptr);
481 TRACE_FT((stderr, "Encoding[%d]: '%s' = '%s' -> '%s'",
482 i, enc, name, ptr));
483 # endif
484 #ifdef PTEX
485 }
486 else if (strcmp(keyword, "ptexmap") == 0) {
487 if ((ptr = strtok(NULL, delim)) == NULL) {
488 XDVI_WARNING((stderr,
489 "Syntax error in entry \"%s\" (skipping line)",
490 ffline));
491 continue;
492 }
493 read_ptexmap_file(ptr);
494 }
495 else if (strcmp(keyword, "replace") == 0) {
496 if ((name = strtok(NULL, delim)) == NULL ||
497 (ptr = strtok(NULL, delim)) == NULL) {
498 XDVI_WARNING((stderr,
499 "Syntax error in entry \"%s\" (skipping line)",
500 ffline));
501 continue;
502 }
503 add_replace_dictionary(name, ptr);
504 #endif
505 } else {
506 /* again, nag them with a popup so that they'll do something
507 about this ... */
508 popup_message(globals.widgets.top_level,
509 MSG_ERR,
510 "Please check the syntax of your config file. "
511 #ifdef PTEX
512 "Valid keywords are: \"enc\", \"dvipsmap\", \"ptexmap\" and \"replace\".",
513 #else
514 "Valid keywords are: \"enc\" and \"dvipsmap\".",
515 #endif
516 "Skipping unknown keyword \"%s\" in config file %s.",
517 keyword, filename);
518 }
519 }
520 *p_tail = NULL; /* terminate linked list of map files */
521
522 fclose(fp);
523 free(filename);
524
525 return open_next_mapfile();
526 }
527
528 # endif /* not DVIPS_SETUP */
529
530
531 /*
532 * Information about Type 1 fonts is stored in an AVL tree.
533 */
534
535 static struct avl_t1 *t1_head = NULL;
536
537
538 /*
539 * Parse line from psfonts.map file.
540 */
541
542 static struct avl_t1 *
dvips_parse(const char * line)543 dvips_parse(const char *line)
544 {
545 const char *w1p, *encp, *pfp, *qp;
546 size_t w1l, encl, pfl, ql;
547 const char *w2p;
548 size_t w2l;
549 const char *p, *p0;
550 const char *err;
551 struct avl_t1 *t1p;
552 char *q;
553
554 w2l = w1l = encl = pfl = ql = 0;
555 err = NULL;
556 p = line;
557 for (;;) { /* loop over words */
558 while (*p == ' ' || *p == '\t') ++p;
559 if (*p == '\0')
560 break;
561
562 if (*p == '"') { /* quoted string */
563 const char *p_end;
564
565 p0 = p + 1;
566 p_end = p0 + strlen(p0);
567 p = memchr(p0, '"', p_end - p0);
568 if (p == NULL) p = p_end;
569 qp = (ql == 0 ? p0 : NULL);
570 ql += p - p0 + 1;
571 if (*p == '"') ++p;
572 continue;
573 }
574
575 if (*p == '<') { /* encoding or pfa/b file */
576 int wtype = 0;
577
578 ++p;
579 if (*p == '<') {
580 wtype = 1; /* font file */
581 ++p;
582 }
583 else if (*p == '[') {
584 wtype = -1; /* encoding file */
585 ++p;
586 }
587
588 /* find word */
589 while (*p == ' ' || *p == '\t') ++p;
590 p0 = p;
591 while (*p != '\0' && *p != ' ' && *p != '\t') ++p;
592
593 if (wtype == 0 && p > p0 + 4 && p[-4] == '.') {
594 if (memcmp(p - 3, "enc", 3) == 0
595 || memcmp(p - 3, "ENC", 3) == 0)
596 wtype = -1;
597 else if (memcmp(p - 3, "pfa", 3) == 0
598 || memcmp(p - 3, "pfb", 3) == 0
599 || memcmp(p - 3, "PFA", 3) == 0
600 || memcmp(p - 3, "PFB", 3) == 0)
601 wtype = 1;
602 }
603
604 if (wtype > 0) {
605 if (pfl != 0)
606 err = "more than one font file given";
607 else {
608 pfp = p0;
609 pfl = p - p0 + 1;
610 }
611 }
612 else if (wtype < 0) {
613 if (encl != 0)
614 err = "more than one encoding file given";
615 else {
616 encp = p0;
617 encl = p - p0 + 1;
618 }
619 }
620 else
621 err = "cannot identify file type";
622 }
623 else { /* if ordinary word */
624 p0 = p;
625 while (*p != '\0' && *p != ' ' && *p != '\t') ++p;
626 if (w1l == 0) {
627 w1p = p0;
628 w1l = p - p0;
629 }
630 else if (w2l == 0) {
631 w2p = p0;
632 w2l = p - p0;
633 }
634 else
635 err = "more than two non-download words given";
636 }
637 } /* end loop over words */
638
639 if (w1l == 0) {
640 TRACE_FT((stderr,
641 "map file %s: line \"%s\" does not give a font name.",
642 p_head->value, line));
643 return NULL;
644 }
645
646 if (err != NULL) {
647 TRACE_FT((stderr, "map file %s, font %.*s: %s", p_head->value,
648 (int) w1l, w1p, err));
649 return NULL;
650 }
651
652 t1p = (struct avl_t1 *) avladd(w1p, w1l, (struct avl **) &t1_head,
653 sizeof(struct avl_t1));
654
655 if (t1p->key != w1p) { /* if existing record */
656 TRACE_FT((stderr,
657 "map file %s, font %.*s: duplicate record; using first one",
658 p_head->value, (int) w1l, w1p));
659 return NULL;
660 }
661
662 t1p->key = q = xmalloc(w1l + w2l + 1 + pfl + encl + ql);
663
664 memcpy(q, w1p, w1l);
665 q += w1l;
666 t1p->psname = t1p->key;
667 if (w2l != 0) {
668 t1p->psname = q;
669 memcpy(q, w2p, w2l);
670 q += w2l;
671 }
672 *q++ = '\0';
673
674 t1p->fontfile = NULL;
675 if (pfl != 0) {
676 t1p->fontfile = q;
677 memcpy(q, pfp, pfl - 1);
678 q += pfl;
679 q[-1] = '\0';
680 }
681
682 t1p->encname = t1p->addinfo = NULL;
683 # if FREETYPE
684 t1p->bad = False;
685 t1p->ft = NULL;
686 # endif
687
688 if (encl != 0) {
689 t1p->encname = q;
690 memcpy(q, encp, encl - 1);
691 q += encl;
692 q[-1] = '\0';
693 }
694
695 if (ql != 0) {
696 t1p->addinfo = q;
697 if (qp != 0) {
698 memcpy(q, qp, ql - 1);
699 q += ql;
700 }
701 else { /* multiple quoted strings; rescan to get them */
702 const char *p_end;
703
704 p = line;
705 p_end = p + strlen(p);
706 for (;;) {
707 while (*p == ' ' || *p == '\t') ++p;
708 if (*p == '\0')
709 break;
710
711 /* found a word */
712 if (*p == '"') {
713 ++p;
714 p0 = p;
715 p = memchr(p0, '"', p_end - p0);
716 if (p == NULL) p = p_end;
717 memcpy(q, p0, p - p0);
718 q += p - p0;
719 *q++ = ' ';
720 if (*p == '\0') break;
721 ++p;
722 }
723 else /* skip unquoted word */
724 while (*p != '\0' && *p != ' ' && *p != '\t') ++p;
725 }
726 }
727 q[-1] = '\0';
728 }
729
730 return t1p;
731 }
732
733 /*
734 * Information on the Ghostscript font aliasing mechanism is kept in
735 * another AVL tree. Each identifier points to a list of strings,
736 * up to one from each Fontmap file. Within a Fontmap file, later entries
737 * for a given string override earlier ones.
738 */
739
740 struct avl_gs { /* structure for gs font information */
741 AVL_COMMON;
742 short fontmap_number; /* sequence of most recent entry */
743 Boolean in_use;
744 struct gs_list *list;
745 };
746
747 struct gs_list { /* list of Fontmap entries for this font name */
748 struct gs_list *next;
749 const char value[0];
750 };
751
752 static struct avl_gs *gs_head = NULL;
753
754 typedef void (*gs_path_proc)(FILE *);
755
756 static const char *env_gs_lib;
757
758 static FILE *
gs_try_fopen(const char * str,unsigned int len,const char * name)759 gs_try_fopen(const char *str, unsigned int len, const char *name)
760 {
761 unsigned int namelen = strlen(name) + 1;
762 FILE *f;
763
764 if (len + namelen + 1 > ffline_len) expandline(len + namelen + 1);
765 memcpy(ffline, str, len);
766 ffline[len] = '/';
767 memcpy(ffline + len + 1, name, namelen);
768
769 f = XFOPEN(ffline, OPEN_MODE);
770
771 TRACE_FT((stderr, "gs_try_fopen: %s: %s", ffline,
772 f != NULL ? "file opened" : strerror(errno)));
773
774 return f;
775 }
776
777 static FILE *
gs_path_fopen(const char * name,gs_path_proc proc)778 gs_path_fopen(const char *name, gs_path_proc proc)
779 {
780 const char *str1 = env_gs_lib;
781 const char *str2 = DEFAULT_GS_LIB_PATH;
782 const char *str1_end, *str2_end;
783 const char *p1, *p2;
784 FILE *f;
785 unsigned int namelen;
786
787 if (str1 == NULL) {
788 str1 = str2;
789 str2 = NULL;
790 }
791
792 str1_end = str1 + strlen(str1);
793
794 for (;;) {
795 p1 = memchr(str1, ':', str1_end - str1);
796 if (p1 == NULL) p1 = str1_end;
797 if (p1 == str1) {
798 if (str2 != NULL) {
799 str2_end = str2 + strlen(str2);
800 for (;;) {
801 p2 = memchr(str2, ':', str2_end - str2);
802 if (p2 == NULL) p2 = str2_end;
803 if (p2 > str2) {
804 f = gs_try_fopen(str2, p2 - str2, name);
805 if (f != NULL) {
806 if (proc != NULL)
807 proc(f);
808 else
809 return f;
810 }
811 }
812 if (*p2 == '\0')
813 break;
814 str2 = p2 + 1;
815 }
816 str2 = NULL;
817 }
818 }
819 else {
820 f = gs_try_fopen(str1, p1 - str1, name);
821 if (f != NULL) {
822 if (proc != NULL)
823 proc(f);
824 else
825 return f;
826 }
827 }
828
829 if (*p1 == '\0')
830 break;
831 str1 = p1 + 1;
832 }
833
834 /* leave the file name in ffline[] for error message */
835 namelen = strlen(name) + 1;
836 if (namelen > ffline_len) expandline(namelen);
837 memcpy(ffline, name, namelen);
838
839 return NULL;
840 }
841
842
843 static FILE *
lookup_gs_font(const char * font,const char ** path_ret)844 lookup_gs_font(const char *font, const char **path_ret)
845 {
846 struct avl_gs *gsfp;
847 int font_len;
848 int i;
849
850 font_len = strlen(font);
851 gsfp = gs_head;
852 for (;;) {
853 if (gsfp == NULL) /* if not found */
854 return NULL;
855
856 i = font_len - gsfp->key_len;
857 if (i == 0)
858 i = memcmp(font, gsfp->key, font_len);
859 if (i == 0) { /* if found */
860 struct gs_list *gl, *gl2, *gl3;
861 FILE *f;
862
863 if (gsfp->in_use) {
864 TRACE_FT((stderr, "Alias loop for %s detected; ignoring.",
865 font));
866 return NULL;
867 }
868
869 /* If we haven't done it yet, reverse the linked list */
870 if (gsfp->fontmap_number != 0) {
871 gsfp->fontmap_number = 0;
872 gl = gsfp->list;
873 gl2 = NULL;
874 while (gl != NULL) {
875 gl3 = gl->next;
876 gl->next = gl2;
877 gl2 = gl;
878 gl = gl3;
879 }
880 gsfp->list = gl2;
881 }
882 gsfp->in_use = True;
883 f = NULL;
884 for (gl = gsfp->list; gl != NULL; gl = gl->next) {
885 if (gl->value[0] == '\0') { /* if alias */
886 TRACE_FT((stderr, "Found alias %s --> %s",
887 font, gl->value + 1));
888 f = lookup_gs_font(gl->value + 1, path_ret);
889 if (f == NULL)
890 TRACE_FT((stderr, "Alias %s not found.",
891 gl->value + 1));
892 if (f != NULL) break;
893 }
894 else {
895 TRACE_FT((stderr, "Checking file %s", gl->value));
896 if (gl->value[0] == '/' || (gl->value[0] == '.'
897 && (gl->value[1] == '/' || (gl->value[1] == '.'
898 && gl->value[2] == '/')))) {
899 f = XFOPEN(gl->value, OPEN_MODE);
900 if (f != NULL) {
901 *path_ret = xstrdup(gl->value);
902 break;
903 }
904 }
905 else {
906 f = gs_path_fopen(gl->value, NULL);
907 if (f != NULL) {
908 *path_ret = xstrdup(ffline);
909 break;
910 }
911 }
912 }
913 }
914 gsfp->in_use = False;
915 return f;
916 }
917 gsfp = (struct avl_gs *) (i < 0 ? gsfp->left : gsfp->right);
918 }
919 }
920
921
922 #define GS_BUF_SIZE 4096
923
924 struct gsfile {
925 FILE *f;
926 unsigned char *buffer;
927 const unsigned char *bufpos;
928 const unsigned char *buf_end;
929 };
930
931 static Boolean
gs_fillbuf(struct gsfile * gsf)932 gs_fillbuf(struct gsfile *gsf)
933 {
934 unsigned char *p;
935 unsigned int len;
936
937 if (gsf->buf_end < gsf->buffer + GS_BUF_SIZE)
938 return False;
939
940 gsf->bufpos = p = gsf->buffer;
941 for (;;) {
942 len = gsf->buf_end - p;
943 if (len <= 0) break;
944 len = fread(p, 1, len, gsf->f);
945 if (len <= 0) break;
946 p += len;
947 }
948 gsf->buf_end = p;
949 return (p > gsf->buffer);
950 }
951
952 static unsigned char gs_ctype[256];
953
954 #define GS_EOF '\0'
955 #define GS_ERR '%'
956 #define LPAREN '('
957 #define RPAREN ')'
958
959 static void
init_gs_ctype(void)960 init_gs_ctype(void)
961 {
962 const char *p;
963
964 for (p = " \t\f\n\r";; ++p) {
965 gs_ctype[(unsigned char) *p] = 1; /* white space */
966 if (*p == '\0') break;
967 }
968 gs_ctype['/'] = 2; /* literal token */
969 gs_ctype['('] = 3; /* string */
970 for (p = ")<>[]{}%"; *p != '\0'; ++p)
971 gs_ctype[(unsigned char) *p] = 4; /* delimiter */
972 }
973
974 static unsigned char
get_gs_character(struct gsfile * gsfp)975 get_gs_character(struct gsfile *gsfp)
976 {
977 unsigned char c;
978
979 for (;;) {
980 if (gsfp->bufpos >= gsfp->buf_end && !gs_fillbuf(gsfp))
981 return '%';
982 c = *gsfp->bufpos++;
983
984 /* Check for comments */
985 if (c == '%') {
986 for (;;) {
987 const unsigned char *p1, *p2;
988
989 p1 = memchr(gsfp->bufpos, '\n',
990 gsfp->buf_end - gsfp->bufpos);
991 if (p1 == NULL) p1 = gsfp->buf_end;
992 p2 = memchr(gsfp->bufpos, '\r', p1 - gsfp->bufpos);
993 if (p2 != NULL) p1 = p2;
994 p2 = memchr(gsfp->bufpos, '\f', p1 - gsfp->bufpos);
995 if (p2 != NULL) p1 = p2;
996 if (p1 < gsfp->buf_end) {
997 gsfp->bufpos = p1 + 1;
998 break;
999 }
1000 if (!gs_fillbuf(gsfp))
1001 return '%';
1002 }
1003 continue;
1004 }
1005
1006 if (gs_ctype[c] != 1)
1007 break;
1008 }
1009
1010 return c;
1011 }
1012
1013 static unsigned char
get_gs_token(struct gsfile * gsfp,unsigned int pos,unsigned int * pos_ret,const char * file_type)1014 get_gs_token(struct gsfile *gsfp,
1015 unsigned int pos,
1016 unsigned int *pos_ret,
1017 const char *file_type)
1018 {
1019 unsigned char gs_t_type;
1020 unsigned char c;
1021 const unsigned char *p0;
1022 unsigned int pos0;
1023 unsigned int depth;
1024
1025 gs_t_type = c = get_gs_character(gsfp);
1026 if (c == '%')
1027 return GS_EOF;
1028
1029 p0 = gsfp->bufpos;
1030 switch (gs_ctype[c]) {
1031 case 0: /* most characters */
1032 case 2: /* '/' */
1033 --p0; /* retain initial character */
1034 pos0 = pos;
1035 for (;;) {
1036 if (gsfp->bufpos >= gsfp->buf_end) {
1037 unsigned int len = gsfp->bufpos - p0;
1038
1039 if (pos + len >= ffline_len) expandline(pos + len);
1040 bcopy(p0, ffline + pos, len);
1041 pos += len;
1042 if (!gs_fillbuf(gsfp))
1043 break;
1044 p0 = gsfp->buffer;
1045 }
1046 if (gs_ctype[*gsfp->bufpos] != 0) {
1047 unsigned int len = gsfp->bufpos - p0;
1048
1049 if (pos + len >= ffline_len) expandline(pos + len);
1050 bcopy(p0, ffline + pos, len);
1051 pos += len;
1052 break;
1053 }
1054 ++gsfp->bufpos;
1055 }
1056 /* Filter out DOS ^Z */
1057 if (pos == pos0 + 1 && ffline[pos0] == '\032')
1058 return GS_EOF;
1059 break;
1060
1061 case 3: /* left parenthesis */
1062 depth = 1;
1063 for (;;) {
1064 const unsigned char *p1, *p2, *p3;
1065
1066 if (gsfp->bufpos >= gsfp->buf_end) {
1067 unsigned int len = gsfp->bufpos - p0;
1068
1069 if (pos + len >= ffline_len) expandline(pos + len);
1070 bcopy(p0, ffline + pos, len);
1071 pos += len;
1072 if (!gs_fillbuf(gsfp)) {
1073 TRACE_FT((stderr,
1074 "unterminated string in %s file; giving up.",
1075 file_type));
1076 return GS_ERR;
1077 }
1078 p0 = gsfp->buffer;
1079 }
1080 p1 = memchr(gsfp->bufpos, RPAREN,
1081 gsfp->buf_end - gsfp->bufpos);
1082 if (p1 == NULL) p1 = gsfp->buf_end;
1083 for (;;) {
1084 p2 = memchr(gsfp->bufpos, LPAREN, p1 - gsfp->bufpos);
1085 if (p2 == NULL) p2 = p1;
1086 p3 = p2;
1087 for (;;) {
1088 if (p3 <= gsfp->bufpos) {
1089 if (c == '\\') --p3;
1090 break;
1091 }
1092 if (p3[-1] != '\\') break;
1093 --p3;
1094 }
1095 c = '\\' - 1 + ((p2 - p3) & 1);
1096 if (p2 >= p1)
1097 break;
1098 if (c != '\\')
1099 ++depth;
1100 gsfp->bufpos = p2 + 1;
1101 c = '\0';
1102 }
1103 if (p1 < gsfp->buf_end) { /* if left parenthesis at p1 */
1104 if (c != '\\') {
1105 if (--depth == 0) {
1106 unsigned int len = p1 - p0;
1107
1108 if (pos + len >= ffline_len)
1109 expandline(pos + len);
1110 bcopy(p0, ffline + pos, len);
1111 pos += len;
1112 gsfp->bufpos = p1 + 1;
1113 break;
1114 }
1115 }
1116 ++p1;
1117 }
1118 gsfp->bufpos = p1;
1119 }
1120 /* We could do backslash escaping here, but it's probably
1121 unnecessary. */
1122 break;
1123
1124 default:
1125 TRACE_FT((stderr,
1126 "invalid character `%c' encountered in %s file; giving up.",
1127 c, file_type));
1128 return GS_ERR;
1129 }
1130
1131 *pos_ret = pos;
1132 return gs_t_type;
1133 }
1134
1135
1136 static short gs_fontmap_number = 0;
1137
1138 static void
process_gs_fontmap(FILE * f)1139 process_gs_fontmap(FILE *f)
1140 {
1141 struct gsfile gsf;
1142 unsigned char buffer[GS_BUF_SIZE];
1143 unsigned char ttype;
1144 unsigned int pos1, pos2, pos3;
1145
1146 ++gs_fontmap_number;
1147
1148 gsf.f = f;
1149 gsf.buffer = buffer;
1150 gsf.bufpos = gsf.buf_end = buffer + GS_BUF_SIZE;
1151
1152 /*
1153 * Allow entries of the following types:
1154 *
1155 * (string) .runlibfile
1156 * (string) .runlibfileifexists
1157 * /identifier (string) ;
1158 * /identifier /alias ;
1159 */
1160
1161 for (;;) {
1162 ttype = get_gs_token(&gsf, 0, &pos1, "Fontmap");
1163 if (ttype == GS_EOF || ttype == GS_ERR)
1164 break;
1165 if (ttype == LPAREN) {
1166 Boolean quiet = False;
1167 FILE *f1;
1168
1169 ttype = get_gs_token(&gsf, pos1, &pos2, "Fontmap");
1170 if (ttype == GS_ERR)
1171 break;
1172 if (ttype == GS_EOF) {
1173 TRACE_FT((stderr,
1174 "unexpected end of Fontmap file; giving up."));
1175 break;
1176 }
1177 if (ttype == '.' && pos2 - pos1 == 19
1178 && memcmp(ffline + pos1, ".runlibfileifexists", 19) == 0)
1179 quiet = True;
1180 else if (ttype != '.' || pos2 - pos1 != 11
1181 || memcmp(ffline + pos1, ".runlibfile", 11) != 0) {
1182 TRACE_FT((stderr, "invalid token following \"(%.*s)\" in Fontmap file; giving up.",
1183 (int) pos1, ffline));
1184 break;
1185 }
1186
1187 ffline[pos1] = '\0';
1188 if (ffline[0] == '/' || (ffline[0] == '.' && (ffline[1] == '/'
1189 || (ffline[1] == '.' && ffline[2] == '/'))))
1190 f1 = XFOPEN(ffline, OPEN_MODE);
1191 else {
1192 char *q;
1193
1194 q = xmemdup(ffline, pos1 + 1);
1195 f1 = gs_path_fopen(q, NULL);
1196 free(q);
1197 }
1198
1199 if (f1 == NULL) {
1200 if (!quiet)
1201 XDVI_WARNING((stderr, "Fontmap .runlibfile: %s: %s",
1202 ffline, strerror(errno)));
1203 else
1204 TRACE_FT((stderr,
1205 "Fontmap .runlibfileifexists: %s: %s\n",
1206 ffline, strerror(errno)));
1207 }
1208 else {
1209 --gs_fontmap_number;
1210 process_gs_fontmap(f1);
1211 }
1212 }
1213 else if (ttype == '/') {
1214 struct avl_gs *gsfp;
1215 struct gs_list *gslp;
1216
1217 ttype = get_gs_token(&gsf, pos1, &pos2, "Fontmap");
1218 if (ttype == GS_ERR)
1219 break;
1220 if (ttype == GS_EOF) {
1221 TRACE_FT((stderr,
1222 "unexpected end of Fontmap file; giving up."));
1223 break;
1224 }
1225 if ((ttype != '/' && ttype != LPAREN)
1226 || pos2 == pos1 /* empty string would mess things up */
1227 || get_gs_token(&gsf, pos2, &pos3, "Fontmap") != ';'
1228 || pos3 != pos2 + 1) {
1229 TRACE_FT((stderr,
1230 "invalid token following \"%.*s\" in Fontmap file; giving up.",
1231 (int) pos1, ffline));
1232 break;
1233 }
1234 if (ttype == '/')
1235 ffline[pos1] = '\0'; /* mark aliases by initial \0 */
1236 ffline[pos2++] = '\0'; /* terminate string */
1237
1238 /* Add to database */
1239 gsfp = (struct avl_gs *) avladd(ffline + 1, pos1 - 1,
1240 (struct avl **) &gs_head, sizeof *gsfp);
1241
1242 if (gsfp->key == ffline + 1) { /* if new record */
1243 gsfp->key = xmemdup(ffline + 1, pos1 - 1);
1244 gsfp->in_use = False;
1245 gsfp->list = NULL;
1246 }
1247 else {
1248 if (strlen(gsfp->list->value + 1) + 2 == pos2 - pos1
1249 && memcmp(gsfp->list->value, ffline + pos1, pos2 - pos1)
1250 == 0)
1251 continue; /* ignore duplicate entry */
1252 if (gsfp->fontmap_number == gs_fontmap_number) {
1253 /* Later entries in a Fontmap file override earlier
1254 ones */
1255 gslp = gsfp->list;
1256 gsfp->list = gslp->next;
1257 free(gslp);
1258 }
1259 }
1260 gslp = xmalloc(sizeof *gslp + pos2 - pos1);
1261 gslp->next = gsfp->list;
1262 gsfp->list = gslp;
1263 memcpy((char *) gslp->value, ffline + pos1, pos2 - pos1);
1264
1265 gsfp->fontmap_number = gs_fontmap_number;
1266 }
1267 else {
1268 TRACE_FT((stderr,
1269 "invalid token \"%s\" in Fontmap file; giving up.",
1270 ffline));
1271 }
1272 }
1273
1274 fclose(f);
1275 }
1276
1277 /*
1278 * Read Ghostscript Fontmap files. These are used if the line in
1279 * psfonts.map does not contain a filename for the font.
1280 *
1281 * For example:
1282 * n019003l NimbusSanL-Regu
1283 */
1284
1285 static void
read_gs_fontmaps(void)1286 read_gs_fontmaps(void)
1287 {
1288 env_gs_lib = getenv("XDVI_GS_LIB");
1289 if (env_gs_lib == NULL)
1290 env_gs_lib = getenv("GS_LIB");
1291
1292 if (gs_ctype[0] == 0)
1293 init_gs_ctype();
1294
1295 (void) gs_path_fopen("Fontmap", process_gs_fontmap);
1296 }
1297
1298
1299 /*
1300 * pre_lookup_t1_font - Find a Type 1 font (or return NULL).
1301 */
1302
1303 static struct avl_t1 *
pre_lookup_t1_font(const char * fontname)1304 pre_lookup_t1_font(const char *fontname)
1305 {
1306 struct avl_t1 *t1p;
1307 size_t len;
1308 int i;
1309
1310 /* first, search for the font */
1311
1312 len = strlen(fontname);
1313 t1p = t1_head;
1314 while (t1p != NULL) {
1315 i = len - t1p->key_len;
1316 if (i == 0)
1317 i = memcmp(fontname, t1p->key, len);
1318 if (i == 0)
1319 return t1p; /* found it */
1320 t1p = (struct avl_t1 *) (i < 0 ? t1p->left : t1p->right);
1321 }
1322
1323 /* next, read in more records in hopes of finding the font */
1324
1325 if (p_head != NULL)
1326 for (;;) {
1327 if (!fgets_long(mapfile)) { /* if end of file */
1328 fclose(mapfile);
1329 p_head = p_head->next;
1330 if (!open_next_mapfile())
1331 return NULL;
1332 continue;
1333 }
1334
1335 if (*ffline < ' ' || *ffline == '*' || *ffline == '#'
1336 || *ffline == ';' || *ffline == '%')
1337 continue;
1338
1339 t1p = dvips_parse(ffline);
1340
1341 if (t1p != NULL && t1p->key_len == len
1342 && memcmp(t1p->key, fontname, len) == 0)
1343 return t1p; /* found it */
1344 }
1345
1346 return NULL;
1347 }
1348
1349 /*
1350 * lookup_t1_font - Find a Type 1 font (or return NULL).
1351 */
1352
1353 Boolean
lookup_t1_font(struct font * fontp,const char * fontname)1354 lookup_t1_font(struct font *fontp,
1355 const char *fontname)
1356 {
1357 struct avl_t1 *t1p;
1358 struct ftfont *ftp;
1359
1360 t1p = pre_lookup_t1_font(fontname);
1361
1362 if (t1p == NULL)
1363 return False;
1364
1365 if (t1p->bad) {
1366 TRACE_FT((stderr,
1367 "Font %s is marked as bad: skipping scalable version",
1368 fontname));
1369 return False;
1370 }
1371
1372 ftp = t1p->ft;
1373 if (ftp != NULL) { /* if it's is already in use at another size */
1374 struct font *first_size;
1375
1376 /* The first node in the linked list of sizes contains the file */
1377 /* reference, so we link in the new node after the first node */
1378 first_size = ftp->first_size;
1379 fontp->next_size = first_size->next_size;
1380 first_size->next_size = fontp;
1381 }
1382 else { /* first use at this size */
1383 t1p->ft = ftp = xmalloc(sizeof *ftp);
1384 ftp->face = NULL;
1385 ftp->t1 = t1p;
1386 ftp->first_size = fontp;
1387 fontp->next_size = NULL;
1388 }
1389 fontp->ft = ftp;
1390 fontp->size = NULL;
1391
1392 return True;
1393 }
1394
1395 FILE *
open_t1_font(struct avl_t1 * t1p,const char ** path_ret)1396 open_t1_font(struct avl_t1 *t1p,
1397 const char **path_ret)
1398 {
1399 FILE *f;
1400
1401 if (t1p->fontfile == NULL) { /* look up in GS Fontmap */
1402 static Boolean gs_fontmap_initialized = False;
1403
1404 if (!gs_fontmap_initialized) {
1405 read_gs_fontmaps();
1406 gs_fontmap_initialized = True;
1407 }
1408
1409 TRACE_FT((stderr,
1410 "Looking for font %.*s using gs method (PS name %s) --",
1411 t1p->key_len, t1p->key, t1p->psname));
1412 f = lookup_gs_font(t1p->psname, path_ret);
1413
1414 if (f == NULL) {
1415 TRACE_FT((stderr, "cannot find Type 1 font %s",
1416 t1p->psname));
1417 return NULL;
1418 }
1419
1420 TRACE_FT((stderr, "Found file %s", *path_ret));
1421 }
1422 else {
1423 char *filename;
1424
1425 filename = kpse_find_file(t1p->fontfile, kpse_type1_format, 0);
1426 if (filename == NULL) {
1427 TRACE_FT((stderr, "cannot find Type 1 font file %s "
1428 "(will try PK version instead).",
1429 t1p->fontfile));
1430 return NULL;
1431 }
1432
1433 f = XFOPEN(filename, OPEN_MODE);
1434 if (f == NULL) {
1435 TRACE_FT((stderr, "cannot open Type 1 font file %s: %s",
1436 filename, strerror(errno)));
1437 free(filename);
1438 return NULL;
1439 }
1440 *path_ret = filename;
1441 }
1442
1443 return f;
1444 }
1445
1446
1447 /*
1448 * Read the encoding vector file. This assumes the same format as afm2tfm.
1449 */
1450
1451 extern struct findrec search_header; /* from special.c */
1452
1453 void
read_encoding(struct avl_enc * encp)1454 read_encoding(struct avl_enc *encp)
1455 {
1456 char *filename;
1457 FILE *f;
1458 struct gsfile gsf;
1459 unsigned char buffer[GS_BUF_SIZE];
1460 jmp_buf err_env;
1461 unsigned char ttype;
1462 unsigned int pos1, pos2;
1463 unsigned int identindex[256];
1464 const char *str;
1465 unsigned int i;
1466
1467 TRACE_FT((stderr, "Reading encoding file %s", encp->key));
1468
1469 encp->valid = False;
1470
1471 /*
1472 * With TDS 1.0/kpathsea 3.5.2(?), encoding files are in texmf/fonts/enc
1473 * and accessed via kpse_enc_format; see e.g.:
1474 * http://tug.org/mailman/htdig/tex-live/2004-January/004734.html
1475 *
1476 * The lookups under kpse_program_text_format and
1477 * kpse_tex_ps_header_format are kept for backwards compatibility.
1478 */
1479
1480 filename = kpse_find_file(encp->key, kpse_enc_format, 0);
1481 if (filename == NULL) {
1482 filename = kpse_find_file(filename, kpse_program_text_format, 0);
1483 if (filename == NULL)
1484 filename = kpse_find_file(filename, kpse_tex_ps_header_format,
1485 True);
1486 }
1487 if (filename == NULL) {
1488 TRACE_FT((stderr,
1489 "cannot find encoding file %s; ignoring encoding", encp->key));
1490 return;
1491 }
1492
1493 f = XFOPEN(filename, OPEN_MODE);
1494 if (f == NULL) {
1495 TRACE_FT((stderr, "cannot open encoding file %s: %s",
1496 filename, strerror(errno)));
1497 free(filename);
1498 return;
1499 }
1500 free(filename);
1501
1502 if (gs_ctype[0] == 0)
1503 init_gs_ctype();
1504
1505 gsf.f = f;
1506 gsf.buffer = buffer;
1507 gsf.bufpos = gsf.buf_end = buffer + GS_BUF_SIZE;
1508
1509 if (!setjmp(err_env)) {
1510 if (get_gs_token(&gsf, 0, &pos1, "encoding") != '/'
1511 || get_gs_character(&gsf) != '[')
1512 longjmp(err_env, 1);
1513
1514 pos1 = 0;
1515 for (i = 0; i < 256; ++i) {
1516 if (get_gs_token(&gsf, pos1, &pos2, "encoding") != '/')
1517 longjmp(err_env, 1);
1518 if (pos2 == pos1 + 8
1519 && memcmp(ffline + pos1, "/.notdef", 8) == 0)
1520 identindex[i] = 0;
1521 else {
1522 ffline[pos1] = '\0';
1523 identindex[i] = pos1 + 1;
1524 pos1 = pos2;
1525 }
1526 }
1527
1528 if (get_gs_character(&gsf) != ']')
1529 longjmp(err_env, 1);
1530
1531 ttype = get_gs_token(&gsf, pos1, &pos2, "encoding");
1532 if (!(ttype == GS_EOF
1533 || (ttype == 'd' && pos2 == pos1 + 3
1534 && memcmp(ffline + pos1, "def", 3) == 0
1535 && get_gs_token(&gsf, pos2, &pos2, "encoding") == GS_EOF)))
1536 longjmp(err_env, 1);
1537
1538 if (pos1 >= ffline_len) expandline(pos1 + 1);
1539 ffline[pos1] = '\0';
1540 str = xmemdup(ffline + 1, pos1);
1541 for (i = 0; i < 256; ++i)
1542 encp->vec[i] =
1543 (identindex[i] != 0 ? str + identindex[i] - 1 : NULL);
1544
1545 encp->valid = True;
1546 }
1547 else /* if error */
1548 TRACE_FT((stderr,
1549 "invalid format in encoding file %s; giving up.", encp->key));
1550
1551 fclose(f);
1552 }
1553
1554 #endif /* FREETYPE || PS */
1555
1556
1557 #if 0
1558 static int mktexpk_io[2];
1559 static struct xchild mktexpk_child = { NULL, 0, True, "font creation", NULL, NULL, mktexpk_ended };
1560
1561 static char *read_from_mktexpk(int ignored);
1562 static void write_to_mktexpk(int ignored);
1563
1564 static struct xio mktexpk_xio = { NULL, 0, XIO_IN,
1565 #if HAVE_POLL
1566 NULL,
1567 #endif
1568 read_from_mktexpk,
1569 NULL, NULL};
1570
1571
1572 static void
1573 mktexpk_ended(int status, struct xchild *this)
1574 {
1575 char str[1024] = "";
1576 char *err_msg = NULL;
1577
1578 fprintf(stderr, "------- MKTEXPK_ENDED!\n");
1579 if (this->io != NULL && WIFEXITED(status)) {
1580 err_msg = (this->io->read_proc)(this->io->fd, NULL);
1581 SNPRINTF(str, 1024, "\nProcess `%s' returned exit code %d.\n",
1582 this->name, WEXITSTATUS(status));
1583 str[1024 - 1] = '\0';
1584 printlog_append_str(str);
1585 if (err_msg != NULL) {
1586 fprintf(stderr, "FROM MKTEXPK: |%s|\n", err_msg);
1587 printlog_append_str(err_msg);
1588 }
1589 }
1590 printlog_enable_closebutton();
1591 /* free(this->name); */
1592 /* free(this->io); */
1593 /* free(this); */
1594
1595 read_from_mktexpk(0);
1596 clear_io(this->io);
1597 (void)close(mktexpk_xio.fd);
1598
1599 if (WIFEXITED(status)) {
1600 if (WEXITSTATUS(status) == 0) {
1601 printlog_append("Done.\n", strlen("Done.\n"));
1602 }
1603 else
1604 sprintf(str, "\nPrint process returned exit code %d.\n",
1605 WEXITSTATUS(status));
1606 }
1607 else if (WIFSIGNALED(status))
1608 sprintf(str, "\nPrint process terminated by signal %d.\n",
1609 WTERMSIG(status));
1610 else
1611 sprintf(str, "\nPrint process returned unknown status 0x%x.\n",
1612 status);
1613
1614
1615 }
1616
1617 static char *
1618 read_from_mktexpk(int fd)
1619 {
1620 int bytes;
1621 char line[80];
1622 char *buf;
1623
1624 fprintf(stderr, "------- READ_FROM_MKTEXPK!\n");
1625 for (;;) {
1626 #ifndef MOTIF
1627 bytes = read(fd, line, sizeof line);
1628 #else
1629 bytes = read(fd, line, sizeof line - 1);
1630 #endif
1631 if (bytes < 0) {
1632 if (AGAIN_CONDITION)
1633 break;
1634 perror("xdvi: read_from_mktexpk");
1635 break;
1636 }
1637
1638 if (bytes == 0)
1639 break;
1640 else {
1641 #ifdef MOTIF
1642 line[bytes] = '\0';
1643 #endif
1644 fprintf(stderr, "------- READ_FROM_MKTEXPK:|%s|\n", line);
1645 printlog_append(line, bytes);
1646 }
1647 }
1648 buf = xmalloc(bytes + 1);
1649 memcpy(buf, line, bytes);
1650 buf[bytes] = '\0';
1651 return buf;
1652 }
1653
1654 static void
1655 write_to_mktexpk(int ignored)
1656 {
1657 UNUSED(ignored);
1658
1659 return;
1660 }
1661 #endif /* 0 */
1662
1663
1664 #if DELAYED_MKTEXPK
1665
1666 /* hash table for names of missing fonts, and their indexes */
1667 static hashTableT missing_font_hash;
1668
1669 /* counters for missing fonts */
1670 static int missing_font_ctr = 0;
1671 static int missing_font_curr = 0;
1672
1673 static const char *const dummy_font_value = ""; /* used as value in hash table of missing fonts ... */
1674
1675 /* static char **all_fonts = NULL; */
1676 /* static size_t all_fonts_size = 0; */
1677
1678 void
reset_missing_font_count(void)1679 reset_missing_font_count(void)
1680 {
1681 missing_font_ctr = missing_font_curr = 0;
1682 }
1683
1684 /* Register font `fname' at size `dpi' as a font for which we'll need
1685 * to create a PK file
1686 */
1687 static void
add_missing_font(const char * fname,int dpi)1688 add_missing_font(const char *fname, int dpi)
1689 {
1690 char *buf = NULL;
1691
1692 if (missing_font_hash.size == 0) {
1693 missing_font_hash = hash_create(197);
1694 }
1695
1696 /* font name (hash key) needs to be dynamically allocated here */
1697 buf = xmalloc(strlen(fname) + strlen(" at ") + LENGTH_OF_INT + 1);
1698 sprintf(buf, "%s at %d", fname, dpi);
1699 if (hash_lookup(missing_font_hash, buf) == NULL) {
1700 missing_font_ctr++;
1701 hash_insert(&missing_font_hash, buf, dummy_font_value);
1702 }
1703 }
1704
1705 /* Check if font `fname' at size `dpi' is in the hash of fonts for which
1706 * we need to create a PK file. If it is, return its index (>= 0) and delete
1707 * it from the hash table; else, return -1.
1708 */
1709 static Boolean
get_and_remove_missing_font(const char * fname,int dpi)1710 get_and_remove_missing_font(const char *fname, int dpi)
1711 {
1712 char buf[1024];
1713
1714 if (missing_font_hash.size == 0)
1715 return False;
1716
1717 SNPRINTF(buf, 1024, "%s at %d", fname, dpi);
1718 buf[1023] = '\0';
1719 if (hash_lookup(missing_font_hash, buf) == NULL) {
1720 return False;
1721 }
1722
1723 hash_remove(&missing_font_hash, buf, dummy_font_value);
1724 return True;
1725 }
1726
1727
1728 static Boolean
message_font_creation(const char * fname,int dpi)1729 message_font_creation(const char *fname, int dpi)
1730 {
1731 if (get_and_remove_missing_font(fname, dpi)) {
1732 missing_font_curr++;
1733 statusline_info(STATUS_MEDIUM,
1734 "Creating PK font: %s at %d dpi (%d of %d) ...",
1735 fname,
1736 dpi,
1737 missing_font_curr,
1738 missing_font_ctr);
1739 force_statusline_update();
1740 return True;
1741 }
1742 return False;
1743 }
1744 #endif /* DELAYED_MKTEXPK */
1745
1746 FILE *
font_open(Boolean load_font_now,struct font * fontp,const char ** font_ret,int * dpi_ret)1747 font_open(
1748 #if DELAYED_MKTEXPK
1749 Boolean load_font_now,
1750 #endif
1751 struct font *fontp,
1752 const char **font_ret,
1753 int *dpi_ret)
1754 {
1755 char *name = NULL;
1756 kpse_glyph_file_type file_ret;
1757 #if DELAYED_MKTEXPK
1758 Boolean message_done = False;
1759 Boolean need_statusline_update = False;
1760 #endif
1761 /* defaults in case of success; filename_ret will be
1762 non-NULL iff the fallback font is used.
1763 */
1764 *font_ret = NULL;
1765 /* filename_ret is NULL iff a T1 version of a font has been used */
1766 fontp->filename = NULL;
1767 *dpi_ret = fontp->fsize;
1768
1769 #ifdef PTEX
1770 /* for kanji, first try jfm's, then 8-bit vf's (not 16bit ovf's). */
1771 if (iskanjifont(fontp->fontname))
1772 name = kpse_find_tfm(fontp->fontname);
1773 else
1774 #endif /* PTEX */
1775 if (resource.omega) { /* for omega, first try 16-bit ovf's, then 8-bit vf's. */
1776 name = kpse_find_ovf(fontp->fontname);
1777 if (name == NULL)
1778 name = kpse_find_vf(fontp->fontname);
1779 }
1780 else {
1781 name = kpse_find_vf(fontp->fontname);
1782 }
1783
1784 if (name) { /* found a vf font */
1785 /* pretend it has the expected dpi value, else caller will complain */
1786 *dpi_ret = fontp->fsize;
1787 fontp->filename = name;
1788 return XFOPEN(name, FOPEN_R_MODE);
1789 }
1790
1791 #if FREETYPE
1792 if (resource.freetype
1793 # if DELAYED_MKTEXPK
1794 && load_font_now
1795 # endif
1796 ) {
1797 /* First attempt: freetype font of correct size
1798 * (for delayed_mtkexpk, only when scanning postamble for the first time)
1799 */
1800 if (lookup_t1_font(fontp, fontp->fontname)) {
1801 TRACE_FT((stderr, "found freetype font %s", fontp->fontname));
1802 return NULL;
1803 }
1804 TRACE_FT((stderr,
1805 "Freetype version of font %s not found, trying pixel version next, then fallback",
1806 fontp->fontname));
1807 }
1808 #endif /* FREETYPE */
1809
1810
1811 /*
1812 TODO:
1813
1814 Probably a better approach would be as follows:
1815
1816 1. Read the postamble to get all font definitions. Then, set:
1817
1818 kpse_set_program_enabled(kpse_any_glyph_format, False, kpse_src_compile);
1819
1820 and run load_font() on all of the fonts, with an array in which to save
1821 the names that don't exist (that returned NULL).
1822
1823 2. Run load_font() again on the fonts that didn't exist in step
1824 (1) and display the output in a window. This somehow needs to
1825 be fork()ed so that the window itself remains responsive.
1826 (Maybe it's easier to call mktexpk directly on the command-line?)
1827
1828 _________________________________________________________
1829 | |
1830 | Xdvi is creating fonts, please be patient ... |
1831 | |
1832 | Font xyz (n of m) |
1833 | |
1834 | Errors: 0 [ Show Details ... ] |
1835 | |
1836 | [ ... some progress meter or busy indicator ... ] |
1837 | |
1838 | |
1839 | [ Exit xdvi ] [ Help ] |
1840 | |
1841 ---------------------------------------------------------
1842
1843 This window can be shown before the main window is opened.
1844
1845 */
1846
1847 /* Second try: PK/GF/... font within allowable size range */
1848 /*
1849 NOTE SU: The problem with this is that it will already use the PK version
1850 of the fallback font (e.g. cmr10.600pk) if the PK version exists, so the
1851 Type1 version of the fallback won't get used at all. But maybe this isn't
1852 that severe, given that the font is grossly wrong anyway.
1853 */
1854 #if DELAYED_MKTEXPK
1855 if (load_font_now) {
1856 fprintf(stderr, "loading font now\n");
1857 if (message_font_creation(fontp->fontname, (int)(fontp->fsize + 0.5))) {
1858 message_done = True;
1859 name = kpse_find_glyph(fontp->fontname, (unsigned)(fontp->fsize + .5),
1860 kpse_any_glyph_format, &file_ret);
1861 }
1862 else {
1863 kpse_set_program_enabled(kpse_any_glyph_format, False, kpse_src_compile);
1864 name = kpse_find_glyph(fontp->fontname, (unsigned)(fontp->fsize + .5),
1865 kpse_any_glyph_format, &file_ret);
1866 /* no success if either name is NULL or the filename returned in file_ret is
1867 a different font */
1868 #if 1
1869 /* ??? Bug with tex/test2.tex if cmbr exists but cmr doesn't ??? */
1870 fprintf(stderr, "creating %s\n", fontp->fontname);
1871 if (!name || strcmp(file_ret.name, fontp->fontname) != 0) {
1872 statusline_info(STATUS_MEDIUM,
1873 "Creating PK font: %s at %d dpi ...",
1874 fontp->fontname,
1875 (int)(fontp->fsize + 0.5));
1876 need_statusline_update = True;
1877 force_statusline_update();
1878 kpse_set_program_enabled(kpse_any_glyph_format, resource.makepk, kpse_src_compile);
1879 name = kpse_find_glyph(fontp->fontname, (unsigned)(fontp->fsize + .5),
1880 kpse_any_glyph_format, &file_ret);
1881 }
1882 #endif
1883 }
1884 }
1885 else {
1886 name = kpse_find_glyph(fontp->fontname, (unsigned)(fontp->fsize + .5),
1887 kpse_any_glyph_format, &file_ret);
1888 }
1889 #else /* DELAYED_MKTEXPK */
1890 name = kpse_find_glyph(fontp->fontname, (unsigned)(fontp->fsize + .5),
1891 kpse_any_glyph_format, &file_ret);
1892 #endif /* DELAYED_MKTEXPK */
1893
1894 if (name) { /* success */
1895 #if DELAYED_MKTEXPK
1896 if (need_statusline_update) {
1897 statusline_info(STATUS_SHORT, "Creating PK font: %s at %d dpi ... done",
1898 fontp->fontname,
1899 (int)(fontp->fsize + 0.5));
1900 force_statusline_update();
1901 }
1902 #endif
1903 *dpi_ret = file_ret.dpi;
1904 fontp->filename = name;
1905 *font_ret = file_ret.name;
1906 TRACE_FT((stderr, "Found pixel version: %s at %d dpi", file_ret.name, *dpi_ret));
1907 #if DELAYED_MKTEXPK
1908 if (message_done) {
1909 statusline_append(STATUS_VERYSHORT, "DUMMY", /* append text, don't overwrite */
1910 "done.");
1911 force_statusline_update();
1912 }
1913 #endif
1914 return XFOPEN(name, FOPEN_R_MODE);
1915 }
1916 #if DELAYED_MKTEXPK
1917 else if (!load_font_now) {
1918 add_missing_font(fontp->fontname, (int)(fontp->fsize + 0.5));
1919 return NULL;
1920 }
1921 #endif
1922 else if (resource.alt_font != NULL) {
1923 /* The strange thing about kpse_find_glyph() is that it
1924 won't create a PK version of alt_font if it doesn't
1925 already exist. So we invoke it explicitly a second time
1926 for that one.
1927 */
1928 TRACE_FT((stderr, "Trying fallback"));
1929 #if FREETYPE
1930 if (resource.freetype
1931 #if DELAYED_MKTEXPK
1932 && load_font_now
1933 #endif
1934 ) {
1935 /* Third attempt: freetype version of fallback font */
1936 if (lookup_t1_font(fontp, resource.alt_font)) {
1937 TRACE_FT((stderr, "found fallback font for %s: %s",
1938 fontp->fontname, resource.alt_font));
1939 *font_ret = xstrdup(resource.alt_font);
1940 return NULL;
1941 }
1942 TRACE_FT((stderr,
1943 "Freetype version of fallback font %s not found, trying pixel version",
1944 resource.alt_font));
1945 }
1946 #endif /* FREETYPE */
1947 /* Fourth attempt: PK version of fallback font */
1948 name = kpse_find_glyph(resource.alt_font, (unsigned)(fontp->fsize + .5),
1949 kpse_any_glyph_format, &file_ret);
1950 if (name) { /* success */
1951 TRACE_FT((stderr, "Success for PK version of fallback"));
1952 *dpi_ret = file_ret.dpi;
1953 fontp->filename = name;
1954 *font_ret = xstrdup(resource.alt_font);
1955 return XFOPEN(name, FOPEN_R_MODE);
1956 }
1957 else {
1958 TRACE_FT((stderr, "Failure for PK version of fallback"));
1959 }
1960 }
1961
1962 /* all other cases are failure */
1963 TRACE_FT((stderr, "Failure"));
1964 return NULL;
1965 }
1966