~ubuntu-branches/ubuntu/wily/gargoyle-free/wily-proposed

« back to all changes in this revision

Viewing changes to tads/tads3/mkchrtab.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Sylvain Beucler
  • Date: 2009-09-11 20:09:43 UTC
  • Revision ID: james.westby@ubuntu.com-20090911200943-idgzoyupq6650zpn
Tags: upstream-2009-08-25
ImportĀ upstreamĀ versionĀ 2009-08-25

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifdef RCSID
 
2
static char RCSid[] =
 
3
"$Header: d:/cvsroot/tads/tads3/mkchrtab.cpp,v 1.3 1999/07/11 00:46:58 MJRoberts Exp $";
 
4
#endif
 
5
 
 
6
/* 
 
7
 *   Copyright (c) 1998, 2002 Michael J. Roberts.  All Rights Reserved.
 
8
 *   
 
9
 *   Please see the accompanying license file, LICENSE.TXT, for information
 
10
 *   on using and copying this software.  
 
11
 */
 
12
/*
 
13
Name
 
14
  mkchrtab.cpp - TADS character table generator
 
15
Function
 
16
  
 
17
Notes
 
18
  
 
19
Modified
 
20
  10/17/98 MJRoberts  - creation (from TADS 2 mkchrtab.c)
 
21
*/
 
22
 
 
23
#include <stdio.h>
 
24
#include <stdlib.h>
 
25
#include <ctype.h>
 
26
#include <string.h>
 
27
 
 
28
#include "t3std.h"
 
29
 
 
30
/*
 
31
 *   Read a number.  Returns zero on success, non-zero on error.
 
32
 */
 
33
static int read_number(unsigned short *result, char **p,
 
34
                       char *infile, int linenum, int optional)
 
35
{
 
36
    unsigned short base;
 
37
    unsigned short acc;
 
38
    int digcnt;
 
39
    
 
40
    /* skip any leading spaces */
 
41
    while (isspace(**p))
 
42
        ++(*p);
 
43
 
 
44
    /* 
 
45
     *   if the entry is optional, and we've reached a comment or the end
 
46
     *   of the line, return failure, but don't print an error (since the
 
47
     *   number is optional, it's not an error if it's not present) 
 
48
     */
 
49
    if (optional &&
 
50
        (**p == '\0' || **p == '\n' || **p == '\r' || **p == '#'))
 
51
        return 2;
 
52
 
 
53
    /*
 
54
     *   Check for a character value 
 
55
     */
 
56
    if (**p == '\'')
 
57
    {
 
58
        unsigned char c;
 
59
        
 
60
        /* get the next character */
 
61
        ++(*p);
 
62
 
 
63
        /* if it's a backslash, escape the next character */
 
64
        if (**p == '\\')
 
65
        {
 
66
            /* skip the backslash */
 
67
            ++(*p);
 
68
 
 
69
            /* the next character gives the value */
 
70
            switch(**p)
 
71
            {
 
72
            case 'n':
 
73
                c = '\n';
 
74
                break;
 
75
 
 
76
            case 'r':
 
77
                c = '\r';
 
78
                break;
 
79
 
 
80
            case 't':
 
81
                c = '\t';
 
82
                break;
 
83
 
 
84
            case '\\':
 
85
                c = '\\';
 
86
                break;
 
87
 
 
88
            case '\'':
 
89
                c = '\'';
 
90
                break;
 
91
 
 
92
            default:
 
93
                printf("%s: line %d: invalid backslash sequence '\\%c'\n",
 
94
                       infile, linenum, **p);
 
95
                return 4;
 
96
            }
 
97
        }
 
98
        else
 
99
        {
 
100
            /* use this value as the character code */
 
101
            c = (unsigned char)**p;
 
102
        }
 
103
 
 
104
        /* skip the character, and make sure we have the closing quote */
 
105
        ++(*p);
 
106
        if (**p != '\'')
 
107
        {
 
108
            printf("%s: line %d: missing close quote\n", infile, linenum);
 
109
            return 5;
 
110
        }
 
111
 
 
112
        /* skip the close quote */
 
113
        ++(*p);
 
114
 
 
115
        /* skip trailing spaces */
 
116
        while (isspace(**p))
 
117
            ++(*p);
 
118
 
 
119
        /* return the result */
 
120
        *result = (unsigned short)c;
 
121
        return 0;
 
122
    }
 
123
 
 
124
    /* 
 
125
     *   determine the base - if there's a leading zero, it's hex or
 
126
     *   octal; otherwise, it's decimal 
 
127
     */
 
128
    if (**p == '0')
 
129
    {
 
130
        /* skip the leading zero */
 
131
        ++(*p);
 
132
        
 
133
        /* if the next character is 'x', it's hex, otherwise it's octal */
 
134
        if (**p == 'x' || **p == 'X')
 
135
        {
 
136
            /* skip the 'x' */
 
137
            ++(*p);
 
138
 
 
139
            /* it's hex */
 
140
            base = 16;
 
141
        }
 
142
        else
 
143
        {
 
144
            /* it's octal */
 
145
            base = 8;
 
146
        }
 
147
    }
 
148
    else
 
149
    {
 
150
        /* no leading zero - it's a decimal number */
 
151
        base = 10;
 
152
    }
 
153
 
 
154
    /* read digits */
 
155
    for (acc = 0, digcnt = 0 ;; ++(*p), ++digcnt)
 
156
    {
 
157
        /* see if we still have a digit */
 
158
        if (isdigit(**p) || (base == 16 && isxdigit(**p)))
 
159
        {
 
160
            unsigned short dig;
 
161
            
 
162
            /* get this digit's value */
 
163
            dig = (unsigned short)(isdigit(**p)
 
164
                                   ? **p - '0'
 
165
                                   : **p - (isupper(**p) ? 'A' : 'a') + 10);
 
166
 
 
167
            /* make sure it's in range for our radix */
 
168
            if (dig >= base)
 
169
            {
 
170
                printf("%s: line %d: invalid digit for radix\n",
 
171
                       infile, linenum);
 
172
                return 3;
 
173
            }
 
174
 
 
175
            /* accumulate this digit */
 
176
            acc *= base;
 
177
            acc += dig;
 
178
        }
 
179
        else
 
180
        {
 
181
            /* that's the end of the number */
 
182
            break;
 
183
        }
 
184
    }
 
185
 
 
186
    /* if we didn't get any valid digits, it's an error */
 
187
    if (digcnt == 0)
 
188
    {
 
189
        printf("%s: line %d: invalid number\n", infile, linenum);
 
190
        return 1;
 
191
    }
 
192
 
 
193
    /* skip any trailing spaces */
 
194
    while (isspace(**p))
 
195
        ++(*p);
 
196
 
 
197
    /* return the accumulated value */
 
198
    *result = acc;
 
199
 
 
200
    /* success */
 
201
    return 0;
 
202
}
 
203
 
 
204
 
 
205
/*
 
206
 *   HTML Entity mapping structure 
 
207
 */
 
208
struct entity_t
 
209
{
 
210
    const char *ename;
 
211
    wchar_t charval;
 
212
};
 
213
 
 
214
/*
 
215
 *   List of HTML TADS entity names and the corresponding Unicode
 
216
 *   character codes 
 
217
 */
 
218
static const struct entity_t entities[] =
 
