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