Commit | Line | Data |
---|---|---|
69695f33 MW |
1 | |
2 | /* Copyright (c) 1999, 2000, 2002, 2005 by Arkkra Enterprises */ | |
3 | /* All rights reserved */ | |
4 | ||
5 | /* This file contains functions related to fonts, | |
6 | * both user defined and native PostScript fonts. | |
7 | */ | |
8 | ||
9 | #include <string.h> | |
10 | #include "defines.h" | |
11 | #include "structs.h" | |
12 | #include "globals.h" | |
13 | ||
14 | ||
15 | /* The font size info is machine generated, so refer to it here. */ | |
16 | /* This gives the initialization for FONTINFO structs for all fonts. */ | |
17 | extern struct FONTINFO Fontinfo[MAXFONTS]; | |
18 | ||
19 | /* map font names to numbers. */ | |
20 | static struct FONTMAP { | |
21 | char *fontname; /* abbreviated (similar to troff-style) | |
22 | * or full font name */ | |
23 | char findex; /* font number */ | |
24 | } Font_table[] = { | |
25 | /*====== this table must be sorted alphabetically to allow | |
26 | *====== binary search!!!!! */ | |
27 | { "AB", FONT_AB }, | |
28 | { "AI", FONT_AI }, | |
29 | { "AR", FONT_AR }, | |
30 | { "AX", FONT_AX }, | |
31 | { "BB", FONT_BB }, | |
32 | { "BI", FONT_BI }, | |
33 | { "BR", FONT_BR }, | |
34 | { "BX", FONT_BX }, | |
35 | { "CB", FONT_CB }, | |
36 | { "CI", FONT_CI }, | |
37 | { "CR", FONT_CR }, | |
38 | { "CX", FONT_CX }, | |
39 | { "HB", FONT_HB }, | |
40 | { "HI", FONT_HI }, | |
41 | { "HR", FONT_HR }, | |
42 | { "HX", FONT_HX }, | |
43 | { "NB", FONT_NB }, | |
44 | { "NI", FONT_NI }, | |
45 | { "NR", FONT_NR }, | |
46 | { "NX", FONT_NX }, | |
47 | { "PB", FONT_PB }, | |
48 | { "PI", FONT_PI }, | |
49 | { "PR", FONT_PR }, | |
50 | { "PX", FONT_PX }, | |
51 | { "TB", FONT_TB }, | |
52 | { "TI", FONT_TI }, | |
53 | { "TR", FONT_TR }, | |
54 | { "TX", FONT_TX }, | |
55 | { "avantgarde bold", FONT_AB }, | |
56 | { "avantgarde boldital", FONT_AX }, | |
57 | { "avantgarde ital", FONT_AI }, | |
58 | { "avantgarde rom", FONT_AR }, | |
59 | { "bookman bold", FONT_BB }, | |
60 | { "bookman boldital", FONT_BX }, | |
61 | { "bookman ital", FONT_BI }, | |
62 | { "bookman rom", FONT_BR }, | |
63 | { "courier bold", FONT_CB }, | |
64 | { "courier boldital", FONT_CX }, | |
65 | { "courier ital", FONT_CI }, | |
66 | { "courier rom", FONT_CR }, | |
67 | { "helvetica bold", FONT_HB }, | |
68 | { "helvetica boldital", FONT_HX }, | |
69 | { "helvetica ital", FONT_HI }, | |
70 | { "helvetica rom", FONT_HR }, | |
71 | { "newcentury bold", FONT_NB }, | |
72 | { "newcentury boldital", FONT_NX }, | |
73 | { "newcentury ital", FONT_NI }, | |
74 | { "newcentury rom", FONT_NR }, | |
75 | { "palatino bold", FONT_PB }, | |
76 | { "palatino boldital", FONT_PX }, | |
77 | { "palatino ital", FONT_PI }, | |
78 | { "palatino rom", FONT_PR }, | |
79 | { "times bold", FONT_TB }, | |
80 | { "times boldital", FONT_TX }, | |
81 | { "times ital", FONT_TI }, | |
82 | { "times rom", FONT_TR } | |
83 | }; | |
84 | ||
85 | /* Strings to look for in a fontfile */ | |
86 | char *Mup_name = "Mup font name:"; | |
87 | char *PostScript_name = "PostScript font name:"; | |
88 | char *PS_definition = "PostScript:"; | |
89 | char *Size_data = "Size data:"; | |
90 | ||
91 | /* static functions */ | |
92 | static int fncmp P((const void *fn1, const void * fn2)); | |
93 | static char *get_expected P((FILE *fontfile_p, char *filename, char *expected, | |
94 | int *lineno_p)); | |
95 | static char *get_noncomment P((FILE *fontfile_p, int *lineno_p)); | |
96 | \f | |
97 | ||
98 | /* given a font number, return its index into Fontinfo table. FONT_TR | |
99 | * is the first entry in the table. | |
100 | * If the font number given is out of range, pfatal. | |
101 | */ | |
102 | ||
103 | int | |
104 | font_index(font) | |
105 | ||
106 | int font; /* which font */ | |
107 | ||
108 | { | |
109 | if ((font < 0) || (font >= MAXFONTS)) { | |
110 | pfatal("font %d out of range", font); | |
111 | } | |
112 | /* offset relative to first valid font */ | |
113 | font = font - FONT_TR; | |
114 | ||
115 | return(font); | |
116 | } | |
117 | \f | |
118 | ||
119 | /* given a fontname, return its number, or FONT_UNKNOWN */ | |
120 | ||
121 | int | |
122 | lookup_font(fontname) | |
123 | ||
124 | char *fontname; | |
125 | ||
126 | { | |
127 | struct FONTMAP *finfo_p; | |
128 | ||
129 | ||
130 | if ((finfo_p = (struct FONTMAP *) bsearch(fontname, Font_table, | |
131 | NUMELEM(Font_table), sizeof(struct FONTMAP), fncmp)) | |
132 | != (struct FONTMAP *) 0) { | |
133 | return(finfo_p->findex); | |
134 | } | |
135 | else { | |
136 | return(FONT_UNKNOWN); | |
137 | } | |
138 | } | |
139 | ||
140 | ||
141 | ||
142 | /* font name comparision function for use by bsearch() */ | |
143 | ||
144 | static int | |
145 | fncmp(fn1, fn2) | |
146 | ||
147 | #ifdef __STDC__ | |
148 | const void *fn1; /* font name to check */ | |
149 | const void *fn2; /* pointer to FONTMAP to compare with. declare as char * | |
150 | * since that's what bsearch() thinks it gives us, | |
151 | * then we cast appropriately */ | |
152 | #else | |
153 | char *fn1; /* font name to check */ | |
154 | char *fn2; /* pointer to FONTMAP to compare with. declare as char * | |
155 | * since that's what bsearch() thinks it gives us, then we | |
156 | * cast appropriately */ | |
157 | #endif | |
158 | ||
159 | { | |
160 | return(strcmp(fn1, ((struct FONTMAP *) fn2)->fontname)); | |
161 | } | |
162 | \f | |
163 | ||
164 | /* Given a font number, return its name. We don't have to do this too often, | |
165 | * it's a simple int compare, and we only need to look through | |
166 | * abbreviated names, so just do linear search. */ | |
167 | ||
168 | char * | |
169 | fontnum2name(font) | |
170 | ||
171 | int font; | |
172 | ||
173 | { | |
174 | int f; | |
175 | int elements; | |
176 | ||
177 | /* divide by 2 because only need to check abbreviations */ | |
178 | elements = NUMELEM(Font_table) / 2; | |
179 | for (f = 0; f < elements; f++) { | |
180 | if (Font_table[f].findex == font) { | |
181 | return(Font_table[f].fontname); | |
182 | } | |
183 | } | |
184 | return("unknown"); | |
185 | } | |
186 | \f | |
187 | ||
188 | /* This handles a fontfile, reading it in, validating its contents, | |
189 | * and saving the information in the Fontinfo array. | |
190 | */ | |
191 | ||
192 | void | |
193 | parse_font_file(filename) | |
194 | ||
195 | char *filename; | |
196 | ||
197 | { | |
198 | FILE *fontfile_p; | |
199 | char *name; /* Mup font name */ | |
200 | char *ps_name; /* PostScript font name */ | |
201 | int findex; /* which font is being defined */ | |
202 | int c; /* character index */ | |
203 | int code; /* "ASCII" code value */ | |
204 | int width, height, ascent; | |
205 | char *buffer; /* line read from file */ | |
206 | int lineno; | |
207 | int max_height, max_ascent; | |
208 | ||
209 | ||
210 | debug(2, "parse_font_file(%s)", filename); | |
211 | ||
212 | if ((fontfile_p = find_file(&filename)) == (FILE *) 0) { | |
213 | l_yyerror(Curr_filename, yylineno, "can't open '%s'", filename); | |
214 | return; | |
215 | } | |
216 | ||
217 | /* first line of file is expected to contain the Mup font name */ | |
218 | lineno = 0; | |
219 | if ((name = get_expected(fontfile_p, filename, Mup_name, &lineno)) | |
220 | != (char *) 0) { | |
221 | if ((findex = lookup_font(name)) == FONT_UNKNOWN) { | |
222 | l_yyerror(filename, lineno, | |
223 | "'%s' is not a valid Mup font name", name); | |
224 | return; | |
225 | } | |
226 | findex = font_index(findex); | |
227 | ||
228 | if (Fontinfo[findex].fontfile != (FILE *) 0) { | |
229 | l_yyerror(filename, lineno, | |
230 | "Font '%s' redefined more than once", name); | |
231 | return; | |
232 | } | |
233 | /* Save the file pointer, since we'll need to read the rest of | |
234 | * the file to put into the Mup output */ | |
235 | Fontinfo[findex].fontfile = fontfile_p; | |
236 | } | |
237 | else { | |
238 | return; | |
239 | } | |
240 | ||
241 | /* Next line of file is expected to contain the PostScript font name */ | |
242 | if ((ps_name = get_expected(fontfile_p, filename, PostScript_name, &lineno)) | |
243 | != (char *) 0) { | |
244 | if (strlen(ps_name) == 0 ) { | |
245 | l_yyerror(filename, lineno, | |
246 | "No PostScript font name value given"); | |
247 | return; | |
248 | } | |
249 | Fontinfo[findex].ps_name = ps_name; | |
250 | } | |
251 | else { | |
252 | return; | |
253 | } | |
254 | ||
255 | /* Next line of file is expected to contain the Size data line */ | |
256 | if ((ps_name = get_expected(fontfile_p, filename, Size_data, &lineno)) | |
257 | == (char *) 0) { | |
258 | return; | |
259 | } | |
260 | ||
261 | max_height = max_ascent = 0; | |
262 | for (c = FIRST_CHAR; c < FIRST_CHAR + CHARS_IN_FONT - 1; c++) { | |
263 | buffer = get_noncomment(fontfile_p, &lineno); | |
264 | if ( sscanf(buffer, "%d %d %d %d", | |
265 | &code, &width, &height, &ascent) != 4) { | |
266 | buffer[strlen(buffer) - 1] = '\0'; | |
267 | l_yyerror(filename, lineno, | |
268 | "size data line has incorrect format: '%s'", | |
269 | buffer); | |
270 | return; | |
271 | } | |
272 | if (c != code) { | |
273 | l_yyerror(filename, lineno, | |
274 | "expecting size data for character %d, but got %d instead", | |
275 | c, code); | |
276 | return; | |
277 | } | |
278 | ||
279 | /* Because of how backspace works (see comment in defines.h) | |
280 | * we need to limit width to 0.5 inch for a DEFAULT_SIZE | |
281 | * character. */ | |
282 | if (width > 500) { | |
283 | l_yyerror(filename, lineno, "width must be less than 500"); | |
284 | return; | |
285 | } | |
286 | ||
287 | /* save size in table */ | |
288 | code = CHAR_INDEX(code); | |
289 | Fontinfo[findex].ch_height[code] = height; | |
290 | Fontinfo[findex].ch_width[code] = width; | |
291 | Fontinfo[findex].ch_ascent[code] = ascent; | |
292 | ||
293 | if (height > max_height) { | |
294 | max_height = height; | |
295 | } | |
296 | if (ascent > max_ascent) { | |
297 | max_ascent = ascent; | |
298 | } | |
299 | } | |
300 | ||
301 | Maxfontheight[findex] = (double) max_height / (double) FONTFACTOR; | |
302 | Maxfontascent[findex] = (double) max_ascent / (double) FONTFACTOR; | |
303 | ||
304 | /* Next line of file is expected to contain the PostScript: line */ | |
305 | if ((ps_name = get_expected(fontfile_p, filename, PS_definition, &lineno)) | |
306 | == (char *) 0) { | |
307 | return; | |
308 | } | |
309 | } | |
310 | \f | |
311 | ||
312 | /* Read from given file. If next non-comment line starts as expected, | |
313 | * return a copy of the rest of the line after any white space. | |
314 | * Otherwise print an error and return 0. | |
315 | */ | |
316 | ||
317 | static char * | |
318 | get_expected(fontfile_p, filename, expected, lineno_p) | |
319 | ||
320 | FILE *fontfile_p; | |
321 | char *filename; | |
322 | char *expected; /* line read is expected to start with this */ | |
323 | int *lineno_p; /* line number where line was found is returned here */ | |
324 | ||
325 | { | |
326 | char *buffer; | |
327 | char *newstring; | |
328 | char *p; | |
329 | ||
330 | buffer = get_noncomment(fontfile_p, lineno_p); | |
331 | if (strncmp(buffer, expected, strlen(expected)) != 0) { | |
332 | l_yyerror(filename, *lineno_p, | |
333 | "Expecting '%s' in font_file '%s'", expected, filename); | |
334 | return((char *) 0); | |
335 | } | |
336 | ||
337 | /* skip any leading white space */ | |
338 | for (buffer += strlen(expected); isspace(*buffer); buffer++) { | |
339 | ; | |
340 | } | |
341 | ||
342 | /* trim any white space from the end of the string */ | |
343 | for (p = buffer + strlen(buffer) - 1; p >= buffer; p--) { | |
344 | if (isspace(*p)) { | |
345 | *p = '\0'; | |
346 | } | |
347 | else { | |
348 | break; | |
349 | } | |
350 | } | |
351 | ||
352 | /* make a copy and return it */ | |
353 | MALLOCA(char, newstring, strlen(buffer) + 1); | |
354 | strcpy(newstring, buffer); | |
355 | return(newstring); | |
356 | } | |
357 | \f | |
358 | ||
359 | /* Read lines from given file until a non-comment line is found, and | |
360 | * return that line. A comment is a line that has # in its first column. | |
361 | * Returns a null string on end of file. The line returned is in a static | |
362 | * buffer overwritten on each call, so caller must save if they need a copy. | |
363 | */ | |
364 | ||
365 | static char * | |
366 | get_noncomment(file, lineno_p) | |
367 | ||
368 | FILE *file; | |
369 | int *lineno_p; /* line number gets sents in and returned here */ | |
370 | ||
371 | { | |
372 | static char buffer[128]; | |
373 | ||
374 | while (fgets(buffer, sizeof(buffer), file) != (char *) 0) { | |
375 | (*lineno_p)++; | |
376 | if ( *buffer != '#') { | |
377 | /* not a comment, so return it */ | |
378 | return(buffer); | |
379 | } | |
380 | } | |
381 | buffer[0] = '\0'; | |
382 | return(buffer); | |
383 | } | |
384 | \f | |
385 | ||
386 | /* return the height for a font in inches for a given size */ | |
387 | ||
388 | double | |
389 | fontheight(font, size) | |
390 | ||
391 | int font; | |
392 | int size; | |
393 | ||
394 | { | |
395 | return( (double) Maxfontheight[font_index(font)] * | |
396 | ((double) size / (double) DFLT_SIZE) ); | |
397 | } | |
398 | ||
399 | ||
400 | ||
401 | /* return the ascent for a font in inches for a given size */ | |
402 | ||
403 | double | |
404 | fontascent(font, size) | |
405 | ||
406 | int font; | |
407 | int size; | |
408 | ||
409 | { | |
410 | return( (double) Maxfontascent[font_index(font)] * | |
411 | ((double) size / (double) DFLT_SIZE) ); | |
412 | } | |
413 | ||
414 | ||
415 | ||
416 | /* return the descent for a font in inches for a given size */ | |
417 | ||
418 | double | |
419 | fontdescent(font, size) | |
420 | ||
421 | int font; | |
422 | int size; | |
423 | ||
424 | { | |
425 | return( fontheight(font, size) - fontascent (font, size) ); | |
426 | } |