219
{
 
220
    { "nbsp", 160 },
 
221
    { "iexcl", 161 },
 
222
    { "cent", 162 },
 
223
    { "pound", 163 },
 
224
    { "curren", 164 },
 
225
    { "yen", 165 },
 
226
    { "brvbar", 166 },
 
227
    { "sect", 167 },
 
228
    { "uml", 168 },
 
229
    { "copy", 169 },
 
230
    { "ordf", 170 },
 
231
    { "laquo", 171 },
 
232
    { "not", 172 },
 
233
    { "shy", 173 },
 
234
    { "reg", 174 },
 
235
    { "macr", 175 },
 
236
    { "deg", 176 },
 
237
    { "plusmn", 177 },
 
238
    { "sup2", 178 },
 
239
    { "sup3", 179 },
 
240
    { "acute", 180 },
 
241
    { "micro", 181 },
 
242
    { "para", 182 },
 
243
    { "middot", 183 },
 
244
    { "cedil", 184 },
 
245
    { "sup1", 185 },
 
246
    { "ordm", 186 },
 
247
    { "raquo", 187 },
 
248
    { "frac14", 188 },
 
249
    { "frac12", 189 },
 
250
    { "frac34", 190 },
 
251
    { "iquest", 191 },
 
252
    { "times", 215 },
 
253
    { "divide", 247 },
 
254
    { "AElig", 198 },
 
255
    { "Aacute", 193 },
 
256
    { "Acirc", 194 },
 
257
    { "Agrave", 192 },
 
258
    { "Aring", 197 },
 
259
    { "Atilde", 195 },
 
260
    { "Auml", 196 },
 
261
    { "Ccedil", 199 },
 
262
    { "ETH", 208 },
 
263
    { "Eacute", 201 },
 
264
    { "Ecirc", 202 },
 
265
    { "Egrave", 200 },
 
266
    { "Euml", 203 },
 
267
    { "Iacute", 205 },
 
268
    { "Icirc", 206 },
 
269
    { "Igrave", 204 },
 
270
    { "Iuml", 207 },
 
271
    { "Ntilde", 209 },
 
272
    { "Oacute", 211 },
 
273
    { "Ocirc", 212 },
 
274
    { "Ograve", 210 },
 
275
    { "Oslash", 216 },
 
276
    { "Otilde", 213 },
 
277
    { "Ouml", 214 },
 
278
    { "THORN", 222 },
 
279
    { "Uacute", 218 },
 
280
    { "Ucirc", 219 },
 
281
    { "Ugrave", 217 },
 
282
    { "Uuml", 220 },
 
283
    { "Yacute", 221 },
 
284
    { "aacute", 225 },
 
285
    { "acirc", 226 },
 
286
    { "aelig", 230 },
 
287
    { "agrave", 224 },
 
288
    { "aring", 229 },
 
289
    { "atilde", 227 },
 
290
    { "auml", 228 },
 
291
    { "ccedil", 231 },
 
292
    { "eacute", 233 },
 
293
    { "ecirc", 234 },
 
294
    { "egrave", 232 },
 
295
    { "eth", 240 },
 
296
    { "euml", 235 },
 
297
    { "iacute", 237 },
 
298
    { "icirc", 238 },
 
299
    { "igrave", 236 },
 
300
    { "iuml", 239 },
 
301
    { "ntilde", 241 },
 
302
    { "oacute", 243 },
 
303
    { "ocirc", 244 },
 
304
    { "ograve", 242 },
 
305
    { "oslash", 248 },
 
306
    { "otilde", 245 },
 
307
    { "ouml", 246 },
 
308
    { "szlig", 223 },
 
309
    { "thorn", 254 },
 
310
    { "uacute", 250 },
 
311
    { "ucirc", 251 },
 
312
    { "ugrave", 249 },
 
313
    { "uuml", 252 },
 
314
    { "yacute", 253 },
 
315
    { "thorn", 254 },
 
316
    { "yuml", 255 },
 
317
 
 
318
    /* TADS extensions to the standard characters */
 
319
    { "lsq", 8216 },
 
320
    { "rsq", 8217 },
 
321
    { "ldq", 8220 },
 
322
    { "rdq", 8221 },
 
323
    { "endash", 8211 },
 
324
    { "emdash", 8212 },
 
325
    { "trade", 8482 },
 
326
 
 
327
    /* HTML 4.0 character extensions */
 
328
    { "ndash", 8211 },
 
329
    { "mdash", 8212 },
 
330
    { "lsquo", 8216 },
 
331
    { "rsquo", 8217 },
 
332
    { "ldquo", 8220 },
 
333
    { "rdquo", 8221 },
 
334
    { "sbquo", 8218 },
 
335
    { "bdquo", 8222 },
 
336
    { "lsaquo", 8249 },
 
337
    { "rsaquo", 8250 },
 
338
    { "dagger", 8224 },
 
339
    { "Dagger", 8225 },
 
340
    { "OElig", 338 },
 
341
    { "oelig", 339 },
 
342
    { "permil", 8240 },
 
343
    { "Yuml", 376 },
 
344
    { "scaron", 353 },
 
345
    { "Scaron", 352 },
 
346
    { "circ", 710 },
 
347
    { "tilde", 732 },
 
348
 
 
349
    /* Greek letters */
 
350
    { "Alpha", 913 },
 
351
    { "Beta", 914 },
 
352
    { "Gamma", 915 },
 
353
    { "Delta", 916 },
 
354
    { "Epsilon", 917 },
 
355
    { "Zeta", 918 },
 
356
    { "Eta", 919 },
 
357
    { "Theta", 920 },
 
358
    { "Iota", 921 },
 
359
    { "Kappa", 922 },
 
360
    { "Lambda", 923 },
 
361
    { "Mu", 924 },
 
362
    { "Nu", 925 },
 
363
    { "Xi", 926 },
 
364
    { "Omicron", 927 },
 
365
    { "Pi", 928 },
 
366
    { "Rho", 929 },
 
367
    { "Sigma", 931 },
 
368
    { "Tau", 932 },
 
369
    { "Upsilon", 933 },
 
370
    { "Phi", 934 },
 
371
    { "Chi", 935 },
 
372
    { "Psi", 936 },
 
373
    { "Omega", 937 },
 
374
    { "alpha", 945 },
 
375
    { "beta", 946 },
 
376
    { "gamma", 947 },
 
377
    { "delta", 948 },
 
378
    { "epsilon", 949 },
 
379
    { "zeta", 950 },
 
380
    { "eta", 951 },
 
381
    { "theta", 952 },
 
382
    { "iota", 953 },
 
383
    { "kappa", 954 },
 
384
    { "lambda", 955 },
 
385
    { "mu", 956 },
 
386
    { "nu", 957 },
 
387
    { "xi", 958 },
 
388
    { "omicron", 959 },
 
389
    { "pi", 960 },
 
390
    { "rho", 961 },
 
391
    { "sigmaf", 962 },
 
392
    { "sigma", 963 },
 
393
    { "tau", 964 },
 
394
    { "upsilon", 965 },
 
395
    { "phi", 966 },
 
396
    { "chi", 967 },
 
397
    { "psi", 968 },
 
398
    { "omega", 969 },
 
399
    { "thetasym", 977 },
 
400
    { "upsih", 978 },
 
401
    { "piv", 982 },
 
402
 
 
403
    /* general punctuation marks */
 
404
    { "bull", 8226 },
 
405
    { "hellip", 8230 },
 
406
    { "prime", 8242 },
 
407
    { "Prime", 8243 },
 
408
    { "oline", 8254 },
 
409
    { "frasl", 8260 },
 
410
 
 
411
    /* letter-like symbols */
 
412
    { "weierp", 8472 },
 
413
    { "image", 8465 },
 
414
    { "real", 8476 },
 
415
    { "alefsym", 8501 },
 
416
 
 
417
    /* arrows */
 
418
    { "larr", 8592 },
 
419
    { "uarr", 8593 },
 
420
    { "rarr", 8594 },
 
421
    { "darr", 8595 },
 
422
    { "harr", 8596 },
 
423
    { "crarr", 8629 },
 
424
    { "lArr", 8656 },
 
425
    { "uArr", 8657 },
 
426
    { "rArr", 8658 },
 
427
    { "dArr", 8659 },
 
428
    { "hArr", 8660 },
 
429
 
 
430
    /* mathematical operators */
 
431
    { "forall", 8704 },
 
432
    { "part", 8706 },
 
433
    { "exist", 8707 },
 
434
    { "empty", 8709 },
 
435
    { "nabla", 8711 },
 
436
    { "isin", 8712 },
 
437
    { "notin", 8713 },
 
438
    { "ni", 8715 },
 
439
    { "prod", 8719 },
 
440
    { "sum", 8721 },
 
441
    { "minus", 8722 },
 
442
    { "lowast", 8727 },
 
443
    { "radic", 8730 },
 
444
    { "prop", 8733 },
 
445
    { "infin", 8734 },
 
446
    { "ang", 8736 },
 
447
    { "and", 8743 },
 
448
    { "or", 8744 },
 
449
    { "cap", 8745 },
 
450
    { "cup", 8746 },
 
451
    { "int", 8747 },
 
452
    { "there4", 8756 },
 
453
    { "sim", 8764 },
 
454
    { "cong", 8773 },
 
455
    { "asymp", 8776 },
 
456
    { "ne", 8800 },
 
457
    { "equiv", 8801 },
 
458
    { "le", 8804 },
 
459
    { "ge", 8805 },
 
460
    { "sub", 8834 },
 
461
    { "sup", 8835 },
 
462
    { "nsub", 8836 },
 
463
    { "sube", 8838 },
 
464
    { "supe", 8839 },
 
465
    { "oplus", 8853 },
 
466
    { "otimes", 8855 },
 
467
    { "perp", 8869 },
 
468
    { "sdot", 8901 },
 
469
    { "lceil", 8968 },
 
470
    { "rceil", 8969 },
 
471
    { "lfloor", 8970 },
 
472
    { "rfloor", 8971 },
 
473
    { "lang", 9001 },
 
474
    { "rang", 9002 },
 
475
 
 
476
    /* geometric shapes */
 
477
    { "loz", 9674 },
 
478
 
 
479
    /* miscellaneous symbols */
 
480
    { "spades", 9824 },
 
481
    { "clubs", 9827 },
 
482
    { "hearts", 9829 },
 
483
    { "diams", 9830 },
 
484
 
 
485
    /* Latin-extended B */
 
486
    { "fnof", 402 },
 
487
 
 
488
    /* Latin-2 characters */
 
489
    { "Aogon", 260 },
 
490
    { "breve", 728 },
 
491
    { "Lstrok", 321 },
 
492
    { "Lcaron", 317 },
 
493
    { "Sacute", 346 },
 
494
    { "Scedil", 350 },
 
495
    { "Tcaron", 356 },
 
496
    { "Zacute", 377 },
 
497
    { "Zcaron", 381 },
 
498
    { "Zdot", 379 },
 
499
    { "aogon", 261 },
 
500
    { "ogon", 731 },
 
501
    { "lstrok", 322 },
 
502
    { "lcaron", 318 },
 
503
    { "sacute", 347 },
 
504
    { "caron", 711 },
 
505
    { "scedil", 351 },
 
506
    { "tcaron", 357 },
 
507
    { "zacute", 378 },
 
508
    { "dblac", 733 },
 
509
    { "zcaron", 382 },
 
510
    { "zdot", 380 },
 
511
    { "Racute", 340 },
 
512
    { "Abreve", 258 },
 
513
    { "Lacute", 313 },
 
514
    { "Cacute", 262 },
 
515
    { "Ccaron", 268 },
 
516
    { "Eogon", 280 },
 
517
    { "Ecaron", 282 },
 
518
    { "Dcaron", 270 },
 
519
    { "Dstrok", 272 },
 
520
    { "Nacute", 323 },
 
521
    { "Ncaron", 327 },
 
522
    { "Odblac", 336 },
 
523
    { "Rcaron", 344 },
 
524
    { "Uring", 366 },
 
525
    { "Udblac", 368 },
 
526
    { "Tcedil", 354 },
 
527
    { "racute", 341 },
 
528
    { "abreve", 259 },
 
529
    { "lacute", 314 },
 
530
    { "cacute", 263 },
 
531
    { "ccaron", 269 },
 
532
    { "eogon", 281 },
 
533
    { "ecaron", 283 },
 
534
    { "dcaron", 271 },
 
535
    { "dstrok", 273 },
 
536
    { "nacute", 324 },
 
537
    { "ncaron", 328 },
 
538
    { "odblac", 337 },
 
539
    { "rcaron", 345 },
 
540
    { "uring", 367 },
 
541
    { "udblac", 369 },
 
542
    { "tcedil", 355 },
 
543
    { "dot", 729 },
 
544
    { 0, 0 }
 
545
};
 
