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