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