]> git.sur5r.net Git - openldap/blob - libraries/liblunicode/ucdata/ucgendat.c
591fcc4f1049717db0e33800f75e3e22e8817249
[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 (fscanf(in, "%[^\n]\n", line) != EOF) {
808         lineno++;
809
810         /*
811          * Skip blank lines and lines that start with a '#'.
812          */
813         if (line[0] == 0 || line[0] == '#')
814           continue;
815
816         /*
817          * If lines need to be skipped, do it here.
818          */
819         if (skip) {
820             skip--;
821             continue;
822         }
823
824         /*
825          * Collect the code.  The code can be up to 6 hex digits in length to
826          * allow surrogates to be specified.
827          */
828         for (s = line, i = code = 0; *s != ';' && i < 6; i++, s++) {
829             code <<= 4;
830             if (*s >= '0' && *s <= '9')
831               code += *s - '0';
832             else if (*s >= 'A' && *s <= 'F')
833               code += (*s - 'A') + 10;
834             else if (*s >= 'a' && *s <= 'f')
835               code += (*s - 'a') + 10;
836         }
837
838         /*
839          * Handle the following special cases:
840          * 1. 4E00-9FA5 CJK Ideographs.
841          * 2. AC00-D7A3 Hangul Syllables.
842          * 3. D800-DFFF Surrogates.
843          * 4. E000-F8FF Private Use Area.
844          * 5. F900-FA2D Han compatibility.
845          */
846         switch (code) {
847           case 0x4e00:
848             /*
849              * The Han ideographs.
850              */
851             add_range(0x4e00, 0x9fff, "Lo", "L");
852
853             /*
854              * Add the characters to the defined category.
855              */
856             add_range(0x4e00, 0x9fa5, "Cp", 0);
857
858             skip = 1;
859             break;
860           case 0xac00:
861             /*
862              * The Hangul syllables.
863              */
864             add_range(0xac00, 0xd7a3, "Lo", "L");
865
866             /*
867              * Add the characters to the defined category.
868              */
869             add_range(0xac00, 0xd7a3, "Cp", 0);
870
871             skip = 1;
872             break;
873           case 0xd800:
874             /*
875              * Make a range of all surrogates and assume some default
876              * properties.
877              */
878             add_range(0x010000, 0x10ffff, "Cs", "L");
879             skip = 5;
880             break;
881           case 0xe000:
882             /*
883              * The Private Use area.  Add with a default set of properties.
884              */
885             add_range(0xe000, 0xf8ff, "Co", "L");
886             skip = 1;
887             break;
888           case 0xf900:
889             /*
890              * The CJK compatibility area.
891              */
892             add_range(0xf900, 0xfaff, "Lo", "L");
893
894             /*
895              * Add the characters to the defined category.
896              */
897             add_range(0xf900, 0xfaff, "Cp", 0);
898
899             skip = 1;
900         }
901
902         if (skip)
903           continue;
904
905         /*
906          * Add the code to the defined category.
907          */
908         ordered_range_insert(code, "Cp", 2);
909
910         /*
911          * Locate the first character property field.
912          */
913         for (i = 0; *s != 0 && i < 2; s++) {
914             if (*s == ';')
915               i++;
916         }
917         for (e = s; *e && *e != ';'; e++) ;
918     
919         ordered_range_insert(code, s, e - s);
920
921         /*
922          * Locate the combining class code.
923          */
924         for (s = e; *s != 0 && i < 3; s++) {
925             if (*s == ';')
926               i++;
927         }
928
929         /*
930          * Convert the combining class code from decimal.
931          */
932         for (ccl_code = 0, e = s; *e && *e != ';'; e++)
933           ccl_code = (ccl_code * 10) + (*e - '0');
934
935         /*
936          * Add the code if it not 0.
937          */
938         if (ccl_code != 0)
939           ordered_ccl_insert(code, ccl_code);
940
941         /*
942          * Locate the second character property field.
943          */
944         for (s = e; *s != 0 && i < 4; s++) {
945             if (*s == ';')
946               i++;
947         }
948         for (e = s; *e && *e != ';'; e++) ;
949
950         ordered_range_insert(code, s, e - s);
951
952         /*
953          * Check for a decomposition.
954          */
955         s = ++e;
956         if (*s != ';') {
957             compat = *s == '<';
958             if (compat) {
959                 /*
960                  * Skip compatibility formatting tag.
961                  */
962                 while (*s++ != '>');
963             }
964             /*
965              * Collect the codes of the decomposition.
966              */
967             for (dectmp_size = 0; *s != ';'; ) {
968                 /*
969                  * Skip all leading non-hex digits.
970                  */
971                 while (!ishdigit(*s))
972                   s++;
973
974                 for (dectmp[dectmp_size] = 0; ishdigit(*s); s++) {
975                     dectmp[dectmp_size] <<= 4;
976                     if (*s >= '0' && *s <= '9')
977                       dectmp[dectmp_size] += *s - '0';
978                     else if (*s >= 'A' && *s <= 'F')
979                       dectmp[dectmp_size] += (*s - 'A') + 10;
980                     else if (*s >= 'a' && *s <= 'f')
981                       dectmp[dectmp_size] += (*s - 'a') + 10;
982                 }
983                 dectmp_size++;
984             }
985
986             /*
987              * If there are any codes in the temporary decomposition array,
988              * then add the character with its decomposition.
989              */
990             if (dectmp_size > 0) {
991                 if (!compat) {
992                     add_decomp(code, 0);
993                 }
994                 add_decomp(code, 1);
995             }
996         }
997
998         /*
999          * Skip to the number field.
1000          */
1001         for (i = 0; i < 3 && *s; s++) {
1002             if (*s == ';')
1003               i++;
1004         }
1005
1006         /*
1007          * Scan the number in.
1008          */
1009         number[0] = number[1] = 0;
1010         for (e = s, neg = wnum = 0; *e && *e != ';'; e++) {
1011             if (*e == '-') {
1012                 neg = 1;
1013                 continue;
1014             }
1015
1016             if (*e == '/') {
1017                 /*
1018                  * Move the the denominator of the fraction.
1019                  */
1020                 if (neg)
1021                   number[wnum] *= -1;
1022                 neg = 0;
1023                 e++;
1024                 wnum++;
1025             }
1026             number[wnum] = (number[wnum] * 10) + (*e - '0');
1027         }
1028
1029         if (e > s) {
1030             /*
1031              * Adjust the denominator in case of integers and add the number.
1032              */
1033             if (wnum == 0)
1034               number[1] = number[0];
1035
1036             add_number(code, number[0], number[1]);
1037         }
1038
1039         /*
1040          * Skip to the start of the possible case mappings.
1041          */
1042         for (s = e, i = 0; i < 4 && *s; s++) {
1043             if (*s == ';')
1044               i++;
1045         }
1046
1047         /*
1048          * Collect the case mappings.
1049          */
1050         cases[0] = cases[1] = cases[2] = 0;
1051         for (i = 0; i < 3; i++) {
1052             while (ishdigit(*s)) {
1053                 cases[i] <<= 4;
1054                 if (*s >= '0' && *s <= '9')
1055                   cases[i] += *s - '0';
1056                 else if (*s >= 'A' && *s <= 'F')
1057                   cases[i] += (*s - 'A') + 10;
1058                 else if (*s >= 'a' && *s <= 'f')
1059                   cases[i] += (*s - 'a') + 10;
1060                 s++;
1061             }
1062             if (*s == ';')
1063               s++;
1064         }
1065         if (cases[0] && cases[1])
1066           /*
1067            * Add the upper and lower mappings for a title case character.
1068            */
1069           add_title(code);
1070         else if (cases[1])
1071           /*
1072            * Add the lower and title case mappings for the upper case
1073            * character.
1074            */
1075           add_upper(code);
1076         else if (cases[0])
1077           /*
1078            * Add the upper and title case mappings for the lower case
1079            * character.
1080            */
1081           add_lower(code);
1082     }
1083 }
1084
1085 static _decomp_t *
1086 find_decomp(unsigned long code, short compat)
1087 {
1088     long l, r, m;
1089     _decomp_t *decs;
1090     
1091     l = 0;
1092     r = (compat ? kdecomps_used : decomps_used) - 1;
1093     decs = compat ? kdecomps : decomps;
1094     while (l <= r) {
1095         m = (l + r) >> 1;
1096         if (code > decs[m].code)
1097           l = m + 1;
1098         else if (code < decs[m].code)
1099           r = m - 1;
1100         else
1101           return &decs[m];
1102     }
1103     return 0;
1104 }
1105
1106 static void
1107 decomp_it(_decomp_t *d, short compat)
1108 {
1109     unsigned long i;
1110     _decomp_t *dp;
1111
1112     for (i = 0; i < d->used; i++) {
1113         if ((dp = find_decomp(d->decomp[i], compat)) != 0)
1114           decomp_it(dp, compat);
1115         else
1116           dectmp[dectmp_size++] = d->decomp[i];
1117     }
1118 }
1119
1120 /*
1121  * Expand all decompositions by recursively decomposing each character
1122  * in the decomposition.
1123  */
1124 static void
1125 expand_decomp(void)
1126 {
1127     unsigned long i;
1128
1129     for (i = 0; i < decomps_used; i++) {
1130         dectmp_size = 0;
1131         decomp_it(&decomps[i], 0);
1132         if (dectmp_size > 0)
1133           add_decomp(decomps[i].code, 0);
1134     }
1135
1136     for (i = 0; i < kdecomps_used; i++) {
1137         dectmp_size = 0;
1138         decomp_it(&kdecomps[i], 1);
1139         if (dectmp_size > 0)
1140           add_decomp(kdecomps[i].code, 1);
1141     }
1142 }
1143
1144 static int
1145 cmpcomps(_comp_t *comp1, _comp_t *comp2)
1146 {
1147     long diff = comp1->code1 - comp2->code1;
1148
1149     if (!diff)
1150         diff = comp1->code2 - comp2->code2;
1151     return (int) diff;
1152 }
1153
1154 /*
1155  * Load composition exclusion data
1156  */
1157 static void
1158 read_compexdata(FILE *in)
1159 {
1160     unsigned short i, code;
1161     char line[512], *s;
1162
1163     (void) memset((char *) compexs, 0, sizeof(unsigned long) << 11);
1164
1165     while (fscanf(in, "%[^\n]\n", line) != EOF) {
1166         /*
1167          * Skip blank lines and lines that start with a '#'.
1168          */
1169         if (line[0] == 0 || line[0] == '#')
1170             continue;
1171
1172         /*
1173          * Collect the code.  Assume max 4 digits
1174          */
1175
1176         for (s = line, i = code = 0; *s != '#' && i < 4; i++, s++) {
1177             code <<= 4;
1178             if (*s >= '0' && *s <= '9')
1179                 code += *s - '0';
1180             else if (*s >= 'A' && *s <= 'F')
1181                 code += (*s - 'A') + 10;
1182             else if (*s >= 'a' && *s <= 'f')
1183                 code += (*s - 'a') + 10;
1184         }
1185         COMPEX_SET(code);
1186     }
1187 }
1188
1189 /*
1190  * Creates array of compositions from decomposition array
1191  */
1192 static void
1193 create_comps(void)
1194 {
1195     unsigned long i, cu;
1196
1197     comps = (_comp_t *) malloc(comps_used * sizeof(_comp_t));
1198
1199     for (i = cu = 0; i < decomps_used; i++) {
1200         if (decomps[i].used != 2 || COMPEX_TEST(decomps[i].code))
1201             continue;
1202         comps[cu].comp = decomps[i].code;
1203         comps[cu].count = 2;
1204         comps[cu].code1 = decomps[i].decomp[0];
1205         comps[cu].code2 = decomps[i].decomp[1];
1206         cu++;
1207     }
1208     comps_used = cu;
1209     qsort(comps, comps_used, sizeof(_comp_t),
1210           (int (*)(const void *, const void *)) cmpcomps);
1211 }
1212
1213 static void
1214 write_cdata(char *opath)
1215 {
1216     FILE *out;
1217     unsigned long i, idx, bytes, nprops;
1218     unsigned short casecnt[2];
1219     char path[BUFSIZ];
1220
1221     /*****************************************************************
1222      *
1223      * Generate the ctype data.
1224      *
1225      *****************************************************************/
1226
1227     /*
1228      * Open the ctype.dat file.
1229      */
1230     sprintf(path, "%s%sctype.dat", opath, LDAP_DIRSEP);
1231     if ((out = fopen(path, "wb")) == 0)
1232       return;
1233
1234     /*
1235      * Collect the offsets for the properties.  The offsets array is
1236      * on a 4-byte boundary to keep things efficient for architectures
1237      * that need such a thing.
1238      */
1239     for (i = idx = 0; i < NUMPROPS; i++) {
1240         propcnt[i] = (proptbl[i].used != 0) ? idx : 0xffff;
1241         idx += proptbl[i].used;
1242     }
1243
1244     /*
1245      * Add the sentinel index which is used by the binary search as the upper
1246      * bound for a search.
1247      */
1248     propcnt[i] = idx;
1249
1250     /*
1251      * Record the actual number of property lists.  This may be different than
1252      * the number of offsets actually written because of aligning on a 4-byte
1253      * boundary.
1254      */
1255     hdr[1] = NUMPROPS;
1256
1257     /*
1258      * Calculate the byte count needed and pad the property counts array to a
1259      * 4-byte boundary.
1260      */
1261     if ((bytes = sizeof(unsigned short) * (NUMPROPS + 1)) & 3)
1262       bytes += 4 - (bytes & 3);
1263     nprops = bytes / sizeof(unsigned short);
1264     bytes += sizeof(unsigned long) * idx;
1265         
1266     /*
1267      * Write the header.
1268      */
1269     fwrite((char *) hdr, sizeof(unsigned short), 2, out);
1270
1271     /*
1272      * Write the byte count.
1273      */
1274     fwrite((char *) &bytes, sizeof(unsigned long), 1, out);
1275
1276     /*
1277      * Write the property list counts.
1278      */
1279     fwrite((char *) propcnt, sizeof(unsigned short), nprops, out);
1280
1281     /*
1282      * Write the property lists.
1283      */
1284     for (i = 0; i < NUMPROPS; i++) {
1285         if (proptbl[i].used > 0)
1286           fwrite((char *) proptbl[i].ranges, sizeof(unsigned long),
1287                  proptbl[i].used, out);
1288     }
1289
1290     fclose(out);
1291
1292     /*****************************************************************
1293      *
1294      * Generate the case mapping data.
1295      *
1296      *****************************************************************/
1297
1298     /*
1299      * Open the case.dat file.
1300      */
1301     sprintf(path, "%s%scase.dat", opath, LDAP_DIRSEP);
1302     if ((out = fopen(path, "wb")) == 0)
1303       return;
1304
1305     /*
1306      * Write the case mapping tables.
1307      */
1308     hdr[1] = upper_used + lower_used + title_used;
1309     casecnt[0] = upper_used;
1310     casecnt[1] = lower_used;
1311
1312     /*
1313      * Write the header.
1314      */
1315     fwrite((char *) hdr, sizeof(unsigned short), 2, out);
1316
1317     /*
1318      * Write the upper and lower case table sizes.
1319      */
1320     fwrite((char *) casecnt, sizeof(unsigned short), 2, out);
1321
1322     if (upper_used > 0)
1323       /*
1324        * Write the upper case table.
1325        */
1326       fwrite((char *) upper, sizeof(_case_t), upper_used, out);
1327
1328     if (lower_used > 0)
1329       /*
1330        * Write the lower case table.
1331        */
1332       fwrite((char *) lower, sizeof(_case_t), lower_used, out);
1333
1334     if (title_used > 0)
1335       /*
1336        * Write the title case table.
1337        */
1338       fwrite((char *) title, sizeof(_case_t), title_used, out);
1339
1340     fclose(out);
1341
1342     /*****************************************************************
1343      *
1344      * Generate the composition data.
1345      *
1346      *****************************************************************/
1347     
1348     /*
1349      * Create compositions from decomposition data
1350      */
1351     create_comps();
1352     
1353     /*
1354      * Open the comp.dat file.
1355      */
1356     sprintf(path, "%s%scomp.dat", opath, LDAP_DIRSEP);
1357     if ((out = fopen(path, "wb")) == 0)
1358         return;
1359     
1360     /*
1361      * Write the header.
1362      */
1363     hdr[1] = (unsigned short) comps_used * 4;
1364     fwrite((char *) hdr, sizeof(unsigned short), 2, out);
1365     
1366     /*
1367      * Write out the byte count to maintain header size.
1368      */
1369     bytes = comps_used * sizeof(_comp_t);
1370     fwrite((char *) &bytes, sizeof(unsigned long), 1, out);
1371     
1372     /*
1373      * Now, if comps exist, write them out.
1374      */
1375     if (comps_used > 0)
1376         fwrite((char *) comps, sizeof(_comp_t), comps_used, out);
1377     
1378     fclose(out);
1379     
1380     /*****************************************************************
1381      *
1382      * Generate the decomposition data.
1383      *
1384      *****************************************************************/
1385
1386     /*
1387      * Fully expand all decompositions before generating the output file.
1388      */
1389     expand_decomp();
1390
1391     /*
1392      * Open the decomp.dat file.
1393      */
1394     sprintf(path, "%s%sdecomp.dat", opath, LDAP_DIRSEP);
1395     if ((out = fopen(path, "wb")) == 0)
1396       return;
1397
1398     hdr[1] = decomps_used;
1399
1400     /*
1401      * Write the header.
1402      */
1403     fwrite((char *) hdr, sizeof(unsigned short), 2, out);
1404
1405     /*
1406      * Write a temporary byte count which will be calculated as the
1407      * decompositions are written out.
1408      */
1409     bytes = 0;
1410     fwrite((char *) &bytes, sizeof(unsigned long), 1, out);
1411
1412     if (decomps_used) {
1413         /*
1414          * Write the list of decomp nodes.
1415          */
1416         for (i = idx = 0; i < decomps_used; i++) {
1417             fwrite((char *) &decomps[i].code, sizeof(unsigned long), 1, out);
1418             fwrite((char *) &idx, sizeof(unsigned long), 1, out);
1419             idx += decomps[i].used;
1420         }
1421
1422         /*
1423          * Write the sentinel index as the last decomp node.
1424          */
1425         fwrite((char *) &idx, sizeof(unsigned long), 1, out);
1426
1427         /*
1428          * Write the decompositions themselves.
1429          */
1430         for (i = 0; i < decomps_used; i++)
1431           fwrite((char *) decomps[i].decomp, sizeof(unsigned long),
1432                  decomps[i].used, out);
1433
1434         /*
1435          * Seek back to the beginning and write the byte count.
1436          */
1437         bytes = (sizeof(unsigned long) * idx) +
1438             (sizeof(unsigned long) * ((hdr[1] << 1) + 1));
1439         fseek(out, sizeof(unsigned short) << 1, 0L);
1440         fwrite((char *) &bytes, sizeof(unsigned long), 1, out);
1441
1442         fclose(out);
1443     }
1444
1445     /*
1446      * Open the kdecomp.dat file.
1447      */
1448     sprintf(path, "%s%skdecomp.dat", opath, LDAP_DIRSEP);
1449     if ((out = fopen(path, "wb")) == 0)
1450       return;
1451
1452     hdr[1] = kdecomps_used;
1453
1454     /*
1455      * Write the header.
1456      */
1457     fwrite((char *) hdr, sizeof(unsigned short), 2, out);
1458
1459     /*
1460      * Write a temporary byte count which will be calculated as the
1461      * decompositions are written out.
1462      */
1463     bytes = 0;
1464     fwrite((char *) &bytes, sizeof(unsigned long), 1, out);
1465
1466     if (kdecomps_used) {
1467         /*
1468          * Write the list of kdecomp nodes.
1469          */
1470         for (i = idx = 0; i < kdecomps_used; i++) {
1471             fwrite((char *) &kdecomps[i].code, sizeof(unsigned long), 1, out);
1472             fwrite((char *) &idx, sizeof(unsigned long), 1, out);
1473             idx += kdecomps[i].used;
1474         }
1475
1476         /*
1477          * Write the sentinel index as the last decomp node.
1478          */
1479         fwrite((char *) &idx, sizeof(unsigned long), 1, out);
1480
1481         /*
1482          * Write the decompositions themselves.
1483          */
1484         for (i = 0; i < kdecomps_used; i++)
1485           fwrite((char *) kdecomps[i].decomp, sizeof(unsigned long),
1486                  kdecomps[i].used, out);
1487
1488         /*
1489          * Seek back to the beginning and write the byte count.
1490          */
1491         bytes = (sizeof(unsigned long) * idx) +
1492             (sizeof(unsigned long) * ((hdr[1] << 1) + 1));
1493         fseek(out, sizeof(unsigned short) << 1, 0L);
1494         fwrite((char *) &bytes, sizeof(unsigned long), 1, out);
1495
1496         fclose(out);
1497     }
1498
1499     /*****************************************************************
1500      *
1501      * Generate the combining class data.
1502      *
1503      *****************************************************************/
1504
1505     /*
1506      * Open the cmbcl.dat file.
1507      */
1508     sprintf(path, "%s%scmbcl.dat", opath, LDAP_DIRSEP);
1509     if ((out = fopen(path, "wb")) == 0)
1510       return;
1511
1512     /*
1513      * Set the number of ranges used.  Each range has a combining class which
1514      * means each entry is a 3-tuple.
1515      */
1516     hdr[1] = ccl_used / 3;
1517
1518     /*
1519      * Write the header.
1520      */
1521     fwrite((char *) hdr, sizeof(unsigned short), 2, out);
1522
1523     /*
1524      * Write out the byte count to maintain header size.
1525      */
1526     bytes = ccl_used * sizeof(unsigned long);
1527     fwrite((char *) &bytes, sizeof(unsigned long), 1, out);
1528
1529     if (ccl_used > 0)
1530       /*
1531        * Write the combining class ranges out.
1532        */
1533       fwrite((char *) ccl, sizeof(unsigned long), ccl_used, out);
1534
1535     fclose(out);
1536
1537     /*****************************************************************
1538      *
1539      * Generate the number data.
1540      *
1541      *****************************************************************/
1542
1543     /*
1544      * Open the num.dat file.
1545      */
1546     sprintf(path, "%s%snum.dat", opath, LDAP_DIRSEP);
1547     if ((out = fopen(path, "wb")) == 0)
1548       return;
1549
1550     /*
1551      * The count part of the header will be the total number of codes that
1552      * have numbers.
1553      */
1554     hdr[1] = (unsigned short) (ncodes_used << 1);
1555     bytes = (ncodes_used * sizeof(_codeidx_t)) + (nums_used * sizeof(_num_t));
1556
1557     /*
1558      * Write the header.
1559      */
1560     fwrite((char *) hdr, sizeof(unsigned short), 2, out);
1561
1562     /*
1563      * Write out the byte count to maintain header size.
1564      */
1565     fwrite((char *) &bytes, sizeof(unsigned long), 1, out);
1566
1567     /*
1568      * Now, if number mappings exist, write them out.
1569      */
1570     if (ncodes_used > 0) {
1571         fwrite((char *) ncodes, sizeof(_codeidx_t), ncodes_used, out);
1572         fwrite((char *) nums, sizeof(_num_t), nums_used, out);
1573     }
1574
1575     fclose(out);
1576 }
1577
1578 static void
1579 usage(char *prog)
1580 {
1581     fprintf(stderr,
1582             "Usage: %s [-o output-directory|-x composition-exclusions]", prog);
1583     fprintf(stderr, " datafile1 datafile2 ...\n\n");
1584     fprintf(stderr,
1585             "-o output-directory\n\t\tWrite the output files to a different");
1586     fprintf(stderr, " directory (default: .).\n");
1587     fprintf(stderr,
1588             "-x composition-exclusion\n\t\tFile of composition codes");
1589     fprintf(stderr, " that should be excluded.\n");
1590     exit(1);
1591 }
1592
1593 int
1594 main(int argc, char *argv[])
1595 {
1596     FILE *in;
1597     char *prog, *opath;
1598
1599     if ((prog = strrchr(argv[0], *LDAP_DIRSEP)) != 0)
1600       prog++;
1601     else
1602       prog = argv[0];
1603
1604     opath = 0;
1605     in = stdin;
1606
1607     argc--;
1608     argv++;
1609
1610     while (argc > 0) {
1611         if (argv[0][0] == '-') {
1612             switch (argv[0][1]) {
1613               case 'o':
1614                 argc--;
1615                 argv++;
1616                 opath = argv[0];
1617                 break;
1618               case 'x':
1619                 argc--;
1620                 argv++;
1621                 if ((in = fopen(argv[0], "rb")) == 0)
1622                   fprintf(stderr,
1623                           "%s: unable to open composition exclusion file %s\n",
1624                           prog, argv[0]);
1625                 else {
1626                     read_compexdata(in);
1627                     fclose(in);
1628                     in = 0;
1629                 }
1630                 break;
1631               default:
1632                 usage(prog);
1633             }
1634         } else {
1635             if (in != stdin && in != NULL)
1636               fclose(in);
1637             if ((in = fopen(argv[0], "rb")) == 0)
1638               fprintf(stderr, "%s: unable to open ctype file %s\n",
1639                       prog, argv[0]);
1640             else {
1641                 read_cdata(in);
1642                 fclose(in);
1643                 in = 0;
1644             }
1645         }
1646         argc--;
1647         argv++;
1648     }
1649
1650     if (opath == 0)
1651       opath = ".";
1652     write_cdata(opath);
1653
1654     return 0;
1655 }