546
 
 
547
 
 
548
/*
 
549
 *   Entity mapping list entry.  We store each entity mapping we find in
 
550
 *   the file in one of these structures, and link the structures together
 
551
 *   into a list. 
 
552
 */
 
553
struct entity_map_t
 
554
{
 
555
    /* 
 
556
     *   Flag: this mapping is a display expansion only (not a round-trip
 
557
     *   mapping).  If this is set, then we contain a display expansion;
 
558
     *   otherwise, we contain a round-trip mapping.  
 
559
     */
 
560
    int disp_only;
 
561
 
 
562
    /* length in bytes of the local mapping for this character */
 
563
    size_t local_len;
 
564
 
 
565
    union
 
566
    {
 
567
        /* if disp_only is false, this gives the local character value */
 
568
        unsigned short local_char;
 
569
 
 
570
        /* if disp_only is true, this gives the display mapping */
 
571
        struct
 
572
        {
 
573
            /* length of the display expansion */
 
574
            size_t exp_len;
 
575
 
 
576
            /* display expansion, in unicode characters */
 
577
            unsigned short expansion[1];
 
578
        } disp;
 
579
    } mapping;
 
580
};
 
581
 
 
582
/*
 
583
 *   Mapping pages.  Each page maps 256 unicode characters; the page is
 
584
 *   selected by the high 8 bits of the unicode code point.  We don't
 
585
 *   allocate a page until we set a character on the page for the first
 
586
 *   time.
 
587
 *   
 
588
 *   Each page contains 256 slots for entity_map_t pointers, so each page
 
589
 *   is an array of (entity_map_t *) elements.  
 
590
 */
 
591
static entity_map_t **G_mapping[256];
 
592
 
 
593
/*
 
594
 *   Construct a unicode character given a page number and index on the
 
595
 *   page 
 
596
 */
 
597
static inline unsigned int make_unicode(int pagenum, int idx)
 
598
{
 
599
    return ((unsigned int)pagenum * 256) + (unsigned int)idx;
 
600
}
 
