xref: /php-src/ext/intl/uchar/uchar.c (revision c39bcaa2)
1 #include "uchar.h"
2 #include "intl_data.h"
3 #include "intl_convert.h"
4 
5 #include <unicode/uchar.h>
6 #include <unicode/utf8.h>
7 
8 #include "uchar_arginfo.h"
9 
10 #define IC_METHOD(mname) PHP_METHOD(IntlChar, mname)
11 
convert_cp(UChar32 * pcp,zend_string * string_codepoint,zend_long int_codepoint)12 static inline int convert_cp(UChar32* pcp, zend_string *string_codepoint, zend_long int_codepoint) {
13 	if (string_codepoint != NULL) {
14 		int32_t i = 0;
15 		size_t string_codepoint_length = ZSTR_LEN(string_codepoint);
16 
17 		if (ZEND_SIZE_T_INT_OVFL(string_codepoint_length)) {
18 			intl_error_set_code(NULL, U_ILLEGAL_ARGUMENT_ERROR);
19 			intl_error_set_custom_msg(NULL, "Input string is too long.", 0);
20 			return FAILURE;
21 		}
22 
23 		U8_NEXT(ZSTR_VAL(string_codepoint), i, string_codepoint_length, int_codepoint);
24 		if ((size_t)i != string_codepoint_length) {
25 			intl_error_set_code(NULL, U_ILLEGAL_ARGUMENT_ERROR);
26 			intl_error_set_custom_msg(NULL, "Passing a UTF-8 character for codepoint requires a string which is exactly one UTF-8 codepoint long.", 0);
27 			return FAILURE;
28 		}
29 	}
30 
31 	if ((int_codepoint < UCHAR_MIN_VALUE) || (int_codepoint > UCHAR_MAX_VALUE)) {
32 		intl_error_set_code(NULL, U_ILLEGAL_ARGUMENT_ERROR);
33 		intl_error_set_custom_msg(NULL, "Codepoint out of range", 0);
34 		return FAILURE;
35 	}
36 	*pcp = (UChar32)int_codepoint;
37 	return SUCCESS;
38 }
39 
parse_code_point_param(INTERNAL_FUNCTION_PARAMETERS,UChar32 * cp)40 static zend_never_inline int parse_code_point_param(INTERNAL_FUNCTION_PARAMETERS, UChar32 *cp) {
41 	zend_string *string_codepoint;
42 	zend_long int_codepoint = 0;
43 	ZEND_PARSE_PARAMETERS_START(1, 1)
44 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
45 	ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
46 	return convert_cp(cp, string_codepoint, int_codepoint);
47 }
48 
49 /* {{{ Converts a numeric codepoint to UTF-8
50  * Acts as an identify function when given a valid UTF-8 encoded codepoint
51  */
IC_METHOD(chr)52 IC_METHOD(chr) {
53 	UChar32 cp;
54 	char buffer[5];
55 	int buffer_len = 0;
56 
57 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
58 		RETURN_NULL();
59 	}
60 
61 	/* We can use unsafe because we know the codepoint is in valid range
62 	 * and that 4 bytes is enough for any unicode point
63 	 */
64 	U8_APPEND_UNSAFE(buffer, buffer_len, cp);
65 	buffer[buffer_len] = 0;
66 	RETURN_STRINGL(buffer, buffer_len);
67 }
68 /* }}} */
69 
70 /* {{{ Converts a UTf-8 encoded codepoint to its integer U32 value
71  * Acts as an identity function when passed a valid integer codepoint
72  */
IC_METHOD(ord)73 IC_METHOD(ord) {
74 	UChar32 cp;
75 
76 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
77 		RETURN_NULL();
78 	}
79 
80 	RETURN_LONG(cp);
81 }
82 /* }}} */
83 
84 /* {{{ */
IC_METHOD(hasBinaryProperty)85 IC_METHOD(hasBinaryProperty) {
86 	UChar32 cp;
87 	zend_long prop;
88 	zend_string *string_codepoint;
89 	zend_long int_codepoint = 0;
90 
91 	ZEND_PARSE_PARAMETERS_START(2, 2)
92 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
93 		Z_PARAM_LONG(prop)
94 	ZEND_PARSE_PARAMETERS_END();
95 
96 	if (convert_cp(&cp, string_codepoint, int_codepoint) == FAILURE) {
97 		RETURN_NULL();
98 	}
99 
100 	RETURN_BOOL(u_hasBinaryProperty(cp, (UProperty)prop));
101 }
102 /* }}} */
103 
104 /* {{{ */
IC_METHOD(getIntPropertyValue)105 IC_METHOD(getIntPropertyValue) {
106 	UChar32 cp;
107 	zend_long prop;
108 	zend_string *string_codepoint;
109 	zend_long int_codepoint = 0;
110 
111 	ZEND_PARSE_PARAMETERS_START(2, 2)
112 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
113 		Z_PARAM_LONG(prop)
114 	ZEND_PARSE_PARAMETERS_END();
115 
116 	if (convert_cp(&cp, string_codepoint, int_codepoint) == FAILURE) {
117 		RETURN_NULL();
118 	}
119 
120 	RETURN_LONG(u_getIntPropertyValue(cp, (UProperty)prop));
121 }
122 /* }}} */
123 
124 /* {{{ */
IC_METHOD(getIntPropertyMinValue)125 IC_METHOD(getIntPropertyMinValue) {
126 	zend_long prop;
127 
128 	ZEND_PARSE_PARAMETERS_START(1, 1)
129 		Z_PARAM_LONG(prop)
130 	ZEND_PARSE_PARAMETERS_END();
131 
132 	RETURN_LONG(u_getIntPropertyMinValue((UProperty)prop));
133 }
134 /* }}} */
135 
136 /* {{{ */
IC_METHOD(getIntPropertyMaxValue)137 IC_METHOD(getIntPropertyMaxValue) {
138 	zend_long prop;
139 
140 	ZEND_PARSE_PARAMETERS_START(1, 1)
141 		Z_PARAM_LONG(prop)
142 	ZEND_PARSE_PARAMETERS_END();
143 
144 	RETURN_LONG(u_getIntPropertyMaxValue((UProperty)prop));
145 }
146 /* }}} */
147 
148 /* {{{ */
IC_METHOD(getNumericValue)149 IC_METHOD(getNumericValue) {
150 	UChar32 cp;
151 
152 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
153 		RETURN_NULL();
154 	}
155 
156 	RETURN_DOUBLE(u_getNumericValue(cp));
157 }
158 /* }}} */
159 
160 /* {{{ */
161 typedef struct _enumCharType_data {
162 	zend_fcall_info fci;
163 	zend_fcall_info_cache fci_cache;
164 } enumCharType_data;
enumCharType_callback(enumCharType_data * context,UChar32 start,UChar32 limit,UCharCategory type)165 static UBool enumCharType_callback(enumCharType_data *context,
166 		UChar32 start, UChar32 limit, UCharCategory type) {
167 	zval retval;
168 	zval args[3];
169 
170 	ZVAL_NULL(&retval);
171 	/* Note that $start is INclusive, while $limit is EXclusive
172 	 * Therefore (0, 32, 15) means CPs 0..31 are of type 15
173 	 */
174 	ZVAL_LONG(&args[0], start);
175 	ZVAL_LONG(&args[1], limit);
176 	ZVAL_LONG(&args[2], type);
177 
178 	context->fci.retval = &retval;
179 	context->fci.param_count = 3;
180 	context->fci.params = args;
181 
182 	if (zend_call_function(&context->fci, &context->fci_cache) == FAILURE) {
183 		intl_error_set_code(NULL, U_INTERNAL_PROGRAM_ERROR);
184 		intl_errors_set_custom_msg(NULL, "enumCharTypes callback failed", 0);
185 		zval_ptr_dtor(&retval);
186 		return 0;
187 	}
188 	zval_ptr_dtor(&retval);
189 	return 1;
190 }
IC_METHOD(enumCharTypes)191 IC_METHOD(enumCharTypes) {
192 	enumCharType_data context;
193 
194 	ZEND_PARSE_PARAMETERS_START(1, 1)
195 		Z_PARAM_FUNC(context.fci, context.fci_cache)
196 	ZEND_PARSE_PARAMETERS_END();
197 	u_enumCharTypes((UCharEnumTypeRange*)enumCharType_callback, &context);
198 }
199 /* }}} */
200 
201 /* {{{ */
IC_METHOD(getBlockCode)202 IC_METHOD(getBlockCode) {
203 	UChar32 cp;
204 
205 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
206 		RETURN_NULL();
207 	}
208 
209 	RETURN_LONG(ublock_getCode(cp));
210 }
211 /* }}} */
212 
213 /* {{{ */
IC_METHOD(charName)214 IC_METHOD(charName) {
215 	UChar32 cp;
216 	zend_string *string_codepoint;
217 	zend_long int_codepoint = 0;
218 	UErrorCode error = U_ZERO_ERROR;
219 	zend_long nameChoice = U_UNICODE_CHAR_NAME;
220 	zend_string *buffer = NULL;
221 	int32_t buffer_len;
222 
223 	ZEND_PARSE_PARAMETERS_START(1, 2)
224 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
225 		Z_PARAM_OPTIONAL
226 		Z_PARAM_LONG(nameChoice)
227 	ZEND_PARSE_PARAMETERS_END();
228 
229 	if (convert_cp(&cp, string_codepoint, int_codepoint) == FAILURE) {
230 		RETURN_NULL();
231 	}
232 
233 	buffer_len = u_charName(cp, (UCharNameChoice)nameChoice, NULL, 0, &error);
234 	buffer = zend_string_alloc(buffer_len, 0);
235 	error = U_ZERO_ERROR;
236 	buffer_len = u_charName(cp, (UCharNameChoice)nameChoice, ZSTR_VAL(buffer), ZSTR_LEN(buffer) + 1, &error);
237 	if (U_FAILURE(error)) {
238 		zend_string_efree(buffer);
239 		INTL_CHECK_STATUS_OR_NULL(error, "Failure getting character name");
240 	}
241 	RETURN_NEW_STR(buffer);
242 }
243 /* }}} */
244 
245 /* {{{ */
IC_METHOD(charFromName)246 IC_METHOD(charFromName) {
247 	char *name;
248 	size_t name_len;
249 	zend_long nameChoice = U_UNICODE_CHAR_NAME;
250 	UChar32 ret;
251 	UErrorCode error = U_ZERO_ERROR;
252 
253 	ZEND_PARSE_PARAMETERS_START(1, 2)
254 		Z_PARAM_STRING(name, name_len)
255 		Z_PARAM_OPTIONAL
256 		Z_PARAM_LONG(nameChoice)
257 	ZEND_PARSE_PARAMETERS_END();
258 
259 	ret = u_charFromName((UCharNameChoice)nameChoice, name, &error);
260 	INTL_CHECK_STATUS_OR_NULL(error, NULL);
261 	RETURN_LONG(ret);
262 }
263 /* }}} */
264 
265 /* {{{ void void IntlChar::enumCharNames(int|string $start, int|string $limit, callable $callback, int $nameChoice = IntlChar::UNICODE_CHAR_NAME) */
266 typedef struct _enumCharNames_data {
267 	zend_fcall_info fci;
268 	zend_fcall_info_cache fci_cache;
269 } enumCharNames_data;
enumCharNames_callback(enumCharNames_data * context,UChar32 code,UCharNameChoice nameChoice,const char * name,int32_t length)270 static UBool enumCharNames_callback(enumCharNames_data *context,
271 									UChar32 code, UCharNameChoice nameChoice,
272 									const char *name, int32_t length) {
273 	zval retval;
274 	zval args[3];
275 
276 	ZVAL_NULL(&retval);
277 	ZVAL_LONG(&args[0], code);
278 	ZVAL_LONG(&args[1], nameChoice);
279 	ZVAL_STRINGL(&args[2], name, length);
280 
281 	context->fci.retval = &retval;
282 	context->fci.param_count = 3;
283 	context->fci.params = args;
284 
285 	if (zend_call_function(&context->fci, &context->fci_cache) == FAILURE) {
286 		intl_error_set_code(NULL, U_INTERNAL_PROGRAM_ERROR);
287 		intl_error_set_custom_msg(NULL, "enumCharNames callback failed", 0);
288 		zval_ptr_dtor(&retval);
289 		zval_ptr_dtor_str(&args[2]);
290 		return 0;
291 	}
292 	zval_ptr_dtor(&retval);
293 	zval_ptr_dtor_str(&args[2]);
294 	return 1;
295 }
IC_METHOD(enumCharNames)296 IC_METHOD(enumCharNames) {
297 	UChar32 start, limit;
298 	zend_string *string_start, *string_limit;
299 	zend_long int_start = 0, int_limit = 0;
300 	enumCharNames_data context;
301 	zend_long nameChoice = U_UNICODE_CHAR_NAME;
302 	UErrorCode error = U_ZERO_ERROR;
303 
304 
305 	ZEND_PARSE_PARAMETERS_START(3, 4)
306 		Z_PARAM_STR_OR_LONG(string_start, int_start)
307 		Z_PARAM_STR_OR_LONG(string_limit, int_limit)
308 		Z_PARAM_FUNC(context.fci, context.fci_cache)
309 		Z_PARAM_OPTIONAL
310 		Z_PARAM_LONG(nameChoice)
311 	ZEND_PARSE_PARAMETERS_END();
312 
313 	if (convert_cp(&start, string_start, int_start) == FAILURE || convert_cp(&limit, string_limit, int_limit) == FAILURE) {
314 		RETURN_FALSE;
315 	}
316 
317 	u_enumCharNames(start, limit, (UEnumCharNamesFn*)enumCharNames_callback, &context, nameChoice, &error);
318 	INTL_CHECK_STATUS(error, NULL);
319 	RETURN_TRUE;
320 }
321 /* }}} */
322 
323 /* {{{ */
IC_METHOD(getPropertyName)324 IC_METHOD(getPropertyName) {
325 	zend_long property;
326 	zend_long nameChoice = U_LONG_PROPERTY_NAME;
327 	const char *ret;
328 
329 	ZEND_PARSE_PARAMETERS_START(1, 2)
330 		Z_PARAM_LONG(property)
331 		Z_PARAM_OPTIONAL
332 		Z_PARAM_LONG(nameChoice)
333 	ZEND_PARSE_PARAMETERS_END();
334 
335 	ret = u_getPropertyName((UProperty)property, (UPropertyNameChoice)nameChoice);
336 	if (ret) {
337 		RETURN_STRING(ret);
338 	} else {
339 		intl_error_set_code(NULL, U_ILLEGAL_ARGUMENT_ERROR);
340 		intl_error_set_custom_msg(NULL, "Failed to get property name", 0);
341 		RETURN_FALSE;
342 	}
343 }
344 /* }}} */
345 
346 /* {{{ */
IC_METHOD(getPropertyEnum)347 IC_METHOD(getPropertyEnum) {
348 	char *alias;
349 	size_t alias_len;
350 
351 	ZEND_PARSE_PARAMETERS_START(1, 1)
352 		Z_PARAM_STRING(alias, alias_len)
353 	ZEND_PARSE_PARAMETERS_END();
354 
355 	RETURN_LONG(u_getPropertyEnum(alias));
356 }
357 /* }}} */
358 
359 /* {{{ */
IC_METHOD(getPropertyValueName)360 IC_METHOD(getPropertyValueName) {
361 	zend_long property, value, nameChoice = U_LONG_PROPERTY_NAME;
362 	const char *ret;
363 
364 	ZEND_PARSE_PARAMETERS_START(2, 3)
365 		Z_PARAM_LONG(property)
366 		Z_PARAM_LONG(value)
367 		Z_PARAM_OPTIONAL
368 		Z_PARAM_LONG(nameChoice)
369 	ZEND_PARSE_PARAMETERS_END();
370 
371 	ret = u_getPropertyValueName((UProperty)property, value, (UPropertyNameChoice)nameChoice);
372 	if (ret) {
373 		RETURN_STRING(ret);
374 	} else {
375 		intl_error_set_code(NULL, U_ILLEGAL_ARGUMENT_ERROR);
376 		intl_error_set_custom_msg(NULL, "Failed to get property name", 0);
377 		RETURN_FALSE;
378 	}
379 }
380 /* }}} */
381 
382 /* {{{ */
IC_METHOD(getPropertyValueEnum)383 IC_METHOD(getPropertyValueEnum) {
384 	zend_long property;
385 	char *name;
386 	size_t name_len;
387 
388 	ZEND_PARSE_PARAMETERS_START(2, 2)
389 		Z_PARAM_LONG(property)
390 		Z_PARAM_STRING(name, name_len)
391 	ZEND_PARSE_PARAMETERS_END();
392 
393 	RETURN_LONG(u_getPropertyValueEnum((UProperty)property, name));
394 }
395 /* }}} */
396 
397 /* {{{ */
IC_METHOD(foldCase)398 IC_METHOD(foldCase) {
399 	UChar32 cp, ret;
400 	zend_long options = U_FOLD_CASE_DEFAULT;
401 	zend_string *string_codepoint;
402 	zend_long int_codepoint = 0;
403 
404 	ZEND_PARSE_PARAMETERS_START(2, 2)
405 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
406 		Z_PARAM_LONG(options)
407 	ZEND_PARSE_PARAMETERS_END();
408 
409 	if (convert_cp(&cp, string_codepoint, int_codepoint) == FAILURE) {
410 		RETURN_NULL();
411 	}
412 
413 	ret = u_foldCase(cp, options);
414 	if (string_codepoint != NULL) {
415 		char buffer[5];
416 		int buffer_len = 0;
417 		U8_APPEND_UNSAFE(buffer, buffer_len, ret);
418 		buffer[buffer_len] = 0;
419 		RETURN_STRINGL(buffer, buffer_len);
420 	} else {
421 		RETURN_LONG(ret);
422 	}
423 }
424 /* }}} */
425 
426 /* {{{ */
IC_METHOD(digit)427 IC_METHOD(digit) {
428 	UChar32 cp;
429 	zend_long radix = 10;
430 	int ret;
431 	zend_string *string_codepoint;
432 	zend_long int_codepoint = 0;
433 
434 	ZEND_PARSE_PARAMETERS_START(1, 2)
435 		Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint)
436 		Z_PARAM_OPTIONAL
437 		Z_PARAM_LONG(radix)
438 	ZEND_PARSE_PARAMETERS_END();
439 
440 	if (convert_cp(&cp, string_codepoint, int_codepoint) == FAILURE) {
441 		RETURN_NULL();
442 	}
443 
444 	ret = u_digit(cp, radix);
445 	if (ret < 0) {
446 		intl_error_set_code(NULL, U_ILLEGAL_ARGUMENT_ERROR);
447 		intl_error_set_custom_msg(NULL, "Invalid digit", 0);
448 		RETURN_FALSE;
449 	}
450 	RETURN_LONG(ret);
451 }
452 /* }}} */
453 
454 /* {{{ */
IC_METHOD(forDigit)455 IC_METHOD(forDigit) {
456 	zend_long digit, radix = 10;
457 
458 	ZEND_PARSE_PARAMETERS_START(1, 2)
459 		Z_PARAM_LONG(digit)
460 		Z_PARAM_OPTIONAL
461 		Z_PARAM_LONG(radix)
462 	ZEND_PARSE_PARAMETERS_END();
463 
464 	RETURN_LONG(u_forDigit(digit, radix));
465 }
466 /* }}} */
467 
468 /* {{{ */
IC_METHOD(charAge)469 IC_METHOD(charAge) {
470 	UChar32 cp;
471 	UVersionInfo version;
472 	int i;
473 
474 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
475 		RETURN_NULL();
476 	}
477 
478 	u_charAge(cp, version);
479 	array_init(return_value);
480 	for(i = 0; i < U_MAX_VERSION_LENGTH; ++i) {
481 		add_next_index_long(return_value, version[i]);
482 	}
483 }
484 /* }}} */
485 
486 /* {{{ */
IC_METHOD(getUnicodeVersion)487 IC_METHOD(getUnicodeVersion) {
488 	UVersionInfo version;
489 	int i;
490 
491 	ZEND_PARSE_PARAMETERS_NONE();
492 
493 	u_getUnicodeVersion(version);
494 	array_init(return_value);
495 	for(i = 0; i < U_MAX_VERSION_LENGTH; ++i) {
496 		add_next_index_long(return_value, version[i]);
497 	}
498 }
499 /* }}} */
500 
501 /* {{{ */
IC_METHOD(getFC_NFKC_Closure)502 IC_METHOD(getFC_NFKC_Closure) {
503 	UChar32 cp;
504 	UChar *closure;
505 	zend_string *u8str;
506 	int32_t closure_len;
507 	UErrorCode error = U_ZERO_ERROR;
508 
509 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) {
510 		RETURN_NULL();
511 	}
512 
513 	closure_len = u_getFC_NFKC_Closure(cp, NULL, 0, &error);
514 	if (closure_len == 0) {
515 		RETURN_EMPTY_STRING();
516 	}
517 	closure = safe_emalloc(sizeof(UChar), closure_len + 1, 0);
518 	error = U_ZERO_ERROR;
519 	closure_len = u_getFC_NFKC_Closure(cp, closure, closure_len, &error);
520 	if (U_FAILURE(error)) {
521 		efree(closure);
522 		INTL_CHECK_STATUS(error, "Failed getting closure");
523 	}
524 
525 	error = U_ZERO_ERROR;
526 	u8str = intl_convert_utf16_to_utf8(closure, closure_len, &error);
527 	INTL_CHECK_STATUS(error, "Failed converting output to UTF8");
528 	efree(closure);
529 	RETVAL_NEW_STR(u8str);
530 }
531 /* }}} */
532 
533 /* {{{ */
534 #define IC_BOOL_METHOD_CHAR(name) \
535 IC_METHOD(name) { \
536 	UChar32 cp; \
537 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) { \
538 		RETURN_NULL(); \
539 	} \
540 	RETURN_BOOL(u_##name(cp)); \
541 }
542 IC_BOOL_METHOD_CHAR(isUAlphabetic)
IC_BOOL_METHOD_CHAR(isULowercase)543 IC_BOOL_METHOD_CHAR(isULowercase)
544 IC_BOOL_METHOD_CHAR(isUUppercase)
545 IC_BOOL_METHOD_CHAR(isUWhiteSpace)
546 IC_BOOL_METHOD_CHAR(islower)
547 IC_BOOL_METHOD_CHAR(isupper)
548 IC_BOOL_METHOD_CHAR(istitle)
549 IC_BOOL_METHOD_CHAR(isdigit)
550 IC_BOOL_METHOD_CHAR(isalpha)
551 IC_BOOL_METHOD_CHAR(isalnum)
552 IC_BOOL_METHOD_CHAR(isxdigit)
553 IC_BOOL_METHOD_CHAR(ispunct)
554 IC_BOOL_METHOD_CHAR(isgraph)
555 IC_BOOL_METHOD_CHAR(isblank)
556 IC_BOOL_METHOD_CHAR(isdefined)
557 IC_BOOL_METHOD_CHAR(isspace)
558 IC_BOOL_METHOD_CHAR(isJavaSpaceChar)
559 IC_BOOL_METHOD_CHAR(isWhitespace)
560 IC_BOOL_METHOD_CHAR(iscntrl)
561 IC_BOOL_METHOD_CHAR(isISOControl)
562 IC_BOOL_METHOD_CHAR(isprint)
563 IC_BOOL_METHOD_CHAR(isbase)
564 IC_BOOL_METHOD_CHAR(isMirrored)
565 IC_BOOL_METHOD_CHAR(isIDStart)
566 IC_BOOL_METHOD_CHAR(isIDPart)
567 IC_BOOL_METHOD_CHAR(isIDIgnorable)
568 IC_BOOL_METHOD_CHAR(isJavaIDStart)
569 IC_BOOL_METHOD_CHAR(isJavaIDPart)
570 #undef IC_BOOL_METHOD_CHAR
571 /* }}} */
572 
573 /* {{{ */
574 #define IC_INT_METHOD_CHAR(name) \
575 IC_METHOD(name) { \
576 	UChar32 cp; \
577 	if (parse_code_point_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, &cp) == FAILURE) { \
578 		RETURN_NULL(); \
579 	} \
580 	RETURN_LONG(u_##name(cp)); \
581 }
582 IC_INT_METHOD_CHAR(charDirection)
583 IC_INT_METHOD_CHAR(charType)
584 IC_INT_METHOD_CHAR(getCombiningClass)
585 IC_INT_METHOD_CHAR(charDigitValue)
586 #undef IC_INT_METHOD_CHAR
587 /* }}} */
588 
589 /* {{{ Returns a utf-8 character if codepoint was passed as a utf-8 sequence
590  * Returns an int otherwise
591  */
592 #define IC_CHAR_METHOD_CHAR(name) \
593 IC_METHOD(name) { \
594 	UChar32 cp, ret; \
595 	zend_string *string_codepoint; \
596 		zend_long int_codepoint = -1; \
597 		ZEND_PARSE_PARAMETERS_START(1, 1) \
598 			Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint) \
599 		ZEND_PARSE_PARAMETERS_END(); \
600 		if (convert_cp(&cp, string_codepoint, int_codepoint) == FAILURE) { \
601 			RETURN_NULL(); \
602 		} \
603 	ret = u_##name(cp); \
604 	if (string_codepoint != NULL) { \
605 		char buffer[5]; \
606 		int buffer_len = 0; \
607 		U8_APPEND_UNSAFE(buffer, buffer_len, ret); \
608 		buffer[buffer_len] = 0; \
609 		RETURN_STRINGL(buffer, buffer_len); \
610 	} else { \
611 		RETURN_LONG(ret); \
612 	} \
613 }
614 IC_CHAR_METHOD_CHAR(charMirror)
615 IC_CHAR_METHOD_CHAR(tolower)
616 IC_CHAR_METHOD_CHAR(toupper)
617 IC_CHAR_METHOD_CHAR(totitle)
618 #if U_ICU_VERSION_MAJOR_NUM >= 52
619 IC_CHAR_METHOD_CHAR(getBidiPairedBracket)
620 #endif /* ICU >= 52 */
621 #undef IC_CHAR_METHOD_CHAR
622 /* }}} */
623 
624 int php_uchar_minit(INIT_FUNC_ARGS) {
625 	register_class_IntlChar();
626 
627 	return SUCCESS;
628 }
629