1 % $Id: mp.w 597 2008-07-03 15:35:34Z taco $
3 % Copyright 2008 Taco Hoekwater.
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.
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.
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/>.
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.
22 % Here is TeX material that gets inserted after \input webmac
24 \def\title{Reading TEX metrics files}
29 @ Needed headers and macros
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 */
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 */
45 #include "mpmp.h" /* internal header */
52 extern font_number mp_read_font_info (MP mp, char *fname);
54 @ The |font_ps_name| for a built-in font should be what PostScript expects.
55 A preliminary name is obtained here from the \.{TFM} name as given in the
56 |fname| argument. This gets updated later from an external table if necessary.
59 font_number mp_read_font_info (MP mp, char *fname) {
60 boolean file_opened; /* has |tfm_infile| been opened? */
61 font_number n; /* the number to return */
62 halfword lf,tfm_lh,bc,ec,nw,nh,nd; /* subfile size parameters */
63 size_t whd_size; /* words needed for heights, widths, and depths */
64 int i,ii; /* |font_info| indices */
65 int jj; /* counts bytes to be ignored */
66 scaled z; /* used to compute the design size */
67 fraction d; /* height, width, or depth as a fraction of design size times $2^{-8}$ */
68 int h_and_d; /* height and depth indices being unpacked */
69 int tfbyte = 0; /* a byte read from the file */
71 @<Open |tfm_infile| for input@>;
72 @<Read data from |tfm_infile|; if there is no room, say so and |goto done|;
73 otherwise |goto bad_tfm| or |goto done| as appropriate@>;
75 @<Complain that the \.{TFM} file is bad@>;
77 if ( file_opened ) (mp->close_file)(mp,mp->tfm_infile);
79 mp->font_ps_name[n]=mp_xstrdup(mp,fname);
80 mp->font_name[n]=mp_xstrdup(mp,fname);
85 @ \MP\ doesn't bother to check the entire \.{TFM} file for errors or explain
86 precisely what is wrong if it does find a problem. Programs called \.{TFtoPL}
88 and \.{PLtoTF} can be used to debug \.{TFM} files.
90 @<Complain that the \.{TFM} file is bad@>=
91 mp_print_err(mp,"Font ");
93 if ( file_opened ) mp_print(mp, " not usable: TFM file is bad");
94 else mp_print(mp, " not usable: TFM file not found");
95 help3("I wasn't able to read the size data for this font so this",
96 "`infont' operation won't produce anything. If the font name",
97 "is right, you might ask an expert to make a TFM file");
99 mp->help_line[0]="is right, try asking an expert to fix the TFM file";
102 @ @<Read data from |tfm_infile|; if there is no room, say so...@>=
103 @<Read the \.{TFM} size fields@>;
104 @<Use the size fields to allocate space in |font_info|@>;
105 @<Read the \.{TFM} header@>;
106 @<Read the character data and the width, height, and depth tables and
109 @ A bad \.{TFM} file can be shorter than it claims to be. The code given here
110 might try to read past the end of the file if this happens. Changes will be
111 needed if it causes a system error to refer to |tfm_infile^| or call
112 |get_tfm_infile| when |eof(tfm_infile)| is true. For example, the definition
113 @^system dependencies@>
114 of |tfget| could be changed to
115 ``|begin get(tfm_infile); if eof(tfm_infile) then goto bad_tfm; end|.''
119 void *tfbyte_ptr = &tfbyte;
120 (mp->read_binary_file)(mp,mp->tfm_infile, &tfbyte_ptr,&wanted);
121 if (wanted==0) goto BAD_TFM;
123 @d read_two(A) { (A)=tfbyte;
124 if ( (A)>127 ) goto BAD_TFM;
125 tfget; (A)=(A)*0400+tfbyte;
127 @d tf_ignore(A) { for (jj=(A);jj>=1;jj--) tfget; }
129 @<Read the \.{TFM} size fields@>=
131 tfget; read_two(tfm_lh);
134 if ( (bc>1+ec)||(ec>255) ) goto BAD_TFM;
138 whd_size=(size_t)((ec+1-bc)+nw+nh+nd);
139 if ( lf<(int)(6+tfm_lh+whd_size) ) goto BAD_TFM;
142 @ Offsets are added to |char_base[n]| and |width_base[n]| so that is not
143 necessary to apply the |so| and |qo| macros when looking up the width of a
144 character in the string pool. In order to ensure nonnegative |char_base|
145 values when |bc>0|, it may be necessary to reserve a few unused |font_info|
148 @<Use the size fields to allocate space in |font_info|@>=
149 if ( mp->next_fmem<(size_t)bc)
150 mp->next_fmem=(size_t)bc; /* ensure nonnegative |char_base| */
151 if (mp->last_fnum==mp->font_max)
152 mp_reallocate_fonts(mp,(mp->font_max+(mp->font_max/4)));
153 while (mp->next_fmem+whd_size>=mp->font_mem_size) {
154 size_t l = mp->font_mem_size+(mp->font_mem_size/4);
155 memory_word *font_info;
156 font_info = mp_xmalloc (mp,(l+1),sizeof(memory_word));
157 memset (font_info,0,sizeof(memory_word)*(l+1));
158 memcpy (font_info,mp->font_info,sizeof(memory_word)*(mp->font_mem_size+1));
159 mp_xfree(mp->font_info);
160 mp->font_info = font_info;
161 mp->font_mem_size = l;
165 mp->font_bc[n]=(eight_bits)bc;
166 mp->font_ec[n]=(eight_bits)ec;
167 mp->char_base[n]=(int)(mp->next_fmem-bc);
168 mp->width_base[n]=(int)(mp->next_fmem+ec-bc+1);
169 mp->height_base[n]=mp->width_base[n]+nw;
170 mp->depth_base[n]=mp->height_base[n]+nh;
171 mp->next_fmem=mp->next_fmem+whd_size;
174 @ @<Read the \.{TFM} header@>=
175 if ( tfm_lh<2 ) goto BAD_TFM;
178 tfget; z=z*0400+tfbyte;
179 tfget; z=z*0400+tfbyte; /* now |z| is 16 times the design size */
180 mp->font_dsize[n]=mp_take_fraction(mp, z,267432584);
181 /* times ${72\over72.27}2^{28}$ to convert from \TeX\ points */
182 tf_ignore(4*(tfm_lh-2))
184 @ @<Read the character data and the width, height, and depth tables...@>=
185 ii=mp->width_base[n];
186 i=mp->char_base[n]+bc;
188 tfget; mp->font_info[i].qqqq.b0=qi(tfbyte);
189 tfget; h_and_d=tfbyte;
190 mp->font_info[i].qqqq.b1=qi(h_and_d / 16);
191 mp->font_info[i].qqqq.b2=qi(h_and_d % 16);
195 while ( i<(int)mp->next_fmem ) {
196 @<Read a four byte dimension, scale it by the design size, store it in
197 |font_info[i]|, and increment |i|@>;
201 @ The raw dimension read into |d| should have magnitude at most $2^{24}$ when
202 interpreted as an integer, and this includes a scale factor of $2^{20}$. Thus
203 we can multiply it by sixteen and think of it as a |fraction| that has been
204 divided by sixteen. This cancels the extra scale factor contained in
207 @<Read a four byte dimension, scale it by the design size, store it in...@>=
210 if ( d>=0200 ) d=d-0400;
211 tfget; d=d*0400+tfbyte;
212 tfget; d=d*0400+tfbyte;
213 tfget; d=d*0400+tfbyte;
214 mp->font_info[i].cint=mp_take_fraction(mp, d*16,mp->font_dsize[n]);
218 @ This function does no longer use the file name parser, because |fname| is
221 @<Open |tfm_infile| for input@>=
223 mp_ptr_scan_file(mp, fname);
224 if ( strlen(mp->cur_area)==0 ) { mp_xfree(mp->cur_area); mp->cur_area=NULL; }
225 if ( strlen(mp->cur_ext)==0 ) {
226 mp_xfree(mp->cur_ext);
227 mp->cur_ext=mp_xstrdup(mp,".tfm");
229 mp_pack_file_name(mp, mp->cur_name,mp->cur_area,mp->cur_ext);
230 mp_xfree(mp->tfm_infile);
231 mp->tfm_infile = (mp->open_file)(mp, mp->name_of_file, "r",mp_filetype_metrics);
232 if ( !mp->tfm_infile ) goto BAD_TFM;