fix default tfm reading
[mplib] / src / texk / web2c / mpdir / lib / psout.w
1 % $Id: mp.web,v 1.8 2005/08/24 10:54:02 taco Exp $
2 % MetaPost, by John Hobby.  Public domain.
3
4 % Much of this program was copied with permission from MF.web Version 1.9
5 % It interprets a language very similar to D.E. Knuth's METAFONT, but with
6 % changes designed to make it more suitable for PostScript output.
7
8 % TeX is a trademark of the American Mathematical Society.
9 % METAFONT is a trademark of Addison-Wesley Publishing Company.
10 % PostScript is a trademark of Adobe Systems Incorporated.
11
12 % Here is TeX material that gets inserted after \input webmac
13 \def\hang{\hangindent 3em\noindent\ignorespaces}
14 \def\textindent#1{\hangindent2.5em\noindent\hbox to2.5em{\hss#1 }\ignorespaces}
15 \def\PASCAL{Pascal}
16 \def\ps{PostScript}
17 \def\ph{\hbox{Pascal-H}}
18 \def\psqrt#1{\sqrt{\mathstrut#1}}
19 \def\k{_{k+1}}
20 \def\pct!{{\char`\%}} % percent sign in ordinary text
21 \font\tenlogo=logo10 % font used for the METAFONT logo
22 \font\logos=logosl10
23 \def\MF{{\tenlogo META}\-{\tenlogo FONT}}
24 \def\MP{{\tenlogo META}\-{\tenlogo POST}}
25 \def\<#1>{$\langle#1\rangle$}
26 \def\section{\mathhexbox278}
27 \let\swap=\leftrightarrow
28 \def\round{\mathop{\rm round}\nolimits}
29 \mathchardef\vb="026A % synonym for `\|'
30 \def\[#1]{} % from pascal web
31 \def\(#1){} % this is used to make section names sort themselves better
32 \def\9#1{} % this is used for sort keys in the index via @@:sort key}{entry@@>
33
34 \let\?=\relax % we want to be able to \write a \?
35
36 \def\title{MetaPost \ps\ output}
37 \def\topofcontents{\hsize 5.5in
38   \vglue -30pt plus 1fil minus 1.5in
39   \def\?##1]{\hbox to 1in{\hfil##1.\ }}
40   }
41 \def\botofcontents{\vskip 0pt plus 1fil minus 1.5in}
42 \pdfoutput=1
43 \pageno=3
44
45
46 @d true 1
47 @d false 0
48 @d null_font 0
49 @d print_err(A) mp_print_err(mp,(A))
50 @d negate(A)   (A)=-(A) /* change the sign of a variable */
51
52 @c
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <stdarg.h>
57 #include <assert.h>
58 #include "avl.h"
59 #include "mplib.h"
60 #include "mpmp.h" /* internal header */
61 #include "mppsout.h" /* internal header */
62 @h
63 @<Declarations@>;
64 @<Static variables in the outer block@>;
65
66 @ There is a small bit of code from the backend that bleads through
67 to the frontend because I do not know how to set up the includes
68 properly. Those are the definitions of |struct libavl_allocator|
69 and |typedef struct psout_data_struct * psout_data|.
70
71 The |libavl_allocator| is a trick that makes sure that frontends 
72 do not need |avl.h|, and the |psout_data| is needed for the backend 
73 data structure.
74
75 @ @(mppsout.h@>=
76 @<Types...@>;
77 typedef struct psout_data_struct {
78   @<Globals@>;
79 } psout_data_struct ;
80 @<Exported function headers@>
81
82 @ @<Exported function headers@>=
83 void mp_backend_initialize (MP mp) ;
84 void mp_backend_free (MP mp) ;
85
86 @
87 @c void mp_backend_initialize (MP mp) {
88   mp->ps = mp_xmalloc(1,sizeof(psout_data_struct));
89   @<Set initial values@>;
90 }
91 void mp_backend_free (MP mp) {
92   @<Dealloc variables@>;
93   enc_free(mp);
94   t1_free(mp);
95   fm_free(mp);
96   mp_xfree(mp->ps);
97   mp->ps = NULL;
98 }
99
100
101 @* Traditional {psfonts.map} loading.
102
103 TODO: It is likely that this code can be removed after a few minor tweaks.
104
105 @ The file |ps_tab_file| gives a table of \TeX\ font names and corresponding
106 PostScript names for fonts that do not have to be downloaded, i.e., fonts that
107 can be used when |internal[prologues]>0|.  Each line consists of a \TeX\ name,
108 one or more spaces, a PostScript name, and possibly a space and some other junk.
109 This routine reads the table, updates |font_ps_name| entries starting after
110 |last_ps_fnum|, and sets |last_ps_fnum:=last_fnum|.  If the file |ps_tab_file|
111 is missing, we assume that the existing font names are OK and nothing needs to
112 be done.
113
114 @d ps_tab_name "psfonts.map"  /* locates font name translation table */
115
116 @<Exported ...@>=
117 void mp_read_psname_table (MP mp) ;
118
119 @ @c void mp_read_psname_table (MP mp) {
120   font_number k; /* font for possible name match */
121   unsigned int lmax; /* upper limit on length of name to match */
122   unsigned int j; /* characters left to read before string gets too long */
123   char *s; /* possible font name to match */
124   text_char c=0; /* character being read from |ps_tab_file| */
125   if ( (mp->ps->ps_tab_file = mp_open_file(mp, ps_tab_name, "r", mp_filetype_fontmap)) ) {
126     @<Set |lmax| to the maximum |font_name| length for fonts
127       |last_ps_fnum+1| through |last_fnum|@>;
128     while (! feof(mp->ps->ps_tab_file) ) {
129       @<Read at most |lmax| characters from |ps_tab_file| into string |s|
130         but |goto common_ending| if there is trouble@>;
131       for (k=mp->last_ps_fnum+1;k<=mp->last_fnum;k++) {
132         if ( mp_xstrcmp(s,mp->font_name[k])==0 ) {
133           @<|flush_string(s)|, read in |font_ps_name[k]|, and
134             |goto common_ending|@>;
135         }
136       }
137       mp_xfree(s);
138     COMMON_ENDING:
139       c = fgetc(mp->ps->ps_tab_file);
140           if (c=='\r') {
141         c = fgetc(mp->ps->ps_tab_file);
142         if (c!='\n') 
143           ungetc(c,mp->ps->ps_tab_file);
144       }
145     }
146     mp->last_ps_fnum=mp->last_fnum;
147     fclose(mp->ps->ps_tab_file);
148   }
149 }
150
151 @ @<Glob...@>=
152 FILE * ps_tab_file; /* file for font name translation table */
153
154 @ @<Set |lmax| to the maximum |font_name| length for fonts...@>=
155 lmax=0;
156 for (k=mp->last_ps_fnum+1;k<=mp->last_fnum;k++) {
157   if (strlen(mp->font_name[k])>lmax ) 
158     lmax=strlen(mp->font_name[k]);
159 }
160
161 @ If we encounter the end of line before we have started reading
162 characters from |ps_tab_file|, we have found an entirely blank 
163 line and we skip over it.  Otherwise, we abort if the line ends 
164 prematurely.  If we encounter a comment character, we also skip 
165 over the line, since recent versions of \.{dvips} allow comments
166 in the font map file.
167
168 TODO: this is probably not safe in the case of a really 
169 broken font map file.
170
171 @<Read at most |lmax| characters from |ps_tab_file| into string |s|...@>=
172 s=mp_xmalloc(lmax+1,1);
173 j=0;
174 while (1) { 
175   if (c == '\n' || c == '\r' ) {
176     if (j==0) {
177       mp_xfree(s); s=NULL; goto COMMON_ENDING;
178     } else {
179       mp_fatal_error(mp, "The psfont map file is bad!");
180     }
181   }
182   c = fgetc(mp->ps->ps_tab_file);
183   if (c=='%' || c=='*' || c==';' || c=='#' ) {
184     mp_xfree(s); s=NULL; goto COMMON_ENDING;
185   }
186   if (c==' ' || c=='\t') break;
187   if (j<lmax) {
188    s[j++] = mp->xord[c];
189   } else { 
190     mp_xfree(s); s=NULL; goto COMMON_ENDING;
191   }
192 }
193 s[j]=0
194
195 @ PostScript font names should be at most 28 characters long but we allow 32
196 just to be safe.
197
198 @<|flush_string(s)|, read in |font_ps_name[k]|, and...@>=
199
200   char *ps_name =NULL;
201   mp_xfree(s);
202   do {  
203     if (c=='\n' || c == '\r') 
204       mp_fatal_error(mp, "The psfont map file is bad!");
205     c = fgetc(mp->ps->ps_tab_file);
206   } while (c==' ' || c=='\t');
207   ps_name = mp_xmalloc(33,1);
208   j=0;
209   do {  
210     if (j>31) {
211       mp_fatal_error(mp, "The psfont map file is bad!");
212     }
213     ps_name[j++] = mp->xord[c];
214     if (c=='\n' || c == '\r')
215       c=' ';  
216     else 
217       c = fgetc(mp->ps->ps_tab_file);
218   } while (c != ' ' && c != '\t');
219   ps_name[j]= 0;
220   mp_xfree(mp->font_ps_name[k]);
221   mp->font_ps_name[k]=ps_name;
222   goto COMMON_ENDING;
223 }
224
225
226
227 @* \[44a] Dealing with font encodings.
228
229 First, here are a few helpers for parsing files
230
231 @d check_buf(size, buf_size)
232     if ((unsigned)(size) > (unsigned)(buf_size)) {
233       char s[128];
234       snprintf(s,128,"buffer overflow: (%d,%d) at file %s, line %d",
235                size,buf_size, __FILE__,  __LINE__ );
236       mp_fatal_error(mp,s);
237     }
238
239 @d append_char_to_buf(c, p, buf, buf_size) do {
240     if (c == 9)
241         c = 32;
242     if (c == 13 || c == EOF)
243         c = 10;
244     if (c != ' ' || (p > buf && p[-1] != 32)) {
245         check_buf(p - buf + 1, (buf_size));
246         *p++ = c; 
247     }
248 } while (0)
249
250 @d append_eol(p, buf, buf_size) do {
251     check_buf(p - buf + 2, (buf_size));
252     if (p - buf > 1 && p[-1] != 10)
253         *p++ = 10;
254     if (p - buf > 2 && p[-2] == 32) {
255         p[-2] = 10;
256         p--;
257     }
258     *p = 0;
259 } while (0)
260
261 @d remove_eol(p, buf) do {
262     p = strend(buf) - 1;
263     if (*p == 10)
264         *p = 0;
265 } while (0)
266
267 @d skip(p, c)   if (*p == c)  p++
268 @d strend(s)    strchr(s, 0)
269 @d str_prefix(s1, s2)  (strncmp((s1), (s2), strlen(s2)) == 0)
270
271
272 @ @<Types...@>=
273 typedef struct {
274     boolean loaded;             /* the encoding has been loaded? */
275     char *file_name;                 /* encoding file name */
276     char *enc_name;              /* encoding true name */
277     integer objnum;             /* object number */
278     char **glyph_names;
279     integer tounicode;          /* object number of associated ToUnicode entry */
280 } enc_entry;
281
282
283
284
285 @d ENC_STANDARD  0
286 @d ENC_BUILTIN   1
287
288 @<Glob...@>=
289 #define ENC_BUF_SIZE  0x1000
290 char enc_line[ENC_BUF_SIZE];
291 FILE *enc_file;
292
293
294 @d enc_getchar()   getc(mp->ps->enc_file)
295 @d enc_eof()       feof(mp->ps->enc_file)
296 @d enc_close()     fclose(mp->ps->enc_file)
297
298 @c 
299 boolean mp_enc_open (MP mp, char *n) {
300   mp->ps->enc_file=mp_open_file(mp, n, "rb", mp_filetype_encoding);
301   if (mp->ps->enc_file!=NULL)
302     return true;
303   else
304    return false;
305 }
306 void mp_enc_getline (MP mp) {
307   char *p;
308   int c;
309 RESTART:
310   if (enc_eof ()) {
311     print_err("unexpected end of file");
312     mp_error(mp);
313   }
314   p = mp->ps->enc_line;
315   do {
316     c = enc_getchar ();
317     append_char_to_buf (c, p, mp->ps->enc_line, ENC_BUF_SIZE);
318   } while (c != 10);
319   append_eol (p, mp->ps->enc_line, ENC_BUF_SIZE);
320   if (p - mp->ps->enc_line < 2 || *mp->ps->enc_line == '%')
321     goto RESTART;
322 }
323 void mp_load_enc (MP mp, char *enc_name, 
324                   char **enc_encname, char **glyph_names){
325   char buf[ENC_BUF_SIZE], *p, *r;
326   int names_count;
327   char *myname;
328   int save_selector = mp->selector;
329   if (!mp_enc_open (mp,enc_name)) {
330       mp_print (mp,"cannot open encoding file for reading");
331       return;
332   }
333   mp_normalize_selector(mp);
334   mp_print (mp,"{");
335   mp_print (mp, enc_name);
336   mp_enc_getline (mp);
337   if (*mp->ps->enc_line != '/' || (r = strchr (mp->ps->enc_line, '[')) == NULL) {
338     remove_eol (r, mp->ps->enc_line);
339     print_err ("invalid encoding vector (a name or `[' missing): `");
340     mp_print(mp,mp->ps->enc_line);
341     mp_print(mp,"'");
342     mp_error(mp);
343   }
344   while (*(r-1)==' ') r--; /* strip trailing spaces from encoding name */
345   myname = mp_xmalloc(r-mp->ps->enc_line,1);
346   memcpy(myname,mp->ps->enc_line+1,(r-mp->ps->enc_line)-1);
347   *(myname+(r-mp->ps->enc_line-1))=0;
348   *enc_encname = myname;
349   while (*r!='[') r++;
350   r++;                        /* skip '[' */
351   names_count = 0;
352   skip (r, ' ');
353   for (;;) {
354     while (*r == '/') {
355       for (p = buf, r++;
356            *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++);
357         *p = 0;
358       skip (r, ' ');
359       if (names_count > 256) {
360         print_err ("encoding vector contains more than 256 names");
361         mp_error(mp);
362       }
363       if (mp_xstrcmp (buf, notdef) != 0)
364         glyph_names[names_count] = mp_xstrdup (buf);
365       names_count++;
366     }
367     if (*r != 10 && *r != '%') {
368       if (str_prefix (r, "] def"))
369         goto DONE;
370       else {
371         remove_eol (r, mp->ps->enc_line);
372         print_err
373           ("invalid encoding vector: a name or `] def' expected: `");
374         mp_print(mp,mp->ps->enc_line);
375         mp_print(mp,"'");
376         mp_error(mp);
377       }
378     }
379     mp_enc_getline (mp);
380     r = mp->ps->enc_line;
381   }
382 DONE:
383   enc_close ();
384   mp_print (mp,"}");
385   mp->selector = save_selector;
386 }
387 void mp_read_enc (MP mp, enc_entry * e) {
388     if (e->loaded)
389         return;
390     e->enc_name = NULL;
391     mp_load_enc (mp,e->file_name, &e->enc_name, e->glyph_names);
392     e->loaded = true;
393 }
394
395 @ |write_enc| is used to write either external encoding (given in map file) or
396  internal encoding (read from the font file); when |glyph_names| is NULL
397  the 2nd argument is a pointer to the encoding entry; otherwise the 3rd is 
398  the object number of the Encoding object
399  
400 @c
401 void mp_write_enc (MP mp, char **glyph_names, enc_entry * e) {
402     int i;
403     int s;
404     int foffset;
405     char **g;
406     if (glyph_names == NULL) {
407         if (e->objnum != 0)     /* the encoding has been written already */
408             return;
409         e->objnum = 1;
410         g = e->glyph_names;
411     } else {
412         g = glyph_names;
413     }
414
415     mp_print(mp,"\n%%%%BeginResource: encoding ");
416     mp_print(mp, e->enc_name);
417     mp_print(mp, "\n/");
418     mp_print(mp, e->enc_name);
419     mp_print(mp, " [ ");
420     foffset = strlen(e->file_name)+3;
421     for (i = 0; i < 256; i++) {
422       s = strlen(g[i]);
423       if (s+1+foffset>=80) {
424             mp_print_ln (mp);
425         foffset = 0;
426       }
427       foffset += s+2;
428       mp_print_char(mp,'/');
429       mp_print(mp, g[i]);
430       mp_print_char(mp,' ');
431     }
432     if (foffset>75)
433            mp_print_ln (mp);
434     mp_print_nl (mp,"] def\n");
435     mp_print(mp,"%%%%EndResource");
436 }
437
438
439 @ All encoding entries go into AVL tree for fast search by name.
440
441 @<Glob...@>=
442 struct avl_table *enc_tree;
443
444 @ Memory management functions for avl 
445
446 @<Static variables in the outer block@>=
447 static const char notdef[] = ".notdef";
448
449 @ @<Declarations@>=
450 static void *avl_xmalloc (struct libavl_allocator *allocator, size_t size);
451 static void avl_xfree (struct libavl_allocator *allocator, void *block);
452
453 @ @c
454 static void *avl_xmalloc (struct libavl_allocator *allocator, size_t size) {
455     assert(allocator);
456     return mp_xmalloc (size,1);
457 }
458 static void avl_xfree (struct libavl_allocator *allocator, void *block) {
459     assert(allocator);
460     mp_xfree (block);
461 }
462
463 @ @<Glob...@>=
464 struct libavl_allocator avl_xallocator;
465
466 @ @<Set initial...@>=
467 mp->ps->avl_xallocator.libavl_malloc=avl_xmalloc;
468 mp->ps->avl_xallocator.libavl_free= avl_xfree;
469 mp->ps->enc_tree = NULL;
470
471 @ @c
472 static int comp_enc_entry (const void *pa, const void *pb, void *p) {
473     assert(p==NULL);
474     return strcmp (((const enc_entry *) pa)->file_name,
475                    ((const enc_entry *) pb)->file_name);
476 }
477 enc_entry * mp_add_enc (MP mp, char *s) {
478     int i;
479     enc_entry tmp, *p;
480     void **aa;
481     if (mp->ps->enc_tree == NULL) {
482       mp->ps->enc_tree = avl_create (comp_enc_entry, NULL, &mp->ps->avl_xallocator);
483     }
484     tmp.file_name = s;
485     p = (enc_entry *) avl_find (mp->ps->enc_tree, &tmp);
486     if (p != NULL)              /* encoding already registered */
487         return p;
488     p = mp_xmalloc (1,sizeof (enc_entry));
489     p->loaded = false;
490     p->file_name = mp_xstrdup (s);
491     p->objnum = 0;
492     p->tounicode = 0;
493     p->glyph_names = mp_xmalloc (256,sizeof (char *));
494     for (i = 0; i < 256; i++)
495         p->glyph_names[i] = (char *) notdef;
496     aa = avl_probe (mp->ps->enc_tree, p);
497     return p;
498 }
499
500 @ cleaning up... 
501
502 @c 
503 static void mp_destroy_enc_entry (void *pa, void *pb) {
504     enc_entry *p;
505     int i;
506
507     p = (enc_entry *) pa;
508     assert(pb==NULL);
509     mp_xfree (p->file_name);
510     if (p->glyph_names != NULL)
511         for (i = 0; i < 256; i++)
512             if (p->glyph_names[i] != notdef)
513                 mp_xfree (p->glyph_names[i]);
514     mp_xfree (p->glyph_names);
515     mp_xfree (p);
516 }
517
518 @ @<Declarations@>=
519 static void enc_free (MP mp);
520
521 @ @c static void enc_free (MP mp) {
522     if (mp->ps->enc_tree != NULL)
523       avl_destroy (mp->ps->enc_tree, mp_destroy_enc_entry);
524 }
525
526 @ @<Exported function headers@>=
527 void mp_load_encodings (MP mp, int lastfnum) ;
528 void mp_font_encodings (MP mp, int lastfnum, int encodings_only) ;
529
530 @ @c void mp_load_encodings (MP mp, int lastfnum) {
531   int f;
532   enc_entry *e;
533   fm_entry *fm_cur;
534   for (f=null_font+1;f<=lastfnum;f++) {
535     if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp,f,&fm_cur)) { 
536       if (fm_cur != NULL && 
537           fm_cur->ps_name != NULL &&
538           is_reencoded (fm_cur)) {
539                 e = fm_cur->encoding;
540                 mp_read_enc (mp,e);
541       }
542     }
543   }
544 }
545 void mp_font_encodings (MP mp, int lastfnum, int encodings_only) {
546   int f;
547   enc_entry *e;
548   fm_entry *fm;
549   for (f=null_font+1;f<=lastfnum;f++) {
550     if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp,f, &fm)) { 
551       if (fm != NULL && (fm->ps_name != NULL)) {
552         if (is_reencoded (fm)) {
553           if (encodings_only || (!is_subsetted (fm))) {
554             e = fm->encoding;
555             mp_write_enc (mp,NULL, e);
556             /* clear for next run */
557             e->objnum = 0;
558           }
559         }
560       }
561     }
562   }
563 }
564
565 @* \[44b] Parsing font map files.
566
567 @d FM_BUF_SIZE     1024
568
569 @<Glob...@>=
570 FILE *fm_file;
571
572 @
573 @d fm_close()      fclose(mp->ps->fm_file)
574 @d fm_getchar()    fgetc(mp->ps->fm_file)
575 @d fm_eof()        feof(mp->ps->fm_file)
576
577 @<Types...@>=
578 enum _mode { FM_DUPIGNORE, FM_REPLACE, FM_DELETE };
579 enum _ltype { MAPFILE, MAPLINE };
580 enum _tfmavail { TFM_UNCHECKED, TFM_FOUND, TFM_NOTFOUND };
581 typedef struct mitem {
582     int mode;                   /* |FM_DUPIGNORE| or |FM_REPLACE| or |FM_DELETE| */
583     int type;                   /* map file or map line */
584     char *map_line;              /* pointer to map file name or map line */
585     int lineno;                 /* line number in map file */
586 } mapitem;
587
588 @ @<Glob...@>=
589 mapitem *mitem;
590 fm_entry *fm_cur;
591 fm_entry *loaded_tfm_found;
592 fm_entry *avail_tfm_found;
593 fm_entry *non_tfm_found;
594 fm_entry *not_avail_tfm_found;
595
596 @ @<Set initial...@>=
597 mp->ps->mitem = NULL;
598
599 @ @<Declarations@>=
600 static const char nontfm[] = "<nontfm>";
601
602 @
603 @d read_field(r, q, buf) do {
604     q = buf;
605     while (*r != ' ' && *r != '\0')
606         *q++ = *r++;
607     *q = '\0';
608     skip (r, ' ');
609 } while (0)
610
611 @d set_field(F) do {
612     if (q > buf)
613         fm->F = mp_xstrdup(buf);
614     if (*r == '\0')
615         goto DONE;
616 } while (0)
617
618 @d cmp_return(a, b)
619     if (a > b)
620         return 1;
621     if (a < b)
622         return -1
623
624 @c
625 static fm_entry *new_fm_entry (void) {
626     fm_entry *fm;
627     fm = mp_xmalloc (1,sizeof(fm_entry));
628     fm->tfm_name = NULL;
629     fm->ps_name = NULL;
630     fm->flags = 4;
631     fm->ff_name = NULL;
632     fm->subset_tag = NULL;
633     fm->encoding = NULL;
634     fm->tfm_num = null_font;
635     fm->tfm_avail = TFM_UNCHECKED;
636     fm->type = 0;
637     fm->slant = 0;
638     fm->extend = 0;
639     fm->ff_objnum = 0;
640     fm->fn_objnum = 0;
641     fm->fd_objnum = 0;
642     fm->charset = NULL;
643     fm->all_glyphs = false;
644     fm->links = 0;
645     fm->pid = -1;
646     fm->eid = -1;
647     return fm;
648 }
649
650 static void delete_fm_entry (fm_entry * fm) {
651     mp_xfree (fm->tfm_name);
652     mp_xfree (fm->ps_name);
653     mp_xfree (fm->ff_name);
654     mp_xfree (fm->subset_tag);
655     mp_xfree (fm->charset);
656     mp_xfree (fm);
657 }
658
659 static ff_entry *new_ff_entry (void) {
660     ff_entry *ff;
661     ff = mp_xmalloc (1,sizeof(ff_entry));
662     ff->ff_name = NULL;
663     ff->ff_path = NULL;
664     return ff;
665 }
666
667 static void delete_ff_entry (ff_entry * ff) {
668     mp_xfree (ff->ff_name);
669     mp_xfree (ff->ff_path);
670     mp_xfree (ff);
671 }
672
673 static char *mk_base_tfm (MP mp, char *tfmname, int *i) {
674     static char buf[SMALL_BUF_SIZE];
675     char *p = tfmname, *r = strend (p) - 1, *q = r;
676     while (q > p && isdigit (*q))
677         --q;
678     if (!(q > p) || q == r || (*q != '+' && *q != '-'))
679         return NULL;
680     check_buf (q - p + 1, SMALL_BUF_SIZE);
681     strncpy (buf, p, (size_t) (q - p));
682     buf[q - p] = '\0';
683     *i = atoi (q);
684     return buf;
685 }
686
687 @ @<Exported function headers@>=
688 boolean mp_has_fm_entry (MP mp,font_number f, fm_entry **fm);
689
690 @ @c
691 boolean mp_has_fm_entry (MP mp,font_number f, fm_entry **fm) {
692     fm_entry *res = NULL;
693     res = mp_fm_lookup (mp, f);
694     if (fm != NULL) {
695        *fm =res;
696     }
697     return (res != NULL);
698 }
699
700 @ @<Glob...@>=
701 struct avl_table *tfm_tree;
702 struct avl_table *ps_tree;
703 struct avl_table *ff_tree;
704
705 @ @<Set initial...@>=
706 mp->ps->tfm_tree = NULL;
707 mp->ps->ps_tree = NULL;
708 mp->ps->ff_tree = NULL;
709
710 @ AVL sort |fm_entry| into |tfm_tree| by |tfm_name |
711
712 @c
713 static int comp_fm_entry_tfm (const void *pa, const void *pb, void *p) {
714     assert(p==NULL);
715     return strcmp (((const fm_entry *) pa)->tfm_name,
716                    ((const fm_entry *) pb)->tfm_name);
717 }
718
719 @ AVL sort |fm_entry| into |ps_tree| by |ps_name|, |slant|, and |extend|
720
721 @c static int comp_fm_entry_ps (const void *pa, const void *pb, void *p) {
722     assert(p==NULL);
723     const fm_entry *p1 = (const fm_entry *) pa, *p2 = (const fm_entry *) pb;
724     int i;
725     assert (p1->ps_name != NULL && p2->ps_name != NULL);
726     if ((i = strcmp (p1->ps_name, p2->ps_name)))
727         return i;
728     cmp_return (p1->slant, p2->slant);
729     cmp_return (p1->extend, p2->extend);
730     if (p1->tfm_name != NULL && p2->tfm_name != NULL &&
731         (i = strcmp (p1->tfm_name, p2->tfm_name)))
732         return i;
733     return 0;
734 }
735
736 @ AVL sort |ff_entry| into |ff_tree| by |ff_name|
737
738 @c static int comp_ff_entry (const void *pa, const void *pb, void *p) {
739     assert(p==NULL);
740     return strcmp (((const ff_entry *) pa)->ff_name,
741                    ((const ff_entry *) pb)->ff_name);
742 }
743
744 @ @c static void create_avl_trees (MP mp) {
745     if (mp->ps->tfm_tree == NULL) {
746         mp->ps->tfm_tree = avl_create (comp_fm_entry_tfm, NULL, &mp->ps->avl_xallocator);
747         assert (mp->ps->tfm_tree != NULL);
748     }
749     if (mp->ps->ps_tree == NULL) {
750         mp->ps->ps_tree = avl_create (comp_fm_entry_ps, NULL, &mp->ps->avl_xallocator);
751         assert (mp->ps->ps_tree != NULL);
752     }
753     if (mp->ps->ff_tree == NULL) {
754         mp->ps->ff_tree = avl_create (comp_ff_entry, NULL, &mp->ps->avl_xallocator);
755         assert (mp->ps->ff_tree != NULL);
756     }
757 }
758
759 @ The function |avl_do_entry| is not completely symmetrical with regards
760 to |tfm_name| and |ps_name handling|, e. g. a duplicate |tfm_name| gives a
761 |goto exit|, and no |ps_name| link is tried. This is to keep it compatible
762 with the original version.
763
764 @d LINK_TFM            0x01
765 @d LINK_PS             0x02
766 @d set_tfmlink(fm)     ((fm)->links |= LINK_TFM)
767 @d set_pslink(fm)      ((fm)->links |= LINK_PS)
768 @d unset_tfmlink(fm)   ((fm)->links &= ~LINK_TFM)
769 @d unset_pslink(fm)    ((fm)->links &= ~LINK_PS)
770 @d has_tfmlink(fm)     ((fm)->links & LINK_TFM)
771 @d has_pslink(fm)      ((fm)->links & LINK_PS)
772
773 @c
774 static int avl_do_entry (MP mp, fm_entry * fp, int mode) {
775     fm_entry *p;
776     void *a;
777     void **aa;
778     char s[128];
779
780     /* handle |tfm_name| link */
781
782     if (strcmp (fp->tfm_name, nontfm)) {
783         p = (fm_entry *) avl_find (mp->ps->tfm_tree, fp);
784         if (p != NULL) {
785             if (mode == FM_DUPIGNORE) {
786                snprintf(s,128,"fontmap entry for `%s' already exists, duplicates ignored",
787                      fp->tfm_name);
788                 mp_warn(mp,s);
789                 goto exit;
790             } else {            /* mode == |FM_REPLACE| / |FM_DELETE| */
791                 if (mp_has_font_size(mp,p->tfm_num)) {
792                     snprintf(s,128,
793                         "fontmap entry for `%s' has been used, replace/delete not allowed",
794                          fp->tfm_name);
795                     mp_warn(mp,s);
796                     goto exit;
797                 }
798                 a = avl_delete (mp->ps->tfm_tree, p);
799                 assert (a != NULL);
800                 unset_tfmlink (p);
801                 if (!has_pslink (p))
802                     delete_fm_entry (p);
803             }
804         }
805         if (mode != FM_DELETE) {
806             aa = avl_probe (mp->ps->tfm_tree, fp);
807             assert (aa != NULL);
808             set_tfmlink (fp);
809         }
810     }
811
812     /* handle |ps_name| link */
813
814     if (fp->ps_name != NULL) {
815         assert (fp->tfm_name != NULL);
816         p = (fm_entry *) avl_find (mp->ps->ps_tree, fp);
817         if (p != NULL) {
818             if (mode == FM_DUPIGNORE) {
819                 snprintf(s,128,
820                     "ps_name entry for `%s' already exists, duplicates ignored",
821                      fp->ps_name);
822                 mp_warn(mp,s);
823                 goto exit;
824             } else {            /* mode == |FM_REPLACE| / |FM_DELETE| */
825                 if (mp_has_font_size(mp,p->tfm_num)) {
826                     /* REPLACE/DELETE not allowed */
827                     snprintf(s,128,
828                         "fontmap entry for `%s' has been used, replace/delete not allowed",
829                          p->tfm_name);
830                     mp_warn(mp,s);
831                     goto exit;
832                 }
833                 a = avl_delete (mp->ps->ps_tree, p);
834                 assert (a != NULL);
835                 unset_pslink (p);
836                 if (!has_tfmlink (p))
837                     delete_fm_entry (p);
838             }
839         }
840         if (mode != FM_DELETE) {
841             aa = avl_probe (mp->ps->ps_tree, fp);
842             assert (aa != NULL);
843             set_pslink (fp);
844         }
845     }
846   exit:
847     if (!has_tfmlink (fp) && !has_pslink (fp))  /* e. g. after |FM_DELETE| */
848         return 1;               /* deallocation of |fm_entry| structure required */
849     else
850         return 0;
851 }
852
853 @ consistency check for map entry, with warn flag 
854
855 @c
856 static int check_fm_entry (MP mp, fm_entry * fm, boolean warn) {
857     int a = 0;
858     char s[128];
859     assert (fm != NULL);
860     if (fm->ps_name != NULL) {
861         if (is_basefont (fm)) {
862             if (is_fontfile (fm) && !is_included (fm)) {
863                 if (warn) {
864                     snprintf(s,128, "invalid entry for `%s': "
865                          "font file must be included or omitted for base fonts",
866                          fm->tfm_name);
867                     mp_warn(mp,s);
868                 }
869                 a += 1;
870             }
871         } else {                /* not a base font */
872             /* if no font file given, drop this entry */
873             /* |if (!is_fontfile (fm)) {
874                  if (warn) {
875                    snprintf(s,128, 
876                         "invalid entry for `%s': font file missing",
877                                                 fm->tfm_name);
878                     mp_warn(mp,s);
879                  }
880                 a += 2;
881             }|
882             */
883         }
884     }
885     if (is_truetype (fm) && is_reencoded (fm) && !is_subsetted (fm)) {
886         if (warn) {
887             snprintf(s,128, 
888                 "invalid entry for `%s': only subsetted TrueType font can be reencoded",
889                  fm->tfm_name);
890                     mp_warn(mp,s);
891         }
892         a += 4;
893     }
894     if ((fm->slant != 0 || fm->extend != 0) &&
895         (is_truetype (fm))) {
896         if (warn) { 
897            snprintf(s,128, 
898                  "invalid entry for `%s': " 
899                  "SlantFont/ExtendFont can be used only with embedded T1 fonts",
900                  fm->tfm_name);
901                     mp_warn(mp,s);
902         }
903         a += 8;
904     }
905     if (abs (fm->slant) > 1000) {
906         if (warn) {
907             snprintf(s,128, 
908                 "invalid entry for `%s': too big value of SlantFont (%g)",
909                  fm->tfm_name, fm->slant / 1000.0);
910                     mp_warn(mp,s);
911         }
912         a += 16;
913     }
914     if (abs (fm->extend) > 2000) {
915         if (warn) {
916             snprintf(s,128, 
917                 "invalid entry for `%s': too big value of ExtendFont (%g)",
918                  fm->tfm_name, fm->extend / 1000.0);
919                     mp_warn(mp,s);
920         }
921         a += 32;
922     }
923     if (fm->pid != -1 &&
924         !(is_truetype (fm) && is_included (fm) &&
925           is_subsetted (fm) && !is_reencoded (fm))) {
926         if (warn) {
927             snprintf(s,128, 
928                 "invalid entry for `%s': "
929                  "PidEid can be used only with subsetted non-reencoded TrueType fonts",
930                  fm->tfm_name);
931                     mp_warn(mp,s);
932         }
933         a += 64;
934     }
935     return a;
936 }
937
938 @ returns true if s is one of the 14 std. font names; speed-trimmed. 
939
940 @c static boolean check_basefont (char *s) {
941     static const char *basefont_names[] = {
942         "Courier",              /* 0:7 */
943         "Courier-Bold",         /* 1:12 */
944         "Courier-Oblique",      /* 2:15 */
945         "Courier-BoldOblique",  /* 3:19 */
946         "Helvetica",            /* 4:9 */
947         "Helvetica-Bold",       /* 5:14 */
948         "Helvetica-Oblique",    /* 6:17 */
949         "Helvetica-BoldOblique",        /* 7:21 */
950         "Symbol",               /* 8:6 */
951         "Times-Roman",          /* 9:11 */
952         "Times-Bold",           /* 10:10 */
953         "Times-Italic",         /* 11:12 */
954         "Times-BoldItalic",     /* 12:16 */
955         "ZapfDingbats"          /* 13:12 */
956     };
957     static const int Index[] =
958         { -1, -1, -1, -1, -1, -1, 8, 0, -1, 4, 10, 9, -1, -1, 5, 2, 12, 6,
959         -1, 3, -1, 7
960     };
961     const size_t n = strlen (s);
962     int k = -1;
963     if (n > 21)
964         return false;
965     if (n == 12) {              /* three names have length 12 */
966         switch (*s) {
967         case 'C':
968             k = 1;              /* Courier-Bold */
969             break;
970         case 'T':
971             k = 11;             /* Times-Italic */
972             break;
973         case 'Z':
974             k = 13;             /* ZapfDingbats */
975             break;
976         default:
977             return false;
978         }
979     } else
980         k = Index[n];
981     if (k > -1 && !strcmp (basefont_names[k], s))
982         return true;
983     return false;
984 };
985
986
987 @d is_cfg_comment(c) (c == 10 || c == '*' || c == '#' || c == ';' || c == '%')
988
989 @c static void fm_scan_line (MP mp) {
990     int a, b, c, j, u = 0, v = 0;
991     float d;
992     fm_entry *fm;
993     char fm_line[FM_BUF_SIZE], buf[FM_BUF_SIZE];
994     char *p, *q, *r, *s;
995     char warn_s[128];
996     switch (mp->ps->mitem->type) {
997     case MAPFILE:
998         p = fm_line;
999         do {
1000             c = fm_getchar ();
1001             append_char_to_buf (c, p, fm_line, FM_BUF_SIZE);
1002         }
1003         while (c != 10);
1004         *(--p) = '\0';
1005         r = fm_line;
1006         break;
1007     case MAPLINE:
1008         r = mp->ps->mitem->map_line;
1009         break;
1010     default:
1011         assert (0);
1012     }
1013     if (*r == '\0' || is_cfg_comment (*r))
1014         return;
1015     fm = new_fm_entry ();
1016     read_field (r, q, buf);
1017     set_field (tfm_name);
1018     p = r;
1019     read_field (r, q, buf);
1020     if (*buf != '<' && *buf != '"')
1021         set_field (ps_name);
1022     else
1023         r = p;                  /* unget the field */
1024     if (isdigit (*r)) {         /* font flags given */
1025         fm->flags = atoi (r);
1026         while (isdigit (*r))
1027             r++;
1028     }
1029     while (1) {                 /* loop through "specials", encoding, font file */
1030         skip (r, ' ');
1031         switch (*r) {
1032         case '\0':
1033             goto DONE;
1034         case '"':              /* opening quote */
1035             r++;
1036             u = v = 0;
1037             do {
1038                 skip (r, ' ');
1039                 if (sscanf (r, "%f %n", &d, &j) > 0) {
1040                     s = r + j;  /* jump behind number, eat also blanks, if any */
1041                     if (*(s - 1) == 'E' || *(s - 1) == 'e')
1042                         s--;    /* e. g. 0.5ExtendFont: \%f = 0.5E */
1043                     if (str_prefix (s, "SlantFont")) {
1044                         d *= 1000.0;    /* correct rounding also for neg. numbers */
1045                         fm->slant = (integer) (d > 0 ? d + 0.5 : d - 0.5);
1046                         r = s + strlen ("SlantFont");
1047                     } else if (str_prefix (s, "ExtendFont")) {
1048                         d *= 1000.0;
1049                         fm->extend = (integer) (d > 0 ? d + 0.5 : d - 0.5);
1050                         if (fm->extend == 1000)
1051                             fm->extend = 0;
1052                         r = s + strlen ("ExtendFont");
1053                     } else {    /* unknown name */
1054                         for (r = s; 
1055                              *r != ' ' && *r != '"' && *r != '\0'; 
1056                              r++); /* jump over name */
1057                         c = *r; /* remember char for temporary end of string */
1058                         *r = '\0';
1059                         snprintf(warn_s,128,
1060                             "invalid entry for `%s': unknown name `%s' ignored",
1061                              fm->tfm_name, s);
1062                         mp_warn(mp,warn_s);
1063                         *r = c;
1064                     }
1065                 } else
1066                     for (; *r != ' ' && *r != '"' && *r != '\0'; r++);
1067             }
1068             while (*r == ' ');
1069             if (*r == '"')      /* closing quote */
1070                 r++;
1071             else {
1072                 snprintf(warn_s,128,
1073                     "invalid entry for `%s': closing quote missing",
1074                      fm->tfm_name);
1075                 mp_warn(mp,warn_s);
1076                 goto bad_line;
1077             }
1078             break;
1079         case 'P':              /* handle cases for subfonts like 'PidEid=3,1' */
1080             if (sscanf (r, "PidEid=%i, %i %n", &a, &b, &c) >= 2) {
1081                 fm->pid = a;
1082                 fm->eid = b;
1083                 r += c;
1084                 break;
1085             }
1086         default:               /* encoding or font file specification */
1087             a = b = 0;
1088             if (*r == '<') {
1089                 a = *r++;
1090                 if (*r == '<' || *r == '[')
1091                     b = *r++;
1092             }
1093             read_field (r, q, buf);
1094             /* encoding, formats: '8r.enc' or '<8r.enc' or '<[8r.enc' */
1095             if (strlen (buf) > 4 && strcasecmp (strend (buf) - 4, ".enc") == 0) {
1096                 fm->encoding = mp_add_enc (mp, buf);
1097                 u = v = 0;      /* u, v used if intervening blank: "<< foo" */
1098             } else if (strlen (buf) > 0) {      /* file name given */
1099                 /* font file, formats:
1100                  * subsetting:    '<cmr10.pfa'
1101                  * no subsetting: '<<cmr10.pfa'
1102                  * no embedding:  'cmr10.pfa'
1103                  */
1104                 if (a == '<' || u == '<') {
1105                   set_included (fm);
1106                   if ((a == '<' && b == 0) || (a == 0 && v == 0))
1107                     set_subsetted (fm);
1108                   /* otherwise b == '<' (or '[') => no subsetting */
1109                 }
1110                 set_field (ff_name);
1111                 u = v = 0;
1112             } else {
1113                 u = a;
1114                 v = b;
1115             }
1116         }
1117     }
1118   DONE:
1119     if (fm->ps_name != NULL && check_basefont (fm->ps_name))
1120         set_basefont (fm);
1121     if (is_fontfile (fm)
1122         && strcasecmp (strend (fm_fontfile (fm)) - 4, ".ttf") == 0)
1123         set_truetype (fm);
1124     if (check_fm_entry (mp,fm, true) != 0)
1125         goto bad_line;
1126     /*
1127        Until here the map line has been completely scanned without errors;
1128        fm points to a valid, freshly filled-out |fm_entry| structure.
1129        Now follows the actual work of registering/deleting.
1130      */
1131     if (avl_do_entry (mp, fm, mp->ps->mitem->mode) == 0)    /* if success */
1132         return;
1133   bad_line:
1134     delete_fm_entry (fm);
1135 }
1136
1137
1138 @c static void fm_read_info (MP mp) {
1139     char *n;
1140     char s[256];
1141     if (mp->ps->tfm_tree == NULL)
1142         create_avl_trees (mp);
1143     if (mp->ps->mitem->map_line == NULL)    /* nothing to do */
1144         return;
1145     mp->ps->mitem->lineno = 1;
1146     switch (mp->ps->mitem->type) {
1147     case MAPFILE:
1148         n = mp->ps->mitem->map_line;
1149         mp->ps->fm_file = mp_open_file(mp, n, "r", mp_filetype_fontmap);
1150         if (!mp->ps->fm_file) {
1151             snprintf(s,256,"cannot open font map file %s",n);
1152             mp_warn(mp,s);
1153         } else {
1154             int save_selector = mp->selector;
1155             mp_normalize_selector(mp);
1156             mp_print (mp, "{");
1157             mp_print (mp, n);
1158             while (!fm_eof ()) {
1159                 fm_scan_line (mp);
1160                 mp->ps->mitem->lineno++;
1161             }
1162             fm_close ();
1163             mp_print (mp,"}");
1164             mp->selector = save_selector;
1165             mp->ps->fm_file = NULL;
1166         }
1167         break;
1168     case MAPLINE:
1169         fm_scan_line (mp);
1170         break;
1171     default:
1172         assert (0);
1173     }
1174     mp->ps->mitem->map_line = NULL;         /* done with this line */
1175     return;
1176 }
1177
1178 @ @c 
1179 scaled mp_round_xn_over_d (MP mp, scaled x, integer  n, integer d) {
1180   boolean positive; /* was |x>=0|? */
1181   unsigned int t,u; /* intermediate quantities */
1182   integer v; /* intermediate quantities */
1183   if ( x>=0 ) {
1184     positive=true;
1185   } else { 
1186     negate(x); positive=false;
1187   };
1188   t=(x % 0100000)*n;
1189   u=(x / 0100000)*n+(t / 0100000);
1190   v=(u % d)*0100000 + (t % 0100000);
1191   if ( u / d>=0100000 ) mp->arith_error=true;
1192   else u=0100000*(u / d) + (v / d);
1193   v = v % d;
1194   if ( 2*v >= d )
1195     u++;
1196   return ( positive ? u : -u );
1197 }
1198 static fm_entry *mk_ex_fm (MP mp, font_number f, fm_entry * basefm, int ex) {
1199     fm_entry *fm;
1200     integer e = basefm->extend;
1201     if (e == 0)
1202         e = 1000;
1203     fm = new_fm_entry ();
1204     fm->flags = basefm->flags;
1205     fm->encoding = basefm->encoding;
1206     fm->type = basefm->type;
1207     fm->slant = basefm->slant;
1208     fm->extend = mp_round_xn_over_d (mp, e, 1000 + ex, 1000); 
1209         /* modify ExtentFont to simulate expansion */
1210     if (fm->extend == 1000)
1211         fm->extend = 0;
1212     fm->tfm_name = mp_xstrdup (mp->font_name[f]);
1213     if (basefm->ps_name != NULL)
1214         fm->ps_name = mp_xstrdup (basefm->ps_name);
1215     fm->ff_name = mp_xstrdup (basefm->ff_name);
1216     fm->ff_objnum = 0;
1217     fm->tfm_num = f;
1218     fm->tfm_avail = TFM_FOUND;
1219     assert (strcmp (fm->tfm_name, nontfm));
1220     return fm;
1221 }
1222
1223 @ @c static void init_fm (fm_entry * fm, font_number f) {
1224     if (fm->tfm_num == null_font ) {
1225         fm->tfm_num = f;
1226         fm->tfm_avail = TFM_FOUND;
1227     }
1228 }
1229
1230 @ @<Declarations@>=
1231 fm_entry * mp_fm_lookup (MP mp, font_number f);
1232
1233 @ @c 
1234 fm_entry * mp_fm_lookup (MP mp, font_number f) {
1235     char *tfm;
1236     fm_entry *fm, *exfm;
1237     fm_entry tmp;
1238     int ai, e;
1239     if (mp->ps->tfm_tree == NULL)
1240         fm_read_info (mp);        /* only to read default map file */
1241     tfm = mp->font_name[f];
1242     assert (strcmp (tfm, nontfm));
1243     /* Look up for full <tfmname>[+-]<expand> */
1244     tmp.tfm_name = tfm;
1245     fm = (fm_entry *) avl_find (mp->ps->tfm_tree, &tmp);
1246     if (fm != NULL) {
1247         init_fm (fm, f);
1248         return (fm_entry *) fm;
1249     }
1250     tfm = mk_base_tfm (mp, mp->font_name[f], &e);
1251     if (tfm == NULL)            /* not an expanded font, nothing to do */
1252         return NULL;
1253
1254     tmp.tfm_name = tfm;
1255     fm = (fm_entry *) avl_find (mp->ps->tfm_tree, &tmp);
1256     if (fm != NULL) {           /* found an entry with the base tfm name, e.g. cmr10 */
1257         return (fm_entry *) fm; /* font expansion uses the base font */
1258         /* the following code would be obsolete, as would be |mk_ex_fm| */
1259         if (!is_t1fontfile (fm) || !is_included (fm)) {
1260             char s[128];
1261             snprintf(s,128,
1262                 "font %s cannot be expanded (not an included Type1 font)", tfm);
1263             mp_warn(mp,s);
1264             return NULL;
1265         }
1266         exfm = mk_ex_fm (mp, f, fm, e);     /* copies all fields from fm except tfm name */
1267         init_fm (exfm, f);
1268         ai = avl_do_entry (mp, exfm, FM_DUPIGNORE);
1269         assert (ai == 0);
1270         return (fm_entry *) exfm;
1271     }
1272     return NULL;
1273 }
1274
1275 @  Early check whether a font file exists. Used e. g. for replacing fonts
1276    of embedded PDF files: Without font file, the font within the embedded
1277    PDF-file is used. Search tree |ff_tree| is used in 1st instance, as it
1278    may be faster than the |kpse_find_file()|, and |kpse_find_file()| is called
1279    only once per font file name + expansion parameter. This might help
1280    keeping speed, if many PDF pages with same fonts are to be embedded.
1281
1282    The |ff_tree| contains only font files, which are actually needed,
1283    so this tree typically is much smaller than the |tfm_tree| or |ps_tree|.
1284
1285 @c 
1286 static ff_entry *check_ff_exist (MP mp, fm_entry * fm) {
1287     ff_entry *ff;
1288     ff_entry tmp;
1289     void **aa;
1290
1291     assert (fm->ff_name != NULL);
1292     tmp.ff_name = fm->ff_name;
1293     ff = (ff_entry *) avl_find (mp->ps->ff_tree, &tmp);
1294     if (ff == NULL) {           /* not yet in database */
1295         ff = new_ff_entry ();
1296         ff->ff_name = mp_xstrdup (fm->ff_name);
1297         ff->ff_path = mp_xstrdup (fm->ff_name);
1298         aa = avl_probe (mp->ps->ff_tree, ff);
1299         assert (aa != NULL);
1300     }
1301     return ff;
1302 }
1303
1304 @ @c 
1305 font_number mp_tfm_lookup (MP mp, char *s, scaled  fs) {
1306 /* looks up for a TFM with name |s| loaded at |fs| size; if found then flushes |s| */
1307   font_number k;
1308   if ( fs != 0 ) { /*  should not be used!  */
1309     for (k = null_font + 1;k<=mp->last_fnum;k++) {
1310       if ( mp_xstrcmp( mp->font_name[k], s) && (mp->font_sizes[k] == fs) ) {
1311          mp_xfree(s);
1312          return k;
1313       }
1314     }
1315   } else {
1316     for (k = null_font + 1;k<=mp->last_fnum;k++) {
1317       if ( mp_xstrcmp(mp->font_name[k], s) ) {
1318         mp_xfree(s);
1319         return k;
1320       }
1321     }
1322   }
1323   return null_font;
1324 }
1325
1326 @ Process map file given by its name or map line contents. Items not
1327 beginning with [+-=] flush default map file, if it has not yet been
1328 read. Leading blanks and blanks immediately following [+-=] are ignored.
1329
1330
1331 @c void mp_process_map_item (MP mp, char *s, int type) {
1332     char *p;
1333     int mode;
1334     if (*s == ' ')
1335         s++;                    /* ignore leading blank */
1336     switch (*s) {
1337     case '+':                  /* +mapfile.map, +mapline */
1338         mode = FM_DUPIGNORE;    /* insert entry, if it is not duplicate */
1339         s++;
1340         break;
1341     case '=':                  /* =mapfile.map, =mapline */
1342         mode = FM_REPLACE;      /* try to replace earlier entry */
1343         s++;
1344         break;
1345     case '-':                  /* -mapfile.map, -mapline */
1346         mode = FM_DELETE;       /* try to delete entry */
1347         s++;
1348         break;
1349     default:
1350         mode = FM_DUPIGNORE;    /* like +, but also: */
1351         mp->ps->mitem->map_line = NULL;     /* flush default map file name */
1352     }
1353     if (*s == ' ')
1354         s++;                    /* ignore blank after [+-=] */
1355     p = s;                      /* map item starts here */
1356     switch (type) {
1357     case MAPFILE:              /* remove blank at end */
1358         while (*p != '\0' && *p != ' ')
1359             p++;
1360         *p = '\0';
1361         break;
1362     case MAPLINE:              /* blank at end allowed */
1363         break;
1364     default:
1365         assert (0);
1366     }
1367     if (mp->ps->mitem->map_line != NULL)    /* read default map file first */
1368         fm_read_info (mp);
1369     if (*s != '\0') {           /* only if real item to process */
1370         mp->ps->mitem->mode = mode;
1371         mp->ps->mitem->type = type;
1372         mp->ps->mitem->map_line = s;
1373         fm_read_info (mp);
1374     }
1375 }
1376
1377 @ @<Exported function headers@>=
1378 void mp_map_file (MP mp, str_number t);
1379 void mp_map_line (MP mp, str_number t);
1380 void mp_init_map_file (MP mp, int is_troff);
1381
1382 @ @c 
1383 void mp_map_file (MP mp, str_number t) {
1384   char *s = mp_xstrdup(mp_str (mp,t));
1385   mp_process_map_item (mp, s, MAPFILE);
1386   mp_xfree (s);
1387 }
1388 void mp_map_line (MP mp, str_number t) {
1389   char *s = mp_xstrdup(mp_str (mp,t));
1390   mp_process_map_item (mp, s, MAPLINE);
1391   mp_xfree (s);
1392 }
1393
1394
1395 @c void mp_init_map_file (MP mp, int is_troff) {
1396     char *r;
1397     mp->ps->mitem = mp_xmalloc (1,sizeof(mapitem));
1398     mp->ps->mitem->mode = FM_DUPIGNORE;
1399     mp->ps->mitem->type = MAPFILE;
1400     mp->ps->mitem->map_line = NULL;
1401     r = (mp->find_file)("mpost.map", "rb", mp_filetype_fontmap);
1402     if (r != NULL) {
1403       mp_xfree(r);
1404       mp->ps->mitem->map_line = mp_xstrdup ("mpost.map");
1405     } else {
1406       if (is_troff) {
1407              mp->ps->mitem->map_line = mp_xstrdup ("troff.map");
1408       } else {
1409              mp->ps->mitem->map_line = mp_xstrdup ("pdftex.map");
1410       }
1411     }
1412 }
1413
1414 @ @<Dealloc variables@>=
1415 if (mp->ps->mitem!=NULL) {
1416   mp_xfree(mp->ps->mitem->map_line);
1417   mp_xfree(mp->ps->mitem);
1418 }
1419
1420 @ cleaning up... 
1421
1422 @c
1423 static void destroy_fm_entry_tfm (void *pa, void *pb) {
1424     fm_entry *fm;
1425     assert(pb==NULL);
1426     fm = (fm_entry *) pa;
1427     if (!has_pslink (fm))
1428         delete_fm_entry (fm);
1429     else
1430         unset_tfmlink (fm);
1431 }
1432 static void destroy_fm_entry_ps (void *pa, void *pb) {
1433     fm_entry *fm;
1434     assert(pb==NULL);
1435     fm = (fm_entry *) pa;
1436     if (!has_tfmlink (fm))
1437         delete_fm_entry (fm);
1438     else
1439         unset_pslink (fm);
1440 }
1441 static void destroy_ff_entry (void *pa, void *pb) {
1442     ff_entry *ff;
1443     assert(pb==NULL);
1444     ff = (ff_entry *) pa;
1445     delete_ff_entry (ff);
1446
1447
1448 @ @<Declarations@>=
1449 static void fm_free (MP mp);
1450
1451 @ @c
1452 static void fm_free (MP mp) {
1453     if (mp->ps->tfm_tree != NULL)
1454         avl_destroy (mp->ps->tfm_tree, destroy_fm_entry_tfm);
1455     if (mp->ps->ps_tree != NULL)
1456         avl_destroy (mp->ps->ps_tree, destroy_fm_entry_ps);
1457     if (mp->ps->ff_tree != NULL)
1458         avl_destroy (mp->ps->ff_tree, destroy_ff_entry);
1459 }
1460
1461 @* \[44c] Helper functions for Type1 fonts.
1462
1463 @<Types...@>=
1464 typedef char char_entry;
1465 typedef unsigned char  Byte;
1466 typedef Byte  Bytef;
1467
1468 @ @<Glob...@>=
1469 char_entry *char_ptr, *char_array;
1470 size_t char_limit;
1471 char *job_id_string;
1472
1473 @ @<Set initial...@>=
1474 mp->ps->char_array = NULL;
1475 mp->ps->job_id_string = NULL;
1476
1477
1478 @d SMALL_ARRAY_SIZE    256
1479 @d Z_NULL  0  
1480
1481 @c 
1482 void mp_set_job_id (MP mp, int year, int month, int day, int time) {
1483     char *name_string, *format_string, *s;
1484     size_t slen;
1485     int i;
1486     if (mp->ps->job_id_string != NULL)
1487        return;
1488     if ( mp->job_name==NULL )
1489        mp->job_name = mp_xstrdup("mpout");
1490     name_string = mp_xstrdup (mp->job_name);
1491     format_string = mp_xstrdup (mp->mem_ident);
1492     slen = SMALL_BUF_SIZE +
1493         strlen (name_string) +
1494         strlen (format_string);
1495     s = mp_xmalloc (slen, sizeof (char));
1496     i = snprintf (s, slen,
1497                   "%.4d/%.2d/%.2d %.2d:%.2d %s %s",
1498                   (year>>16),
1499                   (month>>16), 
1500                   (day>>16), 
1501                   (time>>16) / 60, 
1502                   (time>>16) % 60,
1503                   name_string, format_string);
1504     mp->ps->job_id_string = mp_xstrdup (s);
1505     mp_xfree (s);
1506     mp_xfree (name_string);
1507     mp_xfree (format_string);
1508 }
1509 static void fnstr_append (MP mp, const char *s) {
1510     size_t l = strlen (s) + 1;
1511     alloc_array (char, l, SMALL_ARRAY_SIZE);
1512     strcat (mp->ps->char_ptr, s);
1513     mp->ps->char_ptr = strend (mp->ps->char_ptr);
1514 }
1515
1516 @ @<Exported function headers@>=
1517 void mp_set_job_id (MP mp, int y, int m, int d, int t) ;
1518
1519 @ @<Dealloc variables@>=
1520 mp_xfree(mp->ps->job_id_string);
1521
1522 @ this is not really a true crc32, but it should be just enough to keep
1523   subsets prefixes somewhat disjunct
1524
1525 @c
1526 static unsigned long crc32 (int oldcrc, const Byte *buf, int len) {
1527   unsigned long ret = 0;
1528   int i;
1529   if (oldcrc==0)
1530         ret = (23<<24)+(45<<16)+(67<<8)+89;
1531   else 
1532       for (i=0;i<len;i++)
1533           ret = (ret<<2)+buf[i];
1534   return ret;
1535 }
1536 boolean mp_char_marked (MP mp,font_number f, eight_bits c) {
1537   integer b; /* |char_base[f]| */
1538   b=mp->char_base[f];
1539   if ( (c>=mp->font_bc[f])&&(c<=mp->font_ec[f])&&(mp->font_info[b+c].qqqq.b3!=0) )
1540     return true;
1541   else
1542     return false;
1543 }
1544
1545 static void make_subset_tag (MP mp, fm_entry * fm_cur, char **glyph_names, int tex_font)
1546 {
1547     char tag[7];
1548     unsigned long crc;
1549     int i;
1550     size_t l ;
1551     if (mp->ps->job_id_string ==NULL)
1552       mp_fatal_error(mp, "no job id!");
1553     l = strlen (mp->ps->job_id_string) + 1;
1554     
1555     alloc_array (char, l, SMALL_ARRAY_SIZE);
1556     strcpy (mp->ps->char_array, mp->ps->job_id_string);
1557     mp->ps->char_ptr = strend (mp->ps->char_array);
1558     if (fm_cur->tfm_name != NULL) {
1559         fnstr_append (mp," TFM name: ");
1560         fnstr_append (mp,fm_cur->tfm_name);
1561     }
1562     fnstr_append (mp," PS name: ");
1563     if (fm_cur->ps_name != NULL)
1564         fnstr_append (mp,fm_cur->ps_name);
1565     fnstr_append (mp," Encoding: ");
1566     if (fm_cur->encoding != NULL && (fm_cur->encoding)->file_name != NULL)
1567         fnstr_append (mp,(fm_cur->encoding)->file_name);
1568     else
1569         fnstr_append (mp,"built-in");
1570     fnstr_append (mp," CharSet: ");
1571     for (i = 0; i < 256; i++)
1572         if (mp_char_marked (mp,tex_font, i) && glyph_names[i] != notdef) {
1573                         if (glyph_names[i]!=NULL) {
1574                           fnstr_append (mp,"/");
1575                           fnstr_append (mp,glyph_names[i]);
1576                         }
1577         }
1578     if (fm_cur->charset != NULL) {
1579         fnstr_append (mp," Extra CharSet: ");
1580         fnstr_append (mp, fm_cur->charset);
1581     }
1582     crc = crc32 (0L, Z_NULL, 0);
1583     crc = crc32 (crc, (Bytef *) mp->ps->char_array, strlen (mp->ps->char_array));
1584     /* we need to fit a 32-bit number into a string of 6 uppercase chars long;
1585      * there are 26 uppercase chars ==> each char represents a number in range
1586      * |0..25|. The maximal number that can be represented by the tag is
1587      * $26^6 - 1$, which is a number between $2^28$ and $2^29$. Thus the bits |29..31|
1588      * of the CRC must be dropped out.
1589      */
1590     for (i = 0; i < 6; i++) {
1591         tag[i] = 'A' + crc % 26;
1592         crc /= 26;
1593     }
1594     tag[6] = 0;
1595     fm_cur->subset_tag = mp_xstrdup (tag);
1596 }
1597
1598
1599
1600
1601 @d external_enc()      (fm_cur->encoding)->glyph_names
1602 @d is_used_char(c)     mp_char_marked (mp, tex_font, c)
1603 @d end_last_eexec_line() 
1604     mp->ps->hexline_length = HEXLINE_WIDTH;
1605     end_hexline(mp); 
1606     mp->ps->t1_eexec_encrypt = false
1607 @d t1_log(s)           mp_print(mp,(char *)s)
1608 @d t1_putchar(c)       fputc(c, mp->ps_file)
1609 @d embed_all_glyphs(tex_font)  false
1610 @d t1_char(c)          c
1611 @d extra_charset()     mp->ps->dvips_extra_charset
1612 @d update_subset_tag()
1613 @d fixedcontent        true
1614
1615 @<Glob...@>=
1616 #define PRINTF_BUF_SIZE     1024
1617 char *dvips_extra_charset;
1618 char *cur_enc_name;
1619 unsigned char *grid;
1620 char *ext_glyph_names[256];
1621 char print_buf[PRINTF_BUF_SIZE];
1622
1623 @ @<Set initial ...@>=
1624 mp->ps->dvips_extra_charset=NULL;
1625
1626
1627 @d t1_getchar()    fgetc(mp->ps->t1_file)
1628 @d t1_ungetchar(c) ungetc(c, mp->ps->t1_file)
1629 @d t1_eof()        feof(mp->ps->t1_file)
1630 @d t1_close()      fclose(mp->ps->t1_file)
1631 @d valid_code(c)   (c >= 0 && c < 256)
1632
1633 @<Static variables in the outer block@>=
1634 static const char *standard_glyph_names[256] =
1635     { notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1636     notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1637     notdef, notdef, notdef, notdef, notdef, notdef,
1638     notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1639     "space", "exclam", "quotedbl", "numbersign",
1640     "dollar", "percent", "ampersand", "quoteright", "parenleft",
1641     "parenright", "asterisk", "plus", "comma", "hyphen", "period",
1642     "slash", "zero", "one", "two", "three", "four", "five", "six", "seven",
1643     "eight", "nine", "colon", "semicolon", "less",
1644     "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F",
1645     "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
1646     "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft",
1647     "backslash", "bracketright", "asciicircum", "underscore",
1648     "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
1649     "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
1650     "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde",
1651     notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1652     notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1653     notdef, notdef, notdef, notdef, notdef, notdef,
1654     notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1655     notdef, notdef, notdef, "exclamdown", "cent",
1656     "sterling", "fraction", "yen", "florin", "section", "currency",
1657     "quotesingle", "quotedblleft", "guillemotleft",
1658     "guilsinglleft", "guilsinglright", "fi", "fl", notdef, "endash",
1659     "dagger", "daggerdbl", "periodcentered", notdef,
1660     "paragraph", "bullet", "quotesinglbase", "quotedblbase",
1661     "quotedblright", "guillemotright", "ellipsis", "perthousand",
1662     notdef, "questiondown", notdef, "grave", "acute", "circumflex",
1663     "tilde", "macron", "breve", "dotaccent", "dieresis", notdef,
1664     "ring", "cedilla", notdef, "hungarumlaut", "ogonek", "caron", "emdash",
1665     notdef, notdef, notdef, notdef, notdef, notdef,
1666     notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1667     notdef, "AE", notdef, "ordfeminine", notdef, notdef,
1668     notdef, notdef, "Lslash", "Oslash", "OE", "ordmasculine", notdef,
1669     notdef, notdef, notdef, notdef, "ae", notdef, notdef,
1670     notdef, "dotlessi", notdef, notdef, "lslash", "oslash", "oe",
1671     "germandbls", notdef, notdef, notdef, notdef };
1672 static const char charstringname[] = "/CharStrings";
1673
1674 @ @<Glob...@>=
1675 char **t1_glyph_names;
1676 char *t1_builtin_glyph_names[256];
1677 char charsetstr[0x4000];
1678 boolean read_encoding_only;
1679 int t1_encoding;
1680
1681 @ @c
1682 #define T1_BUF_SIZE   0x10
1683
1684 #define CS_HSTEM            1
1685 #define CS_VSTEM            3
1686 #define CS_VMOVETO          4
1687 #define CS_RLINETO          5
1688 #define CS_HLINETO          6
1689 #define CS_VLINETO          7
1690 #define CS_RRCURVETO        8
1691 #define CS_CLOSEPATH        9
1692 #define CS_CALLSUBR         10
1693 #define CS_RETURN           11
1694 #define CS_ESCAPE           12
1695 #define CS_HSBW             13
1696 #define CS_ENDCHAR          14
1697 #define CS_RMOVETO          21
1698 #define CS_HMOVETO          22
1699 #define CS_VHCURVETO        30
1700 #define CS_HVCURVETO        31
1701 #define CS_1BYTE_MAX        (CS_HVCURVETO + 1)
1702
1703 #define CS_DOTSECTION       CS_1BYTE_MAX + 0
1704 #define CS_VSTEM3           CS_1BYTE_MAX + 1
1705 #define CS_HSTEM3           CS_1BYTE_MAX + 2
1706 #define CS_SEAC             CS_1BYTE_MAX + 6
1707 #define CS_SBW              CS_1BYTE_MAX + 7
1708 #define CS_DIV              CS_1BYTE_MAX + 12
1709 #define CS_CALLOTHERSUBR    CS_1BYTE_MAX + 16
1710 #define CS_POP              CS_1BYTE_MAX + 17
1711 #define CS_SETCURRENTPOINT  CS_1BYTE_MAX + 33
1712 #define CS_2BYTE_MAX        (CS_SETCURRENTPOINT + 1)
1713 #define CS_MAX              CS_2BYTE_MAX
1714
1715 @ @<Types...@>=
1716 typedef unsigned char byte;
1717 typedef struct {
1718     byte nargs;                 /* number of arguments */
1719     boolean bottom;             /* take arguments from bottom of stack? */
1720     boolean clear;              /* clear stack? */
1721     boolean valid;
1722 } cc_entry;                     /* CharString Command */
1723 typedef struct {
1724     char *glyph_name;                 /* glyph name (or notdef for Subrs entry) */
1725     byte *data;
1726     unsigned short len;         /* length of the whole string */
1727     unsigned short cslen;       /* length of the encoded part of the string */
1728     boolean is_used;
1729     boolean valid;
1730 } cs_entry;
1731
1732 @ @<Glob...@>=
1733 unsigned short t1_dr, t1_er;
1734 unsigned short t1_c1, t1_c2;
1735 unsigned short t1_cslen;
1736 short t1_lenIV;
1737
1738 @ @<Set initial...@>=
1739 mp->ps->t1_c1 = 52845; 
1740 mp->ps->t1_c2 = 22719;
1741
1742 @ @<Types...@>=
1743 typedef char t1_line_entry;
1744 typedef char t1_buf_entry;
1745
1746 @ @<Glob...@>=
1747 t1_line_entry *t1_line_ptr, *t1_line_array;
1748 size_t t1_line_limit;
1749 t1_buf_entry *t1_buf_ptr, *t1_buf_array;
1750 size_t t1_buf_limit;
1751 int cs_start;
1752 cs_entry *cs_tab, *cs_ptr, *cs_notdef;
1753 char *cs_dict_start, *cs_dict_end;
1754 int cs_count, cs_size, cs_size_pos;
1755 cs_entry *subr_tab;
1756 char *subr_array_start, *subr_array_end;
1757 int subr_max, subr_size, subr_size_pos;
1758
1759 @ @<Set initial...@>=
1760 mp->ps->t1_line_array = NULL;
1761 mp->ps->t1_buf_array = NULL;
1762
1763
1764  This list contains the begin/end tokens commonly used in the 
1765  /Subrs array of a Type 1 font.                                
1766
1767 @<Static variables in the outer block@>=
1768 static const char *cs_token_pairs_list[][2] = {
1769     {" RD", "NP"},
1770     {" -|", "|"},
1771     {" RD", "noaccess put"},
1772     {" -|", "noaccess put"},
1773     {NULL, NULL}
1774 };
1775
1776 @ @<Glob...@>=
1777 const char **cs_token_pair;
1778 boolean t1_pfa, t1_cs, t1_scan, t1_eexec_encrypt, t1_synthetic;
1779 int t1_in_eexec;  /* 0 before eexec-encrypted, 1 during, 2 after */
1780 long t1_block_length;
1781 int last_hexbyte;
1782 FILE *t1_file;
1783 int hexline_length;
1784
1785
1786 @d HEXLINE_WIDTH 64
1787
1788 @<Set initial ...@>=
1789 mp->ps->hexline_length = HEXLINE_WIDTH;
1790
1791
1792 @d t1_prefix(s)        str_prefix(mp->ps->t1_line_array, s)
1793 @d t1_buf_prefix(s)    str_prefix(mp->ps->t1_buf_array, s)
1794 @d t1_suffix(s)        str_suffix(mp->ps->t1_line_array, mp->ps->t1_line_ptr, s)
1795 @d t1_buf_suffix(s)    str_suffix(mp->ps->t1_buf_array, mp->ps->t1_buf_ptr, s)
1796 @d t1_charstrings()    strstr(mp->ps->t1_line_array, charstringname)
1797 @d t1_subrs()          t1_prefix("/Subrs")
1798 @d t1_end_eexec()      t1_suffix("mark currentfile closefile")
1799 @d t1_cleartomark()    t1_prefix("cleartomark")
1800
1801 @d isdigit(A) ((A)>='0'&&(A)<='9')
1802
1803 @c
1804 static void end_hexline (MP mp) {
1805     if (mp->ps->hexline_length == HEXLINE_WIDTH) {
1806         fputs ("\n", mp->ps_file);
1807         mp->ps->hexline_length = 0;
1808     }
1809 }
1810 static void t1_check_pfa (MP mp) {
1811     const int c = t1_getchar ();
1812     mp->ps->t1_pfa = (c != 128) ? true : false;
1813     t1_ungetchar (c);
1814 }
1815 static int t1_getbyte (MP mp)
1816 {
1817     int c = t1_getchar ();
1818     if (mp->ps->t1_pfa)
1819         return c;
1820     if (mp->ps->t1_block_length == 0) {
1821         if (c != 128)
1822          mp_fatal_error (mp, "invalid marker");
1823         c = t1_getchar ();
1824         if (c == 3) {
1825             while (!t1_eof ())
1826                 t1_getchar ();
1827             return EOF;
1828         }
1829         mp->ps->t1_block_length = t1_getchar () & 0xff;
1830         mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 8;
1831         mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 16;
1832         mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 24;
1833         c = t1_getchar ();
1834     }
1835     mp->ps->t1_block_length--;
1836     return c;
1837 }
1838 static int hexval (int c) {
1839     if (c >= 'A' && c <= 'F')
1840         return c - 'A' + 10;
1841     else if (c >= 'a' && c <= 'f')
1842         return c - 'a' + 10;
1843     else if (c >= '0' && c <= '9')
1844         return c - '0';
1845     else
1846         return -1;
1847 }
1848 static byte edecrypt (MP mp, byte cipher) {
1849     byte plain;
1850     if (mp->ps->t1_pfa) {
1851         while (cipher == 10 || cipher == 13)
1852             cipher = t1_getbyte (mp);
1853         mp->ps->last_hexbyte = cipher = (hexval (cipher) << 4) + hexval (t1_getbyte (mp));
1854     }
1855     plain = (cipher ^ (mp->ps->t1_dr >> 8));
1856     mp->ps->t1_dr = (cipher + mp->ps->t1_dr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1857     return plain;
1858 }
1859 static byte cdecrypt (MP mp, byte cipher, unsigned short *cr)
1860 {
1861     const byte plain = (cipher ^ (*cr >> 8));
1862     *cr = (cipher + *cr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1863     return plain;
1864 }
1865 static byte eencrypt (MP mp, byte plain)
1866 {
1867     const byte cipher = (plain ^ (mp->ps->t1_er >> 8));
1868     mp->ps->t1_er = (cipher + mp->ps->t1_er) * mp->ps->t1_c1 + mp->ps->t1_c2;
1869     return cipher;
1870 }
1871
1872 static byte cencrypt (MP mp, byte plain, unsigned short *cr)
1873 {
1874     const byte cipher = (plain ^ (*cr >> 8));
1875     *cr = (cipher + *cr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1876     return cipher;
1877 }
1878
1879 static char *eol (char *s) {
1880     char *p = strend (s);
1881     if (p - s > 1 && p[-1] != 10) {
1882         *p++ = 10;
1883         *p = 0;
1884     }
1885     return p;
1886 }
1887 static float t1_scan_num (MP mp, char *p, char **r)
1888 {
1889     float f;
1890     char s[128];
1891     skip (p, ' ');
1892     if (sscanf (p, "%g", &f) != 1) {
1893         remove_eol (p, mp->ps->t1_line_array); 
1894             snprintf(s,128, "a number expected: `%s'", mp->ps->t1_line_array);
1895         mp_fatal_error(mp,s);
1896     }
1897     if (r != NULL) {
1898         for (; isdigit (*p) || *p == '.' ||
1899              *p == 'e' || *p == 'E' || *p == '+' || *p == '-'; p++);
1900         *r = p;
1901     }
1902     return f;
1903 }
1904
1905 static boolean str_suffix (const char *begin_buf, const char *end_buf,
1906                            const char *s)
1907 {
1908     const char *s1 = end_buf - 1, *s2 = strend (s) - 1;
1909     if (*s1 == 10)
1910         s1--;
1911     while (s1 >= begin_buf && s2 >= s) {
1912         if (*s1-- != *s2--)
1913             return false;
1914     }
1915     return s2 < s;
1916 }
1917
1918 @
1919
1920 @d alloc_array(T, n, s) do {
1921     if (mp->ps->T##_array == NULL) {
1922         mp->ps->T##_limit = (s);
1923         if ((unsigned)(n) > mp->ps->T##_limit)
1924             mp->ps->T##_limit = (n);
1925         mp->ps->T##_array = mp_xmalloc (mp->ps->T##_limit,sizeof(T##_entry));
1926         mp->ps->T##_ptr = mp->ps->T##_array;
1927     }
1928     else if ((unsigned)(mp->ps->T##_ptr - mp->ps->T##_array + (n)) > mp->ps->T##_limit) {
1929         size_t last_ptr_index;
1930         last_ptr_index = mp->ps->T##_ptr - mp->ps->T##_array;
1931         mp->ps->T##_limit *= 2;
1932         if ((unsigned)(mp->ps->T##_ptr - mp->ps->T##_array + (n)) > mp->ps->T##_limit)
1933             mp->ps->T##_limit = mp->ps->T##_ptr - mp->ps->T##_array + (n);
1934         mp->ps->T##_array = mp_xrealloc(mp->ps->T##_array, mp->ps->T##_limit , sizeof (T##_entry));
1935         mp->ps->T##_ptr = mp->ps->T##_array + last_ptr_index;
1936     }
1937 } while (0)
1938
1939 @d out_eexec_char(A)      t1_outhex(mp,(A))
1940  
1941 @c
1942 static void t1_outhex (MP mp, byte b)
1943 {
1944     static char *hexdigits = "0123456789ABCDEF";
1945     t1_putchar (hexdigits[b / 16]);
1946     t1_putchar (hexdigits[b % 16]);
1947     mp->ps->hexline_length += 2;
1948     end_hexline (mp);
1949 }
1950 static void t1_getline (MP mp) {
1951     int c, l, eexec_scan;
1952     char *p;
1953     static const char eexec_str[] = "currentfile eexec";
1954     static int eexec_len = 17;  /* |strlen(eexec_str)| */
1955   RESTART:
1956     if (t1_eof ())
1957         mp_fatal_error (mp,"unexpected end of file");
1958     mp->ps->t1_line_ptr = mp->ps->t1_line_array;
1959     alloc_array (t1_line, 1, T1_BUF_SIZE);
1960     mp->ps->t1_cslen = 0;
1961     eexec_scan = 0;
1962     c = t1_getbyte (mp);
1963     if (c == EOF)
1964         goto EXIT;
1965     while (!t1_eof ()) {
1966         if (mp->ps->t1_in_eexec == 1)
1967             c = edecrypt (mp,c);
1968         alloc_array (t1_line, 1, T1_BUF_SIZE);
1969         append_char_to_buf (c, mp->ps->t1_line_ptr, mp->ps->t1_line_array, mp->ps->t1_line_limit);
1970         if (mp->ps->t1_in_eexec == 0 && eexec_scan >= 0 && eexec_scan < eexec_len) {
1971             if (mp->ps->t1_line_array[eexec_scan] == eexec_str[eexec_scan])
1972                 eexec_scan++;
1973             else
1974                 eexec_scan = -1;
1975         }
1976         if (c == 10 || (mp->ps->t1_pfa && eexec_scan == eexec_len && c == 32))
1977             break;
1978         if (mp->ps->t1_cs && mp->ps->t1_cslen == 0 && 
1979             (mp->ps->t1_line_ptr - mp->ps->t1_line_array > 4) &&
1980             (t1_suffix (" RD ") || t1_suffix (" -| "))) {
1981             p = mp->ps->t1_line_ptr - 5;
1982             while (*p != ' ')
1983                 p--;
1984             mp->ps->t1_cslen = l = t1_scan_num (mp, p + 1, 0);
1985             mp->ps->cs_start = mp->ps->t1_line_ptr - mp->ps->t1_line_array;     
1986                   /* |mp->ps->cs_start| is an index now */
1987             alloc_array (t1_line, l, T1_BUF_SIZE);
1988             while (l-- > 0)
1989                 *mp->ps->t1_line_ptr++ = edecrypt (mp,t1_getbyte (mp));
1990         }
1991         c = t1_getbyte (mp);
1992     }
1993     alloc_array (t1_line, 2, T1_BUF_SIZE);      /* |append_eol| can append 2 chars */
1994     append_eol (mp->ps->t1_line_ptr, mp->ps->t1_line_array, mp->ps->t1_line_limit);
1995     if (mp->ps->t1_line_ptr - mp->ps->t1_line_array < 2)
1996         goto RESTART;
1997     if (eexec_scan == eexec_len)
1998         mp->ps->t1_in_eexec = 1;
1999   EXIT:
2000     /* ensure that |mp->ps->t1_buf_array| has as much room as |t1_line_array| */
2001     mp->ps->t1_buf_ptr = mp->ps->t1_buf_array;
2002     alloc_array (t1_buf, mp->ps->t1_line_limit, mp->ps->t1_line_limit);
2003 }
2004
2005 static void t1_putline (MP mp)
2006 {
2007     char *p = mp->ps->t1_line_array;
2008     if (mp->ps->t1_line_ptr - mp->ps->t1_line_array <= 1)
2009         return;
2010     if (mp->ps->t1_eexec_encrypt) {
2011         while (p < mp->ps->t1_line_ptr)
2012             out_eexec_char (eencrypt (mp,*p++));
2013     } else {
2014         while (p < mp->ps->t1_line_ptr)
2015             t1_putchar (*p++);
2016         }
2017 }
2018
2019 static void t1_puts (MP mp, const char *s)
2020 {
2021     if (s != mp->ps->t1_line_array)
2022         strcpy (mp->ps->t1_line_array, s);
2023     mp->ps->t1_line_ptr = strend (mp->ps->t1_line_array);
2024     t1_putline (mp);
2025 }
2026
2027 static void t1_printf (MP mp, const char *fmt, ...)
2028 {
2029     va_list args;
2030     va_start (args, fmt);
2031     vsprintf (mp->ps->t1_line_array, fmt, args);
2032     t1_puts (mp,mp->ps->t1_line_array);
2033     va_end (args);
2034 }
2035
2036 static void t1_init_params (MP mp, char *open_name_prefix,
2037                            char *cur_file_name) {
2038   if ((open_name_prefix != NULL) && strlen(open_name_prefix)) {
2039     t1_log (open_name_prefix);
2040     t1_log (cur_file_name);
2041   }
2042     mp->ps->t1_lenIV = 4;
2043     mp->ps->t1_dr = 55665;
2044     mp->ps->t1_er = 55665;
2045     mp->ps->t1_in_eexec = 0;
2046     mp->ps->t1_cs = false;
2047     mp->ps->t1_scan = true;
2048     mp->ps->t1_synthetic = false;
2049     mp->ps->t1_eexec_encrypt = false;
2050     mp->ps->t1_block_length = 0;
2051     t1_check_pfa (mp);
2052 }
2053 static void  t1_close_font_file (MP mp, const char *close_name_suffix) {
2054   if ((close_name_suffix != NULL) && strlen(close_name_suffix)) {
2055     t1_log (close_name_suffix);
2056   }
2057   t1_close ();
2058 }
2059
2060 static void  t1_check_block_len (MP mp, boolean decrypt) {
2061     int l, c;
2062     char s[128];
2063     if (mp->ps->t1_block_length == 0)
2064         return;
2065     c = t1_getbyte (mp);
2066     if (decrypt)
2067         c = edecrypt (mp,c);
2068     l = mp->ps->t1_block_length;
2069     if (!(l == 0 && (c == 10 || c == 13))) {
2070         snprintf(s,128,"%i bytes more than expected were ignored", l+ 1);
2071         mp_warn(mp,s);
2072         while (l-- > 0)
2073           t1_getbyte (mp);
2074     }
2075 }
2076 static void  t1_start_eexec (MP mp, fm_entry *fm_cur) {
2077     int i;
2078     if (!mp->ps->t1_pfa)
2079      t1_check_block_len (mp, false);
2080     for (mp->ps->t1_line_ptr = mp->ps->t1_line_array, i = 0; i < 4; i++) {
2081       edecrypt (mp, t1_getbyte (mp));
2082       *mp->ps->t1_line_ptr++ = 0;
2083     }
2084     mp->ps->t1_eexec_encrypt = true;
2085         if (!mp->ps->read_encoding_only)
2086           if (is_included (fm_cur))
2087         t1_putline (mp);          /* to put the first four bytes */
2088 }
2089 static void  t1_stop_eexec (MP mp) {
2090     int c;
2091     end_last_eexec_line ();
2092     if (!mp->ps->t1_pfa)
2093       t1_check_block_len (mp,true);
2094     else {
2095         c = edecrypt (mp, t1_getbyte (mp));
2096         if (!(c == 10 || c == 13)) {
2097            if (mp->ps->last_hexbyte == 0)
2098               t1_puts (mp,"00");
2099            else
2100               mp_warn (mp,"unexpected data after eexec");
2101         }
2102     }
2103     mp->ps->t1_cs = false;
2104     mp->ps->t1_in_eexec = 2;
2105 }
2106 static void  t1_modify_fm (MP mp) {
2107   mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2108 }
2109
2110 static void  t1_modify_italic (MP mp) {
2111   mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2112 }
2113
2114 @ @<Types...@>=
2115 typedef struct {
2116     const char *pdfname;
2117     const char *t1name;
2118     float value;
2119     boolean valid;
2120 } key_entry;
2121
2122 @
2123 @d FONT_KEYS_NUM  11
2124
2125 @<Declarations@>=
2126 static key_entry font_keys[FONT_KEYS_NUM] = {
2127     {"Ascent", "Ascender", 0, false},
2128     {"CapHeight", "CapHeight", 0, false},
2129     {"Descent", "Descender", 0, false},
2130     {"FontName", "FontName", 0, false},
2131     {"ItalicAngle", "ItalicAngle", 0, false},
2132     {"StemV", "StdVW", 0, false},
2133     {"XHeight", "XHeight", 0, false},
2134     {"FontBBox", "FontBBox", 0, false},
2135     {"", "", 0, false},
2136     {"", "", 0, false},
2137     {"", "", 0, false}
2138 };
2139
2140
2141
2142 @d ASCENT_CODE         0
2143 @d CAPHEIGHT_CODE      1
2144 @d DESCENT_CODE        2
2145 @d FONTNAME_CODE       3
2146 @d ITALIC_ANGLE_CODE   4
2147 @d STEMV_CODE          5
2148 @d XHEIGHT_CODE        6
2149 @d FONTBBOX1_CODE      7
2150 @d FONTBBOX2_CODE      8
2151 @d FONTBBOX3_CODE      9
2152 @d FONTBBOX4_CODE      10
2153 @d MAX_KEY_CODE (FONTBBOX1_CODE + 1)
2154
2155 @c
2156 static void  t1_scan_keys (MP mp, int tex_font,fm_entry *fm_cur) {
2157     int i, k;
2158     char *p, *r;
2159     key_entry *key;
2160     if (fm_extend (fm_cur) != 0 || fm_slant (fm_cur) != 0) {
2161         if (t1_prefix ("/FontMatrix")) {
2162             t1_modify_fm (mp);
2163             return;
2164         }
2165         if (t1_prefix ("/ItalicAngle")) {
2166             t1_modify_italic (mp);
2167             return;
2168         }
2169     }
2170     if (t1_prefix ("/FontType")) {
2171         p = mp->ps->t1_line_array + strlen ("FontType") + 1;
2172         if ((i = t1_scan_num (mp,p, 0)) != 1) {
2173             char s[128];
2174             snprintf(s,125,"Type%d fonts unsupported by metapost", i);
2175             mp_fatal_error(mp,s);
2176         }
2177         return;
2178     }
2179     for (key = font_keys; key - font_keys < MAX_KEY_CODE; key++)
2180         if (str_prefix (mp->ps->t1_line_array + 1, key->t1name))
2181             break;
2182     if (key - font_keys == MAX_KEY_CODE)
2183         return;
2184     key->valid = true;
2185     p = mp->ps->t1_line_array + strlen (key->t1name) + 1;
2186     skip (p, ' ');
2187     if ((k = key - font_keys) == FONTNAME_CODE) {
2188         if (*p != '/') {
2189           char s[128];
2190           remove_eol (p, mp->ps->t1_line_array);
2191           snprintf(s,128,"a name expected: `%s'", mp->ps->t1_line_array);
2192           mp_fatal_error(mp,s);
2193         }
2194         r = ++p;                /* skip the slash */
2195         if (is_included (fm_cur)) {
2196           /* save the fontname */
2197           strncpy (mp->ps->fontname_buf, p, FONTNAME_BUF_SIZE);
2198           for (i=0; mp->ps->fontname_buf[i] != 10; i++);
2199           mp->ps->fontname_buf[i]=0;
2200           
2201           if(is_subsetted (fm_cur)) {
2202             if (fm_cur->encoding!=NULL && fm_cur->encoding->glyph_names!=NULL)
2203               make_subset_tag (mp,fm_cur, fm_cur->encoding->glyph_names, tex_font);
2204             else
2205               make_subset_tag (mp,fm_cur, mp->ps->t1_builtin_glyph_names, tex_font);
2206
2207             alloc_array (t1_line, (r-mp->ps->t1_line_array+6+1+strlen(mp->ps->fontname_buf)+1), 
2208                          T1_BUF_SIZE);
2209             strncpy (r, fm_cur->subset_tag , 6);
2210             *(r+6) = '-';
2211             strncpy (r+7, mp->ps->fontname_buf, strlen(mp->ps->fontname_buf)+1);
2212             mp->ps->t1_line_ptr = eol (r);
2213           } else {
2214             /* |for (q = p; *q != ' ' && *q != 10; *q++);|*/
2215             /*|*q = 0;|*/
2216             mp->ps->t1_line_ptr = eol (r);
2217           }
2218         }
2219         return;
2220     }
2221     if ((k == STEMV_CODE || k == FONTBBOX1_CODE)
2222         && (*p == '[' || *p == '{'))
2223         p++;
2224     if (k == FONTBBOX1_CODE) {
2225         for (i = 0; i < 4; i++) {
2226             key[i].value = t1_scan_num (mp, p, &r);
2227             p = r;
2228         }
2229         return;
2230     }
2231     key->value = t1_scan_num (mp, p, 0);
2232 }
2233 static void  t1_scan_param (MP mp, int tex_font,fm_entry *fm_cur)
2234 {
2235     static const char *lenIV = "/lenIV";
2236     if (!mp->ps->t1_scan || *mp->ps->t1_line_array != '/')
2237         return;
2238     if (t1_prefix (lenIV)) {
2239         mp->ps->t1_lenIV = t1_scan_num (mp,mp->ps->t1_line_array + strlen (lenIV), 0);
2240         return;
2241     }
2242     t1_scan_keys (mp, tex_font,fm_cur);
2243 }
2244 static void  copy_glyph_names (char **glyph_names, int a, int b) {
2245     if (glyph_names[b] != notdef) {
2246         mp_xfree (glyph_names[b]);
2247         glyph_names[b] = (char *) notdef;
2248     }
2249     if (glyph_names[a] != notdef) {
2250         glyph_names[b] = mp_xstrdup (glyph_names[a]);
2251     }
2252 }
2253 static void  t1_builtin_enc (MP mp) {
2254     int i, a, b, c, counter = 0;
2255     char *r, *p;
2256     /*
2257      * At this moment "/Encoding" is the prefix of |mp->ps->t1_line_array|
2258      */
2259     if (t1_suffix ("def")) {    /* predefined encoding */
2260         sscanf (mp->ps->t1_line_array + strlen ("/Encoding"), "%256s", mp->ps->t1_buf_array);
2261         if (strcmp (mp->ps->t1_buf_array, "StandardEncoding") == 0) {
2262             for (i = 0; i < 256; i++)
2263                 if (standard_glyph_names[i] == notdef)
2264                     mp->ps->t1_builtin_glyph_names[i] = (char *) notdef;
2265                 else
2266                     mp->ps->t1_builtin_glyph_names[i] =
2267                         mp_xstrdup (standard_glyph_names[i]);
2268             mp->ps->t1_encoding = ENC_STANDARD;
2269         } else {
2270             char s[128];
2271             snprintf(s,128, "cannot subset font (unknown predefined encoding `%s')",
2272                         mp->ps->t1_buf_array);
2273             mp_fatal_error(mp,s);
2274         }
2275         return;
2276     } else
2277         mp->ps->t1_encoding = ENC_BUILTIN;
2278     /*
2279      * At this moment "/Encoding" is the prefix of |mp->ps->t1_line_array|, and the encoding is
2280      * not a predefined encoding
2281      *
2282      * We have two possible forms of Encoding vector. The first case is
2283      *
2284      *     /Encoding [/a /b /c...] readonly def
2285      *
2286      * and the second case can look like
2287      *
2288      *     /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for
2289      *     dup 0 /x put
2290      *     dup 1 /y put
2291      *     ...
2292      *     readonly def
2293      */
2294     for (i = 0; i < 256; i++)
2295         mp->ps->t1_builtin_glyph_names[i] = (char *) notdef;
2296     if (t1_prefix ("/Encoding [") || t1_prefix ("/Encoding[")) {        /* the first case */
2297         r = strchr (mp->ps->t1_line_array, '[') + 1;
2298         skip (r, ' ');
2299         for (;;) {
2300             while (*r == '/') {
2301                 for (p = mp->ps->t1_buf_array, r++;
2302                      *r != 32 && *r != 10 && *r != ']' && *r != '/';
2303                      *p++ = *r++);
2304                 *p = 0;
2305                 skip (r, ' ');
2306                 if (counter > 255) {
2307                    mp_fatal_error
2308                         (mp, "encoding vector contains more than 256 names");
2309                 }
2310                 if (strcmp (mp->ps->t1_buf_array, notdef) != 0)
2311                   mp->ps->t1_builtin_glyph_names[counter] = mp_xstrdup (mp->ps->t1_buf_array);
2312                 counter++;
2313             }
2314             if (*r != 10 && *r != '%') {
2315                 if (str_prefix (r, "] def")
2316                     || str_prefix (r, "] readonly def"))
2317                     break;
2318                 else {
2319                     char s[128];
2320                     remove_eol (r, mp->ps->t1_line_array);
2321                     snprintf(s,128,"a name or `] def' or `] readonly def' expected: `%s'",
2322                                     mp->ps->t1_line_array);
2323                     mp_fatal_error(mp,s);
2324                 }
2325             }
2326             t1_getline (mp);
2327             r = mp->ps->t1_line_array;
2328         }
2329     } else {                    /* the second case */
2330         p = strchr (mp->ps->t1_line_array, 10);
2331         for (;;) {
2332             if (*p == 10) {
2333                 t1_getline (mp);
2334                 p = mp->ps->t1_line_array;
2335             }
2336             /*
2337                check for `dup <index> <glyph> put'
2338              */
2339             if (sscanf (p, "dup %i%256s put", &i, mp->ps->t1_buf_array) == 2 &&
2340                 *mp->ps->t1_buf_array == '/' && valid_code (i)) {
2341                 if (strcmp (mp->ps->t1_buf_array + 1, notdef) != 0)
2342                     mp->ps->t1_builtin_glyph_names[i] = 
2343                       mp_xstrdup (mp->ps->t1_buf_array + 1);
2344                 p = strstr (p, " put") + strlen (" put");
2345                 skip (p, ' ');
2346             }
2347             /*
2348                check for `dup dup <to> exch <from> get put'
2349              */
2350             else if (sscanf (p, "dup dup %i exch %i get put", &b, &a) == 2
2351                      && valid_code (a) && valid_code (b)) {
2352                 copy_glyph_names (mp->ps->t1_builtin_glyph_names, a, b);
2353                 p = strstr (p, " get put") + strlen (" get put");
2354                 skip (p, ' ');
2355             }
2356             /*
2357                check for `dup dup <from> <size> getinterval <to> exch putinterval'
2358              */
2359             else if (sscanf
2360                      (p, "dup dup %i %i getinterval %i exch putinterval",
2361                       &a, &c, &b) == 3 && valid_code (a) && valid_code (b)
2362                      && valid_code (c)) {
2363                 for (i = 0; i < c; i++)
2364                     copy_glyph_names (mp->ps->t1_builtin_glyph_names, a + i, b + i);
2365                 p = strstr (p, " putinterval") + strlen (" putinterval");
2366                 skip (p, ' ');
2367             }
2368             /*
2369                check for `def' or `readonly def'
2370              */
2371             else if ((p == mp->ps->t1_line_array || (p > mp->ps->t1_line_array && p[-1] == ' '))
2372                      && strcmp (p, "def\n") == 0)
2373                 return;
2374             /*
2375                skip an unrecognizable word
2376              */
2377             else {
2378                 while (*p != ' ' && *p != 10)
2379                     p++;
2380                 skip (p, ' ');
2381             }
2382         }
2383     }
2384 }
2385
2386 static void  t1_check_end (MP mp) {
2387     if (t1_eof ())
2388         return;
2389     t1_getline (mp);
2390     if (t1_prefix ("{restore}"))
2391         t1_putline (mp);
2392 }
2393
2394 @ @<Types...@>=
2395 typedef struct {
2396     char *ff_name;              /* base name of font file */
2397     char *ff_path;              /* full path to font file */
2398 } ff_entry;
2399
2400 @ @c
2401 static boolean t1_open_fontfile (MP mp, fm_entry *fm_cur,const char *open_name_prefix) {
2402     ff_entry *ff;
2403     ff = check_ff_exist (mp, fm_cur);
2404     if (ff->ff_path != NULL) {
2405         mp->ps->t1_file = mp_open_file(mp,ff->ff_path, "rb", mp_filetype_font);
2406     } else {
2407         mp_warn (mp, "cannot open Type 1 font file for reading");
2408         return false;
2409     }
2410     t1_init_params (mp,(char *)open_name_prefix,fm_cur->ff_name);
2411     mp->ps->fontfile_found = true;
2412     return true;
2413 }
2414
2415 static void  t1_scan_only (MP mp, int tex_font, fm_entry *fm_cur) {
2416     do {
2417         t1_getline (mp);
2418         t1_scan_param (mp,tex_font, fm_cur);
2419     }
2420     while (mp->ps->t1_in_eexec == 0);
2421     t1_start_eexec (mp,fm_cur);
2422     do {
2423         t1_getline (mp);
2424         t1_scan_param (mp,tex_font, fm_cur);
2425     }
2426     while (!(t1_charstrings () || t1_subrs ()));
2427 }
2428
2429 static void  t1_include (MP mp, int tex_font, fm_entry *fm_cur) {
2430     do {
2431         t1_getline (mp);
2432         t1_scan_param (mp,tex_font, fm_cur);
2433         t1_putline (mp);
2434     }
2435     while (mp->ps->t1_in_eexec == 0);
2436     t1_start_eexec (mp,fm_cur);
2437     do {
2438         t1_getline (mp);
2439         t1_scan_param (mp,tex_font, fm_cur);
2440         t1_putline (mp);
2441     }
2442     while (!(t1_charstrings () || t1_subrs ()));
2443     mp->ps->t1_cs = true;
2444     do {
2445         t1_getline (mp);
2446         t1_putline (mp);
2447     }
2448     while (!t1_end_eexec ());
2449     t1_stop_eexec (mp);
2450     if (fixedcontent) {         /* copy 512 zeros (not needed for PDF) */
2451         do {
2452             t1_getline (mp);
2453             t1_putline (mp);
2454         }
2455         while (!t1_cleartomark ());
2456         t1_check_end (mp);        /* write "{restore}if" if found */
2457     }
2458 }
2459
2460 @
2461 @d check_subr(SUBR) if (SUBR >= mp->ps->subr_size || SUBR < 0) {
2462         char s[128];
2463         snprintf(s,128,"Subrs array: entry index out of range (%i)",SUBR);
2464         mp_fatal_error(mp,s);
2465   }
2466
2467 @c
2468 static const char **check_cs_token_pair (MP mp) {
2469     const char **p = (const char **) cs_token_pairs_list;
2470     for (; p[0] != NULL; ++p)
2471         if (t1_buf_prefix (p[0]) && t1_buf_suffix (p[1]))
2472             return p;
2473     return NULL;
2474 }
2475
2476 static void cs_store (MP mp, boolean is_subr) {
2477     char *p;
2478     cs_entry *ptr;
2479     int subr;
2480     for (p = mp->ps->t1_line_array, mp->ps->t1_buf_ptr = mp->ps->t1_buf_array; *p != ' ';
2481          *mp->ps->t1_buf_ptr++ = *p++);
2482     *mp->ps->t1_buf_ptr = 0;
2483     if (is_subr) {
2484         subr = t1_scan_num (mp, p + 1, 0);
2485         check_subr (subr);
2486         ptr = mp->ps->subr_tab + subr;
2487     } else {
2488         ptr = mp->ps->cs_ptr++;
2489         if (mp->ps->cs_ptr - mp->ps->cs_tab > mp->ps->cs_size) {
2490           char s[128];
2491           snprintf(s,128,"CharStrings dict: more entries than dict size (%i)",mp->ps->cs_size);
2492           mp_fatal_error(mp,s);
2493         }
2494         if (strcmp (mp->ps->t1_buf_array + 1, notdef) == 0)     /* skip the slash */
2495             ptr->glyph_name = (char *) notdef;
2496         else
2497             ptr->glyph_name = mp_xstrdup (mp->ps->t1_buf_array + 1);
2498     }
2499     /* copy " RD " + cs data to |mp->ps->t1_buf_array| */
2500     memcpy (mp->ps->t1_buf_array, mp->ps->t1_line_array + mp->ps->cs_start - 4,
2501             (unsigned) (mp->ps->t1_cslen + 4));
2502     /* copy the end of cs data to |mp->ps->t1_buf_array| */
2503     for (p = mp->ps->t1_line_array + mp->ps->cs_start + mp->ps->t1_cslen, mp->ps->t1_buf_ptr =
2504          mp->ps->t1_buf_array + mp->ps->t1_cslen + 4; *p != 10; *mp->ps->t1_buf_ptr++ = *p++);
2505     *mp->ps->t1_buf_ptr++ = 10;
2506     if (is_subr && mp->ps->cs_token_pair == NULL)
2507         mp->ps->cs_token_pair = check_cs_token_pair (mp);
2508     ptr->len = mp->ps->t1_buf_ptr - mp->ps->t1_buf_array;
2509     ptr->cslen = mp->ps->t1_cslen;
2510     ptr->data = mp_xmalloc (ptr->len , sizeof (byte));
2511     memcpy (ptr->data, mp->ps->t1_buf_array, ptr->len);
2512     ptr->valid = true;
2513 }
2514
2515 #define store_subr(mp)    cs_store(mp,true)
2516 #define store_cs(mp)      cs_store(mp,false)
2517
2518 #define CC_STACK_SIZE       24
2519
2520 static integer cc_stack[CC_STACK_SIZE], *stack_ptr = cc_stack;
2521 static cc_entry cc_tab[CS_MAX];
2522 static boolean is_cc_init = false;
2523
2524
2525 #define cc_pop(N)                       \
2526     if (stack_ptr - cc_stack < (N))     \
2527         stack_error(N);                 \
2528     stack_ptr -= N
2529
2530 #define stack_error(N) {                \
2531     char s[256];                        \
2532     snprintf(s,255,"CharString: invalid access (%i) to stack (%i entries)", \
2533                  (int) N, (int)(stack_ptr - cc_stack));                  \
2534     mp_warn(mp,s);                    \
2535     goto cs_error;                    \
2536 }
2537
2538
2539 #define cc_get(N)   ((N) < 0 ? *(stack_ptr + (N)) : *(cc_stack + (N)))
2540
2541 #define cc_push(V)  *stack_ptr++ = V
2542 #define cc_clear()  stack_ptr = cc_stack
2543
2544 #define set_cc(N, B, A, C) \
2545     cc_tab[N].nargs = A;   \
2546     cc_tab[N].bottom = B;  \
2547     cc_tab[N].clear = C;   \
2548     cc_tab[N].valid = true
2549
2550 static void cc_init (void) {
2551     int i;
2552     if (is_cc_init)
2553         return;
2554     for (i = 0; i < CS_MAX; i++)
2555         cc_tab[i].valid = false;
2556     set_cc (CS_HSTEM, true, 2, true);
2557     set_cc (CS_VSTEM, true, 2, true);
2558     set_cc (CS_VMOVETO, true, 1, true);
2559     set_cc (CS_RLINETO, true, 2, true);
2560     set_cc (CS_HLINETO, true, 1, true);
2561     set_cc (CS_VLINETO, true, 1, true);
2562     set_cc (CS_RRCURVETO, true, 6, true);
2563     set_cc (CS_CLOSEPATH, false, 0, true);
2564     set_cc (CS_CALLSUBR, false, 1, false);
2565     set_cc (CS_RETURN, false, 0, false);
2566     /*
2567        |set_cc(CS_ESCAPE,          false,  0, false);|
2568      */
2569     set_cc (CS_HSBW, true, 2, true);
2570     set_cc (CS_ENDCHAR, false, 0, true);
2571     set_cc (CS_RMOVETO, true, 2, true);
2572     set_cc (CS_HMOVETO, true, 1, true);
2573     set_cc (CS_VHCURVETO, true, 4, true);
2574     set_cc (CS_HVCURVETO, true, 4, true);
2575     set_cc (CS_DOTSECTION, false, 0, true);
2576     set_cc (CS_VSTEM3, true, 6, true);
2577     set_cc (CS_HSTEM3, true, 6, true);
2578     set_cc (CS_SEAC, true, 5, true);
2579     set_cc (CS_SBW, true, 4, true);
2580     set_cc (CS_DIV, false, 2, false);
2581     set_cc (CS_CALLOTHERSUBR, false, 0, false);
2582     set_cc (CS_POP, false, 0, false);
2583     set_cc (CS_SETCURRENTPOINT, true, 2, true);
2584     is_cc_init = true;
2585 }
2586
2587 @
2588
2589 @d cs_getchar(mp)    cdecrypt(mp,*data++, &cr)
2590
2591 @d mark_subr(mp,n)    cs_mark(mp,0, n)
2592 @d mark_cs(mp,s)      cs_mark(mp,s, 0)
2593 @d SMALL_BUF_SIZE      256
2594
2595 @c
2596 static void cs_warn (MP mp, const char *cs_name, int subr, const char *fmt, ...) {
2597     char buf[SMALL_BUF_SIZE];
2598     char s[300];
2599     va_list args;
2600     va_start (args, fmt);
2601     vsprintf (buf, fmt, args);
2602     va_end (args);
2603     if (cs_name == NULL) {
2604         snprintf(s,299,"Subr (%i): %s", (int) subr, buf);
2605     } else {
2606        snprintf(s,299,"CharString (/%s): %s", cs_name, buf);
2607     }
2608     mp_warn(mp,s);
2609 }
2610
2611 static void cs_mark (MP mp, const char *cs_name, int subr)
2612 {
2613     byte *data;
2614     int i, b, cs_len;
2615     integer a, a1, a2;
2616     unsigned short cr;
2617     static integer lastargOtherSubr3 = 3;       /* the argument of last call to
2618                                                    OtherSubrs[3] */
2619     cs_entry *ptr;
2620     cc_entry *cc;
2621     if (cs_name == NULL) {
2622         check_subr (subr);
2623         ptr = mp->ps->subr_tab + subr;
2624         if (!ptr->valid)
2625           return;
2626     } else {
2627         if (mp->ps->cs_notdef != NULL &&
2628             (cs_name == notdef || strcmp (cs_name, notdef) == 0))
2629             ptr = mp->ps->cs_notdef;
2630         else {
2631             for (ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
2632                 if (strcmp (ptr->glyph_name, cs_name) == 0)
2633                     break;
2634             if (ptr == mp->ps->cs_ptr) {
2635                 char s[128];
2636                 snprintf (s,128,"glyph `%s' undefined", cs_name);
2637                 mp_warn(mp,s);
2638                 return;
2639             }
2640             if (ptr->glyph_name == notdef)
2641                 mp->ps->cs_notdef = ptr;
2642         }
2643     }
2644     /* only marked CharString entries and invalid entries can be skipped;
2645        valid marked subrs must be parsed to keep the stack in sync */
2646     if (!ptr->valid || (ptr->is_used && cs_name != NULL))
2647         return;
2648     ptr->is_used = true;
2649     cr = 4330;
2650     cs_len = ptr->cslen;
2651     data = ptr->data + 4;
2652     for (i = 0; i < mp->ps->t1_lenIV; i++, cs_len--)
2653         cs_getchar (mp);
2654     while (cs_len > 0) {
2655         --cs_len;
2656         b = cs_getchar (mp);
2657         if (b >= 32) {
2658             if (b <= 246)
2659                 a = b - 139;
2660             else if (b <= 250) {
2661                 --cs_len;
2662                 a = ((b - 247) << 8) + 108 + cs_getchar (mp);
2663             } else if (b <= 254) {
2664                 --cs_len;
2665                 a = -((b - 251) << 8) - 108 - cs_getchar (mp);
2666             } else {
2667                 cs_len -= 4;
2668                 a = (cs_getchar (mp) & 0xff) << 24;
2669                 a |= (cs_getchar (mp) & 0xff) << 16;
2670                 a |= (cs_getchar (mp) & 0xff) << 8;
2671                 a |= (cs_getchar (mp) & 0xff) << 0;
2672                 if (sizeof (integer) > 4 && (a & 0x80000000))
2673                     a |= ~0x7FFFFFFF;
2674             }
2675             cc_push (a);
2676         } else {
2677             if (b == CS_ESCAPE) {
2678                 b = cs_getchar (mp) + CS_1BYTE_MAX;
2679                 cs_len--;
2680             }
2681             if (b >= CS_MAX) {
2682                 cs_warn (mp,cs_name, subr, "command value out of range: %i",
2683                          (int) b);
2684                 goto cs_error;
2685             }
2686             cc = cc_tab + b;
2687             if (!cc->valid) {
2688                 cs_warn (mp,cs_name, subr, "command not valid: %i", (int) b);
2689                 goto cs_error;
2690             }
2691             if (cc->bottom) {
2692                 if (stack_ptr - cc_stack < cc->nargs)
2693                     cs_warn (mp,cs_name, subr,
2694                              "less arguments on stack (%i) than required (%i)",
2695                              (int) (stack_ptr - cc_stack), (int) cc->nargs);
2696                 else if (stack_ptr - cc_stack > cc->nargs)
2697                     cs_warn (mp,cs_name, subr,
2698                              "more arguments on stack (%i) than required (%i)",
2699                              (int) (stack_ptr - cc_stack), (int) cc->nargs);
2700             }
2701             switch (cc - cc_tab) {
2702             case CS_CALLSUBR:
2703                 a1 = cc_get (-1);
2704                 cc_pop (1);
2705                 mark_subr (mp,a1);
2706                 if (!mp->ps->subr_tab[a1].valid) {
2707                     cs_warn (mp,cs_name, subr, "cannot call subr (%i)", (int) a1);
2708                     goto cs_error;
2709                 }
2710                 break;
2711             case CS_DIV:
2712                 cc_pop (2);
2713                 cc_push (0);
2714                 break;
2715             case CS_CALLOTHERSUBR:
2716                 if (cc_get (-1) == 3)
2717                     lastargOtherSubr3 = cc_get (-3);
2718                 a1 = cc_get (-2) + 2;
2719                 cc_pop (a1);
2720                 break;
2721             case CS_POP:
2722                 cc_push (lastargOtherSubr3);
2723                 /* the only case when we care about the value being pushed onto
2724                    stack is when POP follows CALLOTHERSUBR (changing hints by
2725                    OtherSubrs[3])
2726                  */
2727                 break;
2728             case CS_SEAC:
2729                 a1 = cc_get (3);
2730                 a2 = cc_get (4);
2731                 cc_clear ();
2732                 mark_cs (mp,standard_glyph_names[a1]);
2733                 mark_cs (mp,standard_glyph_names[a2]);
2734                 break;
2735             default:
2736                 if (cc->clear)
2737                     cc_clear ();
2738             }
2739         }
2740     }
2741     return;
2742   cs_error:                    /* an error occured during parsing */
2743     cc_clear ();
2744     ptr->valid = false;
2745     ptr->is_used = false;
2746 }
2747
2748 static void t1_subset_ascii_part (MP mp, int tex_font, fm_entry *fm_cur)
2749 {
2750     int i, j;
2751     t1_getline (mp);
2752     while (!t1_prefix ("/Encoding")) {
2753           t1_scan_param (mp,tex_font, fm_cur);
2754         t1_putline (mp);
2755         t1_getline (mp);
2756     }
2757     t1_builtin_enc (mp);
2758     if (is_reencoded (fm_cur))
2759         mp->ps->t1_glyph_names = external_enc ();
2760     else
2761         mp->ps->t1_glyph_names = mp->ps->t1_builtin_glyph_names;
2762         /* 
2763     |if (is_included (fm_cur) && is_subsetted (fm_cur)) {
2764             make_subset_tag (fm_cur, t1_glyph_names, tex_font);
2765         update_subset_tag ();
2766     }|
2767     */
2768     if ((!is_subsetted (fm_cur)) && mp->ps->t1_encoding == ENC_STANDARD)
2769         t1_puts (mp,"/Encoding StandardEncoding def\n");
2770     else {
2771         t1_puts
2772             (mp,"/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n");
2773         for (i = 0, j = 0; i < 256; i++) {
2774             if (is_used_char (i) && mp->ps->t1_glyph_names[i] != notdef) {
2775                 j++;
2776                 t1_printf (mp,"dup %i /%s put\n", (int) t1_char (i),
2777                            mp->ps->t1_glyph_names[i]);
2778             }
2779         }
2780         /* We didn't mark anything for the Encoding array. */
2781         /* We add "dup 0 /.notdef put" for compatibility   */
2782         /* with Acrobat 5.0.                               */
2783         if (j == 0)
2784             t1_puts (mp,"dup 0 /.notdef put\n");
2785         t1_puts (mp,"readonly def\n");
2786     }
2787     do {
2788         t1_getline (mp);
2789         t1_scan_param (mp,tex_font, fm_cur);
2790         if (!t1_prefix ("/UniqueID"))   /* ignore UniqueID for subsetted fonts */
2791             t1_putline (mp);
2792     }
2793     while (mp->ps->t1_in_eexec == 0);
2794 }
2795
2796 #define t1_subr_flush(mp)  t1_flush_cs(mp,true)
2797 #define t1_cs_flush(mp)    t1_flush_cs(mp,false)
2798
2799 static void cs_init (MP mp) {
2800     mp->ps->cs_ptr = mp->ps->cs_tab = NULL;
2801     mp->ps->cs_dict_start = mp->ps->cs_dict_end = NULL;
2802     mp->ps->cs_count = mp->ps->cs_size = mp->ps->cs_size_pos = 0;
2803     mp->ps->cs_token_pair = NULL;
2804     mp->ps->subr_tab = NULL;
2805     mp->ps->subr_array_start = mp->ps->subr_array_end = NULL;
2806     mp->ps->subr_max = mp->ps->subr_size = mp->ps->subr_size_pos = 0;
2807 }
2808
2809 static void init_cs_entry ( cs_entry * cs) {
2810     cs->data = NULL;
2811     cs->glyph_name = NULL;
2812     cs->len = 0;
2813     cs->cslen = 0;
2814     cs->is_used = false;
2815     cs->valid = false;
2816 }
2817
2818 static void t1_mark_glyphs (MP mp, int tex_font);
2819
2820 static void t1_read_subrs (MP mp, int tex_font, fm_entry *fm_cur)
2821 {
2822     int i, s;
2823     cs_entry *ptr;
2824     t1_getline (mp);
2825     while (!(t1_charstrings () || t1_subrs ())) {
2826         t1_scan_param (mp,tex_font, fm_cur);
2827         t1_putline (mp);
2828         t1_getline (mp);
2829     }
2830   FOUND:
2831     mp->ps->t1_cs = true;
2832     mp->ps->t1_scan = false;
2833     if (!t1_subrs ())
2834         return;
2835     mp->ps->subr_size_pos = strlen ("/Subrs") + 1;
2836     /* |subr_size_pos| points to the number indicating dict size after "/Subrs" */
2837     mp->ps->subr_size = t1_scan_num (mp,mp->ps->t1_line_array + mp->ps->subr_size_pos, 0);
2838     if (mp->ps->subr_size == 0) {
2839         while (!t1_charstrings ())
2840             t1_getline (mp);
2841         return;
2842     }
2843         /*    |subr_tab = xtalloc (subr_size, cs_entry);| */
2844         mp->ps->subr_tab = (cs_entry *)mp_xmalloc (mp->ps->subr_size, sizeof (cs_entry));
2845     for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2846         init_cs_entry (ptr);
2847     mp->ps->subr_array_start = mp_xstrdup (mp->ps->t1_line_array);
2848     t1_getline (mp);
2849     while (mp->ps->t1_cslen) {
2850         store_subr (mp);
2851         t1_getline (mp);
2852     }
2853     /* mark the first four entries without parsing */
2854     for (i = 0; i < mp->ps->subr_size && i < 4; i++)
2855         mp->ps->subr_tab[i].is_used = true;
2856     /* the end of the Subrs array might have more than one line so we need to
2857        concatnate them to |subr_array_end|. Unfortunately some fonts don't have
2858        the Subrs array followed by the CharStrings dict immediately (synthetic
2859        fonts). If we cannot find CharStrings in next |POST_SUBRS_SCAN| lines then
2860        we will treat the font as synthetic and ignore everything until next
2861        Subrs is found
2862      */
2863 #define POST_SUBRS_SCAN     5
2864     s = 0;
2865     *mp->ps->t1_buf_array = 0;
2866     for (i = 0; i < POST_SUBRS_SCAN; i++) {
2867         if (t1_charstrings ())
2868             break;
2869         s += mp->ps->t1_line_ptr - mp->ps->t1_line_array;
2870         alloc_array (t1_buf, s, T1_BUF_SIZE);
2871         strcat (mp->ps->t1_buf_array, mp->ps->t1_line_array);
2872         t1_getline (mp);
2873     }
2874     mp->ps->subr_array_end = mp_xstrdup (mp->ps->t1_buf_array);
2875     if (i == POST_SUBRS_SCAN) { /* CharStrings not found;
2876                                    suppose synthetic font */
2877         for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2878             if (ptr->valid)
2879                 mp_xfree (ptr->data);
2880         mp_xfree (mp->ps->subr_tab);
2881         mp_xfree (mp->ps->subr_array_start);
2882         mp_xfree (mp->ps->subr_array_end);
2883         cs_init (mp);
2884         mp->ps->t1_cs = false;
2885         mp->ps->t1_synthetic = true;
2886         while (!(t1_charstrings () || t1_subrs ()))
2887             t1_getline (mp);
2888         goto FOUND;
2889     }
2890 }
2891
2892 @ @c
2893 static void t1_flush_cs (MP mp, boolean is_subr)
2894 {
2895     char *p;
2896     byte *r, *return_cs = NULL;
2897     cs_entry *tab, *end_tab, *ptr;
2898     char *start_line, *line_end;
2899     int count, size_pos;
2900     unsigned short cr, cs_len = 0; /* to avoid warning about uninitialized use of |cs_len| */
2901     if (is_subr) {
2902         start_line = mp->ps->subr_array_start;
2903         line_end =  mp->ps->subr_array_end;
2904         size_pos =  mp->ps->subr_size_pos;
2905         tab =  mp->ps->subr_tab;
2906         count =  mp->ps->subr_max + 1;
2907         end_tab =  mp->ps->subr_tab + count;
2908     } else {
2909         start_line =  mp->ps->cs_dict_start;
2910         line_end =  mp->ps->cs_dict_end;
2911         size_pos =  mp->ps->cs_size_pos;
2912         tab =  mp->ps->cs_tab;
2913         end_tab =  mp->ps->cs_ptr;
2914         count =  mp->ps->cs_count;
2915     }
2916     mp->ps->t1_line_ptr = mp->ps->t1_line_array;
2917     for (p = start_line; p - start_line < size_pos;)
2918         *mp->ps->t1_line_ptr++ = *p++;
2919     while (isdigit (*p))
2920         p++;
2921     sprintf (mp->ps->t1_line_ptr, "%u", count);
2922     strcat (mp->ps->t1_line_ptr, p);
2923     mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2924     t1_putline (mp);
2925
2926     /* create |return_cs| to replace unsused subr's */
2927     if (is_subr) {
2928         cr = 4330;
2929         cs_len = 0;
2930         return_cs = mp_xmalloc ( (mp->ps->t1_lenIV + 1) , sizeof(byte));
2931         if ( mp->ps->t1_lenIV > 0) {
2932             for (cs_len = 0, r = return_cs; cs_len <  mp->ps->t1_lenIV; cs_len++, r++)
2933                 *r = cencrypt (mp,0x00, &cr);
2934             *r = cencrypt (mp,CS_RETURN, &cr);
2935         } else {
2936             *return_cs = CS_RETURN;
2937         }
2938         cs_len++;
2939     }
2940
2941     for (ptr = tab; ptr < end_tab; ptr++) {
2942         if (ptr->is_used) {
2943             if (is_subr)
2944                 sprintf (mp->ps->t1_line_array, "dup %i %u", (int) (ptr - tab),
2945                          ptr->cslen);
2946             else
2947                 sprintf (mp->ps->t1_line_array, "/%s %u", ptr->glyph_name, ptr->cslen);
2948             p = strend (mp->ps->t1_line_array);
2949             memcpy (p, ptr->data, ptr->len);
2950             mp->ps->t1_line_ptr = p + ptr->len;
2951             t1_putline (mp);
2952         } else {
2953             /* replace unsused subr's by |return_cs| */
2954             if (is_subr) {
2955                 sprintf (mp->ps->t1_line_array, "dup %i %u%s ", (int) (ptr - tab),
2956                          cs_len,  mp->ps->cs_token_pair[0]);
2957                 p = strend (mp->ps->t1_line_array);
2958                 memcpy (p, return_cs, cs_len);
2959                 mp->ps->t1_line_ptr = p + cs_len;
2960                 t1_putline (mp);
2961                 sprintf (mp->ps->t1_line_array, " %s",  mp->ps->cs_token_pair[1]);
2962                 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2963                 t1_putline (mp);
2964             }
2965         }
2966         mp_xfree (ptr->data);
2967         if (ptr->glyph_name != notdef)
2968             mp_xfree (ptr->glyph_name);
2969     }
2970     sprintf (mp->ps->t1_line_array, "%s", line_end);
2971     mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2972     t1_putline (mp);
2973     if (is_subr)
2974         mp_xfree (return_cs);
2975     mp_xfree (tab);
2976     mp_xfree (start_line);
2977     mp_xfree (line_end);
2978 }
2979
2980 static void t1_mark_glyphs (MP mp, int tex_font)
2981 {
2982     int i;
2983     char *charset = extra_charset ();
2984     char *g, *s, *r;
2985     cs_entry *ptr;
2986     if (mp->ps->t1_synthetic || embed_all_glyphs (tex_font)) {  /* mark everything */
2987         if (mp->ps->cs_tab != NULL)
2988             for (ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
2989                 if (ptr->valid)
2990                     ptr->is_used = true;
2991         if (mp->ps->subr_tab != NULL) {
2992             for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2993                 if (ptr->valid)
2994                     ptr->is_used = true;
2995             mp->ps->subr_max = mp->ps->subr_size - 1;
2996         }
2997         return;
2998     }
2999     mark_cs (mp,notdef);
3000     for (i = 0; i < 256; i++)
3001         if (is_used_char (i)) {
3002             if (mp->ps->t1_glyph_names[i] == notdef) {
3003                 char s[128];
3004                 snprintf(s,128, "character %i is mapped to %s", i, notdef);
3005                 mp_warn(mp,s);
3006             } else
3007                 mark_cs (mp,mp->ps->t1_glyph_names[i]);
3008         }
3009     if (charset == NULL)
3010         goto SET_SUBR_MAX;
3011     g = s = charset + 1;        /* skip the first '/' */
3012     r = strend (g);
3013     while (g < r) {
3014         while (*s != '/' && s < r)
3015             s++;
3016         *s = 0;                 /* terminate g by rewriting '/' to 0 */
3017         mark_cs (mp,g);
3018         g = s + 1;
3019     }
3020   SET_SUBR_MAX:
3021     if (mp->ps->subr_tab != NULL)
3022         for (mp->ps->subr_max = -1, ptr = mp->ps->subr_tab; 
3023                  ptr - mp->ps->subr_tab < mp->ps->subr_size; 
3024              ptr++)
3025             if (ptr->is_used && ptr - mp->ps->subr_tab > mp->ps->subr_max)
3026                 mp->ps->subr_max = ptr - mp->ps->subr_tab;
3027 }
3028
3029 static void t1_subset_charstrings (MP mp, int tex_font) 
3030 {
3031     cs_entry *ptr;
3032     mp->ps->cs_size_pos =
3033         strstr (mp->ps->t1_line_array, charstringname) + strlen (charstringname)
3034         - mp->ps->t1_line_array + 1;
3035     /* |cs_size_pos| points to the number indicating
3036        dict size after "/CharStrings" */
3037     mp->ps->cs_size = t1_scan_num (mp,mp->ps->t1_line_array + mp->ps->cs_size_pos, 0);
3038     mp->ps->cs_ptr = mp->ps->cs_tab = mp_xmalloc (mp->ps->cs_size, sizeof(cs_entry));
3039     for (ptr = mp->ps->cs_tab; ptr - mp->ps->cs_tab < mp->ps->cs_size; ptr++)
3040         init_cs_entry (ptr);
3041     mp->ps->cs_notdef = NULL;
3042     mp->ps->cs_dict_start = mp_xstrdup (mp->ps->t1_line_array);
3043     t1_getline (mp);
3044     while (mp->ps->t1_cslen) {
3045         store_cs (mp);
3046         t1_getline (mp);
3047     }
3048     mp->ps->cs_dict_end = mp_xstrdup (mp->ps->t1_line_array);
3049     t1_mark_glyphs (mp,tex_font);
3050     if (mp->ps->subr_tab != NULL) {
3051         if (mp->ps->cs_token_pair == NULL) 
3052             mp_fatal_error
3053                 (mp, "This Type 1 font uses mismatched subroutine begin/end token pairs.");
3054         t1_subr_flush (mp);
3055     }
3056     for (mp->ps->cs_count = 0, ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
3057         if (ptr->is_used)
3058             mp->ps->cs_count++;
3059     t1_cs_flush (mp);
3060 }
3061
3062 static void t1_subset_end (MP mp)
3063 {
3064     if (mp->ps->t1_synthetic) {         /* copy to "dup /FontName get exch definefont pop" */
3065         while (!strstr (mp->ps->t1_line_array, "definefont")) {
3066             t1_getline (mp);
3067             t1_putline (mp);
3068         }
3069         while (!t1_end_eexec ())
3070             t1_getline (mp);      /* ignore the rest */
3071         t1_putline (mp);          /* write "mark currentfile closefile" */
3072     } else
3073         while (!t1_end_eexec ()) {      /* copy to "mark currentfile closefile" */
3074             t1_getline (mp);
3075             t1_putline (mp);
3076         }
3077     t1_stop_eexec (mp);
3078     if (fixedcontent) {         /* copy 512 zeros (not needed for PDF) */
3079         while (!t1_cleartomark ()) {
3080             t1_getline (mp);
3081             t1_putline (mp);
3082         }
3083         if (!mp->ps->t1_synthetic)      /* don't check "{restore}if" for synthetic fonts */
3084             t1_check_end (mp);    /* write "{restore}if" if found */
3085     }
3086 }
3087
3088 static int t1_updatefm (MP mp, int f, fm_entry *fm)
3089 {
3090   char *s, *p;
3091   mp->ps->read_encoding_only = true;
3092   if (!t1_open_fontfile (mp,fm,NULL)) {
3093         return 0;
3094   }
3095   t1_scan_only (mp,f, fm);
3096   s = mp_xstrdup(mp->ps->fontname_buf);
3097   p = s;
3098   while (*p != ' ' && *p != 0) 
3099      p++;
3100   *p=0;
3101   fm->ps_name = s;
3102   t1_close_font_file (mp,"");
3103   return 1;
3104 }
3105
3106
3107 static void  writet1 (MP mp, int tex_font, fm_entry *fm_cur) {
3108         int save_selector = mp->selector;
3109     mp_normalize_selector(mp);
3110     mp->ps->read_encoding_only = false;
3111     if (!is_included (fm_cur)) {        /* scan parameters from font file */
3112       if (!t1_open_fontfile (mp,fm_cur,"{"))
3113             return;
3114             t1_scan_only (mp,tex_font, fm_cur);
3115         t1_close_font_file (mp,"}");
3116         return;
3117     }
3118     if (!is_subsetted (fm_cur)) {       /* include entire font */
3119       if (!t1_open_fontfile (mp,fm_cur,"<<"))
3120             return;
3121           t1_include (mp,tex_font,fm_cur);
3122         t1_close_font_file (mp,">>");
3123         return;
3124     }
3125     /* partial downloading */
3126     if (!t1_open_fontfile (mp,fm_cur,"<"))
3127         return;
3128     t1_subset_ascii_part (mp,tex_font,fm_cur);
3129     t1_start_eexec (mp,fm_cur);
3130     cc_init ();
3131     cs_init (mp);
3132     t1_read_subrs (mp,tex_font, fm_cur);
3133     t1_subset_charstrings (mp,tex_font);
3134     t1_subset_end (mp);
3135     t1_close_font_file (mp,">");
3136     mp->selector = save_selector; 
3137 }
3138
3139 @ @<Declarations@>=
3140 static void t1_free (MP mp);
3141
3142 @ @c
3143 static void  t1_free (MP mp) {
3144   mp_xfree (mp->ps->t1_line_array);
3145   mp_xfree (mp->ps->t1_buf_array);
3146 }
3147
3148
3149 @* \[44d] Embedding fonts.
3150
3151 @ The |tfm_num| is officially of type |font_number|, but that
3152 type does not exist yet at this point in the output order.
3153
3154 @<Types...@>=
3155 typedef struct {
3156     char *tfm_name;             /* TFM file name */
3157     char *ps_name;              /* PostScript name */
3158     integer flags;              /* font flags */
3159     char *ff_name;              /* font file name */
3160     char *subset_tag;           /* pseudoUniqueTag for subsetted font */
3161     enc_entry *encoding;        /* pointer to corresponding encoding */
3162     unsigned int tfm_num;       /* number of the TFM refering this entry */
3163     unsigned short type;        /* font type (T1/TTF/...) */
3164     short slant;                /* SlantFont */
3165     short extend;               /* ExtendFont */
3166     integer ff_objnum;          /* FontFile object number */
3167     integer fn_objnum;          /* FontName/BaseName object number */
3168     integer fd_objnum;          /* FontDescriptor object number */
3169     char *charset;              /* string containing used glyphs */
3170     boolean all_glyphs;         /* embed all glyphs? */
3171     unsigned short links;       /* link flags from |tfm_tree| and |ps_tree| */
3172     short tfm_avail;            /* flags whether a tfm is available */
3173     short pid;                  /* Pid for truetype fonts */
3174     short eid;                  /* Eid for truetype fonts */
3175 } fm_entry;
3176
3177
3178
3179 @<Glob...@>=
3180 #define FONTNAME_BUF_SIZE 128
3181 boolean fontfile_found;
3182 boolean is_otf_font;
3183 char fontname_buf[FONTNAME_BUF_SIZE];
3184
3185
3186 @d F_INCLUDED          0x01
3187 @d F_SUBSETTED         0x02
3188 @d F_TRUETYPE          0x04
3189 @d F_BASEFONT          0x08
3190
3191 @d set_included(fm)    ((fm)->type |= F_INCLUDED)
3192 @d set_subsetted(fm)   ((fm)->type |= F_SUBSETTED)
3193 @d set_truetype(fm)    ((fm)->type |= F_TRUETYPE)
3194 @d set_basefont(fm)    ((fm)->type |= F_BASEFONT)
3195
3196 @d is_included(fm)     ((fm)->type & F_INCLUDED)
3197 @d is_subsetted(fm)    ((fm)->type & F_SUBSETTED)
3198 @d is_truetype(fm)     ((fm)->type & F_TRUETYPE)
3199 @d is_basefont(fm)     ((fm)->type & F_BASEFONT)
3200 @d is_reencoded(fm)    ((fm)->encoding != NULL)
3201 @d is_fontfile(fm)     (fm_fontfile(fm) != NULL)
3202 @d is_t1fontfile(fm)   (is_fontfile(fm) && !is_truetype(fm))
3203
3204 @d fm_slant(fm)        (fm)->slant
3205 @d fm_extend(fm)       (fm)->extend
3206 @d fm_fontfile(fm)     (fm)->ff_name
3207
3208 @<Exported function headers@>=
3209 boolean mp_font_is_reencoded (MP mp, int f);
3210 boolean mp_font_is_included (MP mp, int f);
3211 boolean mp_font_is_subsetted (MP mp, int f);
3212
3213 @ @c
3214 boolean mp_font_is_reencoded (MP mp, int f) {
3215   fm_entry *fm;
3216   if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f, &fm)) { 
3217     if (fm != NULL 
3218         && (fm->ps_name != NULL)
3219         && is_reencoded (fm))
3220       return 1;
3221   }
3222   return 0;
3223 }
3224 boolean mp_font_is_included (MP mp, int f) {
3225   fm_entry *fm;
3226   if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f, &fm)) { 
3227     if (fm != NULL 
3228         && (fm->ps_name != NULL && fm->ff_name != NULL) 
3229         && is_included (fm))
3230       return 1;
3231   }
3232   return 0;
3233 }
3234 boolean mp_font_is_subsetted (MP mp, int f) {
3235   fm_entry *fm;
3236   if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f,&fm)) { 
3237     if (fm != NULL 
3238           && (fm->ps_name != NULL && fm->ff_name != NULL) 
3239           && is_included (fm) && is_subsetted (fm))
3240       return 1;
3241   }
3242   return 0;
3243 }
3244
3245 @ @<Exported function headers@>=
3246 char * mp_fm_encoding_name (MP mp, int f);
3247 char * mp_fm_font_name (MP mp, int f);
3248 char * mp_fm_font_subset_name (MP mp, int f);
3249
3250
3251 @c char * mp_fm_encoding_name (MP mp, int f) {
3252   enc_entry *e;
3253   fm_entry *fm;
3254   if (mp_has_fm_entry (mp, f, &fm)) { 
3255     if (fm != NULL && (fm->ps_name != NULL)) {
3256       if (is_reencoded (fm)) {
3257         e = fm->encoding;
3258         if (e->enc_name!=NULL)
3259           return mp_xstrdup(e->enc_name);
3260       } else {
3261         return NULL;
3262       }
3263     }
3264   }
3265   print_err ("fontmap encoding problems for font ");
3266   mp_print(mp,mp->font_name[f]);
3267   mp_error(mp); 
3268   return NULL;
3269 }
3270 char * mp_fm_font_name (MP mp, int f) {
3271   fm_entry *fm;
3272   if (mp_has_fm_entry (mp, f,&fm)) { 
3273     if (fm != NULL && (fm->ps_name != NULL)) {
3274       if (mp_font_is_included(mp, f) && !mp->font_ps_name_fixed[f]) {
3275         /* find the real fontname, and update |ps_name| and |subset_tag| if needed */
3276         if (t1_updatefm(mp,f,fm)) {
3277           mp->font_ps_name_fixed[f] = true;
3278         } else {
3279           print_err ("font loading problems for font ");
3280           mp_print(mp,mp->font_name[f]);
3281           mp_error(mp);
3282         }
3283       }
3284       return mp_xstrdup(fm->ps_name);
3285     }
3286   }
3287   print_err ("fontmap name problems for font ");
3288   mp_print(mp,mp->font_name[f]);
3289   mp_error(mp); 
3290   return NULL;
3291 }
3292
3293 char * mp_fm_font_subset_name (MP mp, int f) {
3294   fm_entry *fm;
3295   if (mp_has_fm_entry (mp, f, &fm)) { 
3296     if (fm != NULL && (fm->ps_name != NULL)) {
3297       if (is_subsetted(fm)) {
3298             char *s = mp_xmalloc(strlen(fm->ps_name)+8,1);
3299         snprintf(s,strlen(fm->ps_name)+8,"%s-%s",fm->subset_tag,fm->ps_name);
3300             return s;
3301       } else {
3302         return mp_xstrdup(fm->ps_name);
3303       }
3304     }
3305   }
3306   print_err ("fontmap name problems for font ");
3307   mp_print(mp,mp->font_name[f]);
3308   mp_error(mp); 
3309   return NULL;
3310 }
3311
3312 @ @<Exported function headers@>=
3313 integer mp_fm_font_slant (MP mp, int f);
3314 integer mp_fm_font_extend (MP mp, int f);
3315
3316
3317 @c integer mp_fm_font_slant (MP mp, int f) {
3318   fm_entry *fm;
3319   if (mp_has_fm_entry (mp, f, &fm)) { 
3320     if (fm != NULL && (fm->ps_name != NULL)) {
3321       return fm->slant;
3322     }
3323   }
3324   return 0;
3325 }
3326 integer mp_fm_font_extend (MP mp, int f) {
3327   fm_entry *fm;
3328   if (mp_has_fm_entry (mp, f, &fm)) { 
3329     if (fm != NULL && (fm->ps_name != NULL)) {
3330       return fm->extend;
3331     }
3332   }
3333   return 0;
3334 }
3335
3336 @ @<Exported function headers@>=
3337 boolean mp_do_ps_font (MP mp, font_number f);
3338
3339 @ @c boolean mp_do_ps_font (MP mp, font_number f) {
3340   fm_entry *fm_cur;
3341   (void)mp_has_fm_entry (mp, f, &fm_cur); /* for side effects */
3342   if (fm_cur == NULL)
3343     return 1;
3344   if (is_truetype(fm_cur) ||
3345          (fm_cur->ps_name == NULL && fm_cur->ff_name == NULL)) {
3346     return 0;
3347   }
3348   if (is_included(fm_cur)) {
3349     mp_print_nl(mp,"%%BeginResource: font ");
3350     if (is_subsetted(fm_cur)) {
3351       mp_print(mp, fm_cur->subset_tag);
3352       mp_print_char(mp,'-');
3353     }
3354     mp_print(mp, fm_cur->ps_name);
3355     mp_print_ln(mp);
3356     writet1 (mp,f,fm_cur);
3357     mp_print_nl(mp,"%%EndResource");
3358     mp_print_ln(mp);
3359   }
3360   return 1;
3361 }
3362
3363 @ Included subset fonts do not need and encoding vector, make
3364 sure we skip that case.
3365
3366 @<Exported...@>=
3367 void mp_list_used_resources (MP mp, int prologues, int procset);
3368
3369 @ @c void mp_list_used_resources (MP mp, int prologues, int procset) {
3370   font_number f; /* fonts used in a text node or as loop counters */
3371   int ff;  /* a loop counter */
3372   font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3373   boolean firstitem;
3374   if ( procset>0 )
3375     mp_print_nl(mp, "%%DocumentResources: procset mpost");
3376   else
3377     mp_print_nl(mp, "%%DocumentResources: procset mpost-minimal");
3378   ldf=null_font;
3379   firstitem=true;
3380   for (f=null_font+1;f<=mp->last_fnum;f++) {
3381     if ( (mp_has_font_size(mp,f))&&(mp_font_is_reencoded(mp,f)) ) {
3382           for (ff=ldf;ff>=null_font;ff--) {
3383         if ( mp_has_font_size(mp,ff) )
3384           if ( mp_xstrcmp(mp->font_enc_name[f],mp->font_enc_name[ff])==0 )
3385             goto FOUND;
3386       }
3387       if ( mp_font_is_subsetted(mp,f) )
3388         goto FOUND;
3389       if ( mp->ps_offset+1+strlen(mp->font_enc_name[f])>
3390            (unsigned)mp->max_print_line )
3391         mp_print_nl(mp, "%%+ encoding");
3392       if ( firstitem ) {
3393         firstitem=false;
3394         mp_print_nl(mp, "%%+ encoding");
3395       }
3396       mp_print_char(mp, ' ');
3397       mp_print(mp, mp->font_enc_name[f]);
3398       ldf=f;
3399     }
3400   FOUND:
3401     ;
3402   }
3403   ldf=null_font;
3404   firstitem=true;
3405   for (f=null_font+1;f<=mp->last_fnum;f++) {
3406     if ( mp_has_font_size(mp,f) ) {
3407       for (ff=ldf;ff>=null_font;ff--) {
3408         if ( mp_has_font_size(mp,ff) )
3409           if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3410             goto FOUND2;
3411       }
3412       if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>
3413                (unsigned)mp->max_print_line )
3414         mp_print_nl(mp, "%%+ font");
3415       if ( firstitem ) {
3416         firstitem=false;
3417         mp_print_nl(mp, "%%+ font");
3418       }
3419       mp_print_char(mp, ' ');
3420           if ( (prologues==3)&&
3421            (mp_font_is_subsetted(mp,f)) )
3422         mp_print(mp, mp_fm_font_subset_name(mp,f));
3423       else
3424         mp_print(mp, mp->font_ps_name[f]);
3425       ldf=f;
3426     }
3427   FOUND2:
3428     ;
3429   }
3430   mp_print_ln(mp);
3431
3432
3433 @ @<Exported...@>=
3434 void mp_list_supplied_resources (MP mp, int prologues, int procset);
3435
3436 @ @c void mp_list_supplied_resources (MP mp, int prologues, int procset) {
3437   font_number f; /* fonts used in a text node or as loop counters */
3438   int ff; /* a loop counter */
3439   font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3440   boolean firstitem;
3441   if ( procset>0 )
3442     mp_print_nl(mp, "%%DocumentSuppliedResources: procset mpost");
3443   else
3444     mp_print_nl(mp, "%%DocumentSuppliedResources: procset mpost-minimal");
3445   ldf=null_font;
3446   firstitem=true;
3447   for (f=null_font+1;f<=mp->last_fnum;f++) {
3448     if ( (mp_has_font_size(mp,f))&&(mp_font_is_reencoded(mp,f)) )  {
3449        for (ff=ldf;ff>= null_font;ff++) {
3450          if ( mp_has_font_size(mp,ff) )
3451            if ( mp_xstrcmp(mp->font_enc_name[f],mp->font_enc_name[ff])==0 )
3452              goto FOUND;
3453         }
3454       if ( (prologues==3)&&(mp_font_is_subsetted(mp,f)))
3455         goto FOUND;
3456       if ( mp->ps_offset+1+strlen(mp->font_enc_name[f])>(unsigned)mp->max_print_line )
3457         mp_print_nl(mp, "%%+ encoding");
3458       if ( firstitem ) {
3459         firstitem=false;
3460         mp_print_nl(mp, "%%+ encoding");
3461       }
3462       mp_print_char(mp, ' ');
3463       mp_print(mp, mp->font_enc_name[f]);
3464       ldf=f;
3465     }
3466   FOUND:
3467     ;
3468   }
3469   ldf=null_font;
3470   firstitem=true;
3471   if (prologues==3) {
3472     for (f=null_font+1;f<=mp->last_fnum;f++) {
3473       if ( mp_has_font_size(mp,f) ) {
3474         for (ff=ldf;ff>= null_font;ff--) {
3475           if ( mp_has_font_size(mp,ff) )
3476             if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3477                goto FOUND2;
3478         }
3479         if ( ! mp_font_is_included(mp,f) )
3480           goto FOUND2;
3481         if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3482           mp_print_nl(mp, "%%+ font");
3483         if ( firstitem ) {
3484           firstitem=false;
3485           mp_print_nl(mp, "%%+ font");
3486         }
3487         mp_print_char(mp, ' ');
3488             if ( mp_font_is_subsetted(mp,f) ) 
3489           mp_print(mp, mp_fm_font_subset_name(mp,f));
3490         else
3491           mp_print(mp, mp->font_ps_name[f]);
3492         ldf=f;
3493       }
3494     FOUND2:
3495       ;
3496     }
3497     mp_print_ln(mp);
3498   }
3499 }
3500
3501 @ @<Exported...@>=
3502 void mp_list_needed_resources (MP mp, int prologues);
3503
3504 @ @c void mp_list_needed_resources (MP mp, int prologues) {
3505   font_number f; /* fonts used in a text node or as loop counters */
3506   int ff; /* a loop counter */
3507   font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3508   boolean firstitem;
3509   ldf=null_font;
3510   firstitem=true;
3511   for (f=null_font+1;f<=mp->last_fnum;f++ ) {
3512     if ( mp_has_font_size(mp,f)) {
3513       for (ff=ldf;ff>=null_font;ff--) {
3514         if ( mp_has_font_size(mp,ff) )
3515           if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3516              goto FOUND;
3517       };
3518       if ((prologues==3)&&(mp_font_is_included(mp,f)) )
3519         goto FOUND;
3520       if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3521         mp_print_nl(mp, "%%+ font");
3522       if ( firstitem ) {
3523         firstitem=false;
3524         mp_print_nl(mp, "%%DocumentNeededResources: font");
3525       }
3526       mp_print_char(mp, ' ');
3527       mp_print(mp, mp->font_ps_name[f]);
3528       ldf=f;
3529     }
3530   FOUND:
3531     ;
3532   }
3533   if ( ! firstitem ) {
3534     mp_print_ln(mp);
3535     ldf=null_font;
3536     firstitem=true;
3537     for (f=null_font+1;f<= mp->last_fnum;f++) {
3538       if ( mp_has_font_size(mp,f) ) {
3539         for (ff=ldf;ff>=null_font;ff-- ) {
3540           if ( mp_has_font_size(mp,ff) )
3541             if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3542               goto FOUND2;
3543         }
3544         if ((prologues==3)&&(mp_font_is_included(mp,f)) )
3545           goto FOUND2;
3546         mp_print(mp, "%%IncludeResource: font ");
3547         mp_print(mp, mp->font_ps_name[f]);
3548         mp_print_ln(mp);
3549         ldf=f;
3550       }
3551     FOUND2:
3552       ;
3553     }
3554   }
3555 }
3556
3557 @ @<Exported...@>=
3558 void mp_write_font_definition (MP mp, font_number f, int prologues);
3559
3560
3561
3562 @d applied_reencoding(A) ((mp_font_is_reencoded(mp,(A)))&&
3563     ((! mp_font_is_subsetted(mp,(A)))||(prologues==2)))
3564
3565 @c void mp_write_font_definition(MP mp, font_number f, int prologues) {
3566   if ( (applied_reencoding(f))||(mp_fm_font_slant(mp,f)!=0)||
3567        (mp_fm_font_extend(mp,f)!=0)||
3568        (mp_xstrcmp(mp->font_name[f],"psyrgo")==0)||
3569        (mp_xstrcmp(mp->font_name[f],"zpzdr-reversed")==0) ) {
3570     if ( (mp_font_is_subsetted(mp,f))&&
3571          (mp_font_is_included(mp,f))&&(prologues==3))
3572       mp_ps_name_out(mp, mp_fm_font_subset_name(mp,f),true);
3573     else 
3574       mp_ps_name_out(mp, mp->font_ps_name[f],true);
3575     mp_ps_print(mp, " fcp");
3576     mp_print_ln(mp);
3577     if ( applied_reencoding(f) ) {
3578       mp_ps_print(mp, "/Encoding ");
3579       mp_ps_print(mp, mp->font_enc_name[f]);
3580       mp_ps_print(mp, " def ");
3581     };
3582     if ( mp_fm_font_slant(mp,f)!=0 ) {
3583       mp_print_int(mp, mp_fm_font_slant(mp,f));
3584       mp_ps_print(mp, " SlantFont ");
3585     };
3586     if ( mp_fm_font_extend(mp,f)!=0 ) {
3587       mp_print_int(mp, mp_fm_font_extend(mp,f));
3588       mp_ps_print(mp, " ExtendFont ");
3589     };
3590     if ( mp_xstrcmp(mp->font_name[f],"psyrgo")==0 ) {
3591       mp_ps_print(mp, " 890 ScaleFont ");
3592       mp_ps_print(mp, " 277 SlantFont ");
3593     };
3594     if ( mp_xstrcmp(mp->font_name[f],"zpzdr-reversed")==0 ) {
3595       mp_ps_print(mp, " FontMatrix [-1 0 0 1 0 0] matrix concatmatrix /FontMatrix exch def ");
3596       mp_ps_print(mp, "/Metrics 2 dict dup begin ");
3597       mp_ps_print(mp, "/space[0 -278]def ");
3598       mp_ps_print(mp, "/a12[-904 -939]def ");
3599       mp_ps_print(mp, "end def ");
3600     };  
3601     mp_ps_print(mp, "currentdict end");
3602     mp_print_ln(mp);
3603     mp_ps_print_defined_name(mp,f,prologues);
3604     mp_ps_print(mp, " exch definefont pop");
3605     mp_print_ln(mp);
3606   }
3607 }
3608
3609 @ @<Exported...@>=
3610 void mp_ps_print_defined_name (MP mp, font_number f, int prologues);
3611
3612
3613 @c  void mp_ps_print_defined_name(MP mp, font_number A, int prologues) {
3614   mp_ps_print(mp, " /");
3615   if ((mp_font_is_subsetted(mp,(A)))&&
3616       (mp_font_is_included(mp,(A)))&&(prologues==3))
3617     mp_print(mp, mp_fm_font_subset_name(mp,(A)));
3618   else 
3619     mp_print(mp, mp->font_ps_name[(A)]);
3620   if ( mp_xstrcmp(mp->font_name[(A)],"psyrgo")==0 )
3621     mp_ps_print(mp, "-Slanted");
3622   if ( mp_xstrcmp(mp->font_name[(A)],"zpzdr-reversed")==0 ) 
3623     mp_ps_print(mp, "-Reverse");
3624   if ( applied_reencoding((A)) ) { 
3625     mp_ps_print(mp, "-");
3626     mp_ps_print(mp, mp->font_enc_name[(A)]); 
3627   }
3628   if ( mp_fm_font_slant(mp,(A))!=0 ) {
3629     mp_ps_print(mp, "-Slant_"); mp_print_int(mp, mp_fm_font_slant(mp,(A))) ;
3630   }
3631   if ( mp_fm_font_extend(mp,(A))!=0 ) {
3632     mp_ps_print(mp, "-Extend_"); mp_print_int(mp, mp_fm_font_extend(mp,(A))); 
3633   }
3634 }
3635
3636 @ @<Include encodings and fonts for edge structure~|h|@>=
3637 mp_font_encodings(mp,mp->last_fnum,prologues==2);
3638 @<Embed fonts that are available@>
3639
3640 @ @<Embed fonts that are available@>=
3641
3642 next_size=0;
3643 @<Make |cur_fsize| a copy of the |font_sizes| array@>;
3644 do {  
3645   done_fonts=true;
3646   for (f=null_font+1;f<=mp->last_fnum;f++) {
3647     if ( cur_fsize[f]!=null ) {
3648       if (prologues==3 ) {
3649         if ( ! mp_do_ps_font(mp,f) ) {
3650               if ( mp_has_fm_entry(mp,f, NULL) ) {
3651             print_err("Font embedding failed");
3652             mp_error(mp);
3653           }
3654         }
3655       }
3656       cur_fsize[f]=link(cur_fsize[f]);
3657       if ( cur_fsize[f]!=null ) { mp_unmark_font(mp, f); done_fonts=false; }
3658     }
3659   }
3660   if ( ! done_fonts )
3661     @<Increment |next_size| and apply |mark_string_chars| to all text nodes with
3662       that size index@>;
3663 } while (! done_fonts);
3664 }
3665
3666 @ @<Increment |next_size| and apply |mark_string_chars| to all text nodes...@>=
3667
3668   next_size++;
3669   mp_apply_mark_string_chars(mp, h, next_size);
3670 }
3671
3672 @ We also need to keep track of which characters are used in text nodes
3673 in the edge structure that is being shipped out.  This is done by procedures
3674 that use the left-over |b3| field in the |char_info| words; i.e.,
3675 |char_info(f)(c).b3| gives the status of character |c| in font |f|.
3676
3677 @<Types...@>=
3678 enum {unused=0, used};
3679
3680 @ @<Exported ...@>=
3681 void mp_unmark_font (MP mp,font_number f) ;
3682
3683 @ @c
3684 void mp_unmark_font (MP mp,font_number f) {
3685   int k; /* an index into |font_info| */
3686   for (k= mp->char_base[f]+mp->font_bc[f];
3687        k<=mp->char_base[f]+mp->font_ec[f];
3688        k++)
3689     mp->font_info[k].qqqq.b3=unused;
3690 }
3691
3692
3693 @ @<Exported...@>=
3694 void mp_print_improved_prologue (MP mp, int prologues, int procset, 
3695                                  int groffmode, int null, pointer h) ;
3696
3697
3698 @
3699 @c
3700 void mp_print_improved_prologue (MP mp, int prologues, int procset, 
3701                                  int groffmode, int null, pointer h) {
3702   quarterword next_size; /* the size index for fonts being listed */
3703   pointer *cur_fsize; /* current positions in |font_sizes| */
3704   boolean done_fonts; /* have we finished listing the fonts in the header? */
3705   font_number f; /* a font number for loops */
3706    
3707   cur_fsize = mp_xmalloc((mp->font_max+1),sizeof(pointer));
3708
3709   mp_list_used_resources(mp, prologues, procset);
3710   mp_list_supplied_resources(mp, prologues, procset);
3711   mp_list_needed_resources(mp, prologues);
3712   mp_print_nl(mp, "%%EndComments");
3713   mp_print_nl(mp, "%%BeginProlog");
3714   if ( procset>0 )
3715     mp_print_nl(mp, "%%BeginResource: procset mpost");
3716   else
3717     mp_print_nl(mp, "%%BeginResource: procset mpost-minimal");
3718   mp_print_nl(mp, "/bd{bind def}bind def"
3719                   "/fshow {exch findfont exch scalefont setfont show}bd");
3720   if ( procset>0 ) @<Print the procset@>;
3721   mp_print_nl(mp, "/fcp{findfont dup length dict begin"
3722                   "{1 index/FID ne{def}{pop pop}ifelse}forall}bd");
3723   mp_print_nl(mp, "/fmc{FontMatrix dup length array copy dup dup}bd"
3724                    "/fmd{/FontMatrix exch def}bd");
3725   mp_print_nl(mp, "/Amul{4 -1 roll exch mul 1000 div}bd"
3726                   "/ExtendFont{fmc 0 get Amul 0 exch put fmd}bd");
3727   if ( groffmode>0 ) {
3728     mp_print_nl(mp, "/ScaleFont{dup fmc 0 get"
3729                         " Amul 0 exch put dup dup 3 get Amul 3 exch put fmd}bd");
3730     };
3731   mp_print_nl(mp, "/SlantFont{fmc 2 get dup 0 eq{pop 1}if"
3732                       " Amul FontMatrix 0 get mul 2 exch put fmd}bd");
3733   mp_print_nl(mp, "%%EndResource");
3734   @<Include encodings and fonts  for edge structure~|h|@>;
3735   mp_print_nl(mp, "%%EndProlog");
3736   mp_print_nl(mp, "%%BeginSetup");
3737   mp_print_ln(mp);
3738   for (f=null_font+1;f<=mp->last_fnum;f++) {
3739     if ( mp_has_font_size(mp,f) ) {
3740       if ( mp_has_fm_entry(mp,f,NULL) ) {
3741         mp_write_font_definition(mp,f,(mp->internal[prologues]>>16));
3742         mp_ps_name_out(mp, mp->font_name[f],true);
3743         mp_ps_print_defined_name(mp,f,(mp->internal[prologues]>>16));
3744         mp_ps_print(mp, " def");
3745       } else {
3746         char s[256];
3747         snprintf(s,256,"font %s cannot be found in any fontmapfile!", mp->font_name[f]);
3748         mp_warn(mp,s);
3749         mp_ps_name_out(mp, mp->font_name[f],true);
3750         mp_ps_name_out(mp, mp->font_name[f],true);
3751         mp_ps_print(mp, " def");
3752       }
3753       mp_print_ln(mp);
3754     }
3755   }
3756   mp_print_nl(mp, "%%EndSetup");
3757   mp_print_nl(mp, "%%Page: 1 1");
3758   mp_print_ln(mp);
3759   mp_xfree(cur_fsize);
3760 }
3761
3762 @ @<Exported...@>=
3763 font_number mp_print_font_comments (MP mp , int prologues, int null, pointer h);
3764
3765
3766
3767 @c 
3768 font_number mp_print_font_comments (MP mp , int prologues, int null, pointer h) {
3769   quarterword next_size; /* the size index for fonts being listed */
3770   pointer *cur_fsize; /* current positions in |font_sizes| */
3771   int ff; /* a loop counter */
3772   boolean done_fonts; /* have we finished listing the fonts in the header? */
3773   font_number f; /* a font number for loops */
3774   scaled ds; /* design size and scale factor for a text node */
3775   font_number ldf=0; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3776   cur_fsize = mp_xmalloc((mp->font_max+1),sizeof(pointer));
3777   if ( prologues>0 ) {
3778     @<Give a \.{DocumentFonts} comment listing all fonts with non-null
3779       |font_sizes| and eliminate duplicates@>;
3780   } else { 
3781     next_size=0;
3782     @<Make |cur_fsize| a copy of the |font_sizes| array@>;
3783     do {  done_fonts=true;
3784       for (f=null_font+1;f<=mp->last_fnum;f++) {
3785         if ( cur_fsize[f]!=null ) {
3786           @<Print the \.{\%*Font} comment for font |f| and advance |cur_fsize[f]|@>;
3787         }
3788         if ( cur_fsize[f]!=null ) { mp_unmark_font(mp, f); done_fonts=false;  };
3789       }
3790       if ( ! done_fonts ) {
3791         @<Increment |next_size| and apply |mark_string_chars| to all text nodes with
3792           that size index@>;
3793       }
3794     } while (! done_fonts);
3795   }
3796   mp_xfree(cur_fsize);
3797   return ldf;
3798 }
3799
3800 @ @<Make |cur_fsize| a copy of the |font_sizes| array@>=
3801 for (f=null_font+1;f<= mp->last_fnum;f++)
3802   cur_fsize[f]=mp->font_sizes[f]
3803
3804 @ It's not a good idea to make any assumptions about the |font_ps_name| entries,
3805 so we carefully remove duplicates.  There is no harm in using a slow, brute-force
3806 search.
3807
3808 @<Give a \.{DocumentFonts} comment listing all fonts with non-null...@>=
3809
3810   ldf=null_font;
3811   for (f=null_font+1;f<= mp->last_fnum;f++) {
3812     if ( mp->font_sizes[f]!=null ) {
3813       if ( ldf==null_font ) 
3814         mp_print_nl(mp, "%%DocumentFonts:");
3815       for (ff=ldf;ff>=null_font;ff--) {
3816         if ( mp->font_sizes[ff]!=null )
3817           if ( mp_xstrcmp(mp->font_ps_name[f],mp->font_ps_name[ff])==0 )
3818             goto FOUND;
3819       }
3820       if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3821         mp_print_nl(mp, "%%+");
3822       mp_print_char(mp, ' ');
3823       mp_print(mp, mp->font_ps_name[f]);
3824       ldf=f;
3825     FOUND:
3826       ;
3827     }
3828   }
3829 }
3830
3831 @ @c
3832 void mp_hex_digit_out (MP mp,small_number d) { 
3833   if ( d<10 ) mp_print_char(mp, d+'0');
3834   else mp_print_char(mp, d+'a'-10);
3835 }
3836
3837 @ We output the marks as a hexadecimal bit string starting at |c| or
3838 |font_bc[f]|, whichever is greater.  If the output has to be truncated
3839 to avoid exceeding |emergency_line_length| the return value says where to
3840 start scanning next time.
3841
3842 @<Declarations@>=
3843 halfword mp_ps_marks_out (MP mp,font_number f, eight_bits c);
3844
3845
3846 @d emergency_line_length 255
3847   /* \ps\ output lines can be this long in unusual circumstances */
3848
3849 @c
3850 halfword mp_ps_marks_out (MP mp,font_number f, eight_bits c) {
3851   eight_bits bc,ec; /* only encode characters between these bounds */
3852   integer lim; /* the maximum number of marks to encode before truncating */
3853   int p; /* |font_info| index for the current character */
3854   int d,b; /* used to construct a hexadecimal digit */
3855   lim=4*(emergency_line_length-mp->ps_offset-4);
3856   bc=mp->font_bc[f];
3857   ec=mp->font_ec[f];
3858   if ( c>bc ) bc=c;
3859   @<Restrict the range |bc..ec| so that it contains no unused characters
3860     at either end and has length at most |lim|@>;
3861   @<Print the initial label indicating that the bitmap starts at |bc|@>;
3862   @<Print a hexadecimal encoding of the marks for characters |bc..ec|@>;
3863   while ( (ec<mp->font_ec[f])&&(mp->font_info[p].qqqq.b3==unused) ) {
3864     p++; ec++;
3865   }
3866   return (ec+1);
3867 }
3868
3869 @ We could save time by setting the return value before the loop that
3870 decrements |ec|, but there is no point in being so tricky.
3871
3872 @<Restrict the range |bc..ec| so that it contains no unused characters...@>=
3873 p=mp->char_base[f]+bc;
3874 while ( (mp->font_info[p].qqqq.b3==unused)&&(bc<ec) ) {
3875   p++; bc++;
3876 }
3877 if ( ec>=bc+lim ) ec=bc+lim-1;
3878 p=mp->char_base[f]+ec;
3879 while ( (mp->font_info[p].qqqq.b3==unused)&&(bc<ec) ) { 
3880   p--; ec--;
3881 }
3882
3883 @ @<Print the initial label indicating that the bitmap starts at |bc|@>=
3884 mp_print_char(mp, ' ');
3885 mp_hex_digit_out(mp, bc / 16);
3886 mp_hex_digit_out(mp, bc % 16);
3887 mp_print_char(mp, ':')
3888
3889
3890
3891 @<Print a hexadecimal encoding of the marks for characters |bc..ec|@>=
3892 b=8; d=0;
3893 for (p=mp->char_base[f]+bc;p<=mp->char_base[f]+ec;p++) {
3894   if ( b==0 ) {
3895     mp_hex_digit_out(mp, d);
3896     d=0; b=8;
3897   }
3898   if ( mp->font_info[p].qqqq.b3!=unused ) d=d+b;
3899   b=b>>1;
3900 }
3901 mp_hex_digit_out(mp, d)
3902
3903
3904 @ Here is a simple function that determines whether there are any marked
3905 characters in font~|f| with character code at least~|c|.
3906
3907 @<Declarations@>=
3908 boolean mp_check_ps_marks (MP mp,font_number f, integer  c) ;
3909
3910 @ @c
3911 boolean mp_check_ps_marks (MP mp,font_number f, integer  c) {
3912   int p; /* |font_info| index for the current character */
3913   for (p=mp->char_base[f]+c;p<=mp->char_base[f]+mp->font_ec[f];p++) {
3914     if ( mp->font_info[p].qqqq.b3==used ) 
3915        return true;
3916   }
3917   return false;
3918 }
3919
3920
3921 @ If the file name is so long that it can't be printed without exceeding
3922 |emergency_line_length| then there will be missing items in the \.{\%*Font:}
3923 line.  We might have to repeat line in order to get the character usage
3924 information to fit within |emergency_line_length|.
3925
3926 TODO: these two defines are also defined in mp.w!
3927
3928 @d link(A)   mp->mem[(A)].hh.rh /* the |link| field of a memory word */
3929 @d sc_factor(A) mp->mem[(A)+1].cint /* the scale factor stored in a font size node */
3930
3931 @<Print the \.{\%*Font} comment for font |f| and advance |cur_fsize[f]|@>=
3932 { integer t=0;
3933   while ( mp_check_ps_marks(mp, f,t) ) {
3934     mp_print_nl(mp, "%*Font: ");
3935     if ( mp->ps_offset+strlen(mp->font_name[f])+12>emergency_line_length )
3936       break;
3937     mp_print(mp, mp->font_name[f]);
3938     mp_print_char(mp, ' ');
3939     ds=(mp->font_dsize[f] + 8) / 16;
3940     mp_print_scaled(mp, mp_take_scaled(mp, ds,sc_factor(cur_fsize[f])));
3941     if ( mp->ps_offset+12>emergency_line_length ) break;
3942     mp_print_char(mp, ' ');
3943     mp_print_scaled(mp, ds);
3944     if ( mp->ps_offset+5>emergency_line_length ) break;
3945     t=mp_ps_marks_out(mp, f,t);
3946   }
3947   cur_fsize[f]=link(cur_fsize[f]);
3948 }
3949
3950 @ @<Print the procset@>=
3951 {
3952   mp_print_nl(mp, "/hlw{0 dtransform exch truncate exch idtransform pop setlinewidth}bd");
3953   mp_print_nl(mp, "/vlw{0 exch dtransform truncate idtransform setlinewidth pop}bd");
3954   mp_print_nl(mp, "/l{lineto}bd/r{rlineto}bd/c{curveto}bd/m{moveto}bd"
3955                   "/p{closepath}bd/n{newpath}bd");
3956   mp_print_nl(mp, "/C{setcmykcolor}bd/G{setgray}bd/R{setrgbcolor}bd"
3957                   "/lj{setlinejoin}bd/ml{setmiterlimit}bd");
3958   mp_print_nl(mp, "/lc{setlinecap}bd/S{stroke}bd/F{fill}bd/q{gsave}bd"
3959                   "/Q{grestore}bd/s{scale}bd/t{concat}bd");
3960   mp_print_nl(mp, "/sd{setdash}bd/rd{[] 0 setdash}bd/P{showpage}bd/B{q F Q}bd/W{clip}bd");
3961 }
3962
3963
3964 @ The prologue defines \.{fshow} and corrects for the fact that \.{fshow}
3965 arguments use |font_name| instead of |font_ps_name|.  Downloaded bitmap fonts
3966 might not have reasonable |font_ps_name| entries, but we just charge ahead
3967 anyway.  The user should not make \&{prologues} positive if this will cause
3968 trouble.
3969 @:prologues_}{\&{prologues} primitive@>
3970
3971 @<Exported...@>=
3972 void mp_print_prologue (MP mp, int prologues, int procset, int ldf);
3973
3974 @ @c 
3975 void mp_print_prologue (MP mp, int prologues, int procset, int ldf) {
3976   font_number f;
3977   mp_print(mp, "%%BeginProlog"); mp_print_ln(mp);
3978   if ( (prologues>0)||(procset>0) ) {
3979     if ( ldf!=null_font ) {
3980       if ( prologues>0 ) {
3981         for (f=null_font+1;f<=mp->last_fnum;f++) {
3982           if ( mp_has_font_size(mp,f) ) {
3983             mp_ps_name_out(mp, mp->font_name[f],true);
3984             mp_ps_name_out(mp, mp->font_ps_name[f],true);
3985             mp_ps_print(mp, " def");
3986             mp_print_ln(mp);
3987           }
3988         }
3989         if ( procset==0 ) {
3990           mp_print(mp, "/fshow {exch findfont exch scalefont setfont show}bind def");
3991           mp_print_ln(mp);
3992         }
3993       }
3994     }
3995     if (procset>0 ) {
3996       mp_print_nl(mp, "%%BeginResource: procset mpost");
3997       if ( (prologues>0)&&(ldf!=null_font) )
3998         mp_print(mp, 
3999         "/bd{bind def}bind def/fshow {exch findfont exch scalefont setfont show}bd");
4000       else
4001         mp_print_nl(mp, "/bd{bind def}bind def");
4002       @<Print the procset@>;
4003       mp_print_nl(mp, "%%EndResource");
4004       mp_print_ln(mp);
4005     }
4006   }
4007   mp_print(mp, "%%EndProlog");
4008 }
4009
4010