601
 
 
602
/*
 
603
 *   Get the mapping for a particular unicode character value 
 
604
 */
 
605
static entity_map_t *get_mapping(unsigned int unicode_char)
 
606
{
 
607
    unsigned int pagenum;
 
608
 
 
609
    /* get the page */
 
610
    pagenum = ((unicode_char >> 8) & 0xff);
 
611
 
 
612
    /* if there's no page allocated here, there's no mapping */
 
613
    if (G_mapping[pagenum] == 0)
 
614
        return 0;
 
615
 
 
616
    /* return the entry at the correct location in this page */
 
617
    return G_mapping[pagenum][unicode_char & 0xff];
 
618
}
 
619
 
 
620
/*
 
621
 *   Set the mapping at a given unicode code point.  If there is no page
 
622
 *   allocated at the appropriate slot yet, we'll allocate a page here.
 
623
 */
 
624
static void set_mapping(unsigned int unicode_char, entity_map_t *mapping)
 
625
{
 
626
    unsigned int pagenum;
 
627
 
 
628
    /* get the page number - it's the high 8 bits of the unicode value */
 
629
    pagenum = ((unicode_char >> 8) & 0xff);
 
630
 
 
631
    /* if the page is not allocated, allocate it now */
 
632
    if (G_mapping[pagenum] == 0)
 
633
    {
 
634
        /* allocate the page and clear it out */
 
635
        G_mapping[pagenum] =
 
636
            (entity_map_t **)t3malloc(256 * sizeof(entity_map_t *));
 
637
        memset(G_mapping[pagenum], 0, 256 * sizeof(entity_map_t *));
 
638
    }
 
639
 
 
640
    /* set the mapping */
 
641
    G_mapping[pagenum][unicode_char & 0xff] = mapping;
 
642
}
 
643
 
 
644
 
 
645
/*
 
646
 *   Read a translation string.  This reads a unicode-to-unicode translation
 
647
 *   that gives the expansion of a unicode character to a string of unicode
 
648
 *   characters for display.  The characters of the expansion can be
 
649
 *   specified with ASCII character enclosed in single quotes, or as a series
 
650
 *   of numbers giving Unicode code points.  
 
651
 */
 
652
static entity_map_t *read_translation(char *p, char *infile, int linenum)
 
653
{
 
654
    unsigned short buf[256];
 
655
    unsigned short *dstp;
 
656
    entity_map_t *mapp;
 
657
 
 
658
    /* skip any intervening whitespace */
 
659
    for ( ; isspace(*p) ; ++p) ;
 
660
 
 
661
    /* read the series of numbers or characters */
 
662
    for (dstp = buf ; *p != '\0' ; )
 
663
    {
 
664
        unsigned short intval;
 
665
 
 
666
        /* skip any leading whitespace */
 
667
        while (isspace(*p))
 
668
            ++p;
 
669
 
 
670
        /* if it's the end of the line or a comment, stop */
 
671
        if (*p == '\0' || *p == '#')
 
672
            break;
 
673
 
 
674
        /* if it's a string, read it */
 
675
        if (*p == '\'')
 
676
        {
 
677
            /* scan until the closing quote */
 
678
            for (++p ; *p != '\'' && *p != '\0' ; ++p)
 
679
            {
 
680
                /* if it's an escape, skip it and read the next char */
 
681
                if (*p == '\\')
 
682
                    ++p;
 
683
 
 
684
                /* if we don't have room, abort */
 
685
                if (dstp >= buf + sizeof(buf))
 
686
                {
 
687
                    printf("%s: line %d: entity mapping is too long "
 
688
                           "(maximum of %d characters are allowed\n",
 
689
                           infile, linenum, sizeof(buf));
 
690
                    return 0;
 
691
                }
 
692
 
 
693
                /* 
 
694
                 *   store this character - since it's given as an ASCII
 
695
                 *   character, it has the same representation in Unicode as
 
696
                 *   it does in ASCII 
 
697
                 */
 
698
                *dstp++ = *p;
 
699
            }
 
700
 
 
701
            /* if we didn't find a closing quote, it's an error */
 
702
            if (*p != '\'')
 
703
            {
 
704
                printf("%s: line %d: no closing quote found in string\n",
 
705
                       infile, linenum);
 
706
                return 0;
 
707
            }
 
708
 
 
709
            /* skip the closing quote */
 
710
            ++p;
 
711
        }
 
712
        else
 
713
        {
 
714
            /* scan the character code */
 
715
            if (read_number(&intval, &p, infile, linenum, FALSE))
 
716
                return 0;
 
717
 
 
718
            /* make sure we haven't overflowed our buffer */
 
719
            if (dstp + 1 > buf + sizeof(buf))
 
720
            {
 
721
                printf("%s: line %d: entity mapping is too long "
 
722
                       "(maximum of %d characters are allowed\n",
 
723
                       infile, linenum, sizeof(buf)/sizeof(buf[0]));
 
724
                return 0;
 
725
            }
 
726
 
 
727
            /* add it to the output list */
 
728
            *dstp++ = intval;
 
729
        }
 
730
    }
 
731
 
 
732
    /* if we didn't get any characters, it's an error */
 
733
    if (dstp == buf)
 
734
    {
 
735
        printf("%s: line %d: no local character codes found after '='\n",
 
736
               infile, linenum);
 
737
        return 0;
 
738
    }
 
739
 
 
740
    /* create a new mapping structure and set it up */
 
741
    mapp = (entity_map_t *)t3malloc(sizeof(entity_map_t)
 
742
                                    + (dstp - buf)*sizeof(buf[0]));
 
743
    mapp->mapping.disp.exp_len = dstp - buf;
 
744
    memcpy(mapp->mapping.disp.expansion, buf, (dstp - buf)*sizeof(buf[0]));
 
745
 
 
746
    /* return the mapping */
 
747
    return mapp;
 
748
}
 
749
 
 
750
/*
 
751
 *   Parse an entity name mapping 
 
752
 */
 
753
static entity_map_t *parse_entity(char *p, char *infile, int linenum,
 
754
                                  unsigned short *unicode_char)
 
755
{
 
756
    const char *start;
 
757
    const struct entity_t *entp;
 
758
    
 
759
    /* find the end of the entity name */
 
760
    start = p;
 
761
    for ( ; isalpha(*p) || isdigit(*p) ; ++p) ;
 
762
 
 
763
    /* scan the list for the entity name */
 
764
    for (entp = entities ; entp->ename != 0 ; ++entp)
 
765
    {
 
766
        /* see if this one is a match - note that case is significant */
 
767
        if (strlen(entp->ename) == (size_t)(p - start)
 
768
            && memcmp(entp->ename, start, p - start) == 0)
 
769
            break;
 
770
    }
 
771
 
 
772
    /* if we didn't find it, it's an error */
 
773
    if (entp->ename == 0)
 
774
    {
 
775
        printf("%s: line %d: unknown entity name \"%.*s\"\n",
 
776
               infile, linenum, p - start, start);
 
777
        return 0;
 
778
    }
 
779
 
 
780
    /* tell the caller what the unicode character is */
 
781
    *unicode_char = entp->charval;
 
782
 
 
783
    /* read and return the translation */
 
784
    return read_translation(p, infile, linenum);
 
785
}
 
786
 
 
787
/*
 
788
 *   Store a local character mapping in a buffer, using the variable-length
 
789
 *   notation.  If the character value is in the range 0-255, we'll store one
 
790
 *   byte; otherwise, we'll store two bytes, high-order 8 bits first.
 
791
 *   Returns the number of bytes stored.
 
792
 *   
 
793
 *   If the output buffer is null, we'll simply return the storage length
 
794
 *   without actually storing anything.  
 
795
 */
 
