1 |
/* $MidnightBSD$ */ |
2 |
/*- |
3 |
* Copyright (c) 2009, 2014 The FreeBSD Foundation |
4 |
* All rights reserved. |
5 |
* |
6 |
* This software was developed by Ed Schouten under sponsorship from the |
7 |
* FreeBSD Foundation. |
8 |
* |
9 |
* Redistribution and use in source and binary forms, with or without |
10 |
* modification, are permitted provided that the following conditions |
11 |
* are met: |
12 |
* 1. Redistributions of source code must retain the above copyright |
13 |
* notice, this list of conditions and the following disclaimer. |
14 |
* 2. Redistributions in binary form must reproduce the above copyright |
15 |
* notice, this list of conditions and the following disclaimer in the |
16 |
* documentation and/or other materials provided with the distribution. |
17 |
* |
18 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
19 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
20 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
21 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
22 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
24 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
25 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
26 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
27 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
28 |
* SUCH DAMAGE. |
29 |
*/ |
30 |
|
31 |
#include <sys/cdefs.h> |
32 |
__FBSDID("$FreeBSD: stable/10/usr.bin/vtfontcvt/vtfontcvt.c 332324 2018-04-09 13:00:03Z emaste $"); |
33 |
|
34 |
#include <sys/types.h> |
35 |
#include <sys/fnv_hash.h> |
36 |
#include <sys/endian.h> |
37 |
#include <sys/param.h> |
38 |
#include <sys/queue.h> |
39 |
|
40 |
#include <assert.h> |
41 |
#include <err.h> |
42 |
#include <stdint.h> |
43 |
#include <stdio.h> |
44 |
#include <stdlib.h> |
45 |
#include <string.h> |
46 |
#include <unistd.h> |
47 |
|
48 |
#define VFNT_MAPS 4 |
49 |
#define VFNT_MAP_NORMAL 0 |
50 |
#define VFNT_MAP_NORMAL_RH 1 |
51 |
#define VFNT_MAP_BOLD 2 |
52 |
#define VFNT_MAP_BOLD_RH 3 |
53 |
|
54 |
static unsigned int width = 8, wbytes, height = 16; |
55 |
|
56 |
struct glyph { |
57 |
TAILQ_ENTRY(glyph) g_list; |
58 |
SLIST_ENTRY(glyph) g_hash; |
59 |
uint8_t *g_data; |
60 |
unsigned int g_index; |
61 |
}; |
62 |
|
63 |
#define FONTCVT_NHASH 4096 |
64 |
TAILQ_HEAD(glyph_list, glyph); |
65 |
static SLIST_HEAD(, glyph) glyph_hash[FONTCVT_NHASH]; |
66 |
static struct glyph_list glyphs[VFNT_MAPS] = { |
67 |
TAILQ_HEAD_INITIALIZER(glyphs[0]), |
68 |
TAILQ_HEAD_INITIALIZER(glyphs[1]), |
69 |
TAILQ_HEAD_INITIALIZER(glyphs[2]), |
70 |
TAILQ_HEAD_INITIALIZER(glyphs[3]), |
71 |
}; |
72 |
static unsigned int glyph_total, glyph_count[4], glyph_unique, glyph_dupe; |
73 |
|
74 |
struct mapping { |
75 |
TAILQ_ENTRY(mapping) m_list; |
76 |
unsigned int m_char; |
77 |
unsigned int m_length; |
78 |
struct glyph *m_glyph; |
79 |
}; |
80 |
|
81 |
TAILQ_HEAD(mapping_list, mapping); |
82 |
static struct mapping_list maps[VFNT_MAPS] = { |
83 |
TAILQ_HEAD_INITIALIZER(maps[0]), |
84 |
TAILQ_HEAD_INITIALIZER(maps[1]), |
85 |
TAILQ_HEAD_INITIALIZER(maps[2]), |
86 |
TAILQ_HEAD_INITIALIZER(maps[3]), |
87 |
}; |
88 |
static unsigned int mapping_total, map_count[4], map_folded_count[4], |
89 |
mapping_unique, mapping_dupe; |
90 |
|
91 |
static void |
92 |
usage(void) |
93 |
{ |
94 |
|
95 |
(void)fprintf(stderr, |
96 |
"usage: vtfontcvt [-w width] [-h height] [-v] normal.bdf [bold.bdf] out.fnt\n"); |
97 |
exit(1); |
98 |
} |
99 |
|
100 |
static void * |
101 |
xmalloc(size_t size) |
102 |
{ |
103 |
void *m; |
104 |
|
105 |
if ((m = malloc(size)) == NULL) |
106 |
errx(1, "memory allocation failure"); |
107 |
return (m); |
108 |
} |
109 |
|
110 |
static int |
111 |
add_mapping(struct glyph *gl, unsigned int c, unsigned int map_idx) |
112 |
{ |
113 |
struct mapping *mp; |
114 |
struct mapping_list *ml; |
115 |
|
116 |
mapping_total++; |
117 |
|
118 |
mp = xmalloc(sizeof *mp); |
119 |
mp->m_char = c; |
120 |
mp->m_glyph = gl; |
121 |
mp->m_length = 0; |
122 |
|
123 |
ml = &maps[map_idx]; |
124 |
if (TAILQ_LAST(ml, mapping_list) != NULL && |
125 |
TAILQ_LAST(ml, mapping_list)->m_char >= c) |
126 |
errx(1, "Bad ordering at character %u\n", c); |
127 |
TAILQ_INSERT_TAIL(ml, mp, m_list); |
128 |
|
129 |
map_count[map_idx]++; |
130 |
mapping_unique++; |
131 |
|
132 |
return (0); |
133 |
} |
134 |
|
135 |
static int |
136 |
dedup_mapping(unsigned int map_idx) |
137 |
{ |
138 |
struct mapping *mp_bold, *mp_normal, *mp_temp; |
139 |
unsigned normal_map_idx = map_idx - VFNT_MAP_BOLD; |
140 |
|
141 |
assert(map_idx == VFNT_MAP_BOLD || map_idx == VFNT_MAP_BOLD_RH); |
142 |
mp_normal = TAILQ_FIRST(&maps[normal_map_idx]); |
143 |
TAILQ_FOREACH_SAFE(mp_bold, &maps[map_idx], m_list, mp_temp) { |
144 |
while (mp_normal->m_char < mp_bold->m_char) |
145 |
mp_normal = TAILQ_NEXT(mp_normal, m_list); |
146 |
if (mp_bold->m_char != mp_normal->m_char) |
147 |
errx(1, "Character %u not in normal font!\n", |
148 |
mp_bold->m_char); |
149 |
if (mp_bold->m_glyph != mp_normal->m_glyph) |
150 |
continue; |
151 |
|
152 |
/* No mapping is needed if it's equal to the normal mapping. */ |
153 |
TAILQ_REMOVE(&maps[map_idx], mp_bold, m_list); |
154 |
free(mp_bold); |
155 |
mapping_dupe++; |
156 |
} |
157 |
return (0); |
158 |
} |
159 |
|
160 |
static struct glyph * |
161 |
add_glyph(const uint8_t *bytes, unsigned int map_idx, int fallback) |
162 |
{ |
163 |
struct glyph *gl; |
164 |
int hash; |
165 |
|
166 |
glyph_total++; |
167 |
glyph_count[map_idx]++; |
168 |
|
169 |
hash = fnv_32_buf(bytes, wbytes * height, FNV1_32_INIT) % FONTCVT_NHASH; |
170 |
SLIST_FOREACH(gl, &glyph_hash[hash], g_hash) { |
171 |
if (memcmp(gl->g_data, bytes, wbytes * height) == 0) { |
172 |
glyph_dupe++; |
173 |
return (gl); |
174 |
} |
175 |
} |
176 |
|
177 |
gl = xmalloc(sizeof *gl); |
178 |
gl->g_data = xmalloc(wbytes * height); |
179 |
memcpy(gl->g_data, bytes, wbytes * height); |
180 |
if (fallback) |
181 |
TAILQ_INSERT_HEAD(&glyphs[map_idx], gl, g_list); |
182 |
else |
183 |
TAILQ_INSERT_TAIL(&glyphs[map_idx], gl, g_list); |
184 |
SLIST_INSERT_HEAD(&glyph_hash[hash], gl, g_hash); |
185 |
|
186 |
glyph_unique++; |
187 |
return (gl); |
188 |
} |
189 |
|
190 |
static int |
191 |
add_char(unsigned curchar, unsigned map_idx, uint8_t *bytes, uint8_t *bytes_r) |
192 |
{ |
193 |
struct glyph *gl; |
194 |
|
195 |
/* Prevent adding two glyphs for 0xFFFD */ |
196 |
if (curchar == 0xFFFD) { |
197 |
if (map_idx < VFNT_MAP_BOLD) |
198 |
gl = add_glyph(bytes, 0, 1); |
199 |
} else if (curchar >= 0x20) { |
200 |
gl = add_glyph(bytes, map_idx, 0); |
201 |
if (add_mapping(gl, curchar, map_idx) != 0) |
202 |
return (1); |
203 |
if (bytes_r != NULL) { |
204 |
gl = add_glyph(bytes_r, map_idx + 1, 0); |
205 |
if (add_mapping(gl, curchar, |
206 |
map_idx + 1) != 0) |
207 |
return (1); |
208 |
} |
209 |
} |
210 |
return (0); |
211 |
} |
212 |
|
213 |
|
214 |
static int |
215 |
parse_bitmap_line(uint8_t *left, uint8_t *right, unsigned int line, |
216 |
unsigned int dwidth) |
217 |
{ |
218 |
uint8_t *p; |
219 |
unsigned int i, subline; |
220 |
|
221 |
if (dwidth != width && dwidth != width * 2) |
222 |
errx(1, "Bitmap with unsupported width %u!\n", dwidth); |
223 |
|
224 |
/* Move pixel data right to simplify splitting double characters. */ |
225 |
line >>= (howmany(dwidth, 8) * 8) - dwidth; |
226 |
|
227 |
for (i = dwidth / width; i > 0; i--) { |
228 |
p = (i == 2) ? right : left; |
229 |
|
230 |
subline = line & ((1 << width) - 1); |
231 |
subline <<= (howmany(width, 8) * 8) - width; |
232 |
|
233 |
if (wbytes == 1) { |
234 |
*p = subline; |
235 |
} else if (wbytes == 2) { |
236 |
*p++ = subline >> 8; |
237 |
*p = subline; |
238 |
} else { |
239 |
errx(1, "Unsupported wbytes %u!\n", wbytes); |
240 |
} |
241 |
|
242 |
line >>= width; |
243 |
} |
244 |
|
245 |
return (0); |
246 |
} |
247 |
|
248 |
static int |
249 |
parse_bdf(FILE *fp, unsigned int map_idx) |
250 |
{ |
251 |
char *ln; |
252 |
size_t length; |
253 |
uint8_t bytes[wbytes * height], bytes_r[wbytes * height]; |
254 |
unsigned int curchar = 0, dwidth = 0, i, line; |
255 |
|
256 |
while ((ln = fgetln(fp, &length)) != NULL) { |
257 |
ln[length - 1] = '\0'; |
258 |
|
259 |
if (strncmp(ln, "ENCODING ", 9) == 0) { |
260 |
curchar = atoi(ln + 9); |
261 |
} |
262 |
|
263 |
if (strncmp(ln, "DWIDTH ", 7) == 0) { |
264 |
dwidth = atoi(ln + 7); |
265 |
} |
266 |
|
267 |
if (strncmp(ln, "BITMAP", 6) == 0 && |
268 |
(ln[6] == ' ' || ln[6] == '\0')) { |
269 |
/* |
270 |
* Assume that the next _height_ lines are bitmap |
271 |
* data. ENDCHAR is allowed to terminate the bitmap |
272 |
* early but is not otherwise checked; any extra data |
273 |
* is ignored. |
274 |
*/ |
275 |
for (i = 0; i < height; i++) { |
276 |
if ((ln = fgetln(fp, &length)) == NULL) |
277 |
errx(1, "Unexpected EOF!\n"); |
278 |
ln[length - 1] = '\0'; |
279 |
if (strcmp(ln, "ENDCHAR") == 0) { |
280 |
memset(bytes + i * wbytes, 0, |
281 |
(height - i) * wbytes); |
282 |
memset(bytes_r + i * wbytes, 0, |
283 |
(height - i) * wbytes); |
284 |
break; |
285 |
} |
286 |
sscanf(ln, "%x", &line); |
287 |
if (parse_bitmap_line(bytes + i * wbytes, |
288 |
bytes_r + i * wbytes, line, dwidth) != 0) |
289 |
return (1); |
290 |
} |
291 |
|
292 |
if (add_char(curchar, map_idx, bytes, |
293 |
dwidth == width * 2 ? bytes_r : NULL) != 0) |
294 |
return (1); |
295 |
} |
296 |
} |
297 |
|
298 |
return (0); |
299 |
} |
300 |
|
301 |
static void |
302 |
set_width(int w) |
303 |
{ |
304 |
|
305 |
if (w <= 0 || w > 128) |
306 |
errx(1, "invalid width %d", w); |
307 |
width = w; |
308 |
wbytes = howmany(width, 8); |
309 |
} |
310 |
|
311 |
static int |
312 |
parse_hex(FILE *fp, unsigned int map_idx) |
313 |
{ |
314 |
char *ln, *p; |
315 |
char fmt_str[8]; |
316 |
size_t length; |
317 |
uint8_t *bytes = NULL, *bytes_r = NULL; |
318 |
unsigned curchar = 0, i, line, chars_per_row, dwidth; |
319 |
int rv = 0; |
320 |
|
321 |
while ((ln = fgetln(fp, &length)) != NULL) { |
322 |
ln[length - 1] = '\0'; |
323 |
|
324 |
if (strncmp(ln, "# Height: ", 10) == 0) { |
325 |
if (bytes != NULL) |
326 |
errx(1, "malformed input: Height tag after font data"); |
327 |
height = atoi(ln + 10); |
328 |
} else if (strncmp(ln, "# Width: ", 9) == 0) { |
329 |
if (bytes != NULL) |
330 |
errx(1, "malformed input: Width tag after font data"); |
331 |
set_width(atoi(ln + 9)); |
332 |
} else if (sscanf(ln, "%6x:", &curchar)) { |
333 |
if (bytes == NULL) { |
334 |
bytes = xmalloc(wbytes * height); |
335 |
bytes_r = xmalloc(wbytes * height); |
336 |
} |
337 |
/* ln is guaranteed to have a colon here. */ |
338 |
p = strchr(ln, ':') + 1; |
339 |
chars_per_row = strlen(p) / height; |
340 |
dwidth = width; |
341 |
if (chars_per_row / 2 > (width + 7) / 8) |
342 |
dwidth *= 2; /* Double-width character. */ |
343 |
snprintf(fmt_str, sizeof(fmt_str), "%%%ux", |
344 |
chars_per_row); |
345 |
|
346 |
for (i = 0; i < height; i++) { |
347 |
sscanf(p, fmt_str, &line); |
348 |
p += chars_per_row; |
349 |
if (parse_bitmap_line(bytes + i * wbytes, |
350 |
bytes_r + i * wbytes, line, dwidth) != 0) { |
351 |
rv = 1; |
352 |
goto out; |
353 |
} |
354 |
} |
355 |
|
356 |
if (add_char(curchar, map_idx, bytes, |
357 |
dwidth == width * 2 ? bytes_r : NULL) != 0) { |
358 |
rv = 1; |
359 |
goto out; |
360 |
} |
361 |
} |
362 |
} |
363 |
out: |
364 |
free(bytes); |
365 |
free(bytes_r); |
366 |
return (rv); |
367 |
} |
368 |
|
369 |
static int |
370 |
parse_file(const char *filename, unsigned int map_idx) |
371 |
{ |
372 |
FILE *fp; |
373 |
size_t len; |
374 |
int rv; |
375 |
|
376 |
fp = fopen(filename, "r"); |
377 |
if (fp == NULL) { |
378 |
perror(filename); |
379 |
return (1); |
380 |
} |
381 |
len = strlen(filename); |
382 |
if (len > 4 && strcasecmp(filename + len - 4, ".hex") == 0) |
383 |
rv = parse_hex(fp, map_idx); |
384 |
else |
385 |
rv = parse_bdf(fp, map_idx); |
386 |
fclose(fp); |
387 |
return (rv); |
388 |
} |
389 |
|
390 |
static void |
391 |
number_glyphs(void) |
392 |
{ |
393 |
struct glyph *gl; |
394 |
unsigned int i, idx = 0; |
395 |
|
396 |
for (i = 0; i < VFNT_MAPS; i++) |
397 |
TAILQ_FOREACH(gl, &glyphs[i], g_list) |
398 |
gl->g_index = idx++; |
399 |
} |
400 |
|
401 |
static int |
402 |
write_glyphs(FILE *fp) |
403 |
{ |
404 |
struct glyph *gl; |
405 |
unsigned int i; |
406 |
|
407 |
for (i = 0; i < VFNT_MAPS; i++) { |
408 |
TAILQ_FOREACH(gl, &glyphs[i], g_list) |
409 |
if (fwrite(gl->g_data, wbytes * height, 1, fp) != 1) |
410 |
return (1); |
411 |
} |
412 |
return (0); |
413 |
} |
414 |
|
415 |
static void |
416 |
fold_mappings(unsigned int map_idx) |
417 |
{ |
418 |
struct mapping_list *ml = &maps[map_idx]; |
419 |
struct mapping *mn, *mp, *mbase; |
420 |
|
421 |
mp = mbase = TAILQ_FIRST(ml); |
422 |
for (mp = mbase = TAILQ_FIRST(ml); mp != NULL; mp = mn) { |
423 |
mn = TAILQ_NEXT(mp, m_list); |
424 |
if (mn != NULL && mn->m_char == mp->m_char + 1 && |
425 |
mn->m_glyph->g_index == mp->m_glyph->g_index + 1) |
426 |
continue; |
427 |
mbase->m_length = mp->m_char - mbase->m_char + 1; |
428 |
mbase = mp = mn; |
429 |
map_folded_count[map_idx]++; |
430 |
} |
431 |
} |
432 |
|
433 |
struct file_mapping { |
434 |
uint32_t source; |
435 |
uint16_t destination; |
436 |
uint16_t length; |
437 |
} __packed; |
438 |
|
439 |
static int |
440 |
write_mappings(FILE *fp, unsigned int map_idx) |
441 |
{ |
442 |
struct mapping_list *ml = &maps[map_idx]; |
443 |
struct mapping *mp; |
444 |
struct file_mapping fm; |
445 |
unsigned int i = 0, j = 0; |
446 |
|
447 |
TAILQ_FOREACH(mp, ml, m_list) { |
448 |
j++; |
449 |
if (mp->m_length > 0) { |
450 |
i += mp->m_length; |
451 |
fm.source = htobe32(mp->m_char); |
452 |
fm.destination = htobe16(mp->m_glyph->g_index); |
453 |
fm.length = htobe16(mp->m_length - 1); |
454 |
if (fwrite(&fm, sizeof fm, 1, fp) != 1) |
455 |
return (1); |
456 |
} |
457 |
} |
458 |
assert(i == j); |
459 |
return (0); |
460 |
} |
461 |
|
462 |
struct file_header { |
463 |
uint8_t magic[8]; |
464 |
uint8_t width; |
465 |
uint8_t height; |
466 |
uint16_t pad; |
467 |
uint32_t glyph_count; |
468 |
uint32_t map_count[4]; |
469 |
} __packed; |
470 |
|
471 |
static int |
472 |
write_fnt(const char *filename) |
473 |
{ |
474 |
FILE *fp; |
475 |
struct file_header fh = { |
476 |
.magic = "VFNT0002", |
477 |
}; |
478 |
|
479 |
fp = fopen(filename, "wb"); |
480 |
if (fp == NULL) { |
481 |
perror(filename); |
482 |
return (1); |
483 |
} |
484 |
|
485 |
fh.width = width; |
486 |
fh.height = height; |
487 |
fh.glyph_count = htobe32(glyph_unique); |
488 |
fh.map_count[0] = htobe32(map_folded_count[0]); |
489 |
fh.map_count[1] = htobe32(map_folded_count[1]); |
490 |
fh.map_count[2] = htobe32(map_folded_count[2]); |
491 |
fh.map_count[3] = htobe32(map_folded_count[3]); |
492 |
if (fwrite(&fh, sizeof fh, 1, fp) != 1) { |
493 |
perror(filename); |
494 |
fclose(fp); |
495 |
return (1); |
496 |
} |
497 |
|
498 |
if (write_glyphs(fp) != 0 || |
499 |
write_mappings(fp, VFNT_MAP_NORMAL) != 0 || |
500 |
write_mappings(fp, 1) != 0 || |
501 |
write_mappings(fp, VFNT_MAP_BOLD) != 0 || |
502 |
write_mappings(fp, 3) != 0) { |
503 |
perror(filename); |
504 |
fclose(fp); |
505 |
return (1); |
506 |
} |
507 |
|
508 |
fclose(fp); |
509 |
return (0); |
510 |
} |
511 |
|
512 |
static void |
513 |
print_font_info(void) |
514 |
{ |
515 |
printf( |
516 |
"Statistics:\n" |
517 |
"- glyph_total: %6u\n" |
518 |
"- glyph_normal: %6u\n" |
519 |
"- glyph_normal_right: %6u\n" |
520 |
"- glyph_bold: %6u\n" |
521 |
"- glyph_bold_right: %6u\n" |
522 |
"- glyph_unique: %6u\n" |
523 |
"- glyph_dupe: %6u\n" |
524 |
"- mapping_total: %6u\n" |
525 |
"- mapping_normal: %6u\n" |
526 |
"- mapping_normal_folded: %6u\n" |
527 |
"- mapping_normal_right: %6u\n" |
528 |
"- mapping_normal_right_folded: %6u\n" |
529 |
"- mapping_bold: %6u\n" |
530 |
"- mapping_bold_folded: %6u\n" |
531 |
"- mapping_bold_right: %6u\n" |
532 |
"- mapping_bold_right_folded: %6u\n" |
533 |
"- mapping_unique: %6u\n" |
534 |
"- mapping_dupe: %6u\n", |
535 |
glyph_total, |
536 |
glyph_count[0], |
537 |
glyph_count[1], |
538 |
glyph_count[2], |
539 |
glyph_count[3], |
540 |
glyph_unique, glyph_dupe, |
541 |
mapping_total, |
542 |
map_count[0], map_folded_count[0], |
543 |
map_count[1], map_folded_count[1], |
544 |
map_count[2], map_folded_count[2], |
545 |
map_count[3], map_folded_count[3], |
546 |
mapping_unique, mapping_dupe); |
547 |
} |
548 |
|
549 |
int |
550 |
main(int argc, char *argv[]) |
551 |
{ |
552 |
int ch, val, verbose = 0; |
553 |
|
554 |
assert(sizeof(struct file_header) == 32); |
555 |
assert(sizeof(struct file_mapping) == 8); |
556 |
|
557 |
while ((ch = getopt(argc, argv, "h:vw:")) != -1) { |
558 |
switch (ch) { |
559 |
case 'h': |
560 |
val = atoi(optarg); |
561 |
if (val <= 0 || val > 128) |
562 |
errx(1, "Invalid height %d", val); |
563 |
height = val; |
564 |
break; |
565 |
case 'v': |
566 |
verbose = 1; |
567 |
break; |
568 |
case 'w': |
569 |
set_width(atoi(optarg)); |
570 |
break; |
571 |
case '?': |
572 |
default: |
573 |
usage(); |
574 |
} |
575 |
} |
576 |
argc -= optind; |
577 |
argv += optind; |
578 |
|
579 |
if (argc < 2 || argc > 3) |
580 |
usage(); |
581 |
|
582 |
wbytes = howmany(width, 8); |
583 |
|
584 |
if (parse_file(argv[0], VFNT_MAP_NORMAL) != 0) |
585 |
return (1); |
586 |
argc--; |
587 |
argv++; |
588 |
if (argc == 2) { |
589 |
if (parse_file(argv[0], VFNT_MAP_BOLD) != 0) |
590 |
return (1); |
591 |
argc--; |
592 |
argv++; |
593 |
} |
594 |
number_glyphs(); |
595 |
dedup_mapping(VFNT_MAP_BOLD); |
596 |
dedup_mapping(VFNT_MAP_BOLD_RH); |
597 |
fold_mappings(0); |
598 |
fold_mappings(1); |
599 |
fold_mappings(2); |
600 |
fold_mappings(3); |
601 |
if (write_fnt(argv[0]) != 0) |
602 |
return (1); |
603 |
|
604 |
if (verbose) |
605 |
print_font_info(); |
606 |
|
607 |
return (0); |
608 |
} |