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