1 /*
2 * $LynxId: makeuctb.c,v 1.48 2013/07/21 00:42:39 tom Exp $
3 *
4 * makeuctb.c, derived from conmakehash.c - kw
5 *
6 * Original comments from conmakehash.c:
7 *
8 * Create arrays for initializing the kernel folded tables (using a hash
9 * table turned out to be to limiting...) Unfortunately we can't simply
10 * preinitialize the tables at compile time since kfree() cannot accept
11 * memory not allocated by kmalloc(), and doing our own memory management
12 * just for this seems like massive overkill.
13 *
14 * Copyright (C) 1995 H. Peter Anvin
15 *
16 * This program is a part of the Linux kernel, and may be freely
17 * copied under the terms of the GNU General Public License (GPL),
18 * version 2, or at your option any later version.
19 */
20
21 #ifndef HAVE_CONFIG_H
22 /* override HTUtils.h fallbacks for cross-compiling */
23 #undef HAVE_LSTAT
24 #undef NO_FILIO_H
25 #define HAVE_LSTAT 1
26 #define NO_FILIO_H 1
27 #endif
28
29 #define DONT_USE_GETTEXT
30 #define DONT_USE_SOCKS5
31 #include <UCDefs.h>
32 #include <UCkd.h>
33
34 /*
35 * Don't try to use LYexit() since this is a standalone file.
36 */
37 #ifdef exit
38 #undef exit
39 #endif /* exit */
40
41 #include <stdlib.h>
42 #include <string.h>
43 #include <ctype.h>
44
45 #define MAX_FONTLEN 256
46
47 /*
48 * We don't deal with UCS4 here. - KW
49 */
50 typedef u16 unicode;
51
52 static FILE *chdr = 0;
53
54 /*
55 * Since we may be writing the formatted file to stdout, ensure that we flush
56 * everything before leaving, since some old (and a few not-so-old) platforms
57 * do not properly implement POSIX 'exit()'.
58 */
59 static void done(int code) GCC_NORETURN;
60
done(int code)61 static void done(int code)
62 {
63 if (chdr != 0) {
64 fflush(chdr);
65 fclose(chdr);
66 }
67 fflush(stderr);
68 exit(code);
69 }
70
usage(void)71 static void usage(void)
72 {
73 static const char *tbl[] =
74 {
75 "Usage: makeuctb [parameters]",
76 "",
77 "Utility to convert .tbl into .h files for Lynx compilation.",
78 "",
79 "Parameters (all are optional):",
80 " 1: the input file (normally {filename}.tbl, but \"-\" for stdin",
81 " 2: the output file (normally {filename}.tbl but \"-\" for stdout",
82 " 3: charset mime name",
83 " 4: charset display name"
84 };
85 unsigned n;
86
87 for (n = 0; n < TABLESIZE(tbl); n++) {
88 fprintf(stderr, "%s\n", tbl[n]);
89 };
90 done(EX_USAGE);
91 }
92
93 #ifdef USE_ASCII_CTYPES
ascii_tolower(int i)94 static int ascii_tolower(int i)
95 {
96 if (91 > i && i > 64)
97 return (i + 32);
98 else
99 return i;
100 }
101 #endif
102
103 /* copied from HTString.c, not everybody has strncasecmp */
strncasecomp(const char * a,const char * b,int n)104 int strncasecomp(const char *a, const char *b, int n)
105 {
106 const char *p;
107 const char *q;
108
109 for (p = a, q = b;; p++, q++) {
110 int diff;
111
112 if (p == (a + n))
113 return 0; /* Match up to n characters */
114 if (!(*p && *q))
115 return (*p - *q);
116 diff = TOLOWER(*p) - TOLOWER(*q);
117 if (diff)
118 return diff;
119 }
120 /*NOTREACHED */
121 }
122
getunicode(char ** p0)123 static int getunicode(char **p0)
124 {
125 char *p = *p0;
126
127 while (*p == ' ' || *p == '\t')
128 p++;
129
130 if (*p == '-') {
131 return -2;
132 } else if (*p != 'U' || p[1] != '+' ||
133 !isxdigit(UCH(p[2])) ||
134 !isxdigit(UCH(p[3])) ||
135 !isxdigit(UCH(p[4])) ||
136 !isxdigit(UCH(p[5])) ||
137 isxdigit(UCH(p[6]))) {
138 return -1;
139 }
140 *p0 = p + 6;
141 return (int) strtol((p + 2), 0, 16);
142 }
143
144 /*
145 * Massive overkill, but who cares?
146 */
147 static unicode unitable[MAX_FONTLEN][255];
148 static int unicount[MAX_FONTLEN];
149
150 static struct unimapdesc_str themap_str =
151 {0, NULL, 0, 0};
152
153 static const char *tblname;
154 static const char *hdrname;
155
156 static int RawOrEnc = 0;
157 static int Raw_found = 0; /* whether explicit R directive found */
158 static int CodePage = 0;
159
160 #define MAX_UNIPAIRS 4500
161
addpair_str(char * str,int un)162 static void addpair_str(char *str, int un)
163 {
164 int i = 0;
165
166 if (un <= 0xfffe) {
167 if (!themap_str.entry_ct) {
168 /*
169 * Initialize the map for replacement strings.
170 */
171 themap_str.entries = (struct unipair_str *) malloc(MAX_UNIPAIRS
172 * sizeof(struct unipair_str));
173
174 if (!themap_str.entries) {
175 fprintf(stderr,
176 "%s: Out of memory\n", tblname);
177 done(EX_DATAERR);
178 }
179 } else {
180 /*
181 * Check that it isn't a duplicate.
182 */
183 for (i = 0; i < themap_str.entry_ct; i++) {
184 if (themap_str.entries[i].unicode == un) {
185 themap_str.entries[i].replace_str = str;
186 return;
187 }
188 }
189 }
190
191 /*
192 * Add to list.
193 */
194 if (themap_str.entry_ct > MAX_UNIPAIRS - 1) {
195 fprintf(stderr,
196 "ERROR: Only %d unicode replacement strings permitted!\n",
197 MAX_UNIPAIRS);
198 done(EX_DATAERR);
199 }
200 themap_str.entries[themap_str.entry_ct].unicode = (u16) un;
201 themap_str.entries[themap_str.entry_ct].replace_str = str;
202 themap_str.entry_ct++;
203 }
204 /* otherwise: ignore */
205 }
206
addpair(int fp,int un)207 static void addpair(int fp, int un)
208 {
209 int i;
210
211 if (!Raw_found) { /* enc not (yet) explicitly given with 'R' */
212 if (fp >= 128) {
213 if (RawOrEnc != UCT_ENC_8BIT && RawOrEnc <= UCT_ENC_8859) {
214 if (fp < 160) { /* cannot be 8859 */
215 RawOrEnc = UCT_ENC_8BIT;
216 } else if (fp != 160 && fp != 173) {
217 RawOrEnc = UCT_ENC_8859; /* hmmm.. more tests needed? */
218 } else if (unicount[fp] == 0 && fp != un) {
219 /* first unicode for fp doesn't map to itself */
220 RawOrEnc = UCT_ENC_8BIT;
221 } else {
222 RawOrEnc = UCT_ENC_8859; /* hmmm.. more tests needed? */
223 }
224 }
225 }
226 }
227 if (un <= 0xfffe) {
228 /*
229 * Check that it isn't a duplicate.
230 */
231 for (i = 0; i < unicount[fp]; i++) {
232 if (unitable[fp][i] == un) {
233 return;
234 }
235 }
236
237 /*
238 * Add to list.
239 */
240 if (unicount[fp] > 254) {
241 fprintf(stderr, "ERROR: Only 255 unicodes/glyph permitted!\n");
242 done(EX_DATAERR);
243 }
244 unitable[fp][unicount[fp]] = (u16) un;
245 unicount[fp]++;
246 }
247 /* otherwise: ignore */
248 }
249
250 static char this_MIMEcharset[UC_MAXLEN_MIMECSNAME + 1];
251 static char this_LYNXcharset[UC_MAXLEN_LYNXCSNAME + 1];
252 static char id_append[UC_MAXLEN_ID_APPEND + 1] = "_";
253 static int this_isDefaultMap = -1;
254 static int useDefaultMap = 1;
255 static int lowest_eight = 999;
256
main(int argc,char ** argv)257 int main(int argc, char **argv)
258 {
259 static const char *first_ifdefs[] =
260 {
261 "/*",
262 " * Compile-in this chunk of code unless we've turned it off specifically",
263 " * or in general (id=%s).",
264 " */",
265 "",
266 "#ifndef INCL_CHARSET%s",
267 "#define INCL_CHARSET%s 1",
268 "",
269 "/*ifdef NO_CHARSET*/",
270 "#ifdef NO_CHARSET",
271 "#undef NO_CHARSET",
272 "#endif",
273 "#define NO_CHARSET 0 /* force default to always be active */",
274 "",
275 "/*ifndef NO_CHARSET%s*/",
276 "#ifndef NO_CHARSET%s",
277 "",
278 "#if ALL_CHARSETS",
279 "#define NO_CHARSET%s 0",
280 "#else",
281 "#define NO_CHARSET%s 1",
282 "#endif",
283 "",
284 "#endif /* ndef(NO_CHARSET%s) */",
285 "",
286 "#if NO_CHARSET%s",
287 "#define UC_CHARSET_SETUP%s /*nothing*/",
288 "#else"
289 };
290 static const char *last_ifdefs[] =
291 {
292 "",
293 "#endif /* NO_CHARSET%s */",
294 "",
295 "#endif /* INCL_CHARSET%s */"
296 };
297
298 FILE *ctbl;
299 char buffer[65536];
300 char *outname = 0;
301 unsigned n;
302 int fontlen;
303 int i, nuni, nent;
304 int fp0 = 0, fp1 = 0, un0, un1;
305 char *p, *p1;
306 char *tbuf, ch;
307 size_t outnamesz, plen;
308
309 if (argc < 2 || argc > 5) {
310 usage();
311 }
312
313 if (!strcmp(argv[1], "-")) {
314 ctbl = stdin;
315 tblname = "stdin";
316 } else {
317 ctbl = fopen(tblname = argv[1], "r");
318 if (!ctbl) {
319 perror(tblname);
320 done(EX_NOINPUT);
321 }
322 }
323
324 if (argc > 2) {
325 if (!strcmp(argv[2], "-")) {
326 chdr = stdout;
327 hdrname = "stdout";
328 } else {
329 hdrname = argv[2];
330 }
331 } else if (ctbl == stdin) {
332 chdr = stdout;
333 hdrname = "stdout";
334 } else if ((outname = (char *) malloc(outnamesz = strlen(tblname) + 3)) != 0) {
335 strlcpy(outname, tblname, outnamesz);
336 hdrname = outname;
337 if ((p = strrchr(outname, '.')) == 0)
338 p = outname + strlen(outname);
339 strlcpy(p, ".h", outnamesz - (p - outname));
340 } else {
341 perror("malloc");
342 done(EX_NOINPUT);
343 }
344
345 if (chdr == 0) {
346 chdr = fopen(hdrname, "w");
347 if (!chdr) {
348 perror(hdrname);
349 done(EX_NOINPUT);
350 }
351 }
352
353 /*
354 * For now we assume the default font is always 256 characters.
355 */
356 fontlen = 256;
357
358 /*
359 * Initialize table.
360 */
361 for (i = 0; i < fontlen; i++) {
362 unicount[i] = 0;
363 }
364
365 /*
366 * Now we comes to the tricky part. Parse the input table.
367 */
368 while (fgets(buffer, (int) sizeof(buffer), ctbl) != NULL) {
369 if ((p = strchr(buffer, '\n')) != NULL) {
370 *p = '\0';
371 } else {
372 fprintf(stderr,
373 "%s: Warning: line too long or incomplete.\n",
374 tblname);
375 }
376
377 /*
378 * Syntax accepted:
379 * <fontpos> <unicode> <unicode> ...
380 * <fontpos> <unicode range> <unicode range> ...
381 * <fontpos> idem
382 * <range> idem
383 * <range> <unicode range>
384 * <unicode> :<replace>
385 * <unicode range> :<replace>
386 * <unicode> "<C replace>"
387 * <unicode range> "<C replace>"
388 *
389 * where <range> ::= <fontpos>-<fontpos>
390 * and <unicode> ::= U+<h><h><h><h>
391 * and <h> ::= <hexadecimal digit>
392 * and <replace> any string not containing '\n' or '\0'
393 * and <C replace> any string with C backslash escapes.
394 */
395 p = buffer;
396 while (*p == ' ' || *p == '\t') {
397 p++;
398 }
399 if (!(*p) || *p == '#') {
400 /*
401 * Skip comment or blank line.
402 */
403 continue;
404 }
405
406 switch (*p) {
407 /*
408 * Raw Unicode? I.e. needs some special
409 * processing. One digit code.
410 */
411 case 'R':
412 if (p[1] == 'a' || p[1] == 'A') {
413 buffer[sizeof(buffer) - 1] = '\0';
414 if (!strncasecomp(p, "RawOrEnc", 8)) {
415 p += 8;
416 }
417 }
418 p++;
419 while (*p == ' ' || *p == '\t') {
420 p++;
421 }
422 RawOrEnc = (int) strtol(p, 0, 10);
423 Raw_found = 1;
424 continue;
425
426 /*
427 * Is this the default table?
428 */
429 case 'D':
430 if (p[1] == 'e' || p[1] == 'E') {
431 buffer[sizeof(buffer) - 1] = '\0';
432 if (!strncasecomp(p, "Default", 7)) {
433 p += 7;
434 }
435 }
436 p++;
437 while (*p == ' ' || *p == '\t') {
438 p++;
439 }
440 this_isDefaultMap = (*p == '1' || TOLOWER(*p) == 'y');
441 continue;
442
443 /*
444 * Is this the default table?
445 */
446 case 'F':
447 if (p[1] == 'a' || p[1] == 'A') {
448 buffer[sizeof(buffer) - 1] = '\0';
449 if (!strncasecomp(p, "FallBack", 8)) {
450 p += 8;
451 }
452 }
453 p++;
454 while (*p == ' ' || *p == '\t') {
455 p++;
456 }
457 useDefaultMap = (*p == '1' || TOLOWER(*p) == 'y');
458 continue;
459
460 case 'M':
461 if (p[1] == 'i' || p[1] == 'I') {
462 buffer[sizeof(buffer) - 1] = '\0';
463 if (!strncasecomp(p, "MIMEName", 8)) {
464 p += 8;
465 }
466 }
467 p++;
468 while (*p == ' ' || *p == '\t') {
469 p++;
470 }
471 sscanf(p, "%40s", this_MIMEcharset);
472 continue;
473
474 /*
475 * Display charset name for options screen.
476 */
477 case 'O':
478 if (p[1] == 'p' || p[1] == 'P') {
479 buffer[sizeof(buffer) - 1] = '\0';
480 if (!strncasecomp(p, "OptionName", 10)) {
481 p += 10;
482 }
483 }
484 p++;
485 while (*p == ' ' || *p == '\t') {
486 p++;
487 }
488 for (i = 0; *p && i < UC_MAXLEN_LYNXCSNAME; p++, i++) {
489 this_LYNXcharset[i] = *p;
490 }
491 this_LYNXcharset[i] = '\0';
492 continue;
493
494 /*
495 * Codepage number. Three or four digit code.
496 */
497 case 'C':
498 if (p[1] == 'o' || p[1] == 'O') {
499 buffer[sizeof(buffer) - 1] = '\0';
500 if (!strncasecomp(p, "CodePage", 8)) {
501 p += 8;
502 }
503 }
504 p++;
505 while (*p == ' ' || *p == '\t') {
506 p++;
507 }
508 CodePage = (int) strtol(p, 0, 10);
509 continue;
510 }
511
512 if (*p == 'U') {
513 un0 = getunicode(&p);
514 if (un0 < 0) {
515 fprintf(stderr, "Bad input line: %s\n", buffer);
516 done(EX_DATAERR);
517 fprintf(stderr,
518 "%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n",
519 tblname, fp0, fp1);
520 done(EX_DATAERR);
521 }
522 un1 = un0;
523 while (*p == ' ' || *p == '\t') {
524 p++;
525 }
526 if (*p == '-') {
527 p++;
528 while (*p == ' ' || *p == '\t') {
529 p++;
530 }
531 un1 = getunicode(&p);
532 if (un1 < 0 || un1 < un0) {
533 fprintf(stderr,
534 "%s: Bad Unicode range U+%x-U+%x\n",
535 tblname, un0, un1);
536 fprintf(stderr, "Bad input line: %s\n", buffer);
537 done(EX_DATAERR);
538 }
539 while (*p == ' ' || *p == '\t') {
540 p++;
541 }
542 }
543
544 if (*p != ':' && *p != '"') {
545 fprintf(stderr, "No ':' or '\"' where expected: %s\n",
546 buffer);
547 continue;
548 }
549
550 /*
551 * Allocate a string large enough for the worst-case use in the
552 * loop using sprintf.
553 */
554 tbuf = (char *) malloc(plen = 5 * strlen(p));
555
556 if (!(p1 = tbuf)) {
557 fprintf(stderr, "%s: Out of memory\n", tblname);
558 done(EX_DATAERR);
559 }
560 if (*p == '"') {
561 /*
562 * Handle "<C replace>".
563 * Copy chars verbatim until first '"' not \-escaped or
564 * end of buffer.
565 */
566 int escaped = 0;
567
568 ch = 0;
569 for (++p; *p != '\0'; p++) {
570 ch = *p;
571 if (escaped) {
572 escaped = 0;
573 } else if (ch == '"') {
574 break;
575 } else if (ch == '\\') {
576 escaped = 1;
577 }
578 *p1++ = ch;
579 }
580 if (escaped || ch != '"') {
581 fprintf(stderr, "Warning: String not terminated: %s\n",
582 buffer);
583 if (escaped)
584 *p1++ = '\n';
585 }
586 } else {
587 /*
588 * We had ':'.
589 */
590 for (++p; *p != '\0'; p++, p1++) {
591 ch = *p;
592 if (UCH(ch) < 32 || ch == '\\' || ch == '\"' ||
593 UCH(ch) >= 127) {
594 snprintf(p1, plen - (p1 - tbuf), "\\%.3o", UCH(ch));
595 p1 += 3;
596 } else {
597 *p1 = ch;
598 }
599 }
600 }
601 *p1 = '\0';
602 for (i = un0; i <= un1; i++) {
603 addpair_str(tbuf, i);
604 }
605 continue;
606 }
607
608 /*
609 * Input line (after skipping spaces) doesn't start with one
610 * of the specially recognized characters, so try to interpret
611 * it as starting with a fontpos.
612 */
613 fp0 = (int) strtol(p, &p1, 0);
614 if (p1 == p) {
615 fprintf(stderr, "Bad input line: %s\n", buffer);
616 done(EX_DATAERR);
617 }
618 p = p1;
619
620 while (*p == ' ' || *p == '\t') {
621 p++;
622 }
623 if (*p == '-') {
624 p++;
625 fp1 = (int) strtol(p, &p1, 0);
626 if (p1 == p) {
627 fprintf(stderr, "Bad input line: %s\n", buffer);
628 done(EX_DATAERR);
629 }
630 p = p1;
631 } else {
632 fp1 = 0;
633 }
634
635 if (fp0 < 0 || fp0 >= fontlen) {
636 fprintf(stderr,
637 "%s: Glyph number (0x%x) larger than font length\n",
638 tblname, fp0);
639 done(EX_DATAERR);
640 }
641 if (fp1 && (fp1 < fp0 || fp1 >= fontlen)) {
642 fprintf(stderr,
643 "%s: Bad end of range (0x%x)\n",
644 tblname, fp1);
645 done(EX_DATAERR);
646 }
647
648 if (fp1) {
649 /*
650 * We have a range; expect the word "idem"
651 * or a Unicode range of the same length.
652 */
653 while (*p == ' ' || *p == '\t') {
654 p++;
655 }
656 if (!StrNCmp(p, "idem", 4)) {
657 for (i = fp0; i <= fp1; i++) {
658 addpair(i, i);
659 }
660 p += 4;
661 } else {
662 un0 = getunicode(&p);
663 while (*p == ' ' || *p == '\t') {
664 p++;
665 }
666 if (*p != '-') {
667 fprintf(stderr,
668 "%s: Corresponding to a range of font positions,",
669 tblname);
670 fprintf(stderr,
671 " there should be a Unicode range.\n");
672 done(EX_DATAERR);
673 }
674 p++;
675 un1 = getunicode(&p);
676 if (un0 < 0 || un1 < 0) {
677 fprintf(stderr,
678 "%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n",
679 tblname, fp0, fp1);
680 done(EX_DATAERR);
681 }
682 if (un1 - un0 != fp1 - fp0) {
683 fprintf(stderr,
684 "%s: Unicode range U+%x-U+%x not of the same length",
685 tblname, un0, un1);
686 fprintf(stderr,
687 " as font position range 0x%x-0x%x\n",
688 fp0, fp1);
689 done(EX_DATAERR);
690 }
691 for (i = fp0; i <= fp1; i++) {
692 addpair(i, un0 - fp0 + i);
693 }
694 }
695 } else {
696 /*
697 * No range; expect a list of unicode values
698 * or unicode ranges for a single font position,
699 * or the word "idem"
700 */
701 while (*p == ' ' || *p == '\t') {
702 p++;
703 }
704 if (!StrNCmp(p, "idem", 4)) {
705 addpair(fp0, fp0);
706 p += 4;
707 }
708 while ((un0 = getunicode(&p)) >= 0) {
709 addpair(fp0, un0);
710 while (*p == ' ' || *p == '\t') {
711 p++;
712 }
713 if (*p == '-') {
714 p++;
715 un1 = getunicode(&p);
716 if (un1 < un0) {
717 fprintf(stderr,
718 "%s: Bad Unicode range 0x%x-0x%x\n",
719 tblname, un0, un1);
720 done(EX_DATAERR);
721 }
722 for (un0++; un0 <= un1; un0++) {
723 addpair(fp0, un0);
724 }
725 }
726 }
727 }
728 while (*p == ' ' || *p == '\t') {
729 p++;
730 }
731 if (*p && *p != '#') {
732 fprintf(stderr, "%s: trailing junk (%s) ignored\n", tblname, p);
733 }
734 }
735
736 /*
737 * Okay, we hit EOF, now output tables.
738 */
739 fclose(ctbl);
740
741 /*
742 * Compute total size of Unicode list.
743 */
744 nuni = 0;
745 for (i = 0; i < fontlen; i++) {
746 nuni += unicount[i];
747 }
748
749 if (argc > 3) {
750 StrNCpy(this_MIMEcharset, argv[3], UC_MAXLEN_MIMECSNAME);
751 } else if (this_MIMEcharset[0] == '\0') {
752 StrNCpy(this_MIMEcharset, tblname, UC_MAXLEN_MIMECSNAME);
753 if ((p = strchr(this_MIMEcharset, '.')) != 0) {
754 *p = '\0';
755 }
756 }
757 for (p = this_MIMEcharset; *p; p++) {
758 *p = (char) TOLOWER(*p);
759 }
760 if (argc > 4) {
761 StrNCpy(this_LYNXcharset, argv[4], UC_MAXLEN_LYNXCSNAME);
762 } else if (this_LYNXcharset[0] == '\0') {
763 StrNCpy(this_LYNXcharset, this_MIMEcharset, UC_MAXLEN_LYNXCSNAME);
764 }
765
766 if (this_isDefaultMap == -1) {
767 this_isDefaultMap = !StrNCmp(this_MIMEcharset, "iso-8859-1", 10);
768 }
769 fprintf(stderr,
770 "makeuctb: %s: %stranslation map",
771 this_MIMEcharset, (this_isDefaultMap ? "default " : ""));
772 if (this_isDefaultMap == 1) {
773 *id_append = '\0';
774 } else {
775 for (i = 0, p = this_MIMEcharset;
776 *p && (i < UC_MAXLEN_ID_APPEND - 1);
777 p++, i++) {
778 id_append[i + 1] = (char) (isalnum(UCH(*p)) ? *p : '_');
779 }
780 id_append[i + 1] = '\0';
781 }
782 fprintf(stderr, " (%s).\n", id_append);
783
784 for (n = 0; n < TABLESIZE(first_ifdefs); n++) {
785 fprintf(chdr, first_ifdefs[n], id_append);
786 fprintf(chdr, "\n");
787 }
788
789 fprintf(chdr, "\n\
790 /*\n\
791 * uni_hash.tbl\n\
792 *\n\
793 * Do not edit this file; it was automatically generated by\n\
794 *\n\
795 * %s %s\n\
796 *\n\
797 */\n\
798 \n\
799 static const u8 dfont_unicount%s[%d] = \n\
800 {\n\t", argv[0], argv[1], id_append, fontlen);
801
802 for (i = 0; i < fontlen; i++) {
803 if (i >= 128 && unicount[i] > 0 && i < lowest_eight) {
804 lowest_eight = i;
805 }
806 fprintf(chdr, "%3d", unicount[i]);
807 if (i == (fontlen - 1)) {
808 fprintf(chdr, "\n};\n");
809 } else if ((i % 8) == 7) {
810 fprintf(chdr, ",\n\t");
811 } else {
812 fprintf(chdr, ", ");
813 }
814 }
815
816 /*
817 * If lowest_eightbit is anything else but 999,
818 * this can't be 7-bit only.
819 */
820 if (lowest_eight != 999 && !RawOrEnc) {
821 RawOrEnc = UCT_ENC_8BIT;
822 }
823
824 if (nuni) {
825 fprintf(chdr, "\nstatic const u16 dfont_unitable%s[%d] = \n{\n\t",
826 id_append, nuni);
827 } else {
828 fprintf(chdr,
829 "\nstatic const u16 dfont_unitable%s[1] = {0}; /* dummy */\n", id_append);
830 }
831
832 fp0 = 0;
833 nent = 0;
834 for (i = 0; i < nuni; i++) {
835 while (nent >= unicount[fp0]) {
836 fp0++;
837 nent = 0;
838 }
839 fprintf(chdr, "0x%04x", unitable[fp0][nent++]);
840 if (i == (nuni - 1)) {
841 fprintf(chdr, "\n};\n");
842 } else if ((i % 8) == 7) {
843 fprintf(chdr, ",\n\t");
844 } else {
845 fprintf(chdr, ", ");
846 }
847 }
848
849 if (themap_str.entry_ct) {
850 fprintf(chdr, "\n\
851 static struct unipair_str repl_map%s[%d] = \n\
852 {\n\t", id_append, themap_str.entry_ct);
853 } else {
854 fprintf(chdr, "\n\
855 /* static struct unipair_str repl_map%s[]; */\n", id_append);
856 }
857
858 for (i = 0; i < themap_str.entry_ct; i++) {
859 fprintf(chdr, "{0x%x,\"%s\"}",
860 themap_str.entries[i].unicode,
861 themap_str.entries[i].replace_str);
862 if (i == (themap_str.entry_ct - 1)) {
863 fprintf(chdr, "\n};\n");
864 } else if ((i % 4) == 3) {
865 fprintf(chdr, ",\n\t");
866 } else {
867 fprintf(chdr, ", ");
868 }
869 }
870 if (themap_str.entry_ct) {
871 fprintf(chdr, "\n\
872 static const struct unimapdesc_str dfont_replacedesc%s = {%d,repl_map%s,",
873 id_append, themap_str.entry_ct, id_append);
874 } else {
875 fprintf(chdr, "\n\
876 static const struct unimapdesc_str dfont_replacedesc%s = {0,NULL,", id_append);
877 }
878 fprintf(chdr, "%d,%d};\n",
879 this_isDefaultMap ? 1 : 0,
880 (useDefaultMap && !this_isDefaultMap) ? 1 : 0
881 );
882
883 fprintf(chdr, "#define UC_CHARSET_SETUP%s UC_Charset_Setup(\
884 \"%s\",\\\n\"%s\",\\\n\
885 dfont_unicount%s,dfont_unitable%s,%d,\\\n\
886 dfont_replacedesc%s,%d,%d,%d)\n",
887 id_append, this_MIMEcharset, this_LYNXcharset,
888 id_append, id_append, nuni, id_append, lowest_eight, RawOrEnc, CodePage);
889
890 for (n = 0; n < TABLESIZE(last_ifdefs); n++) {
891 fprintf(chdr, last_ifdefs[n], id_append);
892 fprintf(chdr, "\n");
893 }
894
895 done(EX_OK);
896 return 0;
897 }
898