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