3
"$Header: d:/cvsroot/tads/TADS2/mkchrtab.c,v 1.2 1999/05/17 02:52:14 MJRoberts Exp $";
7
* Copyright (c) 1998, 2002 Michael J. Roberts. All Rights Reserved.
9
* Please see the accompanying license file, LICENSE.TXT, for information
10
* on using and copying this software.
14
mkchrtab.c - TADS character table generator
20
05/31/98 MJRoberts - Creation
39
* Read a number. Returns zero on success, non-zero on error.
41
static int read_number(unsigned int *result, char **p,
42
char *infile, int linenum, int is_char)
48
/* skip any leading spaces */
53
* Check for a character value
59
/* get the next character */
62
/* if it's a backslash, escape the next character */
65
/* skip the backslash */
68
/* the next character gives the value */
92
printf("%s: line %d: invalid backslash sequence '\\%c'\n",
93
infile, linenum, **p);
99
/* use this value as the character code */
100
c = (unsigned char)**p;
103
/* skip the character, and make sure we have the closing quote */
107
printf("%s: line %d: missing close quote\n", infile, linenum);
111
/* skip the close quote */
114
/* skip trailing spaces */
118
/* return the result */
119
*result = (unsigned int)c;
124
* determine the base - if there's a leading zero, it's hex or
125
* octal; otherwise, it's decimal
129
/* skip the leading zero */
132
/* if the next character is 'x', it's hex, otherwise it's octal */
133
if (**p == 'x' || **p == 'X')
149
/* no leading zero - it's a decimal number */
154
for (acc = 0, digcnt = 0 ;; ++(*p), ++digcnt)
156
/* see if we still have a digit */
157
if (isdigit(**p) || (base == 16 && isxdigit(**p)))
161
/* get this digit's value */
162
dig = (unsigned int)(isdigit(**p)
164
: **p - (isupper(**p) ? 'A' : 'a') + 10);
166
/* make sure it's in range for our radix */
169
printf("%s: line %d: invalid digit for radix\n",
174
/* accumulate this digit */
180
/* that's the end of the number */
185
/* if we didn't get any valid digits, it's an error */
188
printf("%s: line %d: invalid number\n", infile, linenum);
192
/* skip any trailing spaces */
196
/* make sure the result isn't too large */
197
if ((is_char && acc > (unsigned int)(unsigned char)0xff)
198
|| acc > (unsigned int)0xffff)
200
printf("%s: line %d: value out of range\n", infile, linenum);
204
/* return the accumulated value */
213
* Check to see if an identifier matches a given string
215
static int id_matches(const char *idp, size_t idlen, const char *str)
217
return (idlen == strlen(str) && memicmp(idp, str, idlen) == 0);
221
* HTML Entity mapping structure
226
unsigned int charval;
230
* List of HTML TADS entity names and the corresponding character codes
232
static const struct entity_t entities[] =
332
/* TADS extensions to the standard characters */
341
/* HTML 4.0 character extensions */
417
/* general punctuation marks */
425
/* letter-like symbols */
444
/* mathematical operators */
490
/* geometric shapes */
493
/* miscellaneous symbols */
499
/* Latin-extended B */
502
/* Latin-2 characters */
562
* Entity mapping list entry. We store each entity mapping we find in
563
* the file in one of these structures, and link the structures together
566
typedef struct entity_map_t entity_map_t;
569
/* next mapping entry in the list */
572
/* HTML entity character code (Unicode value) */
573
unsigned int html_char;
575
/* length of the expansion */
578
/* local character set expansion */
579
unsigned char expansion[1];
583
* Parse an entity name mapping
585
static entity_map_t *parse_entity(char *p, char *infile, int linenum)
588
const struct entity_t *entp;
589
unsigned char buf[CMAP_MAX_ENTITY_EXPANSION];
593
/* find the end of the entity name */
595
for ( ; isalpha(*p) || isdigit(*p) ; ++p) ;
597
/* scan the list for the entity name */
598
for (entp = entities ; entp->ename != 0 ; ++entp)
600
/* see if this one is a match - note that case is significant */
601
if (strlen(entp->ename) == (size_t)(p - start)
602
&& memcmp(entp->ename, start, p - start) == 0)
606
/* if we didn't find it, it's an error */
607
if (entp->ename == 0)
609
printf("%s: line %d: unknown entity name \"%.*s\"\n",
610
infile, linenum, p - start, start);
614
/* skip any intervening whitespace and check for the '=' sign */
615
for ( ; isspace(*p) ; ++p) ;
618
printf("%s: line %d: expected '=' after entity name\n",
626
/* read the series of numbers */
627
for (dstp = buf ; *p != '\0' ; )
632
/* skip any leading whitespace */
636
/* if it's the end of the line or a comment, stop */
637
if (*p == '\0' || *p == '#')
640
/* scan the character code */
641
if (read_number(&intval, &p, infile, linenum, TRUE))
643
c = (unsigned char)intval;
645
/* make sure we haven't overflowed our buffer */
646
if (dstp >= buf + sizeof(buf))
648
printf("%s: line %d: entity mapping is too long (maximum of %d "
649
"characters are allowed\n",
650
infile, linenum, sizeof(buf));
654
/* add it to the output list */
658
/* if we didn't get any characters, it's an error */
661
printf("%s: line %d: no local character codes found after '='\n",
666
/* create a new mapping structure and set it up */
667
mapp = (entity_map_t *)malloc(sizeof(entity_map_t) + dstp - buf);
669
mapp->html_char = entp->charval;
670
mapp->exp_len = dstp - buf;
671
memcpy(mapp->expansion, buf, dstp - buf);
673
/* return the new mapping structure */
679
* Unicode mapping table entry
681
typedef struct unicode_map_t unicode_map_t;
684
/* corresponding Unicode code point */
685
unsigned int unicode_val;
689
* Generate a mapping table by associating two Unicode mapping tables
691
static void gen_unicode_mapping(unicode_map_t map_from[256],
692
unicode_map_t map_to[256],
693
unsigned char result_fwd[256],
694
unsigned char result_fwd_set[256],
695
unsigned char result_rev[256],
696
unsigned char result_rev_set[256])
701
* For each item in the 'from' map, find the entry in the 'to' map
702
* with the same Unicode value. This gives the value that we store
703
* in the result table at the 'from' character index location.
705
for (i = 0 ; i < 256 ; ++i)
709
/* find this 'from' Unicode value in the 'to' table */
710
for (j = 0 ; j < 256 ; ++j)
712
/* if they match, map it */
713
if (map_to[j].unicode_val == map_from[i].unicode_val)
715
/* set the forward mapping, if it's not already set */
716
if (!result_fwd_set[i])
719
result_fwd_set[i] = TRUE;
722
/* set the reverse mapping, if it's not already set */
723
if (!result_rev_set[j])
726
result_rev_set[j] = TRUE;
729
/* no need to look any further */
737
* Load a Unicode mapping file
739
static void load_unicode_file(char *filename, unicode_map_t map[256],
740
char *infile, int linenum)
745
/* open the unicode file */
746
fp = osfoprs(filename, OSFTTEXT);
749
printf("%s: line %d: unable to open unicode mapping file \"%s\"\n",
750
infile, linenum, filename);
755
for (linenum_u = 1 ;; ++linenum_u)
762
/* read the next line */
763
if (osfgets(buf, sizeof(buf), fp) == 0)
766
/* skip leading spaces */
767
for (p = buf ; isspace(*p) ; ++p) ;
769
/* if it's blank or starts with a comment, ignore it */
770
if (*p == 0x1a || *p == '#' || *p == '\n' || *p == '\r' || *p == '\0')
773
/* read the first number - this is the native character value */
774
if (read_number(&n1, &p, filename, linenum_u, TRUE))
777
/* read the second number */
778
if (read_number(&n2, &p, filename, linenum_u, FALSE))
781
/* set the association */
782
map[n1].unicode_val = n2;
785
/* done with the file */
790
* Generate the HTML named entity mappings for the native character set
792
static void gen_unicode_html_mapping(unicode_map_t map_native[256],
793
entity_map_t **entity_first,
794
entity_map_t **entity_last)
798
/* go through the native characters and find the named entity for each */
799
for (i = 0 ; i < 255 ; ++i)
801
const struct entity_t *entity;
804
* scan the named entity table to find an entity with the same
805
* Unicode value as this native character's Unicode mapping
807
for (entity = entities ; entity->ename != 0 ; ++entity)
809
/* if this one matches the Unicode value, map it */
810
if (entity->charval == map_native[i].unicode_val)
814
/* create a new mapping structure */
815
mapp = (entity_map_t *)malloc(sizeof(entity_map_t) + 1);
819
mapp->html_char = map_native[i].unicode_val;
821
mapp->expansion[0] = (unsigned char)i;
824
* link it at the head of the list, so that any explicit
825
* mapping specified by the user for the same entity
826
* already or subsequently will override it (this will
827
* happen because the users's entries always go at the
830
mapp->nxt = *entity_first;
831
if (*entity_last == 0)
833
*entity_first = mapp;
835
/* no need to look any further */
844
* Parse Unicode mapping files
846
static void parse_unicode_files(char *val, size_t vallen,
847
char *infile, int linenum,
848
unsigned char input_map[256],
849
unsigned char input_map_set[256],
850
unsigned char output_map[256],
851
unsigned char output_map_set[256],
852
entity_map_t **entity_first,
853
entity_map_t **entity_last)
855
char fn_native[OSFNMAX];
856
char fn_internal[OSFNMAX];
858
unicode_map_t map_native[256];
859
unicode_map_t map_internal[256];
861
/* retrieve the filenames */
863
fn_internal[0] = '\0';
870
/* if we're at a comment, we're done */
874
/* find the end of the current identifier */
875
for (id = val ; vallen > 0 && isalpha(*val) ; ++val, --vallen) ;
878
/* see what we have */
879
if (id_matches(id, idlen, "native"))
881
else if (id_matches(id, idlen, "internal"))
885
printf("%s: line %d: expected 'internal' or 'native', "
886
"found '%.*s'\n", infile, linenum, idlen, id);
890
/* if the current name has already been matched, it's an error */
893
printf("%s: line %d: '%.*s' specified more than once\n",
894
infile, linenum, idlen, id);
898
/* scan ahead to the '=' */
899
while (vallen > 0 && isspace(*val))
902
/* make sure we have the '=' */
903
if (vallen == 0 || *val != '=')
905
printf("%s: line %d: expected '=' after '%.*s'\n",
906
infile, linenum, idlen, id);
910
/* skip intervening spaces */
912
while (vallen > 0 && isspace(*val))
915
/* make sure we have a filename */
918
printf("%s: line %d: expected filename after '='\n",
923
/* check for a quote */
924
if (*val == '"' || *val == '\'')
926
/* remember the quote */
934
/* we have no quote */
938
/* scan the filename */
939
for ( ; vallen > 0 ; ++val, --vallen)
941
/* check for a quote */
942
if (qu != '\0' && *val == qu)
949
* if it's stuttered, keep a single copy and keep going;
950
* otherwise, we're done
952
if (vallen > 1 && *(val+1) == qu)
954
/* just skip the first quote, and keep the second */
958
/* that's the matching close quote - we're done */
963
/* copy this character */
967
/* null-terminate the filename */
970
/* skip trailing spaces */
971
while (vallen > 0 && isspace(*val))
975
/* make sure we got both filenames */
976
if (fn_internal[0] == '\0' || fn_native[0] == '\0')
978
printf("%s: line %d: must specify both 'native' and 'internal'"
979
" with 'unicode'\n", infile, linenum);
983
/* load the two files */
984
load_unicode_file(fn_internal, map_internal, infile, linenum);
985
load_unicode_file(fn_native, map_native, infile, linenum);
987
/* generate the forward and reverse mappings */
988
gen_unicode_mapping(map_native, map_internal, input_map, input_map_set,
989
output_map, output_map_set);
990
gen_unicode_mapping(map_internal, map_native, output_map, output_map_set,
991
input_map, input_map_set);
993
/* generate the HTML named entity mappings */
994
gen_unicode_html_mapping(map_native, entity_first, entity_last);
1001
int main(int argc, char **argv)
1004
unsigned char input_map[256];
1005
unsigned char output_map[256];
1006
unsigned char input_map_set[256];
1007
unsigned char output_map_set[256];
1014
static char sig[] = CMAP_SIG_S100;
1015
int strict_mode = FALSE;
1017
char ldesc[CMAP_LDESC_MAX_LEN + 1];
1019
unsigned char lenbuf[2];
1021
entity_map_t *entity_first;
1022
entity_map_t *entity_last;
1024
/* no parameters have been specified yet */
1025
memset(id, 0, sizeof(id));
1029
/* we have no entities in our entity mapping list yet */
1030
entity_first = entity_last = 0;
1033
for (curarg = 1 ; curarg < argc && argv[curarg][0] == '-' ; ++curarg)
1035
if (!stricmp(argv[curarg], "-strict"))
1037
/* they want extra warnings */
1042
/* consume all remaining options so we get a usage message */
1048
/* check for required arguments */
1049
if (curarg + 1 >= argc)
1051
printf("usage: mkchrtab [options] <source> <dest>\n"
1052
" <source> is the input file\n"
1053
" <dest> is the output file\n"
1055
" -strict warn if any codes 128-255 are unassigned\n");
1058
* The information about what goes in the file made the message way too
1059
* long, so this has been removed. Users will want to the documentation
1060
* instead of the usage message for information this detailed, so it
1061
* didn't seem useful to keep it in here.
1064
"The source file contains one entry per line, as follows:\n"
1066
"Set the internal character set identifier, which can be up "
1067
"to four letters long\n"
1068
"(note that the mapping file MUST contain an ID entry):\n"
1071
printf("Set the internal character set's full display name:\n"
1072
" LDESC = full name of character set\n"
1074
"Set system-dependent extra information (the meaning varies "
1076
" EXTRA_SYSTEM_INFO = info-string\n"
1078
"Set the native default character:\n"
1079
" NATIVE_DEFAULT = charval\n"
1080
"Set the internal default character:\n"
1081
" INTERNAL_DEFAULT = charval\n");
1082
printf("Load Unicode mapping files:\n"
1083
" UNICODE NATIVE=native-mapping INTERNAL=internal-mapping\n"
1085
"Reversibly map a native character code to an internal code:\n"
1086
" native <-> internal\n"
1088
"Map a native code to an internal code, and map the internal "
1089
"code back\nto a different native code:\n"
1090
" native -> internal -> native\n"
1092
"Map a native code to an internal code, where the internal "
1093
"code is already\nmapped to a native code by a previous line:\n"
1094
" native -> internal\n"
1096
printf("Map an internal code to a native code, where the native "
1097
"code is already\nmapped to an internal code by a previous "
1099
" native <- internal\n"
1101
"Map an HTML entity name to a native code or string:\n"
1102
" &entity = internal-code [internal-code ...]\n"
1104
"Numbers can be specified in decimal (default), octal (by "
1105
"prefixing the number\nwith a zero, as in '037'), or hex (by "
1106
"prefixing the number with '0x', as in\n'0xb2'). A number "
1107
"can also be entered as a character by enclosing the\n"
1108
"character in single quotes.\n"
1110
"Blank lines and lines starting with a pound sign ('#') are "
1116
/* get the input and output filenames */
1117
infile = argv[curarg];
1118
outfile = argv[curarg + 1];
1121
* initialize the tables - by default, a character code in one
1122
* character set maps to the same code in the other character set
1124
for (p = input_map, i = 0 ; i < sizeof(input_map)/sizeof(input_map[0]) ;
1126
*p = (unsigned char)i;
1128
for (p = output_map, i = 0 ;
1129
i < sizeof(output_map)/sizeof(output_map[0]) ; ++i, ++p)
1130
*p = (unsigned char)i;
1133
* initialize the "set" flags all to false, since we haven't set any
1134
* of the values yet -- we'll use these flags to detect when the
1135
* user attempts to set the same value more than once, so that we
1136
* can issue a warning (multiple mappings are almost certainly in
1139
for (i = 0 ; i < sizeof(input_map_set)/sizeof(input_map_set[0]) ; ++i)
1140
input_map_set[i] = output_map_set[i] = FALSE;
1142
/* open the input file */
1143
fp = osfoprs(infile, OSFTTEXT);
1146
printf("error: unable to open input file \"%s\"\n", infile);
1150
/* parse the input file */
1151
for (linenum = 1 ; ; ++linenum)
1155
unsigned int n1, n2, n3;
1159
/* presume we're going to set both values */
1160
set_input = set_output = TRUE;
1162
/* read the next line */
1163
if (osfgets(buf, sizeof(buf), fp) == 0)
1166
/* scan off leading spaces */
1167
for (p = buf ; isspace(*p) ; ++p) ;
1169
/* if this line is blank, or starts with a '#', ignore it */
1170
if (*p == '\0' || *p == '\n' || *p == '\r' || *p == '#')
1173
/* check for special directives */
1174
if (isalpha(*p) || *p == '_')
1181
/* find the end of the directive name */
1182
for (sp = p ; isalpha(*sp) || *sp == '_' ; ++sp) ;
1185
/* find the equals sign, if present */
1186
for (val = sp ; isspace(*val) ; ++val) ;
1189
/* skip the '=' and any spaces that follow */
1190
for (++val ; isspace(*val) ; ++val) ;
1192
/* find the end of the value */
1193
for (sp = val ; *sp != '\n' && *sp != '\r' && *sp != '\0' ;
1196
/* note its length */
1201
/* there's no value */
1205
/* see what we have */
1206
if (id_matches(p, idlen, "id"))
1208
/* this directive requires a value */
1212
/* ID's can never be more than four characters long */
1215
printf("%s: line %d: ID too long - no more than four "
1216
"characters are allowed\n", infile, linenum);
1220
/* remember the ID */
1221
memcpy(id, val, vallen);
1225
else if (id_matches(p, idlen, "ldesc"))
1227
/* this directive requires a value */
1231
/* make sure it fits */
1232
if (vallen > sizeof(ldesc) - 1)
1234
printf("%s: line %d: LDESC too long - no more than %u "
1235
"characters are allowed\n", infile, linenum,
1240
/* remember the ldesc */
1241
memcpy(ldesc, val, vallen);
1242
ldesc[vallen] = '\0';
1245
else if (id_matches(p, idlen, "extra_system_info"))
1247
/* this directive requires a value */
1251
/* allocate space for it */
1252
sys_info = (char *)malloc(vallen + 1);
1253
memcpy(sys_info, val, vallen);
1254
sys_info[vallen] = '\0';
1256
else if (id_matches(p, idlen, "native_default"))
1261
/* this directive requires a value */
1265
/* parse the character value */
1266
if (read_number(&nval, &val, infile, linenum, TRUE))
1269
/* apply the default */
1270
for (i = 128 ; i < 256 ; ++i)
1272
/* set the default only if we haven't mapped this one */
1273
if (!output_map_set[i])
1274
output_map[i] = nval;
1277
else if (id_matches(p, idlen, "internal_default"))
1282
/* this directive requires a value */
1286
/* parse the character value */
1287
if (read_number(&nval, &val, infile, linenum, TRUE))
1290
/* apply the default */
1291
for (i = 128 ; i < 256 ; ++i)
1293
/* apply the default only if we haven't set this one */
1294
if (!input_map_set[i])
1295
input_map[i] = nval;
1298
else if (id_matches(p, idlen, "unicode"))
1300
/* skip the 'unicode' string and any intervening spaces */
1301
for (p += idlen ; isspace(*p) ; ++p) ;
1303
/* parse the unicode files */
1304
parse_unicode_files(p, strlen(p), infile, linenum,
1305
input_map, input_map_set,
1306
output_map, output_map_set,
1307
&entity_first, &entity_last);
1311
/* unknown directive */
1312
printf("%s: line %d: invalid directive '%.*s'\n",
1313
infile, linenum, idlen, p);
1316
/* done processing this line */
1319
/* come here if the directive needs a value and there isn't one */
1321
printf("%s: line %d: '=' required with directive '%.*s'\n",
1322
infile, linenum, idlen, p);
1326
/* check for an entity name */
1335
* parse the entity - if it succeeds, link the resulting
1336
* mapping entry into our list
1338
mapp = parse_entity(p, infile, linenum);
1341
if (entity_last == 0)
1342
entity_first = mapp;
1344
entity_last->nxt = mapp;
1352
/* read the first number */
1353
if (read_number(&n1, &p, infile, linenum, TRUE))
1356
/* determine which operator we have */
1359
/* make sure it's "<->" or "<-" */
1360
if (*(p+1) == '-' && *(p+2) != '>')
1362
/* skip the operator */
1366
* This is a "from" translation - it only affects the
1367
* output mapping from the internal character set to the
1368
* native character set. Read the second number. There
1369
* is no third number, since we don't want to change the
1372
if (read_number(&n2, &p, infile, linenum, TRUE))
1376
* The forward translation is not affected; set only the
1377
* output translation. Note that the first number was
1378
* the output (native) value for the internal index in
1379
* the second number, so move the first value to n3.
1384
else if (*(p+1) == '-' && *(p+2) == '>')
1390
* this is a reversible translation, so we only need one
1391
* more number - the third number is implicitly the same
1395
if (read_number(&n2, &p, infile, linenum, TRUE))
1400
printf("%s: line %d: invalid operator - expected <->\n",
1407
/* make sure it's "->" */
1410
printf("%s: line %d: invalid operator - expected ->\n",
1418
/* get the next number */
1419
if (read_number(&n2, &p, infile, linenum, TRUE))
1423
* we may or may not have a third number - if we have
1424
* another -> operator, read the third number; if we don't,
1425
* the reverse translation is not affected by this entry
1429
/* make sure it's "->" */
1432
printf("%s: line %d: invalid operator - expected ->\n",
1440
/* read the third number */
1441
if (read_number(&n3, &p, infile, linenum, TRUE))
1447
* There's no third number - the reverse translation is
1448
* not affected by this line.
1455
printf("%s: line %d: invalid operator - expected "
1456
"-> or <-> or <-\n",
1461
/* make sure we're at the end of the line, and warn if not */
1462
if (*p != '\0' && *p != '\n' && *p != '\r' && *p != '#')
1463
printf("%s: line %d: extra characters at end of line ignored\n",
1466
/* set the input mapping, if necessary */
1469
/* warn the user if this value has already been set before */
1470
if (input_map_set[n1])
1471
printf("%s: line %d: warning - native character %u has "
1472
"already been\n mapped to internal value %u\n",
1473
infile, linenum, n1, input_map[n1]);
1478
/* note that it's been set */
1479
input_map_set[n1] = TRUE;
1482
/* set the output mapping, if necessary */
1485
/* warn the user if this value has already been set before */
1486
if (output_map_set[n2])
1487
printf("%s: line %d: warning - internal character %u has "
1488
"already been\n mapped to native value %u\n",
1489
infile, linenum, n2, input_map[n2]);
1492
output_map[n2] = n3;
1494
/* note that it's been set */
1495
output_map_set[n2] = TRUE;
1499
/* we're done with the input file */
1503
* It's an error if we didn't get an ID or LDESC
1507
printf("Error: No ID was specified. An ID is required.\n");
1510
else if (ldesc[0] == '\0')
1512
printf("Error: No LDESC was specified. An LDESC is required.\n");
1516
/* open the output file */
1517
fp = osfopwb(outfile, OSFTCMAP);
1520
printf("error: unable to open output file \"%s\"\n", outfile);
1524
/* write our signature */
1525
if (osfwb(fp, sig, sizeof(sig)))
1526
printf("error writing signature to output file\n");
1528
/* write the ID and LDESC */
1529
len = strlen(ldesc) + 1;
1531
if (osfwb(fp, id, 4)
1532
|| osfwb(fp, lenbuf, 2)
1533
|| osfwb(fp, ldesc, len))
1534
printf("error writing ID information to output file\n");
1536
/* write the mapping tables */
1537
if (osfwb(fp, input_map, sizeof(input_map))
1538
|| osfwb(fp, output_map, sizeof(output_map)))
1539
printf("error writing character maps to output file\n");
1541
/* write the extra system information if present */
1544
/* write it out, with the "SYSI" flag so we know it's there */
1545
len = strlen(sys_info) + 1;
1547
if (osfwb(fp, "SYSI", 4)
1548
|| osfwb(fp, lenbuf, 2)
1549
|| osfwb(fp, sys_info, len))
1550
printf("error writing EXTRA_SYSTEM_INFO to output file\n");
1552
/* we're done with the allocated buffer now */
1557
* Write the entity mapping list, if we have any entities
1559
if (entity_first != 0)
1562
entity_map_t *next_entity;
1566
/* write out the entity list header */
1567
if (osfwb(fp, "ENTY", 4))
1568
printf("error writing entity marker to output file\n");
1570
/* run through the list, writing out each entry */
1571
for (entp = entity_first ; entp != 0 ; entp = next_entity)
1573
/* write out this entity */
1574
oswp2(lenbuf, entp->exp_len);
1575
oswp2(cvalbuf, entp->html_char);
1576
if (osfwb(fp, lenbuf, 2)
1577
|| osfwb(fp, cvalbuf, 2)
1578
|| osfwb(fp, entp->expansion, entp->exp_len))
1580
printf("error writing entity mapping to output file\n");
1584
/* remember the next entity before we delete this one */
1585
next_entity = entp->nxt;
1587
/* we're done with this entity, so we can delete it now */
1592
* write out the end marker, which is just a length marker and
1593
* character marker of zero
1597
if (osfwb(fp, lenbuf, 2)
1598
|| osfwb(fp, cvalbuf, 2))
1599
printf("error writing entity list end marker to output file\n");
1602
/* write the end-of-file marker */
1603
if (osfwb(fp, "$EOF", 4))
1604
printf("error writing end-of-file marker to output file\n");
1606
/* done with the output file */
1609
/* if we're in strict mode, check for unassigned mappings */
1612
int in_cnt, out_cnt;
1615
/* count unassigned characters */
1616
for (i = 128, in_cnt = out_cnt = 0 ; i < 256 ; ++i)
1618
if (!input_map_set[i])
1620
if (!output_map_set[i])
1624
/* if we have any unassigned native characters, list them */
1627
printf("\nUnassigned native -> internal mappings:\n ");
1628
for (i = 128, cnt = 0 ; i < 256 ; ++i)
1630
if (!input_map_set[i])
1632
/* go to a new line if necessary */
1639
/* display this item */
1647
/* list unassigned internal characters */
1650
printf("\nUnassigned internal -> native mappings:\n ");
1651
for (i = 128, cnt = 0 ; i < 256 ; ++i)
1653
if (!output_map_set[i])
1655
/* go to a new line if necessary */
1662
/* display this item */