]> git.sur5r.net Git - openldap/blob - libraries/liblunicode/ucdata/ucdata.c
151e0ac1057f3c260aff7b1f42eac2a51a84bc25
[openldap] / libraries / liblunicode / ucdata / ucdata.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: ucdata.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/bytes.h>
34 #include <ac/stdlib.h>
35 #include <ac/string.h>
36 #include <ac/unistd.h>
37
38
39 #include "ucdata.h"
40
41 /**************************************************************************
42  *
43  * Miscellaneous types, data, and support functions.
44  *
45  **************************************************************************/
46
47 typedef struct {
48     ac_uint2 bom;
49     ac_uint2 cnt;
50     union {
51         ac_uint4 bytes;
52         ac_uint2 len[2]; 
53     } size;
54 } _ucheader_t;
55
56 /*
57  * A simple array of 32-bit masks for lookup.
58  */
59 static unsigned long masks32[32] = {
60         0x00000001UL, 0x00000002UL, 0x00000004UL, 0x00000008UL,
61         0x00000010UL, 0x00000020UL, 0x00000040UL, 0x00000080UL,
62         0x00000100UL, 0x00000200UL, 0x00000400UL, 0x00000800UL,
63         0x00001000UL, 0x00002000UL, 0x00004000UL, 0x00008000UL,
64         0x00010000UL, 0x00020000UL, 0x00040000UL, 0x00080000UL,
65         0x00100000UL, 0x00200000UL, 0x00400000UL, 0x00800000UL,
66         0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL,
67         0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL
68 };
69
70 #define endian_short(cc) (((cc) >> 8) | (((cc) & 0xff) << 8))
71 #define endian_long(cc) ((((cc) & 0xff) << 24)|((((cc) >> 8) & 0xff) << 16)|\
72                         ((((cc) >> 16) & 0xff) << 8)|((cc) >> 24))
73
74 static FILE *
75 _ucopenfile(char *paths, char *filename, char *mode)
76 {
77     FILE *f;
78     char *fp, *dp, *pp, path[BUFSIZ];
79
80     if (filename == 0 || *filename == 0)
81       return 0;
82
83     dp = paths;
84     while (dp && *dp) {
85         pp = path;
86         while (*dp && *dp != ':')
87           *pp++ = *dp++;
88         *pp++ = *LDAP_DIRSEP;
89
90         fp = filename;
91         while (*fp)
92           *pp++ = *fp++;
93         *pp = 0;
94
95         if ((f = fopen(path, mode)) != 0)
96           return f;
97
98         if (*dp == ':')
99           dp++;
100     }
101
102     return 0;
103 }
104
105 /**************************************************************************
106  *
107  * Support for the character properties.
108  *
109  **************************************************************************/
110
111 static unsigned long  _ucprop_size;
112 static unsigned short *_ucprop_offsets;
113 static unsigned long  *_ucprop_ranges;
114
115 /*
116  * Return -1 on error, 0 if okay
117  */
118 static int
119 _ucprop_load(char *paths, int reload)
120 {
121     FILE *in;
122     unsigned long size, i;
123     _ucheader_t hdr;
124
125     if (_ucprop_size > 0) {
126         if (!reload)
127           /*
128            * The character properties have already been loaded.
129            */
130           return 0;
131
132         /*
133          * Unload the current character property data in preparation for
134          * loading a new copy.  Only the first array has to be deallocated
135          * because all the memory for the arrays is allocated as a single
136          * block.
137          */
138         free((char *) _ucprop_offsets);
139         _ucprop_size = 0;
140     }
141
142     if ((in = _ucopenfile(paths, "ctype.dat", "rb")) == 0)
143       return -1;
144
145     /*
146      * Load the header.
147      */
148     fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
149
150     if (hdr.bom == 0xfffe) {
151         hdr.cnt = endian_short(hdr.cnt);
152         hdr.size.bytes = endian_long(hdr.size.bytes);
153     }
154
155     if ((_ucprop_size = hdr.cnt) == 0) {
156         fclose(in);
157         return -1;
158     }
159
160     /*
161      * Allocate all the storage needed for the lookup table.
162      */
163     _ucprop_offsets = (unsigned short *) malloc(hdr.size.bytes);
164
165     /*
166      * Calculate the offset into the storage for the ranges.  The offsets
167      * array is on a 4-byte boundary and one larger than the value provided in
168      * the header count field.  This means the offset to the ranges must be
169      * calculated after aligning the count to a 4-byte boundary.
170      */
171     if ((size = ((hdr.cnt + 1) * sizeof(unsigned short))) & 3)
172       size += 4 - (size & 3);
173     size >>= 1;
174     _ucprop_ranges = (unsigned long *) (_ucprop_offsets + size);
175
176     /*
177      * Load the offset array.
178      */
179     fread((char *) _ucprop_offsets, sizeof(unsigned short), size, in);
180
181     /*
182      * Do an endian swap if necessary.  Don't forget there is an extra node on
183      * the end with the final index.
184      */
185     if (hdr.bom == 0xfffe) {
186         for (i = 0; i <= _ucprop_size; i++)
187           _ucprop_offsets[i] = endian_short(_ucprop_offsets[i]);
188     }
189
190     /*
191      * Load the ranges.  The number of elements is in the last array position
192      * of the offsets.
193      */
194     fread((char *) _ucprop_ranges, sizeof(unsigned long),
195           _ucprop_offsets[_ucprop_size], in);
196
197     fclose(in);
198
199     /*
200      * Do an endian swap if necessary.
201      */
202     if (hdr.bom == 0xfffe) {
203         for (i = 0; i < _ucprop_offsets[_ucprop_size]; i++)
204           _ucprop_ranges[i] = endian_long(_ucprop_ranges[i]);
205     }
206     return 0;
207 }
208
209 static void
210 _ucprop_unload(void)
211 {
212     if (_ucprop_size == 0)
213       return;
214
215     /*
216      * Only need to free the offsets because the memory is allocated as a
217      * single block.
218      */
219     free((char *) _ucprop_offsets);
220     _ucprop_size = 0;
221 }
222
223 static int
224 _ucprop_lookup(unsigned long code, unsigned long n)
225 {
226     long l, r, m;
227
228     if (_ucprop_size == 0)
229       return 0;
230
231     /*
232      * There is an extra node on the end of the offsets to allow this routine
233      * to work right.  If the index is 0xffff, then there are no nodes for the
234      * property.
235      */
236     if ((l = _ucprop_offsets[n]) == 0xffff)
237       return 0;
238
239     /*
240      * Locate the next offset that is not 0xffff.  The sentinel at the end of
241      * the array is the max index value.
242      */
243     for (m = 1;
244          n + m < _ucprop_size && _ucprop_offsets[n + m] == 0xffff; m++) ;
245
246     r = _ucprop_offsets[n + m] - 1;
247
248     while (l <= r) {
249         /*
250          * Determine a "mid" point and adjust to make sure the mid point is at
251          * the beginning of a range pair.
252          */
253         m = (l + r) >> 1;
254         m -= (m & 1);
255         if (code > _ucprop_ranges[m + 1])
256           l = m + 2;
257         else if (code < _ucprop_ranges[m])
258           r = m - 2;
259         else if (code >= _ucprop_ranges[m] && code <= _ucprop_ranges[m + 1])
260           return 1;
261     }
262     return 0;
263 }
264
265 int
266 ucisprop(unsigned long code, unsigned long mask1, unsigned long mask2)
267 {
268     unsigned long i;
269
270     if (mask1 == 0 && mask2 == 0)
271       return 0;
272
273     for (i = 0; mask1 && i < 32; i++) {
274         if ((mask1 & masks32[i]) && _ucprop_lookup(code, i))
275           return 1;
276     }
277
278     for (i = 32; mask2 && i < _ucprop_size; i++) {
279         if ((mask2 & masks32[i & 31]) && _ucprop_lookup(code, i))
280           return 1;
281     }
282
283     return 0;
284 }
285
286 /**************************************************************************
287  *
288  * Support for case mapping.
289  *
290  **************************************************************************/
291
292 static unsigned long _uccase_size;
293 static unsigned short _uccase_len[2];
294 static unsigned long *_uccase_map;
295
296 /*
297  * Return -1 on error, 0 if okay
298  */
299 static int
300 _uccase_load(char *paths, int reload)
301 {
302     FILE *in;
303     unsigned long i;
304     _ucheader_t hdr;
305
306     if (_uccase_size > 0) {
307         if (!reload)
308           /*
309            * The case mappings have already been loaded.
310            */
311           return 0;
312
313         free((char *) _uccase_map);
314         _uccase_size = 0;
315     }
316
317     if ((in = _ucopenfile(paths, "case.dat", "rb")) == 0)
318       return -1;
319
320     /*
321      * Load the header.
322      */
323     fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
324
325     if (hdr.bom == 0xfffe) {
326         hdr.cnt = endian_short(hdr.cnt);
327         hdr.size.len[0] = endian_short(hdr.size.len[0]);
328         hdr.size.len[1] = endian_short(hdr.size.len[1]);
329     }
330
331     /*
332      * Set the node count and lengths of the upper and lower case mapping
333      * tables.
334      */
335     _uccase_size = hdr.cnt * 3;
336     _uccase_len[0] = hdr.size.len[0] * 3;
337     _uccase_len[1] = hdr.size.len[1] * 3;
338
339     _uccase_map = (unsigned long *)
340         malloc(_uccase_size * sizeof(unsigned long));
341
342     /*
343      * Load the case mapping table.
344      */
345     fread((char *) _uccase_map, sizeof(unsigned long), _uccase_size, in);
346
347     /*
348      * Do an endian swap if necessary.
349      */
350     if (hdr.bom == 0xfffe) {
351         for (i = 0; i < _uccase_size; i++)
352           _uccase_map[i] = endian_long(_uccase_map[i]);
353     }
354     fclose(in);
355     return 0;
356 }
357
358 static void
359 _uccase_unload(void)
360 {
361     if (_uccase_size == 0)
362       return;
363
364     free((char *) _uccase_map);
365     _uccase_size = 0;
366 }
367
368 static unsigned long
369 _uccase_lookup(unsigned long code, long l, long r, int field)
370 {
371     long m;
372
373     /*
374      * Do the binary search.
375      */
376     while (l <= r) {
377         /*
378          * Determine a "mid" point and adjust to make sure the mid point is at
379          * the beginning of a case mapping triple.
380          */
381         m = (l + r) >> 1;
382         m -= (m % 3);
383         if (code > _uccase_map[m])
384           l = m + 3;
385         else if (code < _uccase_map[m])
386           r = m - 3;
387         else if (code == _uccase_map[m])
388           return _uccase_map[m + field];
389     }
390
391     return code;
392 }
393
394 unsigned long
395 uctoupper(unsigned long code)
396 {
397     int field;
398     long l, r;
399
400     if (ucisupper(code))
401       return code;
402
403     if (ucislower(code)) {
404         /*
405          * The character is lower case.
406          */
407         field = 2;
408         l = _uccase_len[0];
409         r = (l + _uccase_len[1]) - 3;
410     } else {
411         /*
412          * The character is title case.
413          */
414         field = 1;
415         l = _uccase_len[0] + _uccase_len[1];
416         r = _uccase_size - 3;
417     }
418     return _uccase_lookup(code, l, r, field);
419 }
420
421 unsigned long
422 uctolower(unsigned long code)
423 {
424     int field;
425     long l, r;
426
427     if (ucislower(code))
428       return code;
429
430     if (ucisupper(code)) {
431         /*
432          * The character is upper case.
433          */
434         field = 1;
435         l = 0;
436         r = _uccase_len[0] - 3;
437     } else {
438         /*
439          * The character is title case.
440          */
441         field = 2;
442         l = _uccase_len[0] + _uccase_len[1];
443         r = _uccase_size - 3;
444     }
445     return _uccase_lookup(code, l, r, field);
446 }
447
448 unsigned long
449 uctotitle(unsigned long code)
450 {
451     int field;
452     long l, r;
453
454     if (ucistitle(code))
455       return code;
456
457     /*
458      * The offset will always be the same for converting to title case.
459      */
460     field = 2;
461
462     if (ucisupper(code)) {
463         /*
464          * The character is upper case.
465          */
466         l = 0;
467         r = _uccase_len[0] - 3;
468     } else {
469         /*
470          * The character is lower case.
471          */
472         l = _uccase_len[0];
473         r = (l + _uccase_len[1]) - 3;
474     }
475     return _uccase_lookup(code, l, r, field);
476 }
477
478 /**************************************************************************
479  *
480  * Support for compositions.
481  *
482  **************************************************************************/
483
484 static unsigned long  _uccomp_size;
485 static unsigned long *_uccomp_data;
486
487 /*
488  * Return -1 on error, 0 if okay
489  */
490 static int
491 _uccomp_load(char *paths, int reload)
492 {
493     FILE *in;
494     unsigned long size, i;
495     _ucheader_t hdr;
496
497     if (_uccomp_size > 0) {
498         if (!reload)
499             /*
500              * The compositions have already been loaded.
501              */
502             return 0;
503
504         free((char *) _uccomp_data);
505         _uccomp_size = 0;
506     }
507
508     if ((in = _ucopenfile(paths, "comp.dat", "rb")) == 0)
509         return -1;
510
511     /*
512      * Load the header.
513      */
514     fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
515
516     if (hdr.bom == 0xfffe) {
517         hdr.cnt = endian_short(hdr.cnt);
518         hdr.size.bytes = endian_long(hdr.size.bytes);
519     }
520
521     _uccomp_size = hdr.cnt;
522     _uccomp_data = (unsigned long *) malloc(hdr.size.bytes);
523
524     /*
525      * Read the composition data in.
526      */
527     size = hdr.size.bytes / sizeof(unsigned long);
528     fread((char *) _uccomp_data, sizeof(unsigned long), size, in);
529
530     /*
531      * Do an endian swap if necessary.
532      */
533     if (hdr.bom == 0xfffe) {
534         for (i = 0; i < size; i++)
535             _uccomp_data[i] = endian_long(_uccomp_data[i]);
536     }
537
538     /*
539      * Assume that the data is ordered on count, so that all compositions
540      * of length 2 come first. Only handling length 2 for now.
541      */
542     for (i = 1; i < size; i += 4)
543       if (_uccomp_data[i] != 2)
544         break;
545     _uccomp_size = i - 1;
546
547     fclose(in);
548     return 0;
549 }
550
551 static void
552 _uccomp_unload(void)
553 {
554     if (_uccomp_size == 0)
555         return;
556
557     free((char *) _uccomp_data);
558     _uccomp_size = 0;
559 }
560
561 int
562 uccomp(unsigned long node1, unsigned long node2, unsigned long *comp)
563 {
564     int l, r, m;
565
566     l = 0;
567     r = _uccomp_size - 1;
568
569     while (l <= r) {
570         m = ((r + l) >> 1);
571         m -= m & 3;
572         if (node1 > _uccomp_data[m+2])
573           l = m + 4;
574         else if (node1 < _uccomp_data[m+2])
575           r = m - 4;
576         else if (node2 > _uccomp_data[m+3])
577           l = m + 4;
578         else if (node2 < _uccomp_data[m+3])
579           r = m - 4;
580         else {
581             *comp = _uccomp_data[m];
582             return 1;
583         }
584     }
585     return 0;
586 }
587
588 int
589 uccomp_hangul(unsigned long *str, int len)
590 {
591     const int SBase = 0xAC00, LBase = 0x1100,
592         VBase = 0x1161, TBase = 0x11A7,
593         LCount = 19, VCount = 21, TCount = 28,
594         NCount = VCount * TCount,   /* 588 */
595         SCount = LCount * NCount;   /* 11172 */
596     
597     int i, rlen;
598     unsigned long ch, last, lindex, sindex;
599
600     last = str[0];
601     rlen = 1;
602     for ( i = 1; i < len; i++ ) {
603         ch = str[i];
604
605         /* check if two current characters are L and V */
606         lindex = last - LBase;
607         if (lindex < (unsigned long) LCount) {
608             unsigned long vindex = ch - VBase;
609             if (vindex < (unsigned long) VCount) {
610                 /* make syllable of form LV */
611                 last = SBase + (lindex * VCount + vindex) * TCount;
612                 str[rlen-1] = last; /* reset last */
613                 continue;
614             }
615         }
616         
617         /* check if two current characters are LV and T */
618         sindex = last - SBase;
619         if (sindex < (unsigned long) SCount
620                         && (sindex % TCount) == 0)
621                 {
622             unsigned long tindex = ch - TBase;
623             if (tindex <= (unsigned long) TCount) {
624                 /* make syllable of form LVT */
625                 last += tindex;
626                 str[rlen-1] = last; /* reset last */
627                 continue;
628             }
629         }
630
631         /* if neither case was true, just add the character */
632         last = ch;
633         str[rlen] = ch;
634         rlen++;
635     }
636     return rlen;
637 }
638
639 int
640 uccanoncomp(unsigned long *str, int len)
641 {
642     int i, stpos, copos;
643     unsigned long cl, prevcl, st, ch, co;
644
645     st = str[0];
646     stpos = 0;
647     copos = 1;
648     prevcl = uccombining_class(st) == 0 ? 0 : 256;
649         
650     for (i = 1; i < len; i++) {
651         ch = str[i];
652         cl = uccombining_class(ch);
653         if (uccomp(st, ch, &co) && (prevcl < cl || prevcl == 0))
654           st = str[stpos] = co;
655         else {
656             if (cl == 0) {
657                 stpos = copos;
658                 st = ch;
659             }
660             prevcl = cl;
661             str[copos++] = ch;
662         }
663     }
664
665     return uccomp_hangul(str, copos);
666 }
667
668 /**************************************************************************
669  *
670  * Support for decompositions.
671  *
672  **************************************************************************/
673
674 static unsigned long  _ucdcmp_size;
675 static unsigned long *_ucdcmp_nodes;
676 static unsigned long *_ucdcmp_decomp;
677
678 static unsigned long  _uckdcmp_size;
679 static unsigned long *_uckdcmp_nodes;
680 static unsigned long *_uckdcmp_decomp;
681
682 /*
683  * Return -1 on error, 0 if okay
684  */
685 static int
686 _ucdcmp_load(char *paths, int reload)
687 {
688     FILE *in;
689     unsigned long size, i;
690     _ucheader_t hdr;
691
692     if (_ucdcmp_size > 0) {
693         if (!reload)
694             /*
695              * The decompositions have already been loaded.
696              */
697           return 0;
698
699         free((char *) _ucdcmp_nodes);
700         _ucdcmp_size = 0;
701     }
702
703     if ((in = _ucopenfile(paths, "decomp.dat", "rb")) == 0)
704         return -1;
705
706     /*
707      * Load the header.
708      */
709     fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
710
711     if (hdr.bom == 0xfffe) {
712         hdr.cnt = endian_short(hdr.cnt);
713         hdr.size.bytes = endian_long(hdr.size.bytes);
714     }
715
716     _ucdcmp_size = hdr.cnt << 1;
717     _ucdcmp_nodes = (unsigned long *) malloc(hdr.size.bytes);
718     _ucdcmp_decomp = _ucdcmp_nodes + (_ucdcmp_size + 1);
719
720     /*
721      * Read the decomposition data in.
722      */
723     size = hdr.size.bytes / sizeof(unsigned long);
724     fread((char *) _ucdcmp_nodes, sizeof(unsigned long), size, in);
725
726     /*
727      * Do an endian swap if necessary.
728      */
729     if (hdr.bom == 0xfffe) {
730         for (i = 0; i < size; i++)
731             _ucdcmp_nodes[i] = endian_long(_ucdcmp_nodes[i]);
732     }
733     fclose(in);
734     return 0;
735 }
736
737 /*
738  * Return -1 on error, 0 if okay
739  */
740 static int
741 _uckdcmp_load(char *paths, int reload)
742 {
743     FILE *in;
744     unsigned long size, i;
745     _ucheader_t hdr;
746
747     if (_uckdcmp_size > 0) {
748         if (!reload)
749             /*
750              * The decompositions have already been loaded.
751              */
752           return 0;
753
754         free((char *) _uckdcmp_nodes);
755         _uckdcmp_size = 0;
756     }
757
758     if ((in = _ucopenfile(paths, "kdecomp.dat", "rb")) == 0)
759         return -1;
760
761     /*
762      * Load the header.
763      */
764     fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
765
766     if (hdr.bom == 0xfffe) {
767         hdr.cnt = endian_short(hdr.cnt);
768         hdr.size.bytes = endian_long(hdr.size.bytes);
769     }
770
771     _uckdcmp_size = hdr.cnt << 1;
772     _uckdcmp_nodes = (unsigned long *) malloc(hdr.size.bytes);
773     _uckdcmp_decomp = _uckdcmp_nodes + (_uckdcmp_size + 1);
774
775     /*
776      * Read the decomposition data in.
777      */
778     size = hdr.size.bytes / sizeof(unsigned long);
779     fread((char *) _uckdcmp_nodes, sizeof(unsigned long), size, in);
780
781     /*
782      * Do an endian swap if necessary.
783      */
784     if (hdr.bom == 0xfffe) {
785         for (i = 0; i < size; i++)
786             _uckdcmp_nodes[i] = endian_long(_uckdcmp_nodes[i]);
787     }
788     fclose(in);
789     return 0;
790 }
791
792 static void
793 _ucdcmp_unload(void)
794 {
795     if (_ucdcmp_size == 0)
796       return;
797
798     /*
799      * Only need to free the offsets because the memory is allocated as a
800      * single block.
801      */
802     free((char *) _ucdcmp_nodes);
803     _ucdcmp_size = 0;
804 }
805
806 static void
807 _uckdcmp_unload(void)
808 {
809     if (_uckdcmp_size == 0)
810       return;
811
812     /*
813      * Only need to free the offsets because the memory is allocated as a
814      * single block.
815      */
816     free((char *) _uckdcmp_nodes);
817     _uckdcmp_size = 0;
818 }
819
820 int
821 ucdecomp(unsigned long code, unsigned long *num, unsigned long **decomp)
822 {
823     long l, r, m;
824
825     if (code < _ucdcmp_nodes[0]) {
826         return 0;
827     }
828
829     l = 0;
830     r = _ucdcmp_nodes[_ucdcmp_size] - 1;
831
832     while (l <= r) {
833         /*
834          * Determine a "mid" point and adjust to make sure the mid point is at
835          * the beginning of a code+offset pair.
836          */
837         m = (l + r) >> 1;
838         m -= (m & 1);
839         if (code > _ucdcmp_nodes[m])
840           l = m + 2;
841         else if (code < _ucdcmp_nodes[m])
842           r = m - 2;
843         else if (code == _ucdcmp_nodes[m]) {
844             *num = _ucdcmp_nodes[m + 3] - _ucdcmp_nodes[m + 1];
845             *decomp = &_ucdcmp_decomp[_ucdcmp_nodes[m + 1]];
846             return 1;
847         }
848     }
849     return 0;
850 }
851
852 int
853 uckdecomp(unsigned long code, unsigned long *num, unsigned long **decomp)
854 {
855     long l, r, m;
856
857     if (code < _uckdcmp_nodes[0]) {
858         return 0;
859     }
860     
861     l = 0;
862     r = _uckdcmp_nodes[_uckdcmp_size] - 1;
863
864     while (l <= r) {
865         /*
866          * Determine a "mid" point and adjust to make sure the mid point is at
867          * the beginning of a code+offset pair.
868          */
869         m = (l + r) >> 1;
870         m -= (m & 1);
871         if (code > _uckdcmp_nodes[m])
872           l = m + 2;
873         else if (code < _uckdcmp_nodes[m])
874           r = m - 2;
875         else if (code == _uckdcmp_nodes[m]) {
876             *num = _uckdcmp_nodes[m + 3] - _uckdcmp_nodes[m + 1];
877             *decomp = &_uckdcmp_decomp[_uckdcmp_nodes[m + 1]];
878             return 1;
879         }
880     }
881     return 0;
882 }
883
884 int
885 ucdecomp_hangul(unsigned long code, unsigned long *num, unsigned long decomp[])
886 {
887     if (!ucishangul(code))
888       return 0;
889
890     code -= 0xac00;
891     decomp[0] = 0x1100 + (unsigned long) (code / 588);
892     decomp[1] = 0x1161 + (unsigned long) ((code % 588) / 28);
893     decomp[2] = 0x11a7 + (unsigned long) (code % 28);
894     *num = (decomp[2] != 0x11a7) ? 3 : 2;
895
896     return 1;
897 }
898
899 /* mode == 0 for canonical, mode == 1 for compatibility */
900 static int
901 uccanoncompatdecomp(const unsigned long *in, int inlen,
902                     unsigned long **out, int *outlen, short mode)
903 {
904     int l, size;
905         unsigned i, j, k;
906     unsigned long num, class, *decomp, hangdecomp[3];
907
908     size = inlen;
909     *out = (unsigned long *) malloc(size * sizeof(**out));
910     if (*out == NULL)
911         return *outlen = -1;
912
913     i = 0;
914     for (j = 0; j < (unsigned) inlen; j++) {
915         if (mode ? uckdecomp(in[j], &num, &decomp) : ucdecomp(in[j], &num, &decomp)) {
916             if ( size - i < num) {
917                 size = inlen + i - j + num - 1;
918                 *out = (unsigned long *) realloc(*out, size * sizeof(**out));
919                 if (*out == NULL)
920                     return *outlen = -1;
921             }
922             for (k = 0; k < num; k++) {
923                 class = uccombining_class(decomp[k]);
924                 if (class == 0) {
925                     (*out)[i] = decomp[k];
926                 } else {
927                     for (l = i; l > 0; l--)
928                         if (class >= uccombining_class((*out)[l-1]))
929                             break;
930                     AC_MEMCPY(*out + l + 1, *out + l, (i - l) * sizeof(**out));
931                     (*out)[l] = decomp[k];
932                 }
933                 i++;
934             }
935         } else if (ucdecomp_hangul(in[j], &num, hangdecomp)) {
936             if (size - i < num) {
937                 size = inlen + i - j + num - 1;
938                 *out = (unsigned long *) realloc(*out, size * sizeof(**out));
939                 if (*out == NULL)
940                     return *outlen = -1;
941             }
942             for (k = 0; k < num; k++) {
943                 (*out)[i] = hangdecomp[k];
944                 i++;
945             }
946         } else {
947             if (size - i < 1) {
948                 size = inlen + i - j;
949                 *out = (unsigned long *) realloc(*out, size * sizeof(**out));
950                 if (*out == NULL)
951                     return *outlen = -1;
952             }
953             class = uccombining_class(in[j]);
954             if (class == 0) {
955                 (*out)[i] = in[j];
956             } else {
957                 for (l = i; l > 0; l--)
958                     if (class >= uccombining_class((*out)[l-1]))
959                         break;
960                 AC_MEMCPY(*out + l + 1, *out + l, (i - l) * sizeof(**out));
961                 (*out)[l] = in[j];
962             }
963             i++;
964         }
965     }
966     return *outlen = i;
967 }
968
969 int
970 uccanondecomp(const unsigned long *in, int inlen,
971               unsigned long **out, int *outlen)
972 {
973     return uccanoncompatdecomp(in, inlen, out, outlen, 0);
974 }
975
976 int
977 uccompatdecomp(const unsigned long *in, int inlen,
978                unsigned long **out, int *outlen)
979 {
980     return uccanoncompatdecomp(in, inlen, out, outlen, 1);
981 }
982
983 /**************************************************************************
984  *
985  * Support for combining classes.
986  *
987  **************************************************************************/
988
989 static unsigned long  _uccmcl_size;
990 static unsigned long *_uccmcl_nodes;
991
992 /*
993  * Return -1 on error, 0 if okay
994  */
995 static int
996 _uccmcl_load(char *paths, int reload)
997 {
998     FILE *in;
999     unsigned long i;
1000     _ucheader_t hdr;
1001
1002     if (_uccmcl_size > 0) {
1003         if (!reload)
1004             /*
1005              * The combining classes have already been loaded.
1006              */
1007             return 0;
1008
1009         free((char *) _uccmcl_nodes);
1010         _uccmcl_size = 0;
1011     }
1012
1013     if ((in = _ucopenfile(paths, "cmbcl.dat", "rb")) == 0)
1014         return -1;
1015
1016     /*
1017      * Load the header.
1018      */
1019     fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
1020
1021     if (hdr.bom == 0xfffe) {
1022         hdr.cnt = endian_short(hdr.cnt);
1023         hdr.size.bytes = endian_long(hdr.size.bytes);
1024     }
1025
1026     _uccmcl_size = hdr.cnt * 3;
1027     _uccmcl_nodes = (unsigned long *) malloc(hdr.size.bytes);
1028
1029     /*
1030      * Read the combining classes in.
1031      */
1032     fread((char *) _uccmcl_nodes, sizeof(unsigned long), _uccmcl_size, in);
1033
1034     /*
1035      * Do an endian swap if necessary.
1036      */
1037     if (hdr.bom == 0xfffe) {
1038         for (i = 0; i < _uccmcl_size; i++)
1039             _uccmcl_nodes[i] = endian_long(_uccmcl_nodes[i]);
1040     }
1041     fclose(in);
1042     return 0;
1043 }
1044
1045 static void
1046 _uccmcl_unload(void)
1047 {
1048     if (_uccmcl_size == 0)
1049       return;
1050
1051     free((char *) _uccmcl_nodes);
1052     _uccmcl_size = 0;
1053 }
1054
1055 unsigned long
1056 uccombining_class(unsigned long code)
1057 {
1058     long l, r, m;
1059
1060     l = 0;
1061     r = _uccmcl_size - 1;
1062
1063     while (l <= r) {
1064         m = (l + r) >> 1;
1065         m -= (m % 3);
1066         if (code > _uccmcl_nodes[m + 1])
1067           l = m + 3;
1068         else if (code < _uccmcl_nodes[m])
1069           r = m - 3;
1070         else if (code >= _uccmcl_nodes[m] && code <= _uccmcl_nodes[m + 1])
1071           return _uccmcl_nodes[m + 2];
1072     }
1073     return 0;
1074 }
1075
1076 /**************************************************************************
1077  *
1078  * Support for numeric values.
1079  *
1080  **************************************************************************/
1081
1082 static unsigned long *_ucnum_nodes;
1083 static unsigned long _ucnum_size;
1084 static short *_ucnum_vals;
1085
1086 /*
1087  * Return -1 on error, 0 if okay
1088  */
1089 static int
1090 _ucnumb_load(char *paths, int reload)
1091 {
1092     FILE *in;
1093     unsigned long size, i;
1094     _ucheader_t hdr;
1095
1096     if (_ucnum_size > 0) {
1097         if (!reload)
1098           /*
1099            * The numbers have already been loaded.
1100            */
1101           return 0;
1102
1103         free((char *) _ucnum_nodes);
1104         _ucnum_size = 0;
1105     }
1106
1107     if ((in = _ucopenfile(paths, "num.dat", "rb")) == 0)
1108       return -1;
1109
1110     /*
1111      * Load the header.
1112      */
1113     fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
1114
1115     if (hdr.bom == 0xfffe) {
1116         hdr.cnt = endian_short(hdr.cnt);
1117         hdr.size.bytes = endian_long(hdr.size.bytes);
1118     }
1119
1120     _ucnum_size = hdr.cnt;
1121     _ucnum_nodes = (unsigned long *) malloc(hdr.size.bytes);
1122     _ucnum_vals = (short *) (_ucnum_nodes + _ucnum_size);
1123
1124     /*
1125      * Read the combining classes in.
1126      */
1127     fread((char *) _ucnum_nodes, sizeof(unsigned char), hdr.size.bytes, in);
1128
1129     /*
1130      * Do an endian swap if necessary.
1131      */
1132     if (hdr.bom == 0xfffe) {
1133         for (i = 0; i < _ucnum_size; i++)
1134           _ucnum_nodes[i] = endian_long(_ucnum_nodes[i]);
1135
1136         /*
1137          * Determine the number of values that have to be adjusted.
1138          */
1139         size = (hdr.size.bytes -
1140                 (_ucnum_size * (sizeof(unsigned long) << 1))) /
1141             sizeof(short);
1142
1143         for (i = 0; i < size; i++)
1144           _ucnum_vals[i] = endian_short(_ucnum_vals[i]);
1145     }
1146     fclose(in);
1147     return 0;
1148 }
1149
1150 static void
1151 _ucnumb_unload(void)
1152 {
1153     if (_ucnum_size == 0)
1154       return;
1155
1156     free((char *) _ucnum_nodes);
1157     _ucnum_size = 0;
1158 }
1159
1160 int
1161 ucnumber_lookup(unsigned long code, struct ucnumber *num)
1162 {
1163     long l, r, m;
1164     short *vp;
1165
1166     l = 0;
1167     r = _ucnum_size - 1;
1168     while (l <= r) {
1169         /*
1170          * Determine a "mid" point and adjust to make sure the mid point is at
1171          * the beginning of a code+offset pair.
1172          */
1173         m = (l + r) >> 1;
1174         m -= (m & 1);
1175         if (code > _ucnum_nodes[m])
1176           l = m + 2;
1177         else if (code < _ucnum_nodes[m])
1178           r = m - 2;
1179         else {
1180             vp = _ucnum_vals + _ucnum_nodes[m + 1];
1181             num->numerator = (int) *vp++;
1182             num->denominator = (int) *vp;
1183             return 1;
1184         }
1185     }
1186     return 0;
1187 }
1188
1189 int
1190 ucdigit_lookup(unsigned long code, int *digit)
1191 {
1192     long l, r, m;
1193     short *vp;
1194
1195     l = 0;
1196     r = _ucnum_size - 1;
1197     while (l <= r) {
1198         /*
1199          * Determine a "mid" point and adjust to make sure the mid point is at
1200          * the beginning of a code+offset pair.
1201          */
1202         m = (l + r) >> 1;
1203         m -= (m & 1);
1204         if (code > _ucnum_nodes[m])
1205           l = m + 2;
1206         else if (code < _ucnum_nodes[m])
1207           r = m - 2;
1208         else {
1209             vp = _ucnum_vals + _ucnum_nodes[m + 1];
1210             if (*vp == *(vp + 1)) {
1211               *digit = *vp;
1212               return 1;
1213             }
1214             return 0;
1215         }
1216     }
1217     return 0;
1218 }
1219
1220 struct ucnumber
1221 ucgetnumber(unsigned long code)
1222 {
1223     struct ucnumber num;
1224
1225     /*
1226      * Initialize with some arbitrary value, because the caller simply cannot
1227      * tell for sure if the code is a number without calling the ucisnumber()
1228      * macro before calling this function.
1229      */
1230     num.numerator = num.denominator = -111;
1231
1232     (void) ucnumber_lookup(code, &num);
1233
1234     return num;
1235 }
1236
1237 int
1238 ucgetdigit(unsigned long code)
1239 {
1240     int dig;
1241
1242     /*
1243      * Initialize with some arbitrary value, because the caller simply cannot
1244      * tell for sure if the code is a number without calling the ucisdigit()
1245      * macro before calling this function.
1246      */
1247     dig = -111;
1248
1249     (void) ucdigit_lookup(code, &dig);
1250
1251     return dig;
1252 }
1253
1254 /**************************************************************************
1255  *
1256  * Setup and cleanup routines.
1257  *
1258  **************************************************************************/
1259
1260 /*
1261  * Return 0 if okay, negative on error
1262  */
1263 int
1264 ucdata_load(char *paths, int masks)
1265 {
1266     int error = 0;
1267
1268     if (masks & UCDATA_CTYPE)
1269       error |= _ucprop_load(paths, 0) < 0 ? UCDATA_CTYPE : 0;
1270     if (masks & UCDATA_CASE)
1271       error |= _uccase_load(paths, 0) < 0 ? UCDATA_CASE : 0;
1272     if (masks & UCDATA_DECOMP)
1273       error |= _ucdcmp_load(paths, 0) < 0 ? UCDATA_DECOMP : 0;
1274     if (masks & UCDATA_CMBCL)
1275       error |= _uccmcl_load(paths, 0) < 0 ? UCDATA_CMBCL : 0;
1276     if (masks & UCDATA_NUM)
1277       error |= _ucnumb_load(paths, 0) < 0 ? UCDATA_NUM : 0;
1278     if (masks & UCDATA_COMP)
1279       error |= _uccomp_load(paths, 0) < 0 ? UCDATA_COMP : 0;
1280     if (masks & UCDATA_KDECOMP)
1281       error |= _uckdcmp_load(paths, 0) < 0 ? UCDATA_KDECOMP : 0;
1282
1283     return -error;
1284 }
1285
1286 void
1287 ucdata_unload(int masks)
1288 {
1289     if (masks & UCDATA_CTYPE)
1290       _ucprop_unload();
1291     if (masks & UCDATA_CASE)
1292       _uccase_unload();
1293     if (masks & UCDATA_DECOMP)
1294       _ucdcmp_unload();
1295     if (masks & UCDATA_CMBCL)
1296       _uccmcl_unload();
1297     if (masks & UCDATA_NUM)
1298       _ucnumb_unload();
1299     if (masks & UCDATA_COMP)
1300       _uccomp_unload();
1301     if (masks & UCDATA_KDECOMP)
1302       _uckdcmp_unload();
1303 }
1304
1305 /*
1306  * Return 0 if okay, negative on error
1307  */
1308 int
1309 ucdata_reload(char *paths, int masks)
1310 {
1311     int error = 0;
1312
1313     if (masks & UCDATA_CTYPE)
1314         error |= _ucprop_load(paths, 1) < 0 ? UCDATA_CTYPE : 0;
1315     if (masks & UCDATA_CASE)
1316         error |= _uccase_load(paths, 1) < 0 ? UCDATA_CASE : 0;
1317     if (masks & UCDATA_DECOMP)
1318         error |= _ucdcmp_load(paths, 1) < 0 ? UCDATA_DECOMP : 0;
1319     if (masks & UCDATA_CMBCL)
1320         error |= _uccmcl_load(paths, 1) < 0 ? UCDATA_CMBCL : 0;
1321     if (masks & UCDATA_NUM)
1322         error |= _ucnumb_load(paths, 1) < 0 ? UCDATA_NUM : 0;
1323     if (masks & UCDATA_COMP)
1324         error |= _uccomp_load(paths, 1) < 0 ? UCDATA_COMP : 0;
1325     if (masks & UCDATA_KDECOMP)
1326         error |= _uckdcmp_load(paths, 1) < 0 ? UCDATA_KDECOMP : 0;
1327
1328     return -error;
1329 }
1330
1331 #ifdef TEST
1332
1333 void
1334 main(void)
1335 {
1336     int dig;
1337     unsigned long i, lo, *dec;
1338     struct ucnumber num;
1339
1340     ucdata_setup(".");
1341
1342     if (ucisweak(0x30))
1343       printf("WEAK\n");
1344     else
1345       printf("NOT WEAK\n");
1346
1347     printf("LOWER 0x%04lX\n", uctolower(0xff3a));
1348     printf("UPPER 0x%04lX\n", uctoupper(0xff5a));
1349
1350     if (ucisalpha(0x1d5))
1351       printf("ALPHA\n");
1352     else
1353       printf("NOT ALPHA\n");
1354
1355     if (ucisupper(0x1d5)) {
1356         printf("UPPER\n");
1357         lo = uctolower(0x1d5);
1358         printf("0x%04lx\n", lo);
1359         lo = uctotitle(0x1d5);
1360         printf("0x%04lx\n", lo);
1361     } else
1362       printf("NOT UPPER\n");
1363
1364     if (ucistitle(0x1d5))
1365       printf("TITLE\n");
1366     else
1367       printf("NOT TITLE\n");
1368
1369     if (uciscomposite(0x1d5))
1370       printf("COMPOSITE\n");
1371     else
1372       printf("NOT COMPOSITE\n");
1373
1374     if (ucdecomp(0x1d5, &lo, &dec)) {
1375         for (i = 0; i < lo; i++)
1376           printf("0x%04lx ", dec[i]);
1377         putchar('\n');
1378     }
1379
1380     if ((lo = uccombining_class(0x41)) != 0)
1381       printf("0x41 CCL %ld\n", lo);
1382
1383     if (ucisxdigit(0xfeff))
1384       printf("0xFEFF HEX DIGIT\n");
1385     else
1386       printf("0xFEFF NOT HEX DIGIT\n");
1387
1388     if (ucisdefined(0x10000))
1389       printf("0x10000 DEFINED\n");
1390     else
1391       printf("0x10000 NOT DEFINED\n");
1392
1393     if (ucnumber_lookup(0x30, &num)) {
1394         if (num.numerator != num.denominator)
1395           printf("UCNUMBER: 0x30 = %d/%d\n", num.numerator, num.denominator);
1396         else
1397           printf("UCNUMBER: 0x30 = %d\n", num.numerator);
1398     } else
1399       printf("UCNUMBER: 0x30 NOT A NUMBER\n");
1400
1401     if (ucnumber_lookup(0xbc, &num)) {
1402         if (num.numerator != num.denominator)
1403           printf("UCNUMBER: 0xbc = %d/%d\n", num.numerator, num.denominator);
1404         else
1405           printf("UCNUMBER: 0xbc = %d\n", num.numerator);
1406     } else
1407       printf("UCNUMBER: 0xbc NOT A NUMBER\n");
1408
1409
1410     if (ucnumber_lookup(0xff19, &num)) {
1411         if (num.numerator != num.denominator)
1412           printf("UCNUMBER: 0xff19 = %d/%d\n", num.numerator, num.denominator);
1413         else
1414           printf("UCNUMBER: 0xff19 = %d\n", num.numerator);
1415     } else
1416       printf("UCNUMBER: 0xff19 NOT A NUMBER\n");
1417
1418     if (ucnumber_lookup(0x4e00, &num)) {
1419         if (num.numerator != num.denominator)
1420           printf("UCNUMBER: 0x4e00 = %d/%d\n", num.numerator, num.denominator);
1421         else
1422           printf("UCNUMBER: 0x4e00 = %d\n", num.numerator);
1423     } else
1424       printf("UCNUMBER: 0x4e00 NOT A NUMBER\n");
1425
1426     if (ucdigit_lookup(0x06f9, &dig))
1427       printf("UCDIGIT: 0x6f9 = %d\n", dig);
1428     else
1429       printf("UCDIGIT: 0x6f9 NOT A NUMBER\n");
1430
1431     dig = ucgetdigit(0x0969);
1432     printf("UCGETDIGIT: 0x969 = %d\n", dig);
1433
1434     num = ucgetnumber(0x30);
1435     if (num.numerator != num.denominator)
1436       printf("UCGETNUMBER: 0x30 = %d/%d\n", num.numerator, num.denominator);
1437     else
1438       printf("UCGETNUMBER: 0x30 = %d\n", num.numerator);
1439
1440     num = ucgetnumber(0xbc);
1441     if (num.numerator != num.denominator)
1442       printf("UCGETNUMBER: 0xbc = %d/%d\n", num.numerator, num.denominator);
1443     else
1444       printf("UCGETNUMBER: 0xbc = %d\n", num.numerator);
1445
1446     num = ucgetnumber(0xff19);
1447     if (num.numerator != num.denominator)
1448       printf("UCGETNUMBER: 0xff19 = %d/%d\n", num.numerator, num.denominator);
1449     else
1450       printf("UCGETNUMBER: 0xff19 = %d\n", num.numerator);
1451
1452     ucdata_cleanup();
1453     exit(0);
1454 }
1455
1456 #endif /* TEST */