]>
Commit | Line | Data |
---|---|---|
14c7c974 A |
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 |