chiark / gitweb /
Merge branch 'arkkra' into shiny
[mup] / mup / mup / font.c
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 }