• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ********************************************************************************
3 *   Copyright (C) 1996-2007, International Business Machines
4 *   Corporation and others.  All Rights Reserved.
5 ********************************************************************************
6 *
7 * File UCHAR.C
8 *
9 * Modification History:
10 *
11 *   Date        Name        Description
12 *   04/02/97    aliu        Creation.
13 *   4/15/99     Madhu       Updated all the function definitions for C Implementation
14 *   5/20/99     Madhu       Added the function u_getVersion()
15 *   8/19/1999   srl         Upgraded scripts to Unicode3.0
16 *   11/11/1999  weiv        added u_isalnum(), cleaned comments
17 *   01/11/2000  helena      Renamed u_getVersion to u_getUnicodeVersion.
18 *   06/20/2000  helena      OS/400 port changes; mostly typecast.
19 ******************************************************************************
20 */
21 
22 #include "unicode/utypes.h"
23 #include "unicode/uchar.h"
24 #include "unicode/uscript.h"
25 #include "unicode/udata.h"
26 #include "umutex.h"
27 #include "cmemory.h"
28 #include "ucln_cmn.h"
29 #include "utrie.h"
30 #include "udataswp.h"
31 #include "unormimp.h" /* JAMO_L_BASE etc. */
32 #include "uprops.h"
33 
34 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
35 
36 /* dynamically loaded Unicode character properties -------------------------- */
37 
38 #define UCHAR_HARDCODE_DATA 1
39 
40 #if UCHAR_HARDCODE_DATA
41 
42 /* uchar_props_data.c is machine-generated by genprops --csource */
43 #include "uchar_props_data.c"
44 
45 #else
46 
47 /*
48  * loaded uprops.dat -
49  * for a description of the file format, see icu/source/tools/genprops/store.c
50  */
51 static const char DATA_NAME[] = "uprops";
52 static const char DATA_TYPE[] = "icu";
53 
54 static UDataMemory *propsData=NULL;
55 static UErrorCode dataErrorCode=U_ZERO_ERROR;
56 
57 static uint8_t formatVersion[4]={ 0, 0, 0, 0 };
58 static UVersionInfo dataVersion={ 0, 0, 0, 0 };
59 
60 static UTrie propsTrie={ 0 }, propsVectorsTrie={ 0 };
61 static const uint32_t *pData32=NULL, *propsVectors=NULL;
62 static int32_t countPropsVectors=0, propsVectorsColumns=0;
63 
64 static int8_t havePropsData=0;     /*  == 0   ->  Data has not been loaded.
65                                     *   < 0   ->  Error occured attempting to load data.
66                                     *   > 0   ->  Data has been successfully loaded.
67                                     */
68 
69 /* index values loaded from uprops.dat */
70 static int32_t indexes[UPROPS_INDEX_COUNT];
71 
72 static UBool U_CALLCONV
isAcceptable(void * context,const char * type,const char * name,const UDataInfo * pInfo)73 isAcceptable(void *context,
74              const char *type, const char *name,
75              const UDataInfo *pInfo) {
76     if(
77         pInfo->size>=20 &&
78         pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
79         pInfo->charsetFamily==U_CHARSET_FAMILY &&
80         pInfo->dataFormat[0]==0x55 &&   /* dataFormat="UPro" */
81         pInfo->dataFormat[1]==0x50 &&
82         pInfo->dataFormat[2]==0x72 &&
83         pInfo->dataFormat[3]==0x6f &&
84         pInfo->formatVersion[0]==4 &&
85         pInfo->formatVersion[2]==UTRIE_SHIFT &&
86         pInfo->formatVersion[3]==UTRIE_INDEX_SHIFT
87     ) {
88         uprv_memcpy(formatVersion, pInfo->formatVersion, 4);
89         uprv_memcpy(dataVersion, pInfo->dataVersion, 4);
90         return TRUE;
91     } else {
92         return FALSE;
93     }
94 }
95 
uchar_cleanup(void)96 static UBool U_CALLCONV uchar_cleanup(void)
97 {
98     if (propsData) {
99         udata_close(propsData);
100         propsData=NULL;
101     }
102     pData32=NULL;
103     propsVectors=NULL;
104     countPropsVectors=0;
105     uprv_memset(dataVersion, 0, U_MAX_VERSION_LENGTH);
106     dataErrorCode=U_ZERO_ERROR;
107     havePropsData=0;
108 
109     return TRUE;
110 }
111 
112 struct UCharProps {
113     UDataMemory *propsData;
114     UTrie propsTrie, propsVectorsTrie;
115     const uint32_t *pData32;
116 };
117 typedef struct UCharProps UCharProps;
118 
119 /* open uprops.icu */
120 static void
_openProps(UCharProps * ucp,UErrorCode * pErrorCode)121 _openProps(UCharProps *ucp, UErrorCode *pErrorCode) {
122     const uint32_t *p;
123     int32_t length;
124 
125     ucp->propsData=udata_openChoice(NULL, DATA_TYPE, DATA_NAME, isAcceptable, NULL, pErrorCode);
126     if(U_FAILURE(*pErrorCode)) {
127         return;
128     }
129 
130     ucp->pData32=p=(const uint32_t *)udata_getMemory(ucp->propsData);
131 
132     /* unserialize the trie; it is directly after the int32_t indexes[UPROPS_INDEX_COUNT] */
133     length=(int32_t)p[UPROPS_PROPS32_INDEX]*4;
134     length=utrie_unserialize(&ucp->propsTrie, (const uint8_t *)(p+UPROPS_INDEX_COUNT), length-64, pErrorCode);
135     if(U_FAILURE(*pErrorCode)) {
136         return;
137     }
138 
139     /* unserialize the properties vectors trie */
140     length=(int32_t)(p[UPROPS_ADDITIONAL_VECTORS_INDEX]-p[UPROPS_ADDITIONAL_TRIE_INDEX])*4;
141     if(length>0) {
142         length=utrie_unserialize(&ucp->propsVectorsTrie, (const uint8_t *)(p+p[UPROPS_ADDITIONAL_TRIE_INDEX]), length, pErrorCode);
143     }
144     if(length<=0 || U_FAILURE(*pErrorCode)) {
145         /*
146          * length==0:
147          * Allow the properties vectors trie to be missing -
148          * also requires propsVectorsColumns=indexes[UPROPS_ADDITIONAL_VECTORS_COLUMNS_INDEX]
149          * to be zero so that this trie is never accessed.
150          */
151         uprv_memset(&ucp->propsVectorsTrie, 0, sizeof(ucp->propsVectorsTrie));
152     }
153 }
154 
155 #endif
156 
157 #if !UCHAR_HARDCODE_DATA
158 static int8_t
uprv_loadPropsData(UErrorCode * pErrorCode)159 uprv_loadPropsData(UErrorCode *pErrorCode) {
160     /* load Unicode character properties data from file if necessary */
161 
162     /*
163      * This lazy intialization with double-checked locking (without mutex protection for
164      * haveNormData==0) is transiently unsafe under certain circumstances.
165      * Check the readme and use u_init() if necessary.
166      */
167     if(havePropsData==0) {
168         UCharProps ucp={ NULL };
169 
170         if(U_FAILURE(*pErrorCode)) {
171             return havePropsData;
172         }
173 
174         /* open the data outside the mutex block */
175         _openProps(&ucp, pErrorCode);
176 
177         if(U_SUCCESS(*pErrorCode)) {
178             /* in the mutex block, set the data for this process */
179             umtx_lock(NULL);
180             if(propsData==NULL) {
181                 propsData=ucp.propsData;
182                 ucp.propsData=NULL;
183                 pData32=ucp.pData32;
184                 ucp.pData32=NULL;
185                 uprv_memcpy(&propsTrie, &ucp.propsTrie, sizeof(propsTrie));
186                 uprv_memcpy(&propsVectorsTrie, &ucp.propsVectorsTrie, sizeof(propsVectorsTrie));
187             }
188 
189             /* initialize some variables */
190             uprv_memcpy(indexes, pData32, sizeof(indexes));
191 
192             /* additional properties */
193             if(indexes[UPROPS_ADDITIONAL_VECTORS_INDEX]!=0) {
194                 propsVectors=pData32+indexes[UPROPS_ADDITIONAL_VECTORS_INDEX];
195                 countPropsVectors=indexes[UPROPS_RESERVED_INDEX]-indexes[UPROPS_ADDITIONAL_VECTORS_INDEX];
196                 propsVectorsColumns=indexes[UPROPS_ADDITIONAL_VECTORS_COLUMNS_INDEX];
197             }
198 
199             havePropsData=1;
200             umtx_unlock(NULL);
201         } else {
202             dataErrorCode=*pErrorCode;
203             havePropsData=-1;
204         }
205         ucln_common_registerCleanup(UCLN_COMMON_UCHAR, uchar_cleanup);
206 
207         /* if a different thread set it first, then close the extra data */
208         udata_close(ucp.propsData); /* NULL if it was set correctly */
209     }
210 
211     return havePropsData;
212 }
213 
214 static int8_t
loadPropsData(void)215 loadPropsData(void) {
216     UErrorCode   errorCode = U_ZERO_ERROR;
217     int8_t       retVal    = uprv_loadPropsData(&errorCode);
218     return retVal;
219 }
220 
221 #endif
222 
223 /* constants and macros for access to the data ------------------------------ */
224 
225 /* getting a uint32_t properties word from the data */
226 #if UCHAR_HARDCODE_DATA
227 
228 #define GET_PROPS(c, result) UTRIE_GET16(&propsTrie, c, result);
229 
230 #else
231 
232 #define HAVE_DATA (havePropsData>0 || loadPropsData()>0)
233 #define GET_PROPS_UNSAFE(c, result) \
234     UTRIE_GET16(&propsTrie, c, result);
235 #define GET_PROPS(c, result) \
236     if(HAVE_DATA) { \
237         GET_PROPS_UNSAFE(c, result); \
238     } else { \
239         (result)=0; \
240     }
241 
242 #endif
243 
244 U_CFUNC UBool
uprv_haveProperties(UErrorCode * pErrorCode)245 uprv_haveProperties(UErrorCode *pErrorCode) {
246     if(U_FAILURE(*pErrorCode)) {
247         return FALSE;
248     }
249 #if !UCHAR_HARDCODE_DATA
250     if(havePropsData==0) {
251         uprv_loadPropsData(pErrorCode);
252     }
253     if(havePropsData<0) {
254         *pErrorCode=dataErrorCode;
255         return FALSE;
256     }
257 #endif
258     return TRUE;
259 }
260 
261 /* API functions ------------------------------------------------------------ */
262 
263 /* Gets the Unicode character's general category.*/
264 U_CAPI int8_t U_EXPORT2
u_charType(UChar32 c)265 u_charType(UChar32 c) {
266     uint32_t props;
267     GET_PROPS(c, props);
268     return (int8_t)GET_CATEGORY(props);
269 }
270 
271 /* Enumerate all code points with their general categories. */
272 struct _EnumTypeCallback {
273     UCharEnumTypeRange *enumRange;
274     const void *context;
275 };
276 
277 static uint32_t U_CALLCONV
_enumTypeValue(const void * context,uint32_t value)278 _enumTypeValue(const void *context, uint32_t value) {
279     return GET_CATEGORY(value);
280 }
281 
282 static UBool U_CALLCONV
_enumTypeRange(const void * context,UChar32 start,UChar32 limit,uint32_t value)283 _enumTypeRange(const void *context, UChar32 start, UChar32 limit, uint32_t value) {
284     /* just cast the value to UCharCategory */
285     return ((struct _EnumTypeCallback *)context)->
286         enumRange(((struct _EnumTypeCallback *)context)->context,
287                   start, limit, (UCharCategory)value);
288 }
289 
290 U_CAPI void U_EXPORT2
u_enumCharTypes(UCharEnumTypeRange * enumRange,const void * context)291 u_enumCharTypes(UCharEnumTypeRange *enumRange, const void *context) {
292     struct _EnumTypeCallback callback;
293 
294     if(enumRange==NULL
295 #if !UCHAR_HARDCODE_DATA
296         || !HAVE_DATA
297 #endif
298     ) {
299         return;
300     }
301 
302     callback.enumRange=enumRange;
303     callback.context=context;
304     utrie_enum(&propsTrie, _enumTypeValue, _enumTypeRange, &callback);
305 }
306 
307 /* Checks if ch is a lower case letter.*/
308 U_CAPI UBool U_EXPORT2
u_islower(UChar32 c)309 u_islower(UChar32 c) {
310     uint32_t props;
311     GET_PROPS(c, props);
312     return (UBool)(GET_CATEGORY(props)==U_LOWERCASE_LETTER);
313 }
314 
315 /* Checks if ch is an upper case letter.*/
316 U_CAPI UBool U_EXPORT2
u_isupper(UChar32 c)317 u_isupper(UChar32 c) {
318     uint32_t props;
319     GET_PROPS(c, props);
320     return (UBool)(GET_CATEGORY(props)==U_UPPERCASE_LETTER);
321 }
322 
323 /* Checks if ch is a title case letter; usually upper case letters.*/
324 U_CAPI UBool U_EXPORT2
u_istitle(UChar32 c)325 u_istitle(UChar32 c) {
326     uint32_t props;
327     GET_PROPS(c, props);
328     return (UBool)(GET_CATEGORY(props)==U_TITLECASE_LETTER);
329 }
330 
331 /* Checks if ch is a decimal digit. */
332 U_CAPI UBool U_EXPORT2
u_isdigit(UChar32 c)333 u_isdigit(UChar32 c) {
334     uint32_t props;
335     GET_PROPS(c, props);
336     return (UBool)(GET_CATEGORY(props)==U_DECIMAL_DIGIT_NUMBER);
337 }
338 
339 U_CAPI UBool U_EXPORT2
u_isxdigit(UChar32 c)340 u_isxdigit(UChar32 c) {
341     uint32_t props;
342 
343     /* check ASCII and Fullwidth ASCII a-fA-F */
344     if(
345         (c<=0x66 && c>=0x41 && (c<=0x46 || c>=0x61)) ||
346         (c>=0xff21 && c<=0xff46 && (c<=0xff26 || c>=0xff41))
347     ) {
348         return TRUE;
349     }
350 
351     GET_PROPS(c, props);
352     return (UBool)(GET_CATEGORY(props)==U_DECIMAL_DIGIT_NUMBER);
353 }
354 
355 /* Checks if the Unicode character is a letter.*/
356 U_CAPI UBool U_EXPORT2
u_isalpha(UChar32 c)357 u_isalpha(UChar32 c) {
358     uint32_t props;
359     GET_PROPS(c, props);
360     return (UBool)((CAT_MASK(props)&U_GC_L_MASK)!=0);
361 }
362 
363 U_CAPI UBool U_EXPORT2
u_isUAlphabetic(UChar32 c)364 u_isUAlphabetic(UChar32 c) {
365     return (u_getUnicodeProperties(c, 1)&U_MASK(UPROPS_ALPHABETIC))!=0;
366 }
367 
368 /* Checks if c is a letter or a decimal digit */
369 U_CAPI UBool U_EXPORT2
u_isalnum(UChar32 c)370 u_isalnum(UChar32 c) {
371     uint32_t props;
372     GET_PROPS(c, props);
373     return (UBool)((CAT_MASK(props)&(U_GC_L_MASK|U_GC_ND_MASK))!=0);
374 }
375 
376 /**
377  * Checks if c is alphabetic, or a decimal digit; implements UCHAR_POSIX_ALNUM.
378  * @internal
379  */
380 U_CFUNC UBool
u_isalnumPOSIX(UChar32 c)381 u_isalnumPOSIX(UChar32 c) {
382     return (UBool)(u_isUAlphabetic(c) || u_isdigit(c));
383 }
384 
385 /* Checks if ch is a unicode character with assigned character type.*/
386 U_CAPI UBool U_EXPORT2
u_isdefined(UChar32 c)387 u_isdefined(UChar32 c) {
388     uint32_t props;
389     GET_PROPS(c, props);
390     return (UBool)(GET_CATEGORY(props)!=0);
391 }
392 
393 /* Checks if the Unicode character is a base form character that can take a diacritic.*/
394 U_CAPI UBool U_EXPORT2
u_isbase(UChar32 c)395 u_isbase(UChar32 c) {
396     uint32_t props;
397     GET_PROPS(c, props);
398     return (UBool)((CAT_MASK(props)&(U_GC_L_MASK|U_GC_N_MASK|U_GC_MC_MASK|U_GC_ME_MASK))!=0);
399 }
400 
401 /* Checks if the Unicode character is a control character.*/
402 U_CAPI UBool U_EXPORT2
u_iscntrl(UChar32 c)403 u_iscntrl(UChar32 c) {
404     uint32_t props;
405     GET_PROPS(c, props);
406     return (UBool)((CAT_MASK(props)&(U_GC_CC_MASK|U_GC_CF_MASK|U_GC_ZL_MASK|U_GC_ZP_MASK))!=0);
407 }
408 
409 U_CAPI UBool U_EXPORT2
u_isISOControl(UChar32 c)410 u_isISOControl(UChar32 c) {
411     return (uint32_t)c<=0x9f && (c<=0x1f || c>=0x7f);
412 }
413 
414 /* Some control characters that are used as space. */
415 #define IS_THAT_CONTROL_SPACE(c) \
416     (c<=0x9f && ((c>=TAB && c<=CR) || (c>=0x1c && c <=0x1f) || c==NL))
417 
418 /* Checks if the Unicode character is a space character.*/
419 U_CAPI UBool U_EXPORT2
u_isspace(UChar32 c)420 u_isspace(UChar32 c) {
421     uint32_t props;
422     GET_PROPS(c, props);
423     return (UBool)((CAT_MASK(props)&U_GC_Z_MASK)!=0 || IS_THAT_CONTROL_SPACE(c));
424 }
425 
426 U_CAPI UBool U_EXPORT2
u_isJavaSpaceChar(UChar32 c)427 u_isJavaSpaceChar(UChar32 c) {
428     uint32_t props;
429     GET_PROPS(c, props);
430     return (UBool)((CAT_MASK(props)&U_GC_Z_MASK)!=0);
431 }
432 
433 /* Checks if the Unicode character is a whitespace character.*/
434 U_CAPI UBool U_EXPORT2
u_isWhitespace(UChar32 c)435 u_isWhitespace(UChar32 c) {
436     uint32_t props;
437     GET_PROPS(c, props);
438     return (UBool)(
439                 ((CAT_MASK(props)&U_GC_Z_MASK)!=0 &&
440                     c!=NBSP && c!=FIGURESP && c!=NNBSP) || /* exclude no-break spaces */
441                 IS_THAT_CONTROL_SPACE(c)
442            );
443 }
444 
445 U_CAPI UBool U_EXPORT2
u_isblank(UChar32 c)446 u_isblank(UChar32 c) {
447     if((uint32_t)c<=0x9f) {
448         return c==9 || c==0x20; /* TAB or SPACE */
449     } else {
450         /* Zs */
451         uint32_t props;
452         GET_PROPS(c, props);
453         return (UBool)(GET_CATEGORY(props)==U_SPACE_SEPARATOR);
454     }
455 }
456 
457 U_CAPI UBool U_EXPORT2
u_isUWhiteSpace(UChar32 c)458 u_isUWhiteSpace(UChar32 c) {
459     return (u_getUnicodeProperties(c, 1)&U_MASK(UPROPS_WHITE_SPACE))!=0;
460 }
461 
462 /* Checks if the Unicode character is printable.*/
463 U_CAPI UBool U_EXPORT2
u_isprint(UChar32 c)464 u_isprint(UChar32 c) {
465     uint32_t props;
466     GET_PROPS(c, props);
467     /* comparing ==0 returns FALSE for the categories mentioned */
468     return (UBool)((CAT_MASK(props)&U_GC_C_MASK)==0);
469 }
470 
471 /**
472  * Checks if c is in \p{graph}\p{blank} - \p{cntrl}.
473  * Implements UCHAR_POSIX_PRINT.
474  * @internal
475  */
476 U_CFUNC UBool
u_isprintPOSIX(UChar32 c)477 u_isprintPOSIX(UChar32 c) {
478     uint32_t props;
479     GET_PROPS(c, props);
480     /*
481      * The only cntrl character in graph+blank is TAB (in blank).
482      * Here we implement (blank-TAB)=Zs instead of calling u_isblank().
483      */
484     return (UBool)((GET_CATEGORY(props)==U_SPACE_SEPARATOR) || u_isgraphPOSIX(c));
485 }
486 
487 U_CAPI UBool U_EXPORT2
u_isgraph(UChar32 c)488 u_isgraph(UChar32 c) {
489     uint32_t props;
490     GET_PROPS(c, props);
491     /* comparing ==0 returns FALSE for the categories mentioned */
492     return (UBool)((CAT_MASK(props)&
493                     (U_GC_CC_MASK|U_GC_CF_MASK|U_GC_CS_MASK|U_GC_CN_MASK|U_GC_Z_MASK))
494                    ==0);
495 }
496 
497 /**
498  * Checks if c is in
499  * [^\p{space}\p{gc=Control}\p{gc=Surrogate}\p{gc=Unassigned}]
500  * with space=\p{Whitespace} and Control=Cc.
501  * Implements UCHAR_POSIX_GRAPH.
502  * @internal
503  */
504 U_CFUNC UBool
u_isgraphPOSIX(UChar32 c)505 u_isgraphPOSIX(UChar32 c) {
506     uint32_t props;
507     GET_PROPS(c, props);
508     /* \p{space}\p{gc=Control} == \p{gc=Z}\p{Control} */
509     /* comparing ==0 returns FALSE for the categories mentioned */
510     return (UBool)((CAT_MASK(props)&
511                     (U_GC_CC_MASK|U_GC_CS_MASK|U_GC_CN_MASK|U_GC_Z_MASK))
512                    ==0);
513 }
514 
515 U_CAPI UBool U_EXPORT2
u_ispunct(UChar32 c)516 u_ispunct(UChar32 c) {
517     uint32_t props;
518     GET_PROPS(c, props);
519     return (UBool)((CAT_MASK(props)&U_GC_P_MASK)!=0);
520 }
521 
522 /* Checks if the Unicode character can start a Unicode identifier.*/
523 U_CAPI UBool U_EXPORT2
u_isIDStart(UChar32 c)524 u_isIDStart(UChar32 c) {
525     /* same as u_isalpha() */
526     uint32_t props;
527     GET_PROPS(c, props);
528     return (UBool)((CAT_MASK(props)&(U_GC_L_MASK|U_GC_NL_MASK))!=0);
529 }
530 
531 /* Checks if the Unicode character can be a Unicode identifier part other than starting the
532  identifier.*/
533 U_CAPI UBool U_EXPORT2
u_isIDPart(UChar32 c)534 u_isIDPart(UChar32 c) {
535     uint32_t props;
536     GET_PROPS(c, props);
537     return (UBool)(
538            (CAT_MASK(props)&
539             (U_GC_ND_MASK|U_GC_NL_MASK|
540              U_GC_L_MASK|
541              U_GC_PC_MASK|U_GC_MC_MASK|U_GC_MN_MASK)
542            )!=0 ||
543            u_isIDIgnorable(c));
544 }
545 
546 /*Checks if the Unicode character can be ignorable in a Java or Unicode identifier.*/
547 U_CAPI UBool U_EXPORT2
u_isIDIgnorable(UChar32 c)548 u_isIDIgnorable(UChar32 c) {
549     if(c<=0x9f) {
550         return u_isISOControl(c) && !IS_THAT_CONTROL_SPACE(c);
551     } else {
552         uint32_t props;
553         GET_PROPS(c, props);
554         return (UBool)(GET_CATEGORY(props)==U_FORMAT_CHAR);
555     }
556 }
557 
558 /*Checks if the Unicode character can start a Java identifier.*/
559 U_CAPI UBool U_EXPORT2
u_isJavaIDStart(UChar32 c)560 u_isJavaIDStart(UChar32 c) {
561     uint32_t props;
562     GET_PROPS(c, props);
563     return (UBool)((CAT_MASK(props)&(U_GC_L_MASK|U_GC_SC_MASK|U_GC_PC_MASK))!=0);
564 }
565 
566 /*Checks if the Unicode character can be a Java identifier part other than starting the
567  * identifier.
568  */
569 U_CAPI UBool U_EXPORT2
u_isJavaIDPart(UChar32 c)570 u_isJavaIDPart(UChar32 c) {
571     uint32_t props;
572     GET_PROPS(c, props);
573     return (UBool)(
574            (CAT_MASK(props)&
575             (U_GC_ND_MASK|U_GC_NL_MASK|
576              U_GC_L_MASK|
577              U_GC_SC_MASK|U_GC_PC_MASK|
578              U_GC_MC_MASK|U_GC_MN_MASK)
579            )!=0 ||
580            u_isIDIgnorable(c));
581 }
582 
583 U_CAPI int32_t U_EXPORT2
u_charDigitValue(UChar32 c)584 u_charDigitValue(UChar32 c) {
585     uint32_t props;
586     GET_PROPS(c, props);
587 
588     if(GET_NUMERIC_TYPE(props)==1) {
589         return GET_NUMERIC_VALUE(props);
590     } else {
591         return -1;
592     }
593 }
594 
595 U_CAPI double U_EXPORT2
u_getNumericValue(UChar32 c)596 u_getNumericValue(UChar32 c) {
597     uint32_t props, numericType, numericValue;
598     GET_PROPS(c, props);
599     numericType=GET_NUMERIC_TYPE(props);
600 
601     if(numericType==0 || numericType>=UPROPS_NT_COUNT) {
602         return U_NO_NUMERIC_VALUE;
603     }
604 
605     numericValue=GET_NUMERIC_VALUE(props);
606 
607     if(numericType<U_NT_COUNT) {
608         /* normal type, the value is stored directly */
609         return numericValue;
610     } else if(numericType==UPROPS_NT_FRACTION) {
611         /* fraction value */
612         int32_t numerator;
613         uint32_t denominator;
614 
615         numerator=(int32_t)numericValue>>UPROPS_FRACTION_NUM_SHIFT;
616         denominator=(numericValue&UPROPS_FRACTION_DEN_MASK)+UPROPS_FRACTION_DEN_OFFSET;
617 
618         if(numerator==0) {
619             numerator=-1;
620         }
621         return (double)numerator/(double)denominator;
622     } else /* numericType==UPROPS_NT_LARGE */ {
623         /* large value with exponent */
624         double numValue;
625         int32_t mant, exp;
626 
627         mant=(int32_t)numericValue>>UPROPS_LARGE_MANT_SHIFT;
628         exp=(int32_t)numericValue&UPROPS_LARGE_EXP_MASK;
629         if(mant==0) {
630             mant=1;
631             exp+=UPROPS_LARGE_EXP_OFFSET_EXTRA;
632         } else if(mant>9) {
633             return U_NO_NUMERIC_VALUE; /* reserved mantissa value */
634         } else {
635             exp+=UPROPS_LARGE_EXP_OFFSET;
636         }
637 
638         numValue=mant;
639 
640         /* multiply by 10^exp without math.h */
641         while(exp>=4) {
642             numValue*=10000.;
643             exp-=4;
644         }
645         switch(exp) {
646         case 3:
647             numValue*=1000.;
648             break;
649         case 2:
650             numValue*=100.;
651             break;
652         case 1:
653             numValue*=10.;
654             break;
655         case 0:
656         default:
657             break;
658         }
659 
660         return numValue;
661     }
662 }
663 
664 /* ICU 3.4: bidi/shaping properties moved to ubidi_props.c */
665 
666 /* ICU 2.1: u_getCombiningClass() moved to unorm.cpp */
667 
668 U_CAPI int32_t U_EXPORT2
u_digit(UChar32 ch,int8_t radix)669 u_digit(UChar32 ch, int8_t radix) {
670     int8_t value;
671     if((uint8_t)(radix-2)<=(36-2)) {
672         value=(int8_t)u_charDigitValue(ch);
673         if(value<0) {
674             /* ch is not a decimal digit, try latin letters */
675             if(ch>=0x61 && ch<=0x7A) {
676                 value=(int8_t)(ch-0x57);  /* ch - 'a' + 10 */
677             } else if(ch>=0x41 && ch<=0x5A) {
678                 value=(int8_t)(ch-0x37);  /* ch - 'A' + 10 */
679             } else if(ch>=0xFF41 && ch<=0xFF5A) {
680                 value=(int8_t)(ch-0xFF37);  /* fullwidth ASCII a-z */
681             } else if(ch>=0xFF21 && ch<=0xFF3A) {
682                 value=(int8_t)(ch-0xFF17);  /* fullwidth ASCII A-Z */
683             }
684         }
685     } else {
686         value=-1;   /* invalid radix */
687     }
688     return (int8_t)((value<radix) ? value : -1);
689 }
690 
691 U_CAPI UChar32 U_EXPORT2
u_forDigit(int32_t digit,int8_t radix)692 u_forDigit(int32_t digit, int8_t radix) {
693     if((uint8_t)(radix-2)>(36-2) || (uint32_t)digit>=(uint32_t)radix) {
694         return 0;
695     } else if(digit<10) {
696         return (UChar32)(0x30+digit);
697     } else {
698         return (UChar32)((0x61-10)+digit);
699     }
700 }
701 
702 /* miscellaneous, and support for uprops.c ---------------------------------- */
703 
704 U_CAPI void U_EXPORT2
u_getUnicodeVersion(UVersionInfo versionArray)705 u_getUnicodeVersion(UVersionInfo versionArray) {
706     if(versionArray!=NULL) {
707         uprv_memcpy(versionArray, dataVersion, U_MAX_VERSION_LENGTH);
708     }
709 }
710 
711 U_CFUNC uint32_t
u_getUnicodeProperties(UChar32 c,int32_t column)712 u_getUnicodeProperties(UChar32 c, int32_t column) {
713     uint16_t vecIndex;
714 
715     if(column==-1) {
716         uint32_t props;
717         GET_PROPS(c, props);
718         return props;
719     } else if(
720 #if !UCHAR_HARDCODE_DATA
721                !HAVE_DATA || countPropsVectors==0 ||
722 #endif
723                column<0 || column>=propsVectorsColumns
724     ) {
725         return 0;
726     } else {
727         UTRIE_GET16(&propsVectorsTrie, c, vecIndex);
728         return propsVectors[vecIndex+column];
729     }
730 }
731 
732 U_CFUNC int32_t
uprv_getMaxValues(int32_t column)733 uprv_getMaxValues(int32_t column) {
734 #if !UCHAR_HARDCODE_DATA
735     if(HAVE_DATA) {
736 #endif
737         switch(column) {
738         case 0:
739             return indexes[UPROPS_MAX_VALUES_INDEX];
740         case 2:
741             return indexes[UPROPS_MAX_VALUES_2_INDEX];
742         default:
743             return 0;
744         }
745 #if !UCHAR_HARDCODE_DATA
746     } else {
747         return 0;
748     }
749 #endif
750 }
751 
752 /*
753  * get Hangul Syllable Type
754  * implemented here so that uchar.c (uhst_addPropertyStarts())
755  * does not depend on uprops.c (u_getIntPropertyValue(c, UCHAR_HANGUL_SYLLABLE_TYPE))
756  */
757 U_CFUNC UHangulSyllableType
uchar_getHST(UChar32 c)758 uchar_getHST(UChar32 c) {
759     /* purely algorithmic; hardcode known characters, check for assigned new ones */
760     if(c<JAMO_L_BASE) {
761         /* U_HST_NOT_APPLICABLE */
762     } else if(c<=0x11ff) {
763         /* Jamo range */
764         if(c<=0x115f) {
765             /* Jamo L range, HANGUL CHOSEONG ... */
766             if(c==0x115f || c<=0x1159 || u_charType(c)==U_OTHER_LETTER) {
767                 return U_HST_LEADING_JAMO;
768             }
769         } else if(c<=0x11a7) {
770             /* Jamo V range, HANGUL JUNGSEONG ... */
771             if(c<=0x11a2 || u_charType(c)==U_OTHER_LETTER) {
772                 return U_HST_VOWEL_JAMO;
773             }
774         } else {
775             /* Jamo T range */
776             if(c<=0x11f9 || u_charType(c)==U_OTHER_LETTER) {
777                 return U_HST_TRAILING_JAMO;
778             }
779         }
780     } else if((c-=HANGUL_BASE)<0) {
781         /* U_HST_NOT_APPLICABLE */
782     } else if(c<HANGUL_COUNT) {
783         /* Hangul syllable */
784         return c%JAMO_T_COUNT==0 ? U_HST_LV_SYLLABLE : U_HST_LVT_SYLLABLE;
785     }
786     return U_HST_NOT_APPLICABLE;
787 }
788 
789 U_CAPI void U_EXPORT2
u_charAge(UChar32 c,UVersionInfo versionArray)790 u_charAge(UChar32 c, UVersionInfo versionArray) {
791     if(versionArray!=NULL) {
792         uint32_t version=u_getUnicodeProperties(c, 0)>>UPROPS_AGE_SHIFT;
793         versionArray[0]=(uint8_t)(version>>4);
794         versionArray[1]=(uint8_t)(version&0xf);
795         versionArray[2]=versionArray[3]=0;
796     }
797 }
798 
799 U_CAPI UScriptCode U_EXPORT2
uscript_getScript(UChar32 c,UErrorCode * pErrorCode)800 uscript_getScript(UChar32 c, UErrorCode *pErrorCode) {
801     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
802         return USCRIPT_INVALID_CODE;
803     }
804     if((uint32_t)c>0x10ffff) {
805         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
806         return USCRIPT_INVALID_CODE;
807     }
808 
809     return (UScriptCode)(u_getUnicodeProperties(c, 0)&UPROPS_SCRIPT_MASK);
810 }
811 
812 U_CAPI UBlockCode U_EXPORT2
ublock_getCode(UChar32 c)813 ublock_getCode(UChar32 c) {
814     return (UBlockCode)((u_getUnicodeProperties(c, 0)&UPROPS_BLOCK_MASK)>>UPROPS_BLOCK_SHIFT);
815 }
816 
817 /* property starts for UnicodeSet ------------------------------------------- */
818 
819 /* for Hangul_Syllable_Type */
820 U_CFUNC void U_EXPORT2
uhst_addPropertyStarts(const USetAdder * sa,UErrorCode * pErrorCode)821 uhst_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode) {
822     UChar32 c;
823     int32_t value, value2;
824 
825     if(U_FAILURE(*pErrorCode)) {
826         return;
827     }
828 
829 #if !UCHAR_HARDCODE_DATA
830     if(!HAVE_DATA) {
831         *pErrorCode=dataErrorCode;
832         return;
833     }
834 #endif
835 
836     /* add code points with hardcoded properties, plus the ones following them */
837 
838     /*
839      * Add Jamo type boundaries for UCHAR_HANGUL_SYLLABLE_TYPE.
840      * First, we add fixed boundaries for the blocks of Jamos.
841      * Then we check in loops to see where the current Unicode version
842      * actually stops assigning such Jamos. We start each loop
843      * at the end of the per-Jamo-block assignments in Unicode 4 or earlier.
844      * (These have not changed since Unicode 2.)
845      */
846     sa->add(sa->set, 0x1100);
847     value=U_HST_LEADING_JAMO;
848     for(c=0x115a; c<=0x115f; ++c) {
849         value2=uchar_getHST(c);
850         if(value!=value2) {
851             value=value2;
852             sa->add(sa->set, c);
853         }
854     }
855 
856     sa->add(sa->set, 0x1160);
857     value=U_HST_VOWEL_JAMO;
858     for(c=0x11a3; c<=0x11a7; ++c) {
859         value2=uchar_getHST(c);
860         if(value!=value2) {
861             value=value2;
862             sa->add(sa->set, c);
863         }
864     }
865 
866     sa->add(sa->set, 0x11a8);
867     value=U_HST_TRAILING_JAMO;
868     for(c=0x11fa; c<=0x11ff; ++c) {
869         value2=uchar_getHST(c);
870         if(value!=value2) {
871             value=value2;
872             sa->add(sa->set, c);
873         }
874     }
875 
876     /* Add Hangul type boundaries for UCHAR_HANGUL_SYLLABLE_TYPE. */
877     for(c=HANGUL_BASE; c<(HANGUL_BASE+HANGUL_COUNT); c+=JAMO_T_COUNT) {
878         sa->add(sa->set, c);
879         sa->add(sa->set, c+1);
880     }
881     sa->add(sa->set, c);
882 }
883 
884 static UBool U_CALLCONV
_enumPropertyStartsRange(const void * context,UChar32 start,UChar32 limit,uint32_t value)885 _enumPropertyStartsRange(const void *context, UChar32 start, UChar32 limit, uint32_t value) {
886     /* add the start code point to the USet */
887     const USetAdder *sa=(const USetAdder *)context;
888     sa->add(sa->set, start);
889     return TRUE;
890 }
891 
892 #define USET_ADD_CP_AND_NEXT(sa, cp) sa->add(sa->set, cp); sa->add(sa->set, cp+1)
893 
894 U_CFUNC void U_EXPORT2
uchar_addPropertyStarts(const USetAdder * sa,UErrorCode * pErrorCode)895 uchar_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode) {
896     if(U_FAILURE(*pErrorCode)) {
897         return;
898     }
899 
900 #if !UCHAR_HARDCODE_DATA
901     if(!HAVE_DATA) {
902         *pErrorCode=dataErrorCode;
903         return;
904     }
905 #endif
906 
907     /* add the start code point of each same-value range of the main trie */
908     utrie_enum(&propsTrie, NULL, _enumPropertyStartsRange, sa);
909 
910     /* add code points with hardcoded properties, plus the ones following them */
911 
912     /* add for u_isblank() */
913     USET_ADD_CP_AND_NEXT(sa, TAB);
914 
915     /* add for IS_THAT_CONTROL_SPACE() */
916     sa->add(sa->set, CR+1); /* range TAB..CR */
917     sa->add(sa->set, 0x1c);
918     sa->add(sa->set, 0x1f+1);
919     USET_ADD_CP_AND_NEXT(sa, NL);
920 
921     /* add for u_isIDIgnorable() what was not added above */
922     sa->add(sa->set, DEL); /* range DEL..NBSP-1, NBSP added below */
923     sa->add(sa->set, HAIRSP);
924     sa->add(sa->set, RLM+1);
925     sa->add(sa->set, INHSWAP);
926     sa->add(sa->set, NOMDIG+1);
927     USET_ADD_CP_AND_NEXT(sa, ZWNBSP);
928 
929     /* add no-break spaces for u_isWhitespace() what was not added above */
930     USET_ADD_CP_AND_NEXT(sa, NBSP);
931     USET_ADD_CP_AND_NEXT(sa, FIGURESP);
932     USET_ADD_CP_AND_NEXT(sa, NNBSP);
933 
934     /* add for u_digit() */
935     sa->add(sa->set, U_a);
936     sa->add(sa->set, U_z+1);
937     sa->add(sa->set, U_A);
938     sa->add(sa->set, U_Z+1);
939     sa->add(sa->set, U_FW_a);
940     sa->add(sa->set, U_FW_z+1);
941     sa->add(sa->set, U_FW_A);
942     sa->add(sa->set, U_FW_Z+1);
943 
944     /* add for u_isxdigit() */
945     sa->add(sa->set, U_f+1);
946     sa->add(sa->set, U_F+1);
947     sa->add(sa->set, U_FW_f+1);
948     sa->add(sa->set, U_FW_F+1);
949 
950     /* add for UCHAR_DEFAULT_IGNORABLE_CODE_POINT what was not added above */
951     sa->add(sa->set, WJ); /* range WJ..NOMDIG */
952     sa->add(sa->set, 0xfff0);
953     sa->add(sa->set, 0xfffb+1);
954     sa->add(sa->set, 0xe0000);
955     sa->add(sa->set, 0xe0fff+1);
956 
957     /* add for UCHAR_GRAPHEME_BASE and others */
958     USET_ADD_CP_AND_NEXT(sa, CGJ);
959 }
960 
961 U_CFUNC void U_EXPORT2
upropsvec_addPropertyStarts(const USetAdder * sa,UErrorCode * pErrorCode)962 upropsvec_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode) {
963     if(U_FAILURE(*pErrorCode)) {
964         return;
965     }
966 
967 #if !UCHAR_HARDCODE_DATA
968     if(!HAVE_DATA) {
969         *pErrorCode=dataErrorCode;
970         return;
971     }
972 #endif
973 
974     /* add the start code point of each same-value range of the properties vectors trie */
975     if(propsVectorsColumns>0) {
976         /* if propsVectorsColumns==0 then the properties vectors trie may not be there at all */
977         utrie_enum(&propsVectorsTrie, NULL, _enumPropertyStartsRange, sa);
978     }
979 }
980