3 * Copyright 2000 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * Copyright 2001 Computing Research Labs, New Mexico State University
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:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
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.
27 /* $Id: ucdata.c,v 1.4 2001/01/02 18:46:20 mleisher Exp $" */
33 #include <ac/string.h>
34 #include <ac/unistd.h>
39 /**************************************************************************
41 * Miscellaneous types, data, and support functions.
43 **************************************************************************/
50 unsigned short len[2];
55 * A simple array of 32-bit masks for lookup.
57 static unsigned long masks32[32] = {
58 0x00000001UL, 0x00000002UL, 0x00000004UL, 0x00000008UL,
59 0x00000010UL, 0x00000020UL, 0x00000040UL, 0x00000080UL,
60 0x00000100UL, 0x00000200UL, 0x00000400UL, 0x00000800UL,
61 0x00001000UL, 0x00002000UL, 0x00004000UL, 0x00008000UL,
62 0x00010000UL, 0x00020000UL, 0x00040000UL, 0x00080000UL,
63 0x00100000UL, 0x00200000UL, 0x00400000UL, 0x00800000UL,
64 0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL,
65 0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL
68 #define endian_short(cc) (((cc) >> 8) | (((cc) & 0xff) << 8))
69 #define endian_long(cc) ((((cc) & 0xff) << 24)|((((cc) >> 8) & 0xff) << 16)|\
70 ((((cc) >> 16) & 0xff) << 8)|((cc) >> 24))
73 _ucopenfile(char *paths, char *filename, char *mode)
76 char *fp, *dp, *pp, path[BUFSIZ];
78 if (filename == 0 || *filename == 0)
84 while (*dp && *dp != ':')
93 if ((f = fopen(path, mode)) != 0)
103 /**************************************************************************
105 * Support for the character properties.
107 **************************************************************************/
109 static unsigned long _ucprop_size;
110 static unsigned short *_ucprop_offsets;
111 static unsigned long *_ucprop_ranges;
114 * Return -1 on error, 0 if okay
117 _ucprop_load(char *paths, int reload)
120 unsigned long size, i;
123 if (_ucprop_size > 0) {
126 * The character properties have already been loaded.
131 * Unload the current character property data in preparation for
132 * loading a new copy. Only the first array has to be deallocated
133 * because all the memory for the arrays is allocated as a single
136 free((char *) _ucprop_offsets);
140 if ((in = _ucopenfile(paths, "ctype.dat", "rb")) == 0)
146 fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
148 if (hdr.bom == 0xfffe) {
149 hdr.cnt = endian_short(hdr.cnt);
150 hdr.size.bytes = endian_long(hdr.size.bytes);
153 if ((_ucprop_size = hdr.cnt) == 0) {
159 * Allocate all the storage needed for the lookup table.
161 _ucprop_offsets = (unsigned short *) malloc(hdr.size.bytes);
164 * Calculate the offset into the storage for the ranges. The offsets
165 * array is on a 4-byte boundary and one larger than the value provided in
166 * the header count field. This means the offset to the ranges must be
167 * calculated after aligning the count to a 4-byte boundary.
169 if ((size = ((hdr.cnt + 1) * sizeof(unsigned short))) & 3)
170 size += 4 - (size & 3);
172 _ucprop_ranges = (unsigned long *) (_ucprop_offsets + size);
175 * Load the offset array.
177 fread((char *) _ucprop_offsets, sizeof(unsigned short), size, in);
180 * Do an endian swap if necessary. Don't forget there is an extra node on
181 * the end with the final index.
183 if (hdr.bom == 0xfffe) {
184 for (i = 0; i <= _ucprop_size; i++)
185 _ucprop_offsets[i] = endian_short(_ucprop_offsets[i]);
189 * Load the ranges. The number of elements is in the last array position
192 fread((char *) _ucprop_ranges, sizeof(unsigned long),
193 _ucprop_offsets[_ucprop_size], in);
198 * Do an endian swap if necessary.
200 if (hdr.bom == 0xfffe) {
201 for (i = 0; i < _ucprop_offsets[_ucprop_size]; i++)
202 _ucprop_ranges[i] = endian_long(_ucprop_ranges[i]);
210 if (_ucprop_size == 0)
214 * Only need to free the offsets because the memory is allocated as a
217 free((char *) _ucprop_offsets);
222 _ucprop_lookup(unsigned long code, unsigned long n)
227 * There is an extra node on the end of the offsets to allow this routine
228 * to work right. If the index is 0xffff, then there are no nodes for the
231 if ((l = _ucprop_offsets[n]) == 0xffff)
235 * Locate the next offset that is not 0xffff. The sentinel at the end of
236 * the array is the max index value.
239 n + m < _ucprop_size && _ucprop_offsets[n + m] == 0xffff; m++) ;
241 r = _ucprop_offsets[n + m] - 1;
245 * Determine a "mid" point and adjust to make sure the mid point is at
246 * the beginning of a range pair.
250 if (code > _ucprop_ranges[m + 1])
252 else if (code < _ucprop_ranges[m])
254 else if (code >= _ucprop_ranges[m] && code <= _ucprop_ranges[m + 1])
261 ucisprop(unsigned long code, unsigned long mask1, unsigned long mask2)
265 if (mask1 == 0 && mask2 == 0)
268 for (i = 0; mask1 && i < 32; i++) {
269 if ((mask1 & masks32[i]) && _ucprop_lookup(code, i))
273 for (i = 32; mask2 && i < _ucprop_size; i++) {
274 if ((mask2 & masks32[i & 31]) && _ucprop_lookup(code, i))
281 /**************************************************************************
283 * Support for case mapping.
285 **************************************************************************/
287 static unsigned long _uccase_size;
288 static unsigned short _uccase_len[2];
289 static unsigned long *_uccase_map;
292 * Return -1 on error, 0 if okay
295 _uccase_load(char *paths, int reload)
301 if (_uccase_size > 0) {
304 * The case mappings have already been loaded.
308 free((char *) _uccase_map);
312 if ((in = _ucopenfile(paths, "case.dat", "rb")) == 0)
318 fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
320 if (hdr.bom == 0xfffe) {
321 hdr.cnt = endian_short(hdr.cnt);
322 hdr.size.len[0] = endian_short(hdr.size.len[0]);
323 hdr.size.len[1] = endian_short(hdr.size.len[1]);
327 * Set the node count and lengths of the upper and lower case mapping
330 _uccase_size = hdr.cnt * 3;
331 _uccase_len[0] = hdr.size.len[0] * 3;
332 _uccase_len[1] = hdr.size.len[1] * 3;
334 _uccase_map = (unsigned long *)
335 malloc(_uccase_size * sizeof(unsigned long));
338 * Load the case mapping table.
340 fread((char *) _uccase_map, sizeof(unsigned long), _uccase_size, in);
343 * Do an endian swap if necessary.
345 if (hdr.bom == 0xfffe) {
346 for (i = 0; i < _uccase_size; i++)
347 _uccase_map[i] = endian_long(_uccase_map[i]);
355 if (_uccase_size == 0)
358 free((char *) _uccase_map);
363 _uccase_lookup(unsigned long code, long l, long r, int field)
368 * Do the binary search.
372 * Determine a "mid" point and adjust to make sure the mid point is at
373 * the beginning of a case mapping triple.
377 if (code > _uccase_map[m])
379 else if (code < _uccase_map[m])
381 else if (code == _uccase_map[m])
382 return _uccase_map[m + field];
389 uctoupper(unsigned long code)
397 if (ucislower(code)) {
399 * The character is lower case.
403 r = (l + _uccase_len[1]) - 3;
406 * The character is title case.
409 l = _uccase_len[0] + _uccase_len[1];
410 r = _uccase_size - 3;
412 return _uccase_lookup(code, l, r, field);
416 uctolower(unsigned long code)
424 if (ucisupper(code)) {
426 * The character is upper case.
430 r = _uccase_len[0] - 3;
433 * The character is title case.
436 l = _uccase_len[0] + _uccase_len[1];
437 r = _uccase_size - 3;
439 return _uccase_lookup(code, l, r, field);
443 uctotitle(unsigned long code)
452 * The offset will always be the same for converting to title case.
456 if (ucisupper(code)) {
458 * The character is upper case.
461 r = _uccase_len[0] - 3;
464 * The character is lower case.
467 r = (l + _uccase_len[1]) - 3;
469 return _uccase_lookup(code, l, r, field);
472 /**************************************************************************
474 * Support for compositions.
476 **************************************************************************/
478 static unsigned long _uccomp_size;
479 static unsigned long *_uccomp_data;
482 * Return -1 on error, 0 if okay
485 _uccomp_load(char *paths, int reload)
488 unsigned long size, i;
491 if (_uccomp_size > 0) {
494 * The compositions have already been loaded.
498 free((char *) _uccomp_data);
502 if ((in = _ucopenfile(paths, "comp.dat", "rb")) == 0)
508 fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
510 if (hdr.bom == 0xfffe) {
511 hdr.cnt = endian_short(hdr.cnt);
512 hdr.size.bytes = endian_long(hdr.size.bytes);
515 _uccomp_size = hdr.cnt;
516 _uccomp_data = (unsigned long *) malloc(hdr.size.bytes);
519 * Read the composition data in.
521 size = hdr.size.bytes / sizeof(unsigned long);
522 fread((char *) _uccomp_data, sizeof(unsigned long), size, in);
525 * Do an endian swap if necessary.
527 if (hdr.bom == 0xfffe) {
528 for (i = 0; i < size; i++)
529 _uccomp_data[i] = endian_long(_uccomp_data[i]);
533 * Assume that the data is ordered on count, so that all compositions
534 * of length 2 come first. Only handling length 2 for now.
536 for (i = 1; i < size; i += 4)
537 if (_uccomp_data[i] != 2)
539 _uccomp_size = i - 1;
547 if (_uccomp_size == 0)
550 free((char *) _uccomp_data);
555 uccomp(unsigned long node1, unsigned long node2, unsigned long *comp)
560 r = _uccomp_size - 1;
565 if (node1 > _uccomp_data[m+2])
567 else if (node1 < _uccomp_data[m+2])
569 else if (node2 > _uccomp_data[m+3])
571 else if (node2 < _uccomp_data[m+3])
574 *comp = _uccomp_data[m];
582 uccomp_hangul(unsigned long *str, int len)
584 const int SBase = 0xAC00, LBase = 0x1100,
585 VBase = 0x1161, TBase = 0x11A7,
586 LCount = 19, VCount = 21, TCount = 28,
587 NCount = VCount * TCount, /* 588 */
588 SCount = LCount * NCount; /* 11172 */
591 unsigned long ch, last, lindex, sindex;
595 for ( i = 1; i < len; i++ ) {
598 /* check if two current characters are L and V */
599 lindex = last - LBase;
600 if (0 <= lindex && lindex < LCount) {
601 unsigned long vindex = ch - VBase;
602 if (0 <= vindex && vindex < VCount) {
603 /* make syllable of form LV */
604 last = SBase + (lindex * VCount + vindex) * TCount;
605 str[rlen-1] = last; /* reset last */
610 /* check if two current characters are LV and T */
611 sindex = last - SBase;
612 if (0 <= sindex && sindex < SCount && (sindex % TCount) == 0) {
613 unsigned long tindex = ch - TBase;
614 if (0 <= tindex && tindex <= TCount) {
615 /* make syllable of form LVT */
617 str[rlen-1] = last; /* reset last */
622 /* if neither case was true, just add the character */
631 uccanoncomp(unsigned long *str, int len)
634 unsigned long cl, prevcl, st, ch, co;
639 prevcl = uccombining_class(st) == 0 ? 0 : 256;
641 for (i = 1; i < len; i++) {
643 cl = uccombining_class(ch);
644 if (uccomp(st, ch, &co) && (prevcl < cl || prevcl == 0))
645 st = str[stpos] = co;
656 return uccomp_hangul(str, copos);
659 /**************************************************************************
661 * Support for decompositions.
663 **************************************************************************/
665 static unsigned long _ucdcmp_size;
666 static unsigned long *_ucdcmp_nodes;
667 static unsigned long *_ucdcmp_decomp;
670 * Return -1 on error, 0 if okay
673 _ucdcmp_load(char *paths, int reload)
676 unsigned long size, i;
679 if (_ucdcmp_size > 0) {
682 * The decompositions have already been loaded.
686 free((char *) _ucdcmp_nodes);
690 if ((in = _ucopenfile(paths, "decomp.dat", "rb")) == 0)
696 fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
698 if (hdr.bom == 0xfffe) {
699 hdr.cnt = endian_short(hdr.cnt);
700 hdr.size.bytes = endian_long(hdr.size.bytes);
703 _ucdcmp_size = hdr.cnt << 1;
704 _ucdcmp_nodes = (unsigned long *) malloc(hdr.size.bytes);
705 _ucdcmp_decomp = _ucdcmp_nodes + (_ucdcmp_size + 1);
708 * Read the decomposition data in.
710 size = hdr.size.bytes / sizeof(unsigned long);
711 fread((char *) _ucdcmp_nodes, sizeof(unsigned long), size, in);
714 * Do an endian swap if necessary.
716 if (hdr.bom == 0xfffe) {
717 for (i = 0; i < size; i++)
718 _ucdcmp_nodes[i] = endian_long(_ucdcmp_nodes[i]);
726 if (_ucdcmp_size == 0)
730 * Only need to free the offsets because the memory is allocated as a
733 free((char *) _ucdcmp_nodes);
738 ucdecomp(unsigned long code, unsigned long *num, unsigned long **decomp)
743 r = _ucdcmp_nodes[_ucdcmp_size] - 1;
747 * Determine a "mid" point and adjust to make sure the mid point is at
748 * the beginning of a code+offset pair.
752 if (code > _ucdcmp_nodes[m])
754 else if (code < _ucdcmp_nodes[m])
756 else if (code == _ucdcmp_nodes[m]) {
757 *num = _ucdcmp_nodes[m + 3] - _ucdcmp_nodes[m + 1];
758 *decomp = &_ucdcmp_decomp[_ucdcmp_nodes[m + 1]];
766 ucdecomp_hangul(unsigned long code, unsigned long *num, unsigned long decomp[])
768 if (!ucishangul(code))
772 decomp[0] = 0x1100 + (unsigned long) (code / 588);
773 decomp[1] = 0x1161 + (unsigned long) ((code % 588) / 28);
774 decomp[2] = 0x11a7 + (unsigned long) (code % 28);
775 *num = (decomp[2] != 0x11a7) ? 3 : 2;
781 uccanondecomp(const unsigned long *in, int inlen,
782 unsigned long **out, int *outlen)
784 int i, j, k, l, size;
785 unsigned long num, class, *decomp, hangdecomp[3];
788 *out = (unsigned long *) malloc(size * sizeof(**out));
793 for (j = 0; j < inlen; j++) {
794 if (ucdecomp(in[j], &num, &decomp)) {
795 if (size - i < num) {
796 size = inlen + i - j + num - 1;
797 *out = (unsigned long *) realloc(*out, size * sizeof(**out));
801 for (k = 0; k < num; k++) {
802 class = uccombining_class(decomp[k]);
804 (*out)[i] = decomp[k];
806 for (l = i; l > 0; l--)
807 if (class >= uccombining_class((*out)[l-1]))
809 memmove(*out + l + 1, *out + l, (i - l) * sizeof(**out));
810 (*out)[l] = decomp[k];
814 } else if (ucdecomp_hangul(in[j], &num, hangdecomp)) {
815 if (size - i < num) {
816 size = inlen + i - j + num - 1;
817 *out = (unsigned long *) realloc(*out, size * sizeof(**out));
821 for (k = 0; k < num; k++) {
822 (*out)[i] = hangdecomp[k];
827 size = inlen + i - j;
828 *out = (unsigned long *) realloc(*out, size * sizeof(**out));
832 class = uccombining_class(in[j]);
836 for (l = i; l > 0; l--)
837 if (class >= uccombining_class((*out)[l-1]))
839 memmove(*out + l + 1, *out + l, (i - l) * sizeof(**out));
848 /**************************************************************************
850 * Support for combining classes.
852 **************************************************************************/
854 static unsigned long _uccmcl_size;
855 static unsigned long *_uccmcl_nodes;
858 * Return -1 on error, 0 if okay
861 _uccmcl_load(char *paths, int reload)
867 if (_uccmcl_size > 0) {
870 * The combining classes have already been loaded.
874 free((char *) _uccmcl_nodes);
878 if ((in = _ucopenfile(paths, "cmbcl.dat", "rb")) == 0)
884 fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
886 if (hdr.bom == 0xfffe) {
887 hdr.cnt = endian_short(hdr.cnt);
888 hdr.size.bytes = endian_long(hdr.size.bytes);
891 _uccmcl_size = hdr.cnt * 3;
892 _uccmcl_nodes = (unsigned long *) malloc(hdr.size.bytes);
895 * Read the combining classes in.
897 fread((char *) _uccmcl_nodes, sizeof(unsigned long), _uccmcl_size, in);
900 * Do an endian swap if necessary.
902 if (hdr.bom == 0xfffe) {
903 for (i = 0; i < _uccmcl_size; i++)
904 _uccmcl_nodes[i] = endian_long(_uccmcl_nodes[i]);
912 if (_uccmcl_size == 0)
915 free((char *) _uccmcl_nodes);
920 uccombining_class(unsigned long code)
925 r = _uccmcl_size - 1;
930 if (code > _uccmcl_nodes[m + 1])
932 else if (code < _uccmcl_nodes[m])
934 else if (code >= _uccmcl_nodes[m] && code <= _uccmcl_nodes[m + 1])
935 return _uccmcl_nodes[m + 2];
940 /**************************************************************************
942 * Support for numeric values.
944 **************************************************************************/
946 static unsigned long *_ucnum_nodes;
947 static unsigned long _ucnum_size;
948 static short *_ucnum_vals;
951 * Return -1 on error, 0 if okay
954 _ucnumb_load(char *paths, int reload)
957 unsigned long size, i;
960 if (_ucnum_size > 0) {
963 * The numbers have already been loaded.
967 free((char *) _ucnum_nodes);
971 if ((in = _ucopenfile(paths, "num.dat", "rb")) == 0)
977 fread((char *) &hdr, sizeof(_ucheader_t), 1, in);
979 if (hdr.bom == 0xfffe) {
980 hdr.cnt = endian_short(hdr.cnt);
981 hdr.size.bytes = endian_long(hdr.size.bytes);
984 _ucnum_size = hdr.cnt;
985 _ucnum_nodes = (unsigned long *) malloc(hdr.size.bytes);
986 _ucnum_vals = (short *) (_ucnum_nodes + _ucnum_size);
989 * Read the combining classes in.
991 fread((char *) _ucnum_nodes, sizeof(unsigned char), hdr.size.bytes, in);
994 * Do an endian swap if necessary.
996 if (hdr.bom == 0xfffe) {
997 for (i = 0; i < _ucnum_size; i++)
998 _ucnum_nodes[i] = endian_long(_ucnum_nodes[i]);
1001 * Determine the number of values that have to be adjusted.
1003 size = (hdr.size.bytes -
1004 (_ucnum_size * (sizeof(unsigned long) << 1))) /
1007 for (i = 0; i < size; i++)
1008 _ucnum_vals[i] = endian_short(_ucnum_vals[i]);
1014 _ucnumb_unload(void)
1016 if (_ucnum_size == 0)
1019 free((char *) _ucnum_nodes);
1024 ucnumber_lookup(unsigned long code, struct ucnumber *num)
1030 r = _ucnum_size - 1;
1033 * Determine a "mid" point and adjust to make sure the mid point is at
1034 * the beginning of a code+offset pair.
1038 if (code > _ucnum_nodes[m])
1040 else if (code < _ucnum_nodes[m])
1043 vp = _ucnum_vals + _ucnum_nodes[m + 1];
1044 num->numerator = (int) *vp++;
1045 num->denominator = (int) *vp;
1053 ucdigit_lookup(unsigned long code, int *digit)
1059 r = _ucnum_size - 1;
1062 * Determine a "mid" point and adjust to make sure the mid point is at
1063 * the beginning of a code+offset pair.
1067 if (code > _ucnum_nodes[m])
1069 else if (code < _ucnum_nodes[m])
1072 vp = _ucnum_vals + _ucnum_nodes[m + 1];
1073 if (*vp == *(vp + 1)) {
1084 ucgetnumber(unsigned long code)
1086 struct ucnumber num;
1089 * Initialize with some arbitrary value, because the caller simply cannot
1090 * tell for sure if the code is a number without calling the ucisnumber()
1091 * macro before calling this function.
1093 num.numerator = num.denominator = -111;
1095 (void) ucnumber_lookup(code, &num);
1101 ucgetdigit(unsigned long code)
1106 * Initialize with some arbitrary value, because the caller simply cannot
1107 * tell for sure if the code is a number without calling the ucisdigit()
1108 * macro before calling this function.
1112 (void) ucdigit_lookup(code, &dig);
1117 /**************************************************************************
1119 * Setup and cleanup routines.
1121 **************************************************************************/
1124 * Return 0 if okay, negative on error
1127 ucdata_load(char *paths, int masks)
1131 if (masks & UCDATA_CTYPE)
1132 error |= _ucprop_load(paths, 0) < 0 ? UCDATA_CTYPE : 0;
1133 if (masks & UCDATA_CASE)
1134 error |= _uccase_load(paths, 0) < 0 ? UCDATA_CASE : 0;
1135 if (masks & UCDATA_DECOMP)
1136 error |= _ucdcmp_load(paths, 0) < 0 ? UCDATA_DECOMP : 0;
1137 if (masks & UCDATA_CMBCL)
1138 error |= _uccmcl_load(paths, 0) < 0 ? UCDATA_CMBCL : 0;
1139 if (masks & UCDATA_NUM)
1140 error |= _ucnumb_load(paths, 0) < 0 ? UCDATA_NUM : 0;
1141 if (masks & UCDATA_COMP)
1142 error |= _uccomp_load(paths, 0) < 0 ? UCDATA_COMP : 0;
1148 ucdata_unload(int masks)
1150 if (masks & UCDATA_CTYPE)
1152 if (masks & UCDATA_CASE)
1154 if (masks & UCDATA_DECOMP)
1156 if (masks & UCDATA_CMBCL)
1158 if (masks & UCDATA_NUM)
1160 if (masks & UCDATA_COMP)
1165 * Return 0 if okay, negative on error
1168 ucdata_reload(char *paths, int masks)
1172 if (masks & UCDATA_CTYPE)
1173 error |= _ucprop_load(paths, 1) < 0 ? UCDATA_CTYPE : 0;
1174 if (masks & UCDATA_CASE)
1175 error |= _uccase_load(paths, 1) < 0 ? UCDATA_CASE : 0;
1176 if (masks & UCDATA_DECOMP)
1177 error |= _ucdcmp_load(paths, 1) < 0 ? UCDATA_DECOMP : 0;
1178 if (masks & UCDATA_CMBCL)
1179 error |= _uccmcl_load(paths, 1) < 0 ? UCDATA_CMBCL : 0;
1180 if (masks & UCDATA_NUM)
1181 error |= _ucnumb_load(paths, 1) < 0 ? UCDATA_NUM : 0;
1182 if (masks & UCDATA_COMP)
1183 error |= _uccomp_load(paths, 1) < 0 ? UCDATA_COMP : 0;
1194 unsigned long i, lo, *dec;
1195 struct ucnumber num;
1202 printf("NOT WEAK\n");
1204 printf("LOWER 0x%04lX\n", uctolower(0xff3a));
1205 printf("UPPER 0x%04lX\n", uctoupper(0xff5a));
1207 if (ucisalpha(0x1d5))
1210 printf("NOT ALPHA\n");
1212 if (ucisupper(0x1d5)) {
1214 lo = uctolower(0x1d5);
1215 printf("0x%04lx\n", lo);
1216 lo = uctotitle(0x1d5);
1217 printf("0x%04lx\n", lo);
1219 printf("NOT UPPER\n");
1221 if (ucistitle(0x1d5))
1224 printf("NOT TITLE\n");
1226 if (uciscomposite(0x1d5))
1227 printf("COMPOSITE\n");
1229 printf("NOT COMPOSITE\n");
1231 if (ucdecomp(0x1d5, &lo, &dec)) {
1232 for (i = 0; i < lo; i++)
1233 printf("0x%04lx ", dec[i]);
1237 if ((lo = uccombining_class(0x41)) != 0)
1238 printf("0x41 CCL %ld\n", lo);
1240 if (ucisxdigit(0xfeff))
1241 printf("0xFEFF HEX DIGIT\n");
1243 printf("0xFEFF NOT HEX DIGIT\n");
1245 if (ucisdefined(0x10000))
1246 printf("0x10000 DEFINED\n");
1248 printf("0x10000 NOT DEFINED\n");
1250 if (ucnumber_lookup(0x30, &num)) {
1251 if (num.numerator != num.denominator)
1252 printf("UCNUMBER: 0x30 = %d/%d\n", num.numerator, num.denominator);
1254 printf("UCNUMBER: 0x30 = %d\n", num.numerator);
1256 printf("UCNUMBER: 0x30 NOT A NUMBER\n");
1258 if (ucnumber_lookup(0xbc, &num)) {
1259 if (num.numerator != num.denominator)
1260 printf("UCNUMBER: 0xbc = %d/%d\n", num.numerator, num.denominator);
1262 printf("UCNUMBER: 0xbc = %d\n", num.numerator);
1264 printf("UCNUMBER: 0xbc NOT A NUMBER\n");
1267 if (ucnumber_lookup(0xff19, &num)) {
1268 if (num.numerator != num.denominator)
1269 printf("UCNUMBER: 0xff19 = %d/%d\n", num.numerator, num.denominator);
1271 printf("UCNUMBER: 0xff19 = %d\n", num.numerator);
1273 printf("UCNUMBER: 0xff19 NOT A NUMBER\n");
1275 if (ucnumber_lookup(0x4e00, &num)) {
1276 if (num.numerator != num.denominator)
1277 printf("UCNUMBER: 0x4e00 = %d/%d\n", num.numerator, num.denominator);
1279 printf("UCNUMBER: 0x4e00 = %d\n", num.numerator);
1281 printf("UCNUMBER: 0x4e00 NOT A NUMBER\n");
1283 if (ucdigit_lookup(0x06f9, &dig))
1284 printf("UCDIGIT: 0x6f9 = %d\n", dig);
1286 printf("UCDIGIT: 0x6f9 NOT A NUMBER\n");
1288 dig = ucgetdigit(0x0969);
1289 printf("UCGETDIGIT: 0x969 = %d\n", dig);
1291 num = ucgetnumber(0x30);
1292 if (num.numerator != num.denominator)
1293 printf("UCGETNUMBER: 0x30 = %d/%d\n", num.numerator, num.denominator);
1295 printf("UCGETNUMBER: 0x30 = %d\n", num.numerator);
1297 num = ucgetnumber(0xbc);
1298 if (num.numerator != num.denominator)
1299 printf("UCGETNUMBER: 0xbc = %d/%d\n", num.numerator, num.denominator);
1301 printf("UCGETNUMBER: 0xbc = %d\n", num.numerator);
1303 num = ucgetnumber(0xff19);
1304 if (num.numerator != num.denominator)
1305 printf("UCGETNUMBER: 0xff19 = %d/%d\n", num.numerator, num.denominator);
1307 printf("UCGETNUMBER: 0xff19 = %d\n", num.numerator);