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