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