]> git.saurik.com Git - apple/boot.git/blob - i386/util/mkfont.c
boot-111.tar.gz
[apple/boot.git] / i386 / util / mkfont.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * mkfont ASCII_BITMAP_INPUT [-c (generate .c file)] [BITMAP_OUTPUT]
27 *
28 * This program parses the ascii bitmap (screen font) description given as
29 * input and produces either a binary font file suitable for use with
30 * "fbshow" or a .c file containing an initialized font_c_t struct.
31 *
32 * If the output file is not specified, it is created in the current directory
33 * and given the name FontFamily-FontFace.PointSize (with a .c appended if
34 * the -c option is specified); e.g. for 18 point Helvetica Bold, the output
35 * file would be: Helvetica-Bold.18.
36 *
37 * The name of the font_c_t struct created by the -c option is
38 * FontFamily_FontFace_PointSize.
39 */
40
41 #define EXPORT_BOOLEAN
42 #import <stdio.h>
43 #import <libc.h>
44 #import <ctype.h>
45 #import <sys/file.h>
46 #import <mach/boolean.h>
47 #import "font.h"
48
49 #define BITSINCR (8*1024*8) /* in honest-to-god bits! */
50 #define MAXLINE 256
51
52 typedef enum {
53 ENDCHAR_LINE, ENCODING_LINE, DWIDTH_LINE, SWIDTH_LINE, BBX_LINE,
54 BITMAP_LINE, DATA_LINE, FONT_LINE, SIZE_LINE, FONTBOUNDINGBOX_LINE,
55 CHARS_LINE, STARTCHAR_LINE, ENDFONT_LINE, STARTPROPERTIES_LINE,
56 ENDPROPERTIES_LINE, UNKNOWN_LINE, STARTFONT_LINE, COMMENT_LINE
57 } line_t;
58
59 typedef struct {
60 char *string;
61 line_t linetype;
62 int len;
63 } linetbl_t;
64
65 #define LINETBL(x) { #x, x##_LINE, (sizeof #x) - 1 }
66
67 linetbl_t linetbl[] = {
68 LINETBL(ENDCHAR),
69 LINETBL(ENCODING),
70 LINETBL(DWIDTH),
71 LINETBL(SWIDTH),
72 LINETBL(BBX),
73 LINETBL(BITMAP),
74 LINETBL(DATA),
75 LINETBL(FONT),
76 LINETBL(SIZE),
77 LINETBL(FONTBOUNDINGBOX),
78 LINETBL(CHARS),
79 LINETBL(STARTCHAR),
80 LINETBL(ENDFONT),
81 LINETBL(STARTPROPERTIES),
82 LINETBL(ENDPROPERTIES),
83 LINETBL(UNKNOWN),
84 LINETBL(STARTFONT),
85 LINETBL(COMMENT),
86 { NULL, UNKNOWN_LINE, 0 }
87 };
88
89 static void read_char_description(void);
90 static void setbits(int bitx, int nbits, int scanbits);
91 static void fatal(const char *format, ...);
92 static void parse_error(void);
93 static void duplicate(char *line);
94 static line_t linetype(char *linebuf);
95 static char *getline(char *buf, int buflen, FILE *stream);
96 static void write_c_file(const char *outfile);
97 static void write_bin_file(const char *outfile);
98
99 const char *program_name;
100 font_t font;
101 unsigned char *bits = NULL;
102 int bitsused; /* in honest-to-god bits */
103 int bitsalloc; /* in honest-to-god bits */
104 char linebuf[MAXLINE];
105 FILE *input, *output;
106
107 void
108 main(int argc, const char * const argv[])
109 {
110 const char *infile;
111 const char *outfile = NULL;
112 char filename[FONTNAMELEN+20];
113 boolean_t did_endfont_line, did_font_line, did_size_line,
114 did_fontboundingbox_line, did_chars_line, did_startfont_line;
115 int chars, chars_processed, nprops, bytes;
116 boolean_t gen_c_file = FALSE;
117 const char *argp;
118 char c;
119 short s1, s2, s3, s4;
120
121 program_name = *argv++; argc--;
122 if (argc < 1 || argc > 3) {
123 fatal("Usage: %s ASCII_BITMAP_INPUT [-c (generate .c file)] "
124 "[BITMAP_OUTPUT]", program_name);
125 }
126
127 infile = *argv++; argc--;
128 while(argc) {
129 if (**argv == '-') {
130 argp = *argv++ + 1;
131 argc--;
132 while (c = *argp++) {
133 switch(c) {
134 case 'c':
135 gen_c_file = TRUE;
136 break;
137 default:
138 fatal("Usage: mkfont "
139 "ASCII_BITMAP_INPUT "
140 "[-c (generate .c file)]");
141 }
142 }
143 }
144 else {
145 outfile = *argv++; argc--;
146 }
147 }
148
149 if ((input = fopen(infile, "r")) == NULL)
150 fatal("Can't open input file %s", infile);
151
152 did_endfont_line = FALSE;
153 did_font_line = FALSE;
154 did_size_line = FALSE;
155 did_fontboundingbox_line = FALSE;
156 did_chars_line = FALSE;
157 did_startfont_line = FALSE;
158 chars_processed = 0;
159 chars = 0;
160
161 while (!did_endfont_line
162 && getline(linebuf, sizeof linebuf, input) != NULL) {
163 switch (linetype(linebuf)) {
164 case COMMENT_LINE:
165 default:
166 break;
167 case ENDCHAR_LINE:
168 case ENCODING_LINE:
169 case DWIDTH_LINE:
170 case SWIDTH_LINE:
171 case BBX_LINE:
172 case BITMAP_LINE:
173 case DATA_LINE:
174 parse_error();
175 case STARTFONT_LINE:
176 if (did_startfont_line)
177 duplicate("STARTFONT");
178 did_startfont_line = TRUE;
179 break;
180 case FONT_LINE:
181 if (sscanf(linebuf, "%*s %s", font.font) != 1)
182 parse_error();
183 if (did_font_line)
184 duplicate("FONT");
185 did_font_line = TRUE;
186 break;
187 case SIZE_LINE:
188 if (sscanf(linebuf, "%*s %hd", &font.size) != 1)
189 parse_error();
190 if (did_size_line)
191 duplicate("SIZE");
192 did_size_line = TRUE;
193 break;
194 case FONTBOUNDINGBOX_LINE:
195 if (sscanf(linebuf, "%*s %hd %hd %hd %hd",
196 &s1, &s2, &s3, &s4) != 4)
197 parse_error();
198 font.bbx.width = s1;
199 font.bbx.height = s2;
200 font.bbx.xoff = s3;
201 font.bbx.yoff = s4;
202 if (did_fontboundingbox_line)
203 duplicate("FONTBOUNDINGBOX");
204 did_fontboundingbox_line = TRUE;
205 break;
206 case CHARS_LINE:
207 if (sscanf(linebuf, "%*s %d", &chars) != 1)
208 parse_error();
209 if (did_chars_line)
210 duplicate("CHARS");
211 did_chars_line = TRUE;
212 break;
213 case STARTCHAR_LINE:
214 read_char_description();
215 chars_processed++;
216 break;
217 case ENDFONT_LINE:
218 did_endfont_line = TRUE;
219 break;
220 case STARTPROPERTIES_LINE:
221 if (sscanf(linebuf, "%*s %d", &nprops) != 1)
222 parse_error();
223 while (nprops-- > 0 && getline(linebuf, sizeof linebuf, input) != NULL)
224 continue;
225 if (nprops != 0 || getline(linebuf, sizeof linebuf, input) == NULL
226 || linetype(linebuf) != ENDPROPERTIES_LINE)
227 parse_error();
228 break;
229 }
230 }
231 fclose(input);
232
233 if (! did_font_line || ! did_size_line || ! did_fontboundingbox_line
234 || ! did_chars_line || ! did_endfont_line || ! did_startfont_line)
235 fatal("Incomplete input file");
236 if (chars_processed != chars)
237 fatal("Input file missing character descriptions");
238 if (bits == NULL)
239 fatal("No bitmaps generated!");
240 if(gen_c_file) {
241 /*
242 * Generate a compilable file.
243 */
244 write_c_file(outfile);
245 }
246 else {
247 write_bin_file(outfile);
248 }
249 }
250
251 static void
252 read_char_description(void)
253 {
254 boolean_t did_endchar_line, did_encoding_line, did_dwidth_line, did_bbx_line,
255 did_bitmap_line;
256 int encoding, scanbits, nbits, h;
257 bitmap_t bm;
258 short s1, s2, s3, s4;
259
260 did_endchar_line = FALSE;
261 did_encoding_line = FALSE;
262 did_dwidth_line = FALSE;
263 did_bbx_line = FALSE;
264 did_bitmap_line = FALSE;
265 nbits = 0;
266 bzero(&bm, sizeof bm);
267 while (! did_endchar_line && getline(linebuf, sizeof linebuf, input) != NULL) {
268 switch (linetype(linebuf)) {
269 case FONT_LINE:
270 case SIZE_LINE:
271 case FONTBOUNDINGBOX_LINE:
272 case ENDFONT_LINE:
273 case CHARS_LINE:
274 case DATA_LINE:
275 case STARTPROPERTIES_LINE:
276 case ENDPROPERTIES_LINE:
277 case STARTFONT_LINE:
278 parse_error();
279 case ENCODING_LINE:
280 if (sscanf(linebuf, "%*s %d", &encoding) != 1)
281 parse_error();
282 if (did_encoding_line)
283 duplicate("ENCODING");
284 did_encoding_line = TRUE;
285 break;
286 case ENDCHAR_LINE:
287 did_endchar_line = TRUE;
288 break;
289 case DWIDTH_LINE:
290 if (sscanf(linebuf, "%*s %hd", &s1) != 1)
291 parse_error();
292 bm.dwidth = s1;
293 if (did_dwidth_line)
294 duplicate("DWIDTH");
295 did_dwidth_line = TRUE;
296 break;
297 case BBX_LINE:
298 if (sscanf(linebuf, "%*s %hd %hd %hd %hd",
299 &s1, &s2, &s3, &s4) != 4)
300 parse_error();
301 bm.bbx.width = s1;
302 bm.bbx.height = s2;
303 bm.bbx.xoff = s3;
304 bm.bbx.yoff = s4;
305
306 if (did_bbx_line)
307 duplicate("BBX");
308 did_bbx_line = TRUE;
309 break;
310 case BITMAP_LINE:
311 if (! did_bbx_line)
312 fatal("BITMAP line not proceeded by BBX line");
313 if (did_bitmap_line)
314 duplicate("BITMAP");
315 did_bitmap_line = TRUE;
316 nbits = bm.bbx.width * bm.bbx.height;
317 while (bitsused + nbits > bitsalloc) {
318 if (bits == NULL) {
319 bits = (unsigned char *)malloc(BITSINCR >> 3);
320 bitsused = 1; /* bitx == 0 means no char */
321 } else
322 bits = (unsigned char *)realloc(bits,
323 (BITSINCR + bitsalloc + 7) >> 3);
324 if (bits == NULL)
325 fatal("Out of memory");
326 bitsalloc += (BITSINCR >> 3) * 8;
327 }
328 bm.bitx = bitsused;
329 for (h = 0; h < bm.bbx.height; h++) {
330 if (getline(linebuf, sizeof linebuf, input) == NULL)
331 fatal("Unexpected EOF on input");
332 if (linetype(linebuf) != DATA_LINE)
333 parse_error();
334 if (sscanf(linebuf, "%x", &scanbits) != 1)
335 parse_error();
336 setbits(bm.bitx + h * bm.bbx.width, bm.bbx.width, scanbits);
337 }
338 break;
339 }
340 }
341 if ( ! did_endchar_line || ! did_encoding_line || ! did_dwidth_line
342 || ! did_bbx_line || ! did_bitmap_line)
343 parse_error();
344 if (encoding >= ENCODEBASE && encoding <= ENCODELAST) {
345 font.bitmaps[encoding - ENCODEBASE] = bm;
346 bitsused += nbits;
347 }
348 return;
349 }
350
351 static void
352 setbits(int bitx, int nbits, int scanbits)
353 {
354 int i, mask;
355
356 for (i = 0; i < nbits; i++) {
357 mask = 0x80 >> ((bitx + i) & 0x7);
358 if (scanbits & (1 << (((nbits + 7) & ~7) - i - 1)))
359 bits[(bitx + i) >> 3] |= mask;
360 else
361 bits[(bitx + i) >> 3] &= ~mask;
362 }
363 }
364
365 static void
366 fatal(const char *format, ...)
367 {
368 va_list ap;
369
370 va_start(ap, format);
371 fprintf(stderr, "%s: ", program_name);
372 vfprintf(stderr, format, ap);
373 fprintf(stderr, "\n");
374 va_end(ap);
375 exit(1);
376 }
377
378 static int lineNum = 0;
379
380 static void
381 parse_error(void)
382 {
383 fatal("Couldn't parse line %d: <%s>", lineNum, linebuf);
384 }
385
386 static void
387 duplicate(char *line)
388 {
389 fatal("Duplicate declaration of %s", line);
390 }
391
392 static line_t
393 linetype(char *linebuf)
394 {
395 linetbl_t *ltp;
396 int len;
397
398 for (ltp = linetbl; ltp->string; ltp++) {
399 if (strncmp(ltp->string, linebuf, ltp->len) == 0
400 && (linebuf[ltp->len] == '\0' || isspace(linebuf[ltp->len])))
401 return ltp->linetype;
402 }
403 len = strlen(linebuf);
404 if (len == 0)
405 return UNKNOWN_LINE;
406 while (--len > 0)
407 if (! isxdigit(*linebuf++))
408 break;
409 return (len == 0) ? DATA_LINE : UNKNOWN_LINE;
410 }
411
412 static char *
413 getline(char *buf, int buflen, FILE *stream)
414 {
415 char *retval;
416 int len;
417
418 retval = fgets(buf, buflen, stream);
419 lineNum++;
420
421 if (retval == NULL)
422 return retval;
423
424 len = strlen(buf);
425 while (len > 0 && isspace(buf[--len]))
426 buf[len] = '\0';
427 return retval;
428 }
429
430 /*
431 * generate raw binary file which will get map_fd'd into
432 * a font_t in fbshow.
433 */
434 static void write_bin_file(const char *outfile)
435 {
436 char filename[FONTNAMELEN+20];
437 FILE *output;
438 int bytes;
439
440 /*
441 * Generate default filename if necessary.
442 */
443 if (outfile == NULL) {
444 sprintf(filename, "%s.%d", font.font, font.size);
445 outfile = filename;
446 }
447 if ((output = fopen(outfile, "w")) == NULL)
448 fatal("Can't create output file %s", outfile);
449
450 /*
451 * Write the font_t.
452 */
453 if (fwrite(&font, sizeof font, 1, output) != 1)
454 fatal("Write to file %s failed", outfile);
455
456 /*
457 * Now the bit array (declared in font_t as size 0).
458 */
459 bytes = (bitsused + 7) >> 3;
460 if (fwrite(bits, sizeof(unsigned char), bytes, output) != bytes) {
461 fatal("Write to file %s failed", output);
462 }
463 fclose(output);
464 }
465
466 /*
467 * Generate a compilable file.
468 */
469 #define FONTNAME_STRING_NAME "fontname"
470 #define BITS_ARRAY_NAME "bits_array"
471
472 static void write_c_file(const char *outfile)
473 {
474 char structname[FONTNAMELEN+20];
475 char filename[FONTNAMELEN+20];
476 char fontname[FONTNAMELEN+20];
477 char *np;
478 FILE *out;
479 char line[120];
480 int bytes;
481 unsigned char *bitp;
482 int loop;
483 bitmap_t *bmap;
484
485 /*
486 * Generate default filename if necessary.
487 */
488 if (outfile == NULL) {
489 sprintf(filename, "%s.%d.c", font.font, font.size);
490 outfile = filename;
491 }
492
493 if ((out = fopen(outfile, "w")) == NULL)
494 fatal("Can't create output file %s", outfile);
495
496 /*
497 * generate the name of the font_c_t struct, converting
498 * possible '-' into '_'.
499 */
500 sprintf(structname, "%s_%d", font.font, font.size);
501 for(np=structname; *np; np++) {
502 if(*np == '-') {
503 *np = '_';
504 }
505 }
506
507 /*
508 * Start emitting code. Place fontname and bits_array first to keep
509 * them static.
510 */
511 fprintf(out, "/* generated by mkfont */\n\n");
512
513 /*
514 * FIXME - maybe this should be passed in in argv...
515 */
516 fprintf(out, "#import \"font.h\"\n\n");
517
518 /*
519 * The bit array first.
520 */
521 fprintf(out, "static const char %s[] = {\n", BITS_ARRAY_NAME);
522 bytes = (bitsused + 7) >> 3;
523 bitp = bits;
524 fprintf(out, "\t");
525 for(loop=0; loop<bytes; loop++) {
526 fprintf(out, "0x%02x, ", *bitp++);
527 if(loop % 8 == 7) {
528 /*
529 * Line wrap.
530 */
531 fprintf(out, "\n\t");
532 }
533 }
534
535 fprintf(out, "\n};\n\n");
536
537 /*
538 * Finally, the font_c_t itself.
539 */
540 fprintf(out, "const font_c_t %s = {\n", structname);
541 fprintf(out, "\t\"%s-%d\",\n", font.font, font.size);
542 fprintf(out, "\t%d,\n", font.size);
543 fprintf(out, "\t{%d, %d, %d, %d},\n",
544 font.bbx.width, font.bbx.height,
545 font.bbx.xoff, font.bbx.yoff);
546
547 /*
548 * bitmap structs.
549 */
550 bmap = font.bitmaps;
551 fprintf(out, "\t{\n");
552 for(loop=0; loop<(ENCODELAST - ENCODEBASE + 1); loop++) {
553 fprintf(out, "\t { {%4d, %4d, %4d, %4d}, %4d, %6d },",
554 bmap->bbx.width, bmap->bbx.height,
555 bmap->bbx.xoff, bmap->bbx.yoff,
556 bmap->dwidth, bmap->bitx);
557 bmap++;
558 fprintf(out, "\t/* 0x%02x */\n", loop + ENCODEBASE);
559 }
560 fprintf(out, "\n\t},\n");
561
562 /*
563 * and the bits array ptr.
564 */
565 fprintf(out, "\t%s,\n", BITS_ARRAY_NAME);
566 fprintf(out, "};\n");
567
568 /*
569 * now some junk to make our code smaller.
570 */
571 fprintf(out, "\n#define %s_BBX_WIDTH\t%d\n",
572 structname, font.bbx.width);
573 fprintf(out, "#define %s_BBX_HEIGHT\t%d\n",
574 structname, font.bbx.height);
575 fprintf(out, "#define %s_BBX_XOFF\t%d\n",
576 structname, font.bbx.xoff);
577 fprintf(out, "#define %s_BBX_YOFF\t%d\n",
578 structname, font.bbx.yoff);
579
580 fclose(out);
581 }
582