]> git.sur5r.net Git - openldap/blob - libraries/liblunicode/ucdata/ucgendat.c
199af435f57a9d25489b155fd02d0dbb40ea67c2
[openldap] / libraries / liblunicode / ucdata / ucgendat.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2004 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15 /* Copyright 2001 Computing Research Labs, New Mexico State University
16  *
17  * Permission is hereby granted, free of charge, to any person obtaining a
18  * copy of this software and associated documentation files (the "Software"),
19  * to deal in the Software without restriction, including without limitation
20  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
21  * and/or sell copies of the Software, and to permit persons to whom the
22  * Software is furnished to do so, subject to the following conditions:
23  *
24  * The above copyright notice and this permission notice shall be included in
25  * all copies or substantial portions of the Software.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
30  * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
31  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
32  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
33  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34  */
35 /* $Id: ucgendat.c,v 1.4 2001/01/02 18:46:20 mleisher Exp $" */
36
37 #include "portable.h"
38 #include "ldap_config.h"
39
40 #include <stdio.h>
41 #include <ac/stdlib.h>
42 #include <ac/string.h>
43 #include <ac/unistd.h>
44
45 #include <ac/bytes.h>
46
47 #include <lutil.h>
48
49 #undef ishdigit
50 #define ishdigit(cc) (((cc) >= '0' && (cc) <= '9') ||\
51                       ((cc) >= 'A' && (cc) <= 'F') ||\
52                       ((cc) >= 'a' && (cc) <= 'f'))
53
54 /*
55  * A header written to the output file with the byte-order-mark and the number
56  * of property nodes.
57  */
58 static ac_uint2 hdr[2] = {0xfeff, 0};
59
60 #define NUMPROPS 50
61 #define NEEDPROPS (NUMPROPS + (4 - (NUMPROPS & 3)))
62
63 typedef struct {
64     char *name;
65     int len;
66 } _prop_t;
67
68 /*
69  * List of properties expected to be found in the Unicode Character Database
70  * including some implementation specific properties.
71  *
72  * The implementation specific properties are:
73  * Cm = Composed (can be decomposed)
74  * Nb = Non-breaking
75  * Sy = Symmetric (has left and right forms)
76  * Hd = Hex digit
77  * Qm = Quote marks
78  * Mr = Mirroring
79  * Ss = Space, other
80  * Cp = Defined character
81  */
82 static _prop_t props[NUMPROPS] = {
83     {"Mn", 2}, {"Mc", 2}, {"Me", 2}, {"Nd", 2}, {"Nl", 2}, {"No", 2},
84     {"Zs", 2}, {"Zl", 2}, {"Zp", 2}, {"Cc", 2}, {"Cf", 2}, {"Cs", 2},
85     {"Co", 2}, {"Cn", 2}, {"Lu", 2}, {"Ll", 2}, {"Lt", 2}, {"Lm", 2},
86     {"Lo", 2}, {"Pc", 2}, {"Pd", 2}, {"Ps", 2}, {"Pe", 2}, {"Po", 2},
87     {"Sm", 2}, {"Sc", 2}, {"Sk", 2}, {"So", 2}, {"L",  1}, {"R",  1},
88     {"EN", 2}, {"ES", 2}, {"ET", 2}, {"AN", 2}, {"CS", 2}, {"B",  1},
89     {"S",  1}, {"WS", 2}, {"ON", 2},
90     {"Cm", 2}, {"Nb", 2}, {"Sy", 2}, {"Hd", 2}, {"Qm", 2}, {"Mr", 2},
91     {"Ss", 2}, {"Cp", 2}, {"Pi", 2}, {"Pf", 2}, {"AL", 2}
92 };
93
94 typedef struct {
95     ac_uint4 *ranges;
96     ac_uint2 used;
97     ac_uint2 size;
98 } _ranges_t;
99
100 static _ranges_t proptbl[NUMPROPS];
101
102 /*
103  * Make sure this array is sized to be on a 4-byte boundary at compile time.
104  */
105 static ac_uint2 propcnt[NEEDPROPS];
106
107 /*
108  * Array used to collect a decomposition before adding it to the decomposition
109  * table.
110  */
111 static ac_uint4 dectmp[64];
112 static ac_uint4 dectmp_size;
113
114 typedef struct {
115     ac_uint4 code;
116     ac_uint2 size;
117     ac_uint2 used;
118     ac_uint4 *decomp;
119 } _decomp_t;
120
121 /*
122  * List of decomposition.  Created and expanded in order as the characters are
123  * encountered. First list contains canonical mappings, second also includes
124  * compatibility mappings.
125  */
126 static _decomp_t *decomps;
127 static ac_uint4 decomps_used;
128 static ac_uint4 decomps_size;
129
130 static _decomp_t *kdecomps;
131 static ac_uint4 kdecomps_used;
132 static ac_uint4 kdecomps_size;
133
134 /*
135  * Composition exclusion table stuff.
136  */
137 #define COMPEX_SET(c) (compexs[(c) >> 5] |= (1 << ((c) & 31)))
138 #define COMPEX_TEST(c) (compexs[(c) >> 5] & (1 << ((c) & 31)))
139 static ac_uint4 compexs[2048];
140
141 /*
142  * Struct for holding a composition pair, and array of composition pairs
143  */
144 typedef struct {
145     ac_uint4 comp;
146     ac_uint4 count;
147     ac_uint4 code1;
148     ac_uint4 code2;
149 } _comp_t;
150
151 static _comp_t *comps;
152 static ac_uint4 comps_used;
153
154 /*
155  * Types and lists for handling lists of case mappings.
156  */
157 typedef struct {
158     ac_uint4 key;
159     ac_uint4 other1;
160     ac_uint4 other2;
161 } _case_t;
162
163 static _case_t *upper;
164 static _case_t *lower;
165 static _case_t *title;
166 static ac_uint4 upper_used;
167 static ac_uint4 upper_size;
168 static ac_uint4 lower_used;
169 static ac_uint4 lower_size;
170 static ac_uint4 title_used;
171 static ac_uint4 title_size;
172
173 /*
174  * Array used to collect case mappings before adding them to a list.
175  */
176 static ac_uint4 cases[3];
177
178 /*
179  * An array to hold ranges for combining classes.
180  */
181 static ac_uint4 *ccl;
182 static ac_uint4 ccl_used;
183 static ac_uint4 ccl_size;
184
185 /*
186  * Structures for handling numbers.
187  */
188 typedef struct {
189     ac_uint4 code;
190     ac_uint4 idx;
191 } _codeidx_t;
192
193 typedef struct {
194     short numerator;
195     short denominator;
196 } _num_t;
197
198 /*
199  * Arrays to hold the mapping of codes to numbers.
200  */
201 static _codeidx_t *ncodes;
202 static ac_uint4 ncodes_used;
203 static ac_uint4 ncodes_size;
204
205 static _num_t *nums;
206 static ac_uint4 nums_used;
207 static ac_uint4 nums_size;
208
209 /*
210  * Array for holding numbers.
211  */
212 static _num_t *nums;
213 static ac_uint4 nums_used;
214 static ac_uint4 nums_size;
215
216 static void
217 add_range(ac_uint4 start, ac_uint4 end, char *p1, char *p2)
218 {
219     int i, j, k, len;
220     _ranges_t *rlp;
221     char *name;
222
223     for (k = 0; k < 2; k++) {
224         if (k == 0) {
225             name = p1;
226             len = 2;
227         } else {
228             if (p2 == 0)
229               break;
230
231             name = p2;
232             len = 1;
233         }
234
235         for (i = 0; i < NUMPROPS; i++) {
236             if (props[i].len == len && memcmp(props[i].name, name, len) == 0)
237               break;
238         }
239
240         if (i == NUMPROPS)
241           continue;
242
243         rlp = &proptbl[i];
244
245         /*
246          * Resize the range list if necessary.
247          */
248         if (rlp->used == rlp->size) {
249             if (rlp->size == 0)
250               rlp->ranges = (ac_uint4 *)
251                   malloc(sizeof(ac_uint4) << 3);
252             else
253               rlp->ranges = (ac_uint4 *)
254                   realloc((char *) rlp->ranges,
255                           sizeof(ac_uint4) * (rlp->size + 8));
256             rlp->size += 8;
257         }
258
259         /*
260          * If this is the first code for this property list, just add it
261          * and return.
262          */
263         if (rlp->used == 0) {
264             rlp->ranges[0] = start;
265             rlp->ranges[1] = end;
266             rlp->used += 2;
267             continue;
268         }
269
270         /*
271          * Optimize the case of adding the range to the end.
272          */
273         j = rlp->used - 1;
274         if (start > rlp->ranges[j]) {
275             j = rlp->used;
276             rlp->ranges[j++] = start;
277             rlp->ranges[j++] = end;
278             rlp->used = j;
279             continue;
280         }
281
282         /*
283          * Need to locate the insertion point.
284          */
285         for (i = 0;
286              i < rlp->used && start > rlp->ranges[i + 1] + 1; i += 2) ;
287
288         /*
289          * If the start value lies in the current range, then simply set the
290          * new end point of the range to the end value passed as a parameter.
291          */
292         if (rlp->ranges[i] <= start && start <= rlp->ranges[i + 1] + 1) {
293             rlp->ranges[i + 1] = end;
294             return;
295         }
296
297         /*
298          * Shift following values up by two.
299          */
300         for (j = rlp->used; j > i; j -= 2) {
301             rlp->ranges[j] = rlp->ranges[j - 2];
302             rlp->ranges[j + 1] = rlp->ranges[j - 1];
303         }
304
305         /*
306          * Add the new range at the insertion point.
307          */
308         rlp->ranges[i] = start;
309         rlp->ranges[i + 1] = end;
310         rlp->used += 2;
311     }
312 }
313
314 static void
315 ordered_range_insert(ac_uint4 c, char *name, int len)
316 {
317     int i, j;
318     ac_uint4 s, e;
319     _ranges_t *rlp;
320
321     if (len == 0)
322       return;
323
324     /*
325      * Deal with directionality codes introduced in Unicode 3.0.
326      */
327     if ((len == 2 && memcmp(name, "BN", 2) == 0) ||
328         (len == 3 &&
329          (memcmp(name, "NSM", 3) == 0 || memcmp(name, "PDF", 3) == 0 ||
330           memcmp(name, "LRE", 3) == 0 || memcmp(name, "LRO", 3) == 0 ||
331           memcmp(name, "RLE", 3) == 0 || memcmp(name, "RLO", 3) == 0))) {
332         /*
333          * Mark all of these as Other Neutral to preserve compatibility with
334          * older versions.
335          */
336         len = 2;
337         name = "ON";
338     }
339
340     for (i = 0; i < NUMPROPS; i++) {
341         if (props[i].len == len && memcmp(props[i].name, name, len) == 0)
342           break;
343     }
344
345     if (i == NUMPROPS)
346       return;
347
348     /*
349      * Have a match, so insert the code in order.
350      */
351     rlp = &proptbl[i];
352
353     /*
354      * Resize the range list if necessary.
355      */
356     if (rlp->used == rlp->size) {
357         if (rlp->size == 0)
358           rlp->ranges = (ac_uint4 *)
359               malloc(sizeof(ac_uint4) << 3);
360         else
361           rlp->ranges = (ac_uint4 *)
362               realloc((char *) rlp->ranges,
363                       sizeof(ac_uint4) * (rlp->size + 8));
364         rlp->size += 8;
365     }
366
367     /*
368      * If this is the first code for this property list, just add it
369      * and return.
370      */
371     if (rlp->used == 0) {
372         rlp->ranges[0] = rlp->ranges[1] = c;
373         rlp->used += 2;
374         return;
375     }
376
377     /*
378      * Optimize the cases of extending the last range and adding new ranges to
379      * the end.
380      */
381     j = rlp->used - 1;
382     e = rlp->ranges[j];
383     s = rlp->ranges[j - 1];
384
385     if (c == e + 1) {
386         /*
387          * Extend the last range.
388          */
389         rlp->ranges[j] = c;
390         return;
391     }
392
393     if (c > e + 1) {
394         /*
395          * Start another range on the end.
396          */
397         j = rlp->used;
398         rlp->ranges[j] = rlp->ranges[j + 1] = c;
399         rlp->used += 2;
400         return;
401     }
402
403     if (c >= s)
404       /*
405        * The code is a duplicate of a code in the last range, so just return.
406        */
407       return;
408
409     /*
410      * The code should be inserted somewhere before the last range in the
411      * list.  Locate the insertion point.
412      */
413     for (i = 0;
414          i < rlp->used && c > rlp->ranges[i + 1] + 1; i += 2) ;
415
416     s = rlp->ranges[i];
417     e = rlp->ranges[i + 1];
418
419     if (c == e + 1)
420       /*
421        * Simply extend the current range.
422        */
423       rlp->ranges[i + 1] = c;
424     else if (c < s) {
425         /*
426          * Add a new entry before the current location.  Shift all entries
427          * before the current one up by one to make room.
428          */
429         for (j = rlp->used; j > i; j -= 2) {
430             rlp->ranges[j] = rlp->ranges[j - 2];
431             rlp->ranges[j + 1] = rlp->ranges[j - 1];
432         }
433         rlp->ranges[i] = rlp->ranges[i + 1] = c;
434
435         rlp->used += 2;
436     }
437 }
438
439 static void
440 add_decomp(ac_uint4 code, short compat)
441 {
442     ac_uint4 i, j, size;
443     _decomp_t **pdecomps;
444     ac_uint4 *pdecomps_used;
445     ac_uint4 *pdecomps_size;
446
447     if (compat) {
448         pdecomps = &kdecomps;
449         pdecomps_used = &kdecomps_used;
450         pdecomps_size = &kdecomps_size;
451     } else {
452         pdecomps = &decomps;
453         pdecomps_used = &decomps_used;
454         pdecomps_size = &decomps_size;
455     }
456     
457     /*
458      * Add the code to the composite property.
459      */
460     if (!compat) {
461         ordered_range_insert(code, "Cm", 2);
462     }
463
464     /*
465      * Locate the insertion point for the code.
466      */
467     for (i = 0; i < *pdecomps_used && code > (*pdecomps)[i].code; i++) ;
468
469     /*
470      * Allocate space for a new decomposition.
471      */
472     if (*pdecomps_used == *pdecomps_size) {
473         if (*pdecomps_size == 0)
474           *pdecomps = (_decomp_t *) malloc(sizeof(_decomp_t) << 3);
475         else
476           *pdecomps = (_decomp_t *)
477               realloc((char *) *pdecomps,
478                       sizeof(_decomp_t) * (*pdecomps_size + 8));
479         (void) memset((char *) (*pdecomps + *pdecomps_size), '\0',
480                       sizeof(_decomp_t) << 3);
481         *pdecomps_size += 8;
482     }
483
484     if (i < *pdecomps_used && code != (*pdecomps)[i].code) {
485         /*
486          * Shift the decomps up by one if the codes don't match.
487          */
488         for (j = *pdecomps_used; j > i; j--)
489           (void) AC_MEMCPY((char *) &(*pdecomps)[j], (char *) &(*pdecomps)[j - 1],
490                         sizeof(_decomp_t));
491     }
492
493     /*
494      * Insert or replace a decomposition.
495      */
496     size = dectmp_size + (4 - (dectmp_size & 3));
497     if ((*pdecomps)[i].size < size) {
498         if ((*pdecomps)[i].size == 0)
499           (*pdecomps)[i].decomp = (ac_uint4 *)
500               malloc(sizeof(ac_uint4) * size);
501         else
502           (*pdecomps)[i].decomp = (ac_uint4 *)
503               realloc((char *) (*pdecomps)[i].decomp,
504                       sizeof(ac_uint4) * size);
505         (*pdecomps)[i].size = size;
506     }
507
508     if ((*pdecomps)[i].code != code)
509       (*pdecomps_used)++;
510
511     (*pdecomps)[i].code = code;
512     (*pdecomps)[i].used = dectmp_size;
513     (void) AC_MEMCPY((char *) (*pdecomps)[i].decomp, (char *) dectmp,
514                   sizeof(ac_uint4) * dectmp_size);
515
516     /*
517      * NOTICE: This needs changing later so it is more general than simply
518      * pairs.  This calculation is done here to simplify allocation elsewhere.
519      */
520     if (!compat && dectmp_size == 2)
521       comps_used++;
522 }
523
524 static void
525 add_title(ac_uint4 code)
526 {
527     ac_uint4 i, j;
528
529     /*
530      * Always map the code to itself.
531      */
532     cases[2] = code;
533
534     if (title_used == title_size) {
535         if (title_size == 0)
536           title = (_case_t *) malloc(sizeof(_case_t) << 3);
537         else
538           title = (_case_t *) realloc((char *) title,
539                                       sizeof(_case_t) * (title_size + 8));
540         title_size += 8;
541     }
542
543     /*
544      * Locate the insertion point.
545      */
546     for (i = 0; i < title_used && code > title[i].key; i++) ;
547
548     if (i < title_used) {
549         /*
550          * Shift the array up by one.
551          */
552         for (j = title_used; j > i; j--)
553           (void) AC_MEMCPY((char *) &title[j], (char *) &title[j - 1],
554                         sizeof(_case_t));
555     }
556
557     title[i].key = cases[2];    /* Title */
558     title[i].other1 = cases[0]; /* Upper */
559     title[i].other2 = cases[1]; /* Lower */
560
561     title_used++;
562 }
563
564 static void
565 add_upper(ac_uint4 code)
566 {
567     ac_uint4 i, j;
568
569     /*
570      * Always map the code to itself.
571      */
572     cases[0] = code;
573
574     /*
575      * If the title case character is not present, then make it the same as
576      * the upper case.
577      */
578     if (cases[2] == 0)
579       cases[2] = code;
580
581     if (upper_used == upper_size) {
582         if (upper_size == 0)
583           upper = (_case_t *) malloc(sizeof(_case_t) << 3);
584         else
585           upper = (_case_t *) realloc((char *) upper,
586                                       sizeof(_case_t) * (upper_size + 8));
587         upper_size += 8;
588     }
589
590     /*
591      * Locate the insertion point.
592      */
593     for (i = 0; i < upper_used && code > upper[i].key; i++) ;
594
595     if (i < upper_used) {
596         /*
597          * Shift the array up by one.
598          */
599         for (j = upper_used; j > i; j--)
600           (void) AC_MEMCPY((char *) &upper[j], (char *) &upper[j - 1],
601                         sizeof(_case_t));
602     }
603
604     upper[i].key = cases[0];    /* Upper */
605     upper[i].other1 = cases[1]; /* Lower */
606     upper[i].other2 = cases[2]; /* Title */
607
608     upper_used++;
609 }
610
611 static void
612 add_lower(ac_uint4 code)
613 {
614     ac_uint4 i, j;
615
616     /*
617      * Always map the code to itself.
618      */
619     cases[1] = code;
620
621     /*
622      * If the title case character is empty, then make it the same as the
623      * upper case.
624      */
625     if (cases[2] == 0)
626       cases[2] = cases[0];
627
628     if (lower_used == lower_size) {
629         if (lower_size == 0)
630           lower = (_case_t *) malloc(sizeof(_case_t) << 3);
631         else
632           lower = (_case_t *) realloc((char *) lower,
633                                       sizeof(_case_t) * (lower_size + 8));
634         lower_size += 8;
635     }
636
637     /*
638      * Locate the insertion point.
639      */
640     for (i = 0; i < lower_used && code > lower[i].key; i++) ;
641
642     if (i < lower_used) {
643         /*
644          * Shift the array up by one.
645          */
646         for (j = lower_used; j > i; j--)
647           (void) AC_MEMCPY((char *) &lower[j], (char *) &lower[j - 1],
648                         sizeof(_case_t));
649     }
650
651     lower[i].key = cases[1];    /* Lower */
652     lower[i].other1 = cases[0]; /* Upper */
653     lower[i].other2 = cases[2]; /* Title */
654
655     lower_used++;
656 }
657
658 static void
659 ordered_ccl_insert(ac_uint4 c, ac_uint4 ccl_code)
660 {
661     ac_uint4 i, j;
662
663     if (ccl_used == ccl_size) {
664         if (ccl_size == 0)
665           ccl = (ac_uint4 *) malloc(sizeof(ac_uint4) * 24);
666         else
667           ccl = (ac_uint4 *)
668               realloc((char *) ccl, sizeof(ac_uint4) * (ccl_size + 24));
669         ccl_size += 24;
670     }
671
672     /*
673      * Optimize adding the first item.
674      */
675     if (ccl_used == 0) {
676         ccl[0] = ccl[1] = c;
677         ccl[2] = ccl_code;
678         ccl_used += 3;
679         return;
680     }
681
682     /*
683      * Handle the special case of extending the range on the end.  This
684      * requires that the combining class codes are the same.
685      */
686     if (ccl_code == ccl[ccl_used - 1] && c == ccl[ccl_used - 2] + 1) {
687         ccl[ccl_used - 2] = c;
688         return;
689     }
690
691     /*
692      * Handle the special case of adding another range on the end.
693      */
694     if (c > ccl[ccl_used - 2] + 1 ||
695         (c == ccl[ccl_used - 2] + 1 && ccl_code != ccl[ccl_used - 1])) {
696         ccl[ccl_used++] = c;
697         ccl[ccl_used++] = c;
698         ccl[ccl_used++] = ccl_code;
699         return;
700     }
701
702     /*
703      * Locate either the insertion point or range for the code.
704      */
705     for (i = 0; i < ccl_used && c > ccl[i + 1] + 1; i += 3) ;
706
707     if (ccl_code == ccl[i + 2] && c == ccl[i + 1] + 1) {
708         /*
709          * Extend an existing range.
710          */
711         ccl[i + 1] = c;
712         return;
713     } else if (c < ccl[i]) {
714         /*
715          * Start a new range before the current location.
716          */
717         for (j = ccl_used; j > i; j -= 3) {
718             ccl[j] = ccl[j - 3];
719             ccl[j - 1] = ccl[j - 4];
720             ccl[j - 2] = ccl[j - 5];
721         }
722         ccl[i] = ccl[i + 1] = c;
723         ccl[i + 2] = ccl_code;
724     }
725 }
726
727 /*
728  * Adds a number if it does not already exist and returns an index value
729  * multiplied by 2.
730  */
731 static ac_uint4
732 make_number(short num, short denom)
733 {
734     ac_uint4 n;
735
736     /*
737      * Determine if the number already exists.
738      */
739     for (n = 0; n < nums_used; n++) {
740         if (nums[n].numerator == num && nums[n].denominator == denom)
741           return n << 1;
742     }
743
744     if (nums_used == nums_size) {
745         if (nums_size == 0)
746           nums = (_num_t *) malloc(sizeof(_num_t) << 3);
747         else
748           nums = (_num_t *) realloc((char *) nums,
749                                     sizeof(_num_t) * (nums_size + 8));
750         nums_size += 8;
751     }
752
753     n = nums_used++;
754     nums[n].numerator = num;
755     nums[n].denominator = denom;
756
757     return n << 1;
758 }
759
760 static void
761 add_number(ac_uint4 code, short num, short denom)
762 {
763     ac_uint4 i, j;
764
765     /*
766      * Insert the code in order.
767      */
768     for (i = 0; i < ncodes_used && code > ncodes[i].code; i++) ;
769
770     /*
771      * Handle the case of the codes matching and simply replace the number
772      * that was there before.
773      */
774     if (i < ncodes_used && code == ncodes[i].code) {
775         ncodes[i].idx = make_number(num, denom);
776         return;
777     }
778
779     /*
780      * Resize the array if necessary.
781      */
782     if (ncodes_used == ncodes_size) {
783         if (ncodes_size == 0)
784           ncodes = (_codeidx_t *) malloc(sizeof(_codeidx_t) << 3);
785         else
786           ncodes = (_codeidx_t *)
787               realloc((char *) ncodes, sizeof(_codeidx_t) * (ncodes_size + 8));
788
789         ncodes_size += 8;
790     }
791
792     /*
793      * Shift things around to insert the code if necessary.
794      */
795     if (i < ncodes_used) {
796         for (j = ncodes_used; j > i; j--) {
797             ncodes[j].code = ncodes[j - 1].code;
798             ncodes[j].idx = ncodes[j - 1].idx;
799         }
800     }
801     ncodes[i].code = code;
802     ncodes[i].idx = make_number(num, denom);
803
804     ncodes_used++;
805 }
806
807 /*
808  * This routine assumes that the line is a valid Unicode Character Database
809  * entry.
810  */
811 static void
812 read_cdata(FILE *in)
813 {
814     ac_uint4 i, lineno, skip, code, ccl_code;
815     short wnum, neg, number[2], compat;
816     char line[512], *s, *e;
817
818     lineno = skip = 0;
819     while (fgets(line, sizeof(line), in)) {
820         if( (s=strchr(line, '\n')) ) *s = '\0';
821         lineno++;
822
823         /*
824          * Skip blank lines and lines that start with a '#'.
825          */
826         if (line[0] == 0 || line[0] == '#')
827           continue;
828
829         /*
830          * If lines need to be skipped, do it here.
831          */
832         if (skip) {
833             skip--;
834             continue;
835         }
836
837         /*
838          * Collect the code.  The code can be up to 6 hex digits in length to
839          * allow surrogates to be specified.
840          */
841         for (s = line, i = code = 0; *s != ';' && i < 6; i++, s++) {
842             code <<= 4;
843             if (*s >= '0' && *s <= '9')
844               code += *s - '0';
845             else if (*s >= 'A' && *s <= 'F')
846               code += (*s - 'A') + 10;
847             else if (*s >= 'a' && *s <= 'f')
848               code += (*s - 'a') + 10;
849         }
850
851         /*
852          * Handle the following special cases:
853          * 1. 4E00-9FA5 CJK Ideographs.
854          * 2. AC00-D7A3 Hangul Syllables.
855          * 3. D800-DFFF Surrogates.
856          * 4. E000-F8FF Private Use Area.
857          * 5. F900-FA2D Han compatibility.
858          * ...Plus additional ranges in newer Unicode versions...
859          */
860         switch (code) {
861           case 0x3400:
862             /* CJK Ideograph Extension A */
863             add_range(0x3400, 0x4db5, "Lo", "L");
864
865             add_range(0x3400, 0x4db5, "Cp", 0);
866
867             skip = 1;
868             break;
869           case 0x4e00:
870             /*
871              * The Han ideographs.
872              */
873             add_range(0x4e00, 0x9fff, "Lo", "L");
874
875             /*
876              * Add the characters to the defined category.
877              */
878             add_range(0x4e00, 0x9fa5, "Cp", 0);
879
880             skip = 1;
881             break;
882           case 0xac00:
883             /*
884              * The Hangul syllables.
885              */
886             add_range(0xac00, 0xd7a3, "Lo", "L");
887
888             /*
889              * Add the characters to the defined category.
890              */
891             add_range(0xac00, 0xd7a3, "Cp", 0);
892
893             skip = 1;
894             break;
895           case 0xd800:
896             /*
897              * Make a range of all surrogates and assume some default
898              * properties.
899              */
900             add_range(0x010000, 0x10ffff, "Cs", "L");
901             skip = 5;
902             break;
903           case 0xe000:
904             /*
905              * The Private Use area.  Add with a default set of properties.
906              */
907             add_range(0xe000, 0xf8ff, "Co", "L");
908             skip = 1;
909             break;
910           case 0xf900:
911             /*
912              * The CJK compatibility area.
913              */
914             add_range(0xf900, 0xfaff, "Lo", "L");
915
916             /*
917              * Add the characters to the defined category.
918              */
919             add_range(0xf900, 0xfaff, "Cp", 0);
920
921             skip = 1;
922             break;
923           case 0x20000:
924             /* CJK Ideograph Extension B */
925             add_range(0x20000, 0x2a6d6, "Lo", "L");
926
927             add_range(0x20000, 0x2a6d6, "Cp", 0);
928
929             skip = 1;
930             break;
931           case 0xf0000:
932             /* Plane 15 private use */
933             add_range(0xf0000, 0xffffd, "Co", "L");
934             skip = 1;
935             break;
936
937           case 0x100000:
938             /* Plane 16 private use */
939             add_range(0x100000, 0x10fffd, "Co", "L");
940             skip = 1;
941             break;
942         }
943
944         if (skip)
945           continue;
946
947         /*
948          * Add the code to the defined category.
949          */
950         ordered_range_insert(code, "Cp", 2);
951
952         /*
953          * Locate the first character property field.
954          */
955         for (i = 0; *s != 0 && i < 2; s++) {
956             if (*s == ';')
957               i++;
958         }
959         for (e = s; *e && *e != ';'; e++) ;
960     
961         ordered_range_insert(code, s, e - s);
962
963         /*
964          * Locate the combining class code.
965          */
966         for (s = e; *s != 0 && i < 3; s++) {
967             if (*s == ';')
968               i++;
969         }
970
971         /*
972          * Convert the combining class code from decimal.
973          */
974         for (ccl_code = 0, e = s; *e && *e != ';'; e++)
975           ccl_code = (ccl_code * 10) + (*e - '0');
976
977         /*
978          * Add the code if it not 0.
979          */
980         if (ccl_code != 0)
981           ordered_ccl_insert(code, ccl_code);
982
983         /*
984          * Locate the second character property field.
985          */
986         for (s = e; *s != 0 && i < 4; s++) {
987             if (*s == ';')
988               i++;
989         }
990         for (e = s; *e && *e != ';'; e++) ;
991
992         ordered_range_insert(code, s, e - s);
993
994         /*
995          * Check for a decomposition.
996          */
997         s = ++e;
998         if (*s != ';') {
999             compat = *s == '<';
1000             if (compat) {
1001                 /*
1002                  * Skip compatibility formatting tag.
1003                  */
1004                 while (*s++ != '>');
1005             }
1006             /*
1007              * Collect the codes of the decomposition.
1008              */
1009             for (dectmp_size = 0; *s != ';'; ) {
1010                 /*
1011                  * Skip all leading non-hex digits.
1012                  */
1013                 while (!ishdigit(*s))
1014                   s++;
1015
1016                 for (dectmp[dectmp_size] = 0; ishdigit(*s); s++) {
1017                     dectmp[dectmp_size] <<= 4;
1018                     if (*s >= '0' && *s <= '9')
1019                       dectmp[dectmp_size] += *s - '0';
1020                     else if (*s >= 'A' && *s <= 'F')
1021                       dectmp[dectmp_size] += (*s - 'A') + 10;
1022                     else if (*s >= 'a' && *s <= 'f')
1023                       dectmp[dectmp_size] += (*s - 'a') + 10;
1024                 }
1025                 dectmp_size++;
1026             }
1027
1028             /*
1029              * If there are any codes in the temporary decomposition array,
1030              * then add the character with its decomposition.
1031              */
1032             if (dectmp_size > 0) {
1033                 if (!compat) {
1034                     add_decomp(code, 0);
1035                 }
1036                 add_decomp(code, 1);
1037             }
1038         }
1039
1040         /*
1041          * Skip to the number field.
1042          */
1043         for (i = 0; i < 3 && *s; s++) {
1044             if (*s == ';')
1045               i++;
1046         }
1047
1048         /*
1049          * Scan the number in.
1050          */
1051         number[0] = number[1] = 0;
1052         for (e = s, neg = wnum = 0; *e && *e != ';'; e++) {
1053             if (*e == '-') {
1054                 neg = 1;
1055                 continue;
1056             }
1057
1058             if (*e == '/') {
1059                 /*
1060                  * Move the the denominator of the fraction.
1061                  */
1062                 if (neg)
1063                   number[wnum] *= -1;
1064                 neg = 0;
1065                 e++;
1066                 wnum++;
1067             }
1068             number[wnum] = (number[wnum] * 10) + (*e - '0');
1069         }
1070
1071         if (e > s) {
1072             /*
1073              * Adjust the denominator in case of integers and add the number.
1074              */
1075             if (wnum == 0)
1076               number[1] = number[0];
1077
1078             add_number(code, number[0], number[1]);
1079         }
1080
1081         /*
1082          * Skip to the start of the possible case mappings.
1083          */
1084         for (s = e, i = 0; i < 4 && *s; s++) {
1085             if (*s == ';')
1086               i++;
1087         }
1088
1089         /*
1090          * Collect the case mappings.
1091          */
1092         cases[0] = cases[1] = cases[2] = 0;
1093         for (i = 0; i < 3; i++) {
1094             while (ishdigit(*s)) {
1095                 cases[i] <<= 4;
1096                 if (*s >= '0' && *s <= '9')
1097                   cases[i] += *s - '0';
1098                 else if (*s >= 'A' && *s <= 'F')
1099                   cases[i] += (*s - 'A') + 10;
1100                 else if (*s >= 'a' && *s <= 'f')
1101                   cases[i] += (*s - 'a') + 10;
1102                 s++;
1103             }
1104             if (*s == ';')
1105               s++;
1106         }
1107         if (cases[0] && cases[1])
1108           /*
1109            * Add the upper and lower mappings for a title case character.
1110            */
1111           add_title(code);
1112         else if (cases[1])
1113           /*
1114            * Add the lower and title case mappings for the upper case
1115            * character.
1116            */
1117           add_upper(code);
1118         else if (cases[0])
1119           /*
1120            * Add the upper and title case mappings for the lower case
1121            * character.
1122            */
1123           add_lower(code);
1124     }
1125 }
1126
1127 static _decomp_t *
1128 find_decomp(ac_uint4 code, short compat)
1129 {
1130     long l, r, m;
1131     _decomp_t *decs;
1132     
1133     l = 0;
1134     r = (compat ? kdecomps_used : decomps_used) - 1;
1135     decs = compat ? kdecomps : decomps;
1136     while (l <= r) {
1137         m = (l + r) >> 1;
1138         if (code > decs[m].code)
1139           l = m + 1;
1140         else if (code < decs[m].code)
1141           r = m - 1;
1142         else
1143           return &decs[m];
1144     }
1145     return 0;
1146 }
1147
1148 static void
1149 decomp_it(_decomp_t *d, short compat)
1150 {
1151     ac_uint4 i;
1152     _decomp_t *dp;
1153
1154     for (i = 0; i < d->used; i++) {
1155         if ((dp = find_decomp(d->decomp[i], compat)) != 0)
1156           decomp_it(dp, compat);
1157         else
1158           dectmp[dectmp_size++] = d->decomp[i];
1159     }
1160 }
1161
1162 /*
1163  * Expand all decompositions by recursively decomposing each character
1164  * in the decomposition.
1165  */
1166 static void
1167 expand_decomp(void)
1168 {
1169     ac_uint4 i;
1170
1171     for (i = 0; i < decomps_used; i++) {
1172         dectmp_size = 0;
1173         decomp_it(&decomps[i], 0);
1174         if (dectmp_size > 0)
1175           add_decomp(decomps[i].code, 0);
1176     }
1177
1178     for (i = 0; i < kdecomps_used; i++) {
1179         dectmp_size = 0;
1180         decomp_it(&kdecomps[i], 1);
1181         if (dectmp_size > 0)
1182           add_decomp(kdecomps[i].code, 1);
1183     }
1184 }
1185
1186 static int
1187 cmpcomps(const void *v_comp1, const void *v_comp2)
1188 {
1189         const _comp_t *comp1 = v_comp1, *comp2 = v_comp2;
1190     long diff = comp1->code1 - comp2->code1;
1191
1192     if (!diff)
1193         diff = comp1->code2 - comp2->code2;
1194     return (int) diff;
1195 }
1196
1197 /*
1198  * Load composition exclusion data
1199  */
1200 static void
1201 read_compexdata(FILE *in)
1202 {
1203     ac_uint2 i, code;
1204     char line[512], *s;
1205
1206     (void) memset((char *) compexs, 0, sizeof(ac_uint4) << 11);
1207
1208     while (fgets(line, sizeof(line), in)) {
1209         if( (s=strchr(line, '\n')) ) *s = '\0';
1210         /*
1211          * Skip blank lines and lines that start with a '#'.
1212          */
1213         if (line[0] == 0 || line[0] == '#')
1214             continue;
1215
1216         /*
1217          * Collect the code.  Assume max 4 digits
1218          */
1219
1220         for (s = line, i = code = 0; *s != '#' && i < 4; i++, s++) {
1221             code <<= 4;
1222             if (*s >= '0' && *s <= '9')
1223                 code += *s - '0';
1224             else if (*s >= 'A' && *s <= 'F')
1225                 code += (*s - 'A') + 10;
1226             else if (*s >= 'a' && *s <= 'f')
1227                 code += (*s - 'a') + 10;
1228         }
1229         COMPEX_SET(code);
1230     }
1231 }
1232
1233 /*
1234  * Creates array of compositions from decomposition array
1235  */
1236 static void
1237 create_comps(void)
1238 {
1239     ac_uint4 i, cu;
1240
1241     comps = (_comp_t *) malloc(comps_used * sizeof(_comp_t));
1242
1243     for (i = cu = 0; i < decomps_used; i++) {
1244         if (decomps[i].used != 2 || COMPEX_TEST(decomps[i].code))
1245             continue;
1246         comps[cu].comp = decomps[i].code;
1247         comps[cu].count = 2;
1248         comps[cu].code1 = decomps[i].decomp[0];
1249         comps[cu].code2 = decomps[i].decomp[1];
1250         cu++;
1251     }
1252     comps_used = cu;
1253     qsort(comps, comps_used, sizeof(_comp_t), cmpcomps);
1254 }
1255
1256 static void
1257 write_cdata(char *opath)
1258 {
1259     FILE *out;
1260         ac_uint4 bytes;
1261     ac_uint4 i, idx, nprops;
1262     ac_uint2 casecnt[2];
1263     char path[BUFSIZ];
1264
1265     /*****************************************************************
1266      *
1267      * Generate the ctype data.
1268      *
1269      *****************************************************************/
1270
1271     /*
1272      * Open the ctype.dat file.
1273      */
1274     snprintf(path, sizeof path, "%s" LDAP_DIRSEP "ctype.dat", opath);
1275     if ((out = fopen(path, "wb")) == 0)
1276       return;
1277
1278     /*
1279      * Collect the offsets for the properties.  The offsets array is
1280      * on a 4-byte boundary to keep things efficient for architectures
1281      * that need such a thing.
1282      */
1283     for (i = idx = 0; i < NUMPROPS; i++) {
1284         propcnt[i] = (proptbl[i].used != 0) ? idx : 0xffff;
1285         idx += proptbl[i].used;
1286     }
1287
1288     /*
1289      * Add the sentinel index which is used by the binary search as the upper
1290      * bound for a search.
1291      */
1292     propcnt[i] = idx;
1293
1294     /*
1295      * Record the actual number of property lists.  This may be different than
1296      * the number of offsets actually written because of aligning on a 4-byte
1297      * boundary.
1298      */
1299     hdr[1] = NUMPROPS;
1300
1301     /*
1302      * Calculate the byte count needed and pad the property counts array to a
1303      * 4-byte boundary.
1304      */
1305     if ((bytes = sizeof(ac_uint2) * (NUMPROPS + 1)) & 3)
1306       bytes += 4 - (bytes & 3);
1307     nprops = bytes / sizeof(ac_uint2);
1308     bytes += sizeof(ac_uint4) * idx;
1309         
1310     /*
1311      * Write the header.
1312      */
1313     fwrite((char *) hdr, sizeof(ac_uint2), 2, out);
1314
1315     /*
1316      * Write the byte count.
1317      */
1318     fwrite((char *) &bytes, sizeof(ac_uint4), 1, out);
1319
1320     /*
1321      * Write the property list counts.
1322      */
1323     fwrite((char *) propcnt, sizeof(ac_uint2), nprops, out);
1324
1325     /*
1326      * Write the property lists.
1327      */
1328     for (i = 0; i < NUMPROPS; i++) {
1329         if (proptbl[i].used > 0)
1330           fwrite((char *) proptbl[i].ranges, sizeof(ac_uint4),
1331                  proptbl[i].used, out);
1332     }
1333
1334     fclose(out);
1335
1336     /*****************************************************************
1337      *
1338      * Generate the case mapping data.
1339      *
1340      *****************************************************************/
1341
1342     /*
1343      * Open the case.dat file.
1344      */
1345     snprintf(path, sizeof path, "%s" LDAP_DIRSEP "case.dat", opath);
1346     if ((out = fopen(path, "wb")) == 0)
1347       return;
1348
1349     /*
1350      * Write the case mapping tables.
1351      */
1352     hdr[1] = upper_used + lower_used + title_used;
1353     casecnt[0] = upper_used;
1354     casecnt[1] = lower_used;
1355
1356     /*
1357      * Write the header.
1358      */
1359     fwrite((char *) hdr, sizeof(ac_uint2), 2, out);
1360
1361     /*
1362      * Write the upper and lower case table sizes.
1363      */
1364     fwrite((char *) casecnt, sizeof(ac_uint2), 2, out);
1365
1366     if (upper_used > 0)
1367       /*
1368        * Write the upper case table.
1369        */
1370       fwrite((char *) upper, sizeof(_case_t), upper_used, out);
1371
1372     if (lower_used > 0)
1373       /*
1374        * Write the lower case table.
1375        */
1376       fwrite((char *) lower, sizeof(_case_t), lower_used, out);
1377
1378     if (title_used > 0)
1379       /*
1380        * Write the title case table.
1381        */
1382       fwrite((char *) title, sizeof(_case_t), title_used, out);
1383
1384     fclose(out);
1385
1386     /*****************************************************************
1387      *
1388      * Generate the composition data.
1389      *
1390      *****************************************************************/
1391     
1392     /*
1393      * Create compositions from decomposition data
1394      */
1395     create_comps();
1396     
1397     /*
1398      * Open the comp.dat file.
1399      */
1400     snprintf(path, sizeof path, "%s" LDAP_DIRSEP "comp.dat", opath);
1401     if ((out = fopen(path, "wb")) == 0)
1402         return;
1403     
1404     /*
1405      * Write the header.
1406      */
1407     hdr[1] = (ac_uint2) comps_used * 4;
1408     fwrite((char *) hdr, sizeof(ac_uint2), 2, out);
1409     
1410     /*
1411      * Write out the byte count to maintain header size.
1412      */
1413     bytes = comps_used * sizeof(_comp_t);
1414     fwrite((char *) &bytes, sizeof(ac_uint4), 1, out);
1415     
1416     /*
1417      * Now, if comps exist, write them out.
1418      */
1419     if (comps_used > 0)
1420         fwrite((char *) comps, sizeof(_comp_t), comps_used, out);
1421     
1422     fclose(out);
1423     
1424     /*****************************************************************
1425      *
1426      * Generate the decomposition data.
1427      *
1428      *****************************************************************/
1429
1430     /*
1431      * Fully expand all decompositions before generating the output file.
1432      */
1433     expand_decomp();
1434
1435     /*
1436      * Open the decomp.dat file.
1437      */
1438     snprintf(path, sizeof path, "%s" LDAP_DIRSEP "decomp.dat", opath);
1439     if ((out = fopen(path, "wb")) == 0)
1440       return;
1441
1442     hdr[1] = decomps_used;
1443
1444     /*
1445      * Write the header.
1446      */
1447     fwrite((char *) hdr, sizeof(ac_uint2), 2, out);
1448
1449     /*
1450      * Write a temporary byte count which will be calculated as the
1451      * decompositions are written out.
1452      */
1453     bytes = 0;
1454     fwrite((char *) &bytes, sizeof(ac_uint4), 1, out);
1455
1456     if (decomps_used) {
1457         /*
1458          * Write the list of decomp nodes.
1459          */
1460         for (i = idx = 0; i < decomps_used; i++) {
1461             fwrite((char *) &decomps[i].code, sizeof(ac_uint4), 1, out);
1462             fwrite((char *) &idx, sizeof(ac_uint4), 1, out);
1463             idx += decomps[i].used;
1464         }
1465
1466         /*
1467          * Write the sentinel index as the last decomp node.
1468          */
1469         fwrite((char *) &idx, sizeof(ac_uint4), 1, out);
1470
1471         /*
1472          * Write the decompositions themselves.
1473          */
1474         for (i = 0; i < decomps_used; i++)
1475           fwrite((char *) decomps[i].decomp, sizeof(ac_uint4),
1476                  decomps[i].used, out);
1477
1478         /*
1479          * Seek back to the beginning and write the byte count.
1480          */
1481         bytes = (sizeof(ac_uint4) * idx) +
1482             (sizeof(ac_uint4) * ((hdr[1] << 1) + 1));
1483         fseek(out, sizeof(ac_uint2) << 1, 0L);
1484         fwrite((char *) &bytes, sizeof(ac_uint4), 1, out);
1485
1486         fclose(out);
1487     }
1488
1489     /*
1490      * Open the kdecomp.dat file.
1491      */
1492     snprintf(path, sizeof path, "%s" LDAP_DIRSEP "kdecomp.dat", opath);
1493     if ((out = fopen(path, "wb")) == 0)
1494       return;
1495
1496     hdr[1] = kdecomps_used;
1497
1498     /*
1499      * Write the header.
1500      */
1501     fwrite((char *) hdr, sizeof(ac_uint2), 2, out);
1502
1503     /*
1504      * Write a temporary byte count which will be calculated as the
1505      * decompositions are written out.
1506      */
1507     bytes = 0;
1508     fwrite((char *) &bytes, sizeof(ac_uint4), 1, out);
1509
1510     if (kdecomps_used) {
1511         /*
1512          * Write the list of kdecomp nodes.
1513          */
1514         for (i = idx = 0; i < kdecomps_used; i++) {
1515             fwrite((char *) &kdecomps[i].code, sizeof(ac_uint4), 1, out);
1516             fwrite((char *) &idx, sizeof(ac_uint4), 1, out);
1517             idx += kdecomps[i].used;
1518         }
1519
1520         /*
1521          * Write the sentinel index as the last decomp node.
1522          */
1523         fwrite((char *) &idx, sizeof(ac_uint4), 1, out);
1524
1525         /*
1526          * Write the decompositions themselves.
1527          */
1528         for (i = 0; i < kdecomps_used; i++)
1529           fwrite((char *) kdecomps[i].decomp, sizeof(ac_uint4),
1530                  kdecomps[i].used, out);
1531
1532         /*
1533          * Seek back to the beginning and write the byte count.
1534          */
1535         bytes = (sizeof(ac_uint4) * idx) +
1536             (sizeof(ac_uint4) * ((hdr[1] << 1) + 1));
1537         fseek(out, sizeof(ac_uint2) << 1, 0L);
1538         fwrite((char *) &bytes, sizeof(ac_uint4), 1, out);
1539
1540         fclose(out);
1541     }
1542
1543     /*****************************************************************
1544      *
1545      * Generate the combining class data.
1546      *
1547      *****************************************************************/
1548
1549     /*
1550      * Open the cmbcl.dat file.
1551      */
1552     snprintf(path, sizeof path, "%s" LDAP_DIRSEP "cmbcl.dat", opath);
1553     if ((out = fopen(path, "wb")) == 0)
1554       return;
1555
1556     /*
1557      * Set the number of ranges used.  Each range has a combining class which
1558      * means each entry is a 3-tuple.
1559      */
1560     hdr[1] = ccl_used / 3;
1561
1562     /*
1563      * Write the header.
1564      */
1565     fwrite((char *) hdr, sizeof(ac_uint2), 2, out);
1566
1567     /*
1568      * Write out the byte count to maintain header size.
1569      */
1570     bytes = ccl_used * sizeof(ac_uint4);
1571     fwrite((char *) &bytes, sizeof(ac_uint4), 1, out);
1572
1573     if (ccl_used > 0)
1574       /*
1575        * Write the combining class ranges out.
1576        */
1577       fwrite((char *) ccl, sizeof(ac_uint4), ccl_used, out);
1578
1579     fclose(out);
1580
1581     /*****************************************************************
1582      *
1583      * Generate the number data.
1584      *
1585      *****************************************************************/
1586
1587     /*
1588      * Open the num.dat file.
1589      */
1590     snprintf(path, sizeof path, "%s" LDAP_DIRSEP "num.dat", opath);
1591     if ((out = fopen(path, "wb")) == 0)
1592       return;
1593
1594     /*
1595      * The count part of the header will be the total number of codes that
1596      * have numbers.
1597      */
1598     hdr[1] = (ac_uint2) (ncodes_used << 1);
1599     bytes = (ncodes_used * sizeof(_codeidx_t)) + (nums_used * sizeof(_num_t));
1600
1601     /*
1602      * Write the header.
1603      */
1604     fwrite((char *) hdr, sizeof(ac_uint2), 2, out);
1605
1606     /*
1607      * Write out the byte count to maintain header size.
1608      */
1609     fwrite((char *) &bytes, sizeof(ac_uint4), 1, out);
1610
1611     /*
1612      * Now, if number mappings exist, write them out.
1613      */
1614     if (ncodes_used > 0) {
1615         fwrite((char *) ncodes, sizeof(_codeidx_t), ncodes_used, out);
1616         fwrite((char *) nums, sizeof(_num_t), nums_used, out);
1617     }
1618
1619     fclose(out);
1620 }
1621
1622 static void
1623 usage(char *prog)
1624 {
1625     fprintf(stderr,
1626             "Usage: %s [-o output-directory|-x composition-exclusions]", prog);
1627     fprintf(stderr, " datafile1 datafile2 ...\n\n");
1628     fprintf(stderr,
1629             "-o output-directory\n\t\tWrite the output files to a different");
1630     fprintf(stderr, " directory (default: .).\n");
1631     fprintf(stderr,
1632             "-x composition-exclusion\n\t\tFile of composition codes");
1633     fprintf(stderr, " that should be excluded.\n");
1634     exit(1);
1635 }
1636
1637 int
1638 main(int argc, char *argv[])
1639 {
1640     FILE *in;
1641     char *prog, *opath;
1642
1643     prog = lutil_progname( "ucgendat", argc, argv );
1644
1645     opath = 0;
1646     in = stdin;
1647
1648     argc--;
1649     argv++;
1650
1651     while (argc > 0) {
1652         if (argv[0][0] == '-') {
1653             switch (argv[0][1]) {
1654               case 'o':
1655                 argc--;
1656                 argv++;
1657                 opath = argv[0];
1658                 break;
1659               case 'x':
1660                 argc--;
1661                 argv++;
1662                 if ((in = fopen(argv[0], "r")) == 0)
1663                   fprintf(stderr,
1664                           "%s: unable to open composition exclusion file %s\n",
1665                           prog, argv[0]);
1666                 else {
1667                     read_compexdata(in);
1668                     fclose(in);
1669                     in = 0;
1670                 }
1671                 break;
1672               default:
1673                 usage(prog);
1674             }
1675         } else {
1676             if (in != stdin && in != NULL)
1677               fclose(in);
1678             if ((in = fopen(argv[0], "r")) == 0)
1679               fprintf(stderr, "%s: unable to open ctype file %s\n",
1680                       prog, argv[0]);
1681             else {
1682                 read_cdata(in);
1683                 fclose(in);
1684                 in = 0;
1685             }
1686         }
1687         argc--;
1688         argv++;
1689     }
1690
1691     if (opath == 0)
1692       opath = ".";
1693     write_cdata(opath);
1694
1695     return 0;
1696 }