796
size_t local_to_buf(unsigned char *dst, unsigned short c)
 
797
{
 
798
    /* if it's in the 0-255 range, it takes one byte, otherwise two */
 
799
    if (c <= 255)
 
800
    {
 
801
        /* store it as a single byte */
 
802
        if (dst != 0)
 
803
            dst[0] = (unsigned char)c;
 
804
 
 
805
        /* we stored one byte */
 
806
        return 1;
 
807
    }
 
808
    else
 
809
    {
 
810
        /* store it as two bytes, high-order byte first */
 
811
        if (dst != 0)
 
812
        {
 
813
            dst[0] = (unsigned char)(c >> 8);
 
814
            dst[1] = (unsigned char)(c & 0xFF);
 
815
        }
 
816
 
 
817
        /* we stored two bytes */
 
818
        return 2;
 
819
    }
 
820
}
 
821
 
 
822
 
 
823
/*
 
824
 *   Main entrypoint 
 
825
 */
 
826
int main(int argc, char **argv)
 
827
{
 
828
    int curarg;
 
829
    osfildef *fp;
 
830
    char *infile;
 
831
    char *outfile;
 
832
    int linenum;
 
833
    int display_mappings;
 
834
    entity_map_t *entp;
 
835
    int roundtrip_count;
 
836
    int disp_count;
 
837
    unsigned long ofs;
 
838
    uchar valbuf[50];
 
839
    ulong disp_bytes;
 
840
    int pagenum;
 
841
    int i;
 
842
    size_t len;
 
843
    unsigned short default_char;
 
844
    int default_char_set;
 
845
    int fatal_err;
 
846
    size_t disp_exp_cnt;
 
847
    ulong disp_exp_len;
 
848
 
 
849
    /* no fatal errors yet */
 
850
    fatal_err = FALSE;
 
851
 
 
852
    /* no mappings yet */
 
853
    roundtrip_count = 0;
 
854
    default_char_set = 0;
 
855
    disp_exp_cnt = 0;
 
856
    disp_exp_len = 0;
 
857
 
 
858
    /* start out in the round-trip unicode<->local section */
 
859
    display_mappings = FALSE;
 
860
 
 
861
#if 1
 
862
    /* 
 
863
     *   there currently are no options, so there's no option scanning
 
864
     *   needed; just start at the first argument 
 
865
     */
 
866
    curarg = 1;
 
867
    
 
868
#else
 
869
    /* scan options */
 
870
    for (curarg = 1 ; curarg < argc && argv[curarg][0] == '-' ; ++curarg)
 
871
    {
 
872
        /* else */
 
873
        {
 
874
            /* consume all remaining options so we get a usage message */
 
875
            curarg = argc;
 
876
            break;
 
877
        }
 
878
    }
 
879
#endif
 
880
 
 
881
    /* check for required arguments */
 
882
    if (curarg + 1 >= argc)
 
883
    {
 
884
        printf("usage: mkchrtab [options] <source> <dest>\n"
 
885
               "  <source> is the input file\n"
 
886
               "  <dest> is the output file\n"
 
887
              );
 
888
        return 1;
 
889
    }
 
890
 
 
891
    /* get the input and output filenames */
 
892
    infile = argv[curarg];
 
893
    outfile = argv[curarg + 1];
 
894
 
 
895
    /* open the input file */
 
896
    fp = osfoprs(infile, OSFTTEXT);
 
897
    if (fp == 0)
 
898
    {
 
899
        printf("error: unable to open input file \"%s\"\n", infile);
 
900
        return 2;
 
901
    }
 
902
 
 
903
    /* parse the input file */
 
904
    for (linenum = 1 ; ; ++linenum)
 
905
    {
 
906
        char buf[256];
 
907
        char *p;
 
908
        unsigned short unicode_char;
 
909
        entity_map_t *mapp;
 
910
 
 
911
        /* read the next line */
 
912
        if (osfgets(buf, sizeof(buf), fp) == 0)
 
913
            break;
 
914
 
 
915
        /* scan off leading spaces */
 
916
        for (p = buf ; *p != '\0' && (isspace(*p) || iscntrl(*p)) ; ++p) ;
 
917
 
 
918
        /* if this line is blank, or starts with a '#', ignore it */
 
919
        if (*p == '\0' || *p == '\n' || *p == '\r' || *p == '#')
 
920
            continue;
 
921
 
 
922
        /* check for directives */
 
923
        len = strlen(p);
 
924
        if (len >= 16
 
925
            && memicmp(p, "display_mappings", 16) == 0
 
926
            && (!isalpha(p[16]) && !isdigit(p[16])))
 
927
        {
 
928
            /* note that we're in display mapping mode */
 
929
            display_mappings = TRUE;
 
930
 
 
931
            /* no need to look any further at this line */
 
932
            continue;
 
933
        }
 
934
        else if (len > 15
 
935
                 && memicmp(p, "default_display", 15) == 0
 
936
                 && isspace(p[15]))
 
937
        {
 
938
            char *nump;
 
939
 
 
940
            /* read the local character value for the default mapping */
 
941
            nump = p + 16;
 
942
            if (!read_number(&default_char, &nump, infile, linenum, FALSE))
 
943
            {
 
944
                /* if we already have a default character, warn about it */
 
945
                if (default_char_set)
 
946
                    printf("%s: line %d: duplicate default_display\n",
 
947
                           infile, linenum);
 
948
 
 
949
                /* note that we have the default character value */
 
950
                default_char_set = TRUE;
 
951
            }
 
952
 
 
953
            /* no need to look any further at this line */
 
954
            continue;
 
955
        }
 
956
 
 
957
        /* check our mode */
 
958
        if (display_mappings)
 
959
        {
 
960
            /* 
 
961
             *   We're doing display mappings: each mapping specifies a
 
962
             *   sequence of one or more unicode characters to substitute for
 
963
             *   a single unicode character on display.  These translations
 
964
             *   can use SGML entity names for the unicode characters.  
 
965
             */
 
966
 
 
967
            /* check for an entity name */
 
968
            if (*p == '&')
 
969
            {
 
970
                /* skip the '&' */
 
971
                ++p;
 
972
                
 
973
                /* parse the entity */
 
974
                mapp = parse_entity(p, infile, linenum, &unicode_char);
 
975
            }
 
976
            else
 
977
            {
 
978
                /* read the Unicode character number */
 
979
                if (read_number(&unicode_char, &p, infile, linenum, FALSE))
 
980
                    continue;
 
981
                
 
982
                /* read the translation */
 
983
                mapp = read_translation(p, infile, linenum);
 
984
            }
 
985
 
 
986
            /*
 
987
             *   If the entry is already set, flag an error and delete the
 
988
             *   entry - if it's set as a round-trip entry, we don't want to
 
989
             *   set it in the display-only section 
 
990
             */
 
991
            if (get_mapping(unicode_char) != 0)
 
992
            {
 
993
                /* flag the error */
 
994
                printf("%s: line %d: mapping previously defined - "
 
995
                       "new mapping ignored\n", infile, linenum);
 
996
                
 
997
                /* delete the mapping and forget it */
 
998
                t3free(mapp);
 
999
                mapp = 0;
 
1000
            }
 
1001
 
 
1002
            /* if we created a mapping, mark it as display-only */
 
1003
            if (mapp != 0)
 
1004
            {
 
1005
                /* mark it as display-only */
 
1006
                mapp->disp_only = TRUE;
 
1007
 
 
1008
                /* 
 
1009
                 *   if this is an expansion into multiple unicode characters
 
1010
                 *   for display, count it among the expansions 
 
1011
                 */
 
1012
                if (mapp->mapping.disp.exp_len > 1)
 
1013
                {
 
1014
                    ++disp_exp_cnt;
 
1015
                    disp_exp_len += mapp->mapping.disp.exp_len;
 
1016
                }
 
1017
            }
 
1018
        }
 
1019
        else
 
1020
        {
 
1021
            unsigned short local_char;
 
1022
            unsigned short extra_char;   
 
1023
 
 
1024
            /*
 
1025
             *   Doing regular translations.  The format must be two
 
1026
             *   columns of numbers; the first number is the local
 
1027
             *   character code, and the second is the unicode character
 
1028
             *   code.
 
1029
             *   
 
1030
             *   Some mapping files contain variations on this format:
 
1031
             *   
 
1032
             *   - Some files use three columns, where the first column is
 
1033
             *   another character set translation (for example, JIS0208
 
1034
             *   uses the first column to give the Shift-JIS code for each
 
1035
             *   character).  In these cases, we'll skip the first column,
 
1036
             *   and use only the last two columns.
 
1037
             *   
 
1038
             *   - Some files for multi-byte (i.e., mixed single- and
 
1039
             *   double-byte characters) have entries for DBCS leading
 
1040
             *   bytes with no Unicode character specified.  In these
 
1041
             *   cases, only one column appears on some lines, with DBCS
 
1042
             *   lead byte value in the local character set, and no
 
1043
             *   Unicode value at all.  We'll simply ignore these lines
 
1044
             *   entirely, since they contribute no information that we
 
1045
             *   need.  
 
1046
             */
 
1047
 
 
1048
            /* 
 
1049
             *   read two numbers - the second one is optional, since
 
1050
             *   we'll skip any single-column entries as explained above 
 
1051
             */
 
1052
            if (read_number(&local_char, &p, infile, linenum, FALSE)
 
1053
                || read_number(&unicode_char, &p, infile, linenum, TRUE))
 
1054
                continue;
 
1055
 
 
1056
            /* 
 
1057
             *   check for a third column - if it's present, drop the
 
1058
             *   first column and keep only the second and third columns 
 
1059
             */
 
1060
            if (!read_number(&extra_char, &p, infile, linenum, TRUE))
 
1061
            {
 
1062
                /* shift everything over one column */
 
1063
                local_char = unicode_char;
 
1064
                unicode_char = extra_char;
 
1065
            }
 
1066
 
 
1067
            /* if the mapping is already in use, don't overwrite it */
 
1068
            if (get_mapping(unicode_char) != 0)
 
1069
            {
 
1070
                /* flag the error */
 
1071
                printf("%s: line %d: mapping previously defined - "
 
1072
                       "new mapping ignored\n", infile, linenum);
 
1073
 
 
1074
                /* skip this mapping */
 
1075
                continue;
 
1076
            }
 
1077
 
 
1078
            /* create a reversible mapping entry */
 
1079
            mapp = (entity_map_t *)t3malloc(sizeof(entity_map_t));
 
1080
            mapp->disp_only = FALSE;
 
1081
            mapp->mapping.local_char = local_char;
 
1082
 
 
1083
            /* count the round-trip mapping */
 
1084
            ++roundtrip_count;
 
1085
        }
 
1086
 
 
1087
        /* add the mapping into our mapping list */
 
1088
        if (mapp != 0)
 
1089
            set_mapping(unicode_char, mapp);
 
1090
    }
 
1091
 
 
1092
    /* we're done with the input file */
 
1093
    osfcls(fp);
 
1094
 
 
1095
    /* open the output file */
 
1096
    fp = osfopwb(outfile, OSFTCMAP);
 
1097
    if (fp == 0)
 
1098
    {
 
1099
        printf("error: unable to open output file \"%s\"\n", outfile);
 
1100
        return 2;
 
1101
    }
 
1102
 
 
1103
    /*
 
1104
     *   Calculate where the unicode-to-local display mapping appears.  This
 
1105
     *   mapping immediately follows the local-to-unicode round-trip mapping;
 
1106
     *   each entry in the round-trip mapping is of a fixed size, so we can
 
1107
     *   easily figure out how much space it will take up.
 
1108
     *   
 
1109
     *   Each round-trip record takes up 4 bytes (two UINT2's)
 
1110
     *.  A UINT4 is needed for this header itself.
 
1111
     *   
 
1112
     *.  The round-trip section contains at least one UINT2 (for its
 
1113
     *   own count header) 
 
1114
     */
 
1115
    ofs = (roundtrip_count * 4) + 4 + 2;
 
1116
    oswp4(valbuf, ofs);
 
1117
 
 
1118
    /* add in the count of round-trip records */
 
1119
    oswp2(valbuf + 4, roundtrip_count);
 
1120
 
 
1121
    /* write out the header */
 
1122
    if (osfwb(fp, valbuf, 6))
 
1123
    {
 
1124
        printf("error writing header\n");
 
1125
        fatal_err = TRUE;
 
1126
        goto done;
 
1127
    }
 
1128
 
 
1129
    /* 
 
1130
     *   Write the round-trip mappings.  Scan the entire set of pages, and
 
1131
     *   write out each entry not marked as "display-only".  
 
1132
     */
 
1133
    for (pagenum = 0 ; pagenum < 256 ; ++pagenum)
 
1134
    {
 
1135
        /* if there's no page here, skip it */
 
1136
        if (G_mapping[pagenum] == 0)
 
1137
            continue;
 
1138
 
 
1139
        /* go through the mappings in this page */
 
1140
        for (i = 0 ; i < 256 ; ++i)
 
1141
        {
 
1142
            /* get the mapping */
 
1143
            entp = G_mapping[pagenum][i];
 
1144
 
 
1145
            /* 
 
1146
             *   if we have no mapping, or this is a display-only mapping,
 
1147
             *   skip it - we're only interested in round-trip mappings here 
 
1148
             */
 
1149
            if (entp == 0 || entp->disp_only)
 
1150
                continue;
 
1151
 
 
1152
            /* 
 
1153
             *   the entry has a UINT2 for the unicode value, followed by a
 
1154
             *   UINT2 for the local character code point 
 
1155
             */
 
1156
            oswp2(valbuf, make_unicode(pagenum, i));
 
1157
            oswp2(valbuf + 2, entp->mapping.local_char);
 
1158
 
 
1159
            /* write it out */
 
1160
            if (osfwb(fp, valbuf, 4))
 
1161
            {
 
1162
                printf("error writing mapping to file\n");
 
1163
                fatal_err = TRUE;
 
1164
                goto done;
 
1165
            }
 
1166
        }
 
1167
    }
 
1168
    
 
1169
    /*
 
1170
     *   Compile information on the display mappings.  We must determine the
 
1171
     *   number of display mappings we have, and the number of bytes we'll
 
1172
     *   need for the display mappings in the output file.
 
1173
     *   
 
1174
     *   Every entry is a display mapping, since a round-trip mapping
 
1175
     *   provides a unicode-to-local mapping.
 
1176
     *   
 
1177
     *   For a round-trip mapping, we simply store the one-byte or two-byte
 
1178
     *   local character sequence given by the local mapping.
 
1179
     *   
 
1180
     *   For a display-only mapping, we must scan the expansion, which is a
 
1181
     *   list of unicode characters.  For each unicode character in the
 
1182
     *   expansion, we must find the round-trip mapping for that unicode
 
1183
     *   character to get its local mapping, and then count the one-byte or
 
1184
     *   two-byte local character sequence for that round-trip mapping.
 
1185
     *   
 
1186
     *   Note that each entry stores a one-byte length prefix, so we must
 
1187
     *   count one additional byte per entry for this prefix.  
 
1188
     */
 
1189
    for (disp_count = 0, disp_bytes = 0, pagenum = 0 ;
 
1190
         pagenum < 256 ; ++pagenum)
 
1191
    {
 
1192
        /* if there's no page here, skip it */
 
1193
        if (G_mapping[pagenum] == 0)
 
1194
            continue;
 
1195
 
 
1196
        /* go through the mappings in this page */
 
1197
        for (i = 0 ; i < 256 ; ++i)
 
1198
        {
 
1199
            size_t local_len;
 
1200
            
 
1201
            /* get the mapping */
 
1202
            entp = G_mapping[pagenum][i];
 
1203
 
 
1204
            /* if we don't have a mapping here, skip this unicode point */
 
1205
            if (entp == 0)
 
1206
                continue;
 
1207
 
 
1208
            /* count the entry */
 
1209
            ++disp_count;
 
1210
 
 
1211
            /* count the length-prefix byte, which all entries have */
 
1212
            ++disp_bytes;
 
1213
 
 
1214
            /* we don't have any bytes in the local length yet */
 
1215
            local_len = 0;
 
1216
 
 
1217
            /* check the mapping type */
 
1218
            if (entp->disp_only)
 
1219
            {
 
1220
                size_t idx;
 
1221
                unsigned short *expp;
 
1222
                
 
1223
                /*
 
1224
                 *   This is a display-only mapping, so we have a list of
 
1225
                 *   unicode characters that we substitute for this unicode
 
1226
                 *   character, then translate to the local character set
 
1227
                 *   for display.  Scan the expansion list and include the
 
1228
                 *   bytes for each character in the expansion list. 
 
1229
                 */
 
1230
                for (idx = 0, expp = entp->mapping.disp.expansion ;
 
1231
                     idx < entp->mapping.disp.exp_len ;
 
1232
                     ++idx, ++expp)
 
1233
                {
 
1234
                    unsigned short uc;
 
1235
                    entity_map_t *entp_uc;
 
1236
                    
 
1237
                    /* get this unicode expansion character */
 
1238
                    uc = *expp;
 
1239
 
 
1240
                    /* look up the mapping for this expansion character */
 
1241
                    entp_uc = get_mapping(uc);
 
1242
 
 
1243
                    /* 
 
1244
                     *   if we don't have a mapping, or it's not a
 
1245
                     *   round-trip mapping, complain; otherwise, count the
 
1246
                     *   local character expansion in our output length 
 
1247
                     */
 
1248
                    if (entp_uc == 0)
 
1249
                    {
 
1250
                        /* the unicode character is unmapped */
 
1251
                        printf("display mapping for unicode character 0x%X "
 
1252
                               "refers to unmapped unicode character 0x%X "
 
1253
                               "in its expansion\n",
 
1254
                               (unsigned)make_unicode(pagenum, i),
 
1255
                               (unsigned)uc);
 
1256
 
 
1257
                        /* note the error */
 
1258
                        fatal_err = TRUE;
 
1259
 
 
1260
                        /* don't scan any further in this expansion */
 
1261
                        break;
 
1262
                    }
 
1263
                    else if (entp_uc->disp_only)
 
1264
                    {
 
1265
                        /* 
 
1266
                         *   the unicode character itself has a display
 
1267
                         *   mapping - recursive display mappings are not
 
1268
                         *   allowed 
 
1269
                         */
 
1270
                        printf("display mapping for unicode character 0x%X "
 
1271
                               "refers to unicode character 0x%X, which "
 
1272
                               "itself has a display mapping - a display "
 
1273
                               "mappings must refer only to round-trip "
 
1274
                               "characters in its expansion\n",
 
1275
                               (unsigned)make_unicode(pagenum, i),
 
1276
                               (unsigned)uc);
 
1277
 
 
1278
                        /* note the error */
 
1279
                        fatal_err = TRUE;
 
1280
 
 
1281
                        /* don't scan any further in this expansion */
 
1282
                        break;
 
1283
                    }
 
1284
                    else
 
1285
                    {
 
1286
                        /* add this local mapping to the total length */
 
1287
                        local_len +=
 
1288
                            local_to_buf(0, entp_uc->mapping.local_char);
 
1289
                    }
 
1290
                }
 
1291
            }
 
1292
            else
 
1293
            {
 
1294
                /* 
 
1295
                 *   this is a round-trip mapping, so we simply store the
 
1296
                 *   one or two bytes given for the local character in the
 
1297
                 *   mapping 
 
1298
                 */
 
1299
                local_len = local_to_buf(0, entp->mapping.local_char);
 
1300
            }
 
1301
 
 
1302
            /* 
 
1303
             *   add local length of this mapping to the total display bytes
 
1304
             *   we've computed so far 
 
1305
             */
 
1306
            disp_bytes += local_len;
 
1307
 
 
1308
            /* 
 
1309
             *   store the local length of this mapping for easy reference
 
1310
             *   when we write out the mapping 
 
1311
             */
 
1312
            entp->local_len = local_len;
 
1313
        }
 
1314
    }
 
1315
 
 
1316
    /* if we have a default character, add it to the display mapping count */
 
1317
    if (default_char_set)
 
1318
    {
 
1319
        /* count an additional display mapping */
 
1320
        ++disp_count;
 
1321
 
 
1322
        /* add the expansion bytes, including the length prefix */
 
1323
        disp_bytes += 1 + local_to_buf(0, default_char);
 
1324
    }
 
1325
 
 
1326
    /* if we found errors compiling the display mappings, abort */
 
1327
    if (fatal_err)
 
1328
        goto done;
 
1329
 
 
1330
    /* 
 
1331
     *   Write out the number of display mappings, and the number of bytes
 
1332
     *   of display mappings.  
 
1333
     */
 
1334
    oswp2(valbuf, disp_count);
 
1335
    oswp4(valbuf + 2, disp_bytes);
 
1336
    if (osfwb(fp, valbuf, 6))
 
1337
    {
 
1338
        printf("error writing display translation header\n");
 
1339
        fatal_err = TRUE;
 
1340
        goto done;
 
1341
    }
 
1342
 
 
1343
    /* check for a default display mapping */
 
1344
    if (default_char_set)
 
1345
    {
 
1346
        size_t len;
 
1347
        
 
1348
        /* 
 
1349
         *   Write out the default display entity.  We store this mapping at
 
1350
         *   the translation for Unicode code point zero. 
 
1351
         */
 
1352
        oswp2(valbuf, 0);
 
1353
        len = local_to_buf(valbuf + 3, default_char);
 
1354
        valbuf[2] = (uchar)len;
 
1355
 
 
1356
        /* write it out */
 
1357
        if (osfwb(fp, valbuf, 3 + len))
 
1358
        {
 
1359
            printf("error writing default_display mapping to output file\n");
 
1360
            fatal_err = TRUE;
 
1361
            goto done;
 
1362
        }
 
1363
    }
 
1364
    else
 
1365
    {
 
1366
        printf("error: no 'default_display' mapping specified\n");
 
1367
        fatal_err = TRUE;
 
1368
        goto done;
 
1369
    }
 
1370
 
 
1371
    /* 
 
1372
     *   write all of the mappings - both the display and round-trip
 
1373
     *   mappings provide unicode-to-local mappings 
 
1374
     */
 
1375
 
 
1376
    /* go through all of the pages */
 
1377
    for (pagenum = 0 ; pagenum < 256 ; ++pagenum)
 
1378
    {
 
1379
        /* if this page isn't present, skip it */
 
1380
        if (G_mapping[pagenum] == 0)
 
1381
            continue;
 
1382
        
 
1383
        /* go through the page */
 
1384
        for (i = 0 ; i < 256 ; ++i)
 
1385
        {
 
1386
            size_t len;
 
1387
 
 
1388
            /* get the mapping */
 
1389
            entp = G_mapping[pagenum][i];
 
1390
 
 
1391
            /* if the mapping doesn't exist, skip it */
 
1392
            if (entp == 0)
 
1393
                continue;
 
1394
                
 
1395
            /* write out this entity's unicode value and local length */
 
1396
            oswp2(valbuf, make_unicode(pagenum, i));
 
1397
            valbuf[2] = (uchar)entp->local_len;
 
1398
            if (osfwb(fp, valbuf, 3))
 
1399
            {
 
1400
                printf("error writing display mapping to output file\n");
 
1401
                break;
 
1402
            }
 
1403
 
 
1404
            /* check the mapping type */
 
1405
            if (entp->disp_only)
 
1406
            {
 
1407
                size_t idx;
 
1408
                unsigned short *expp;
 
1409
                
 
1410
                /* 
 
1411
                 *   display-only mapping - translate the local expansion
 
1412
                 *   into unicode character 
 
1413
                 */
 
1414
                for (idx = 0, expp = entp->mapping.disp.expansion ;
 
1415
                     idx < entp->mapping.disp.exp_len ;
 
1416
                     ++idx, ++expp)
 
1417
                {
 
1418
                    unsigned short uc;
 
1419
                    entity_map_t *entp_uc;
 
1420
                    
 
1421
                    /* get this unicode expansion character */
 
1422
                    uc = *expp;
 
1423
                    
 
1424
                    /* look up the mapping for this expansion character */
 
1425
                    entp_uc = get_mapping(uc);
 
1426
 
 
1427
                    /* write this character's local mapping */
 
1428
                    len = local_to_buf(valbuf, entp_uc->mapping.local_char);
 
1429
                    if (osfwb(fp, valbuf, len))
 
1430
                    {
 
1431
                        printf("error writing display mapping to file\n");
 
1432
                        fatal_err = TRUE;
 
1433
                        goto done;
 
1434
                    }
 
1435
                }
 
1436
            }
 
1437
            else
 
1438
            {
 
1439
                /* it's a round-trip mapping - store the local mapping */
 
1440
                len = local_to_buf(valbuf, entp->mapping.local_char);
 
1441
                if (osfwb(fp, valbuf, len))
 
1442
                {
 
1443
                    printf("error writing display mapping to file\n");
 
1444
                    fatal_err = TRUE;
 
1445
                    goto done;
 
1446
                }
 
1447
            }
 
1448
        }
 
1449
    }
 
1450
 
 
1451
    /*
 
1452
     *   Write out the display-only expansions.  This is different than the
 
1453
     *   display mappings we just wrote in that this time we're going to
 
1454
     *   write out the *unicode* expansions for any sequences that turn into
 
1455
     *   multiple displayed unicode characters for a single unicode input
 
1456
     *   character.
 
1457
     */
 
1458
    oswp2(valbuf, disp_exp_cnt);
 
1459
    oswp4(valbuf + 2, disp_exp_len);
 
1460
    if (osfwb(fp, valbuf, 6))
 
1461
    {
 
1462
        printf("error writing display expansion to file\n");
 
1463
        fatal_err = TRUE;
 
1464
        goto done;
 
1465
    }
 
1466
 
 
1467
    /* scan the pages and write out the expansions */
 
1468
    for (pagenum = 0 ; pagenum < 256 ; ++pagenum)
 
1469
    {
 
1470
        /* if this page isn't present, skip it */
 
1471
        if (G_mapping[pagenum] == 0)
 
1472
            continue;
 
1473
 
 
1474
        /* go through the page */
 
1475
        for (i = 0 ; i < 256 ; ++i)
 
1476
        {
 
1477
            size_t idx;
 
1478
 
 
1479
            /* get the mapping */
 
1480
            entp = G_mapping[pagenum][i];
 
1481
 
 
1482
            /* 
 
1483
             *   if the mapping doesn't exist, or it's not a display-only
 
1484
             *   mapping, or it doesn't expand to multiple unicode
 
1485
             *   characters, skip it 
 
1486
             */
 
1487
            if (entp == 0
 
1488
                || !entp->disp_only
 
1489
                || entp->mapping.disp.exp_len < 2)
 
1490
                continue;
 
1491
 
 
1492
            /* write the unicode value and the expansion length */
 
1493
            oswp2(valbuf, make_unicode(pagenum, i));
 
1494
            valbuf[2] = (unsigned char)entp->mapping.disp.exp_len;
 
1495
            if (osfwb(fp, valbuf, 3))
 
1496
            {
 
1497
                printf("error writing display expansion to file\n");
 
1498
                fatal_err = TRUE;
 
1499
                goto done;
 
1500
            }
 
1501
 
 
1502
            /* write the expansion characters */
 
1503
            for (idx = 0 ; idx < entp->mapping.disp.exp_len ; ++idx)
 
1504
            {
 
1505
                oswp2(valbuf, entp->mapping.disp.expansion[idx]);
 
1506
                if (osfwb(fp, valbuf, 2))
 
1507
                {
 
1508
                    printf("error writing display expansion to file\n");
 
1509
                    fatal_err = TRUE;
 
1510
                    goto done;
 
1511
                }
 
1512
            }
 
1513
        }
 
1514
    }
 
1515
 
 
1516
    /* write out the end-of-file marker */
 
1517
    if (osfwb(fp, "$EOF", 4))
 
1518
        printf("error writing end-of-file marker\n");
 
1519
 
 
1520
done:
 
1521
    /* delete the entity list */
 
1522
    for (pagenum = 0 ; pagenum < 256 ; ++pagenum)
 
1523
    {
 
1524
        /* if there's no mapping here, ignore it */
 
1525
        if (G_mapping[pagenum] == 0)
 
1526
            continue;
 
1527
 
 
1528
        /* delete each entry on the page */
 
1529
        for (i = 0 ; i < 256 ; ++i)
 
1530
        {
 
1531
            if (G_mapping[pagenum][i] != 0)
 
1532
                t3free(G_mapping[pagenum][i]);
 
1533
        }
 
1534
 
 
1535
        /* delete the page itself */
 
1536
        t3free(G_mapping[pagenum]);
 
1537
    }
 
1538
 
 
1539
    /* done with the output file */
 
1540
    osfcls(fp);
 
1541
 
 
1542
    /* if we had a fatal error, delete the file */
 
1543
    if (fatal_err)
 
1544
        osfdel(outfile);
 
1545
 
 
1546
    /* success */
 
1547
    return 0;
 
1548
}
 
1549