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