split off mem i/o; remove unused test_pen; bump version number; drop separate mptfmin.h
[mplib] / src / texk / web2c / mpdir / tfmin.w
1 % $Id: mp.w 597 2008-07-03 15:35:34Z taco $
2 %
3 % Copyright 2008 Taco Hoekwater.
4 %
5 % This program is free software: you can redistribute it and/or modify
6 % it under the terms of the GNU General Public License as published by
7 % the Free Software Foundation, either version 2 of the License, or
8 % (at your option) any later version.
9 %
10 % This program is distributed in the hope that it will be useful,
11 % but WITHOUT ANY WARRANTY; without even the implied warranty of
12 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 % GNU General Public License for more details.
14 %
15 % You should have received a copy of the GNU General Public License
16 % along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 %
18 % TeX is a trademark of the American Mathematical Society.
19 % METAFONT is a trademark of Addison-Wesley Publishing Company.
20 % PostScript is a trademark of Adobe Systems Incorporated.
21
22 % Here is TeX material that gets inserted after \input webmac
23
24 \def\title{Reading TEX metrics files}
25 \pdfoutput=1
26
27 @ Introduction.
28
29 @ Needed headers and macros
30
31 @d qi(A) (quarterword)(A) /* to store eight bits in a quarterword */
32 @d null_font 0 /* the |font_number| for an empty font */
33 @d false 0
34 @d true 1
35 @d hlp1(A) mp->help_line[0]=A; }
36 @d hlp2(A,B) mp->help_line[1]=A; hlp1(B)
37 @d hlp3(A,B,C) mp->help_line[2]=A; hlp2(B,C)
38 @d help3  { mp->help_ptr=3; hlp3 /* use this with three help lines */
39
40 @c 
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include "mplib.h"
45 #include "mpmp.h" /* internal header */
46 @h
47
48 @ The |font_ps_name| for a built-in font should be what PostScript expects.
49 A preliminary name is obtained here from the \.{TFM} name as given in the
50 |fname| argument.  This gets updated later from an external table if necessary.
51
52 @c
53 font_number mp_read_font_info (MP mp, char *fname) {
54   boolean file_opened; /* has |tfm_infile| been opened? */
55   font_number n; /* the number to return */
56   halfword lf,tfm_lh,bc,ec,nw,nh,nd; /* subfile size parameters */
57   size_t whd_size; /* words needed for heights, widths, and depths */
58   int i,ii; /* |font_info| indices */
59   int jj; /* counts bytes to be ignored */
60   scaled z; /* used to compute the design size */
61   fraction d; /* height, width, or depth as a fraction of design size times $2^{-8}$ */
62   int h_and_d; /* height and depth indices being unpacked */
63   int tfbyte = 0; /* a byte read from the file */
64   n=null_font;
65   @<Open |tfm_infile| for input@>;
66   @<Read data from |tfm_infile|; if there is no room, say so and |goto done|;
67     otherwise |goto bad_tfm| or |goto done| as appropriate@>;
68 BAD_TFM:
69   @<Complain that the \.{TFM} file is bad@>;
70 DONE:
71   if ( file_opened ) (mp->close_file)(mp,mp->tfm_infile);
72   if ( n!=null_font ) { 
73     mp->font_ps_name[n]=mp_xstrdup(mp,fname);
74     mp->font_name[n]=mp_xstrdup(mp,fname);
75   }
76   return n;
77 }
78
79 @ \MP\ doesn't bother to check the entire \.{TFM} file for errors or explain
80 precisely what is wrong if it does find a problem.  Programs called \.{TFtoPL}
81 @.TFtoPL@> @.PLtoTF@>
82 and \.{PLtoTF} can be used to debug \.{TFM} files.
83
84 @<Complain that the \.{TFM} file is bad@>=
85 mp_print_err(mp,"Font ");
86 mp_print(mp, fname);
87 if ( file_opened ) mp_print(mp, " not usable: TFM file is bad");
88 else mp_print(mp, " not usable: TFM file not found");
89 help3("I wasn't able to read the size data for this font so this",
90   "`infont' operation won't produce anything. If the font name",
91   "is right, you might ask an expert to make a TFM file");
92 if ( file_opened )
93   mp->help_line[0]="is right, try asking an expert to fix the TFM file";
94 mp_error(mp)
95
96 @ @<Read data from |tfm_infile|; if there is no room, say so...@>=
97 @<Read the \.{TFM} size fields@>;
98 @<Use the size fields to allocate space in |font_info|@>;
99 @<Read the \.{TFM} header@>;
100 @<Read the character data and the width, height, and depth tables and
101   |goto done|@>
102
103 @ A bad \.{TFM} file can be shorter than it claims to be.  The code given here
104 might try to read past the end of the file if this happens.  Changes will be
105 needed if it causes a system error to refer to |tfm_infile^| or call
106 |get_tfm_infile| when |eof(tfm_infile)| is true.  For example, the definition
107 @^system dependencies@>
108 of |tfget| could be changed to
109 ``|begin get(tfm_infile); if eof(tfm_infile) then goto bad_tfm; end|.''
110
111 @d tfget do { 
112   size_t wanted=1; 
113   void *tfbyte_ptr = &tfbyte;
114   (mp->read_binary_file)(mp,mp->tfm_infile, &tfbyte_ptr,&wanted); 
115   if (wanted==0) goto BAD_TFM; 
116 } while (0)
117 @d read_two(A) { (A)=tfbyte;
118   if ( (A)>127 ) goto BAD_TFM;
119   tfget; (A)=(A)*0400+tfbyte;
120 }
121 @d tf_ignore(A) { for (jj=(A);jj>=1;jj--) tfget; }
122
123 @<Read the \.{TFM} size fields@>=
124 tfget; read_two(lf);
125 tfget; read_two(tfm_lh);
126 tfget; read_two(bc);
127 tfget; read_two(ec);
128 if ( (bc>1+ec)||(ec>255) ) goto BAD_TFM;
129 tfget; read_two(nw);
130 tfget; read_two(nh);
131 tfget; read_two(nd);
132 whd_size=(size_t)((ec+1-bc)+nw+nh+nd);
133 if ( lf<(int)(6+tfm_lh+whd_size) ) goto BAD_TFM;
134 tf_ignore(10)
135
136 @ Offsets are added to |char_base[n]| and |width_base[n]| so that is not
137 necessary to apply the |so|  and |qo| macros when looking up the width of a
138 character in the string pool.  In order to ensure nonnegative |char_base|
139 values when |bc>0|, it may be necessary to reserve a few unused |font_info|
140 elements.
141
142 @<Use the size fields to allocate space in |font_info|@>=
143 if ( mp->next_fmem<(size_t)bc) 
144   mp->next_fmem=(size_t)bc; /* ensure nonnegative |char_base| */
145 if (mp->last_fnum==mp->font_max)
146   mp_reallocate_fonts(mp,(mp->font_max+(mp->font_max/4)));
147 while (mp->next_fmem+whd_size>=mp->font_mem_size) {
148   size_t l = mp->font_mem_size+(mp->font_mem_size/4);
149   memory_word *font_info;
150   font_info = mp_xmalloc (mp,(l+1),sizeof(memory_word));
151   memset (font_info,0,sizeof(memory_word)*(l+1));
152   memcpy (font_info,mp->font_info,sizeof(memory_word)*(mp->font_mem_size+1));
153   mp_xfree(mp->font_info);
154   mp->font_info = font_info;
155   mp->font_mem_size = l;
156 }
157 mp->last_fnum++;
158 n=mp->last_fnum;
159 mp->font_bc[n]=(eight_bits)bc;
160 mp->font_ec[n]=(eight_bits)ec;
161 mp->char_base[n]=(int)(mp->next_fmem-bc);
162 mp->width_base[n]=(int)(mp->next_fmem+ec-bc+1);
163 mp->height_base[n]=mp->width_base[n]+nw;
164 mp->depth_base[n]=mp->height_base[n]+nh;
165 mp->next_fmem=mp->next_fmem+whd_size;
166
167
168 @ @<Read the \.{TFM} header@>=
169 if ( tfm_lh<2 ) goto BAD_TFM;
170 tf_ignore(4);
171 tfget; read_two(z);
172 tfget; z=z*0400+tfbyte;
173 tfget; z=z*0400+tfbyte; /* now |z| is 16 times the design size */
174 mp->font_dsize[n]=mp_take_fraction(mp, z,267432584);
175   /* times ${72\over72.27}2^{28}$ to convert from \TeX\ points */
176 tf_ignore(4*(tfm_lh-2))
177
178 @ @<Read the character data and the width, height, and depth tables...@>=
179 ii=mp->width_base[n];
180 i=mp->char_base[n]+bc;
181 while ( i<ii ) { 
182   tfget; mp->font_info[i].qqqq.b0=qi(tfbyte);
183   tfget; h_and_d=tfbyte;
184   mp->font_info[i].qqqq.b1=qi(h_and_d / 16);
185   mp->font_info[i].qqqq.b2=qi(h_and_d % 16);
186   tfget; tfget;
187   i++;
188 }
189 while ( i<(int)mp->next_fmem ) {
190   @<Read a four byte dimension, scale it by the design size, store it in
191     |font_info[i]|, and increment |i|@>;
192 }
193 goto DONE
194
195 @ The raw dimension read into |d| should have magnitude at most $2^{24}$ when
196 interpreted as an integer, and this includes a scale factor of $2^{20}$.  Thus
197 we can multiply it by sixteen and think of it as a |fraction| that has been
198 divided by sixteen.  This cancels the extra scale factor contained in
199 |font_dsize[n|.
200
201 @<Read a four byte dimension, scale it by the design size, store it in...@>=
202
203 tfget; d=tfbyte;
204 if ( d>=0200 ) d=d-0400;
205 tfget; d=d*0400+tfbyte;
206 tfget; d=d*0400+tfbyte;
207 tfget; d=d*0400+tfbyte;
208 mp->font_info[i].cint=mp_take_fraction(mp, d*16,mp->font_dsize[n]);
209 i++;
210 }
211
212 @ This function does no longer use the file name parser, because |fname| is
213 a C string already.
214
215 @<Open |tfm_infile| for input@>=
216 file_opened=false;
217 mp_ptr_scan_file(mp, fname);
218 if ( strlen(mp->cur_area)==0 ) { mp_xfree(mp->cur_area); mp->cur_area=NULL; }
219 if ( strlen(mp->cur_ext)==0 )  { 
220     mp_xfree(mp->cur_ext); 
221     mp->cur_ext=mp_xstrdup(mp,".tfm"); 
222 }
223 mp_pack_file_name(mp, mp->cur_name,mp->cur_area,mp->cur_ext);
224 mp->tfm_infile = (mp->open_file)(mp, mp->name_of_file, "r",mp_filetype_metrics);
225 if ( !mp->tfm_infile  ) goto BAD_TFM;
226 file_opened=true
227
228
229
230
231
232
233
234