2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
26 * mkfont ASCII_BITMAP_INPUT [-c (generate .c file)] [BITMAP_OUTPUT]
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.
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.
37 * The name of the font_c_t struct created by the -c option is
38 * FontFamily_FontFace_PointSize.
41 #define EXPORT_BOOLEAN
46 #import <mach/boolean.h>
49 #define BITSINCR (8*1024*8) /* in honest-to-god bits! */
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
65 #define LINETBL(x) { #x, x##_LINE, (sizeof #x) - 1 }
67 linetbl_t linetbl
[] = {
77 LINETBL(FONTBOUNDINGBOX
),
81 LINETBL(STARTPROPERTIES
),
82 LINETBL(ENDPROPERTIES
),
86 { NULL
, UNKNOWN_LINE
, 0 }
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
);
99 const char *program_name
;
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
;
108 main(int argc
, const char * const argv
[])
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
;
119 short s1
, s2
, s3
, s4
;
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
);
127 infile
= *argv
++; argc
--;
132 while (c
= *argp
++) {
138 fatal("Usage: mkfont "
139 "ASCII_BITMAP_INPUT "
140 "[-c (generate .c file)]");
145 outfile
= *argv
++; argc
--;
149 if ((input
= fopen(infile
, "r")) == NULL
)
150 fatal("Can't open input file %s", infile
);
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
;
161 while (!did_endfont_line
162 && getline(linebuf
, sizeof linebuf
, input
) != NULL
) {
163 switch (linetype(linebuf
)) {
176 if (did_startfont_line
)
177 duplicate("STARTFONT");
178 did_startfont_line
= TRUE
;
181 if (sscanf(linebuf
, "%*s %s", font
.font
) != 1)
185 did_font_line
= TRUE
;
188 if (sscanf(linebuf
, "%*s %hd", &font
.size
) != 1)
192 did_size_line
= TRUE
;
194 case FONTBOUNDINGBOX_LINE
:
195 if (sscanf(linebuf
, "%*s %hd %hd %hd %hd",
196 &s1
, &s2
, &s3
, &s4
) != 4)
199 font
.bbx
.height
= s2
;
202 if (did_fontboundingbox_line
)
203 duplicate("FONTBOUNDINGBOX");
204 did_fontboundingbox_line
= TRUE
;
207 if (sscanf(linebuf
, "%*s %d", &chars
) != 1)
211 did_chars_line
= TRUE
;
214 read_char_description();
218 did_endfont_line
= TRUE
;
220 case STARTPROPERTIES_LINE
:
221 if (sscanf(linebuf
, "%*s %d", &nprops
) != 1)
223 while (nprops
-- > 0 && getline(linebuf
, sizeof linebuf
, input
) != NULL
)
225 if (nprops
!= 0 || getline(linebuf
, sizeof linebuf
, input
) == NULL
226 || linetype(linebuf
) != ENDPROPERTIES_LINE
)
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");
239 fatal("No bitmaps generated!");
242 * Generate a compilable file.
244 write_c_file(outfile
);
247 write_bin_file(outfile
);
252 read_char_description(void)
254 boolean_t did_endchar_line
, did_encoding_line
, did_dwidth_line
, did_bbx_line
,
256 int encoding
, scanbits
, nbits
, h
;
258 short s1
, s2
, s3
, s4
;
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
;
266 bzero(&bm
, sizeof bm
);
267 while (! did_endchar_line
&& getline(linebuf
, sizeof linebuf
, input
) != NULL
) {
268 switch (linetype(linebuf
)) {
271 case FONTBOUNDINGBOX_LINE
:
275 case STARTPROPERTIES_LINE
:
276 case ENDPROPERTIES_LINE
:
280 if (sscanf(linebuf
, "%*s %d", &encoding
) != 1)
282 if (did_encoding_line
)
283 duplicate("ENCODING");
284 did_encoding_line
= TRUE
;
287 did_endchar_line
= TRUE
;
290 if (sscanf(linebuf
, "%*s %hd", &s1
) != 1)
295 did_dwidth_line
= TRUE
;
298 if (sscanf(linebuf
, "%*s %hd %hd %hd %hd",
299 &s1
, &s2
, &s3
, &s4
) != 4)
312 fatal("BITMAP line not proceeded by BBX line");
315 did_bitmap_line
= TRUE
;
316 nbits
= bm
.bbx
.width
* bm
.bbx
.height
;
317 while (bitsused
+ nbits
> bitsalloc
) {
319 bits
= (unsigned char *)malloc(BITSINCR
>> 3);
320 bitsused
= 1; /* bitx == 0 means no char */
322 bits
= (unsigned char *)realloc(bits
,
323 (BITSINCR
+ bitsalloc
+ 7) >> 3);
325 fatal("Out of memory");
326 bitsalloc
+= (BITSINCR
>> 3) * 8;
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
)
334 if (sscanf(linebuf
, "%x", &scanbits
) != 1)
336 setbits(bm
.bitx
+ h
* bm
.bbx
.width
, bm
.bbx
.width
, scanbits
);
341 if ( ! did_endchar_line
|| ! did_encoding_line
|| ! did_dwidth_line
342 || ! did_bbx_line
|| ! did_bitmap_line
)
344 if (encoding
>= ENCODEBASE
&& encoding
<= ENCODELAST
) {
345 font
.bitmaps
[encoding
- ENCODEBASE
] = bm
;
352 setbits(int bitx
, int nbits
, int scanbits
)
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
;
361 bits
[(bitx
+ i
) >> 3] &= ~mask
;
366 fatal(const char *format
, ...)
370 va_start(ap
, format
);
371 fprintf(stderr
, "%s: ", program_name
);
372 vfprintf(stderr
, format
, ap
);
373 fprintf(stderr
, "\n");
378 static int lineNum
= 0;
383 fatal("Couldn't parse line %d: <%s>", lineNum
, linebuf
);
387 duplicate(char *line
)
389 fatal("Duplicate declaration of %s", line
);
393 linetype(char *linebuf
)
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
;
403 len
= strlen(linebuf
);
407 if (! isxdigit(*linebuf
++))
409 return (len
== 0) ? DATA_LINE
: UNKNOWN_LINE
;
413 getline(char *buf
, int buflen
, FILE *stream
)
418 retval
= fgets(buf
, buflen
, stream
);
425 while (len
> 0 && isspace(buf
[--len
]))
431 * generate raw binary file which will get map_fd'd into
432 * a font_t in fbshow.
434 static void write_bin_file(const char *outfile
)
436 char filename
[FONTNAMELEN
+20];
441 * Generate default filename if necessary.
443 if (outfile
== NULL
) {
444 sprintf(filename
, "%s.%d", font
.font
, font
.size
);
447 if ((output
= fopen(outfile
, "w")) == NULL
)
448 fatal("Can't create output file %s", outfile
);
453 if (fwrite(&font
, sizeof font
, 1, output
) != 1)
454 fatal("Write to file %s failed", outfile
);
457 * Now the bit array (declared in font_t as size 0).
459 bytes
= (bitsused
+ 7) >> 3;
460 if (fwrite(bits
, sizeof(unsigned char), bytes
, output
) != bytes
) {
461 fatal("Write to file %s failed", output
);
467 * Generate a compilable file.
469 #define FONTNAME_STRING_NAME "fontname"
470 #define BITS_ARRAY_NAME "bits_array"
472 static void write_c_file(const char *outfile
)
474 char structname
[FONTNAMELEN
+20];
475 char filename
[FONTNAMELEN
+20];
476 char fontname
[FONTNAMELEN
+20];
486 * Generate default filename if necessary.
488 if (outfile
== NULL
) {
489 sprintf(filename
, "%s.%d.c", font
.font
, font
.size
);
493 if ((out
= fopen(outfile
, "w")) == NULL
)
494 fatal("Can't create output file %s", outfile
);
497 * generate the name of the font_c_t struct, converting
498 * possible '-' into '_'.
500 sprintf(structname
, "%s_%d", font
.font
, font
.size
);
501 for(np
=structname
; *np
; np
++) {
508 * Start emitting code. Place fontname and bits_array first to keep
511 fprintf(out
, "/* generated by mkfont */\n\n");
514 * FIXME - maybe this should be passed in in argv...
516 fprintf(out
, "#import \"font.h\"\n\n");
519 * The bit array first.
521 fprintf(out
, "static const char %s[] = {\n", BITS_ARRAY_NAME
);
522 bytes
= (bitsused
+ 7) >> 3;
525 for(loop
=0; loop
<bytes
; loop
++) {
526 fprintf(out
, "0x%02x, ", *bitp
++);
531 fprintf(out
, "\n\t");
535 fprintf(out
, "\n};\n\n");
538 * Finally, the font_c_t itself.
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
);
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
);
558 fprintf(out
, "\t/* 0x%02x */\n", loop
+ ENCODEBASE
);
560 fprintf(out
, "\n\t},\n");
563 * and the bits array ptr.
565 fprintf(out
, "\t%s,\n", BITS_ARRAY_NAME
);
566 fprintf(out
, "};\n");
569 * now some junk to make our code smaller.
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
);