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