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