chiark / gitweb /
Merge branch 'arkkra' into shiny
[mup] / mup / mup / font.c
CommitLineData
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. */
17extern struct FONTINFO Fontinfo[MAXFONTS];
18
19/* map font names to numbers. */
20static 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 */
86char *Mup_name = "Mup font name:";
87char *PostScript_name = "PostScript font name:";
88char *PS_definition = "PostScript:";
89char *Size_data = "Size data:";
90
91/* static functions */
92static int fncmp P((const void *fn1, const void * fn2));
93static char *get_expected P((FILE *fontfile_p, char *filename, char *expected,
94 int *lineno_p));
95static 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
103int
104font_index(font)
105
106int 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
121int
122lookup_font(fontname)
123
124char *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
144static int
145fncmp(fn1, fn2)
146
147#ifdef __STDC__
148const void *fn1; /* font name to check */
149const 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
153char *fn1; /* font name to check */
154char *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
168char *
169fontnum2name(font)
170
171int 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
192void
193parse_font_file(filename)
194
195char *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
317static char *
318get_expected(fontfile_p, filename, expected, lineno_p)
319
320FILE *fontfile_p;
321char *filename;
322char *expected; /* line read is expected to start with this */
323int *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
365static char *
366get_noncomment(file, lineno_p)
367
368FILE *file;
369int *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
388double
389fontheight(font, size)
390
391int font;
392int 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
403double
404fontascent(font, size)
405
406int font;
407int 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
418double
419fontdescent(font, size)
420
421int font;
422int size;
423
424{
425 return( fontheight(font, size) - fontascent (font, size) );
426}