diff --git a/ext/intl/grapheme/grapheme_string.c b/ext/intl/grapheme/grapheme_string.c index 34dd2ed369cfc..776b7a3ec6ae7 100644 --- a/ext/intl/grapheme/grapheme_string.c +++ b/ext/intl/grapheme/grapheme_string.c @@ -84,6 +84,7 @@ PHP_FUNCTION(grapheme_strpos) char *haystack, *needle; size_t haystack_len, needle_len; const char *found; + char *locale = ""; zend_long loffset = 0; int32_t offset = 0; size_t noffset = 0; @@ -121,7 +122,7 @@ PHP_FUNCTION(grapheme_strpos) } /* do utf16 part of the strpos */ - ret_pos = grapheme_strpos_utf16(haystack, haystack_len, needle, needle_len, offset, NULL, 0 /* fIgnoreCase */, 0 /* last */ ); + ret_pos = grapheme_strpos_utf16(haystack, haystack_len, needle, needle_len, offset, NULL, 0 /* fIgnoreCase */, 0, locale /* last */ ); if ( ret_pos >= 0 ) { RETURN_LONG(ret_pos); @@ -134,19 +135,20 @@ PHP_FUNCTION(grapheme_strpos) /* {{{ Find position of first occurrence of a string within another, ignoring case differences */ PHP_FUNCTION(grapheme_stripos) { - char *haystack, *needle; - size_t haystack_len, needle_len; + char *haystack, *needle, *locale = ""; + size_t haystack_len, needle_len, locale_len = 0; const char *found; zend_long loffset = 0; int32_t offset = 0; zend_long ret_pos; int is_ascii; - ZEND_PARSE_PARAMETERS_START(2, 3) + ZEND_PARSE_PARAMETERS_START(2, 4) Z_PARAM_STRING(haystack, haystack_len) Z_PARAM_STRING(needle, needle_len) Z_PARAM_OPTIONAL Z_PARAM_LONG(loffset) + Z_PARAM_STRING_OR_NULL(locale, locale_len) ZEND_PARSE_PARAMETERS_END(); if ( OUTSIDE_STRING(loffset, haystack_len) ) { @@ -185,7 +187,7 @@ PHP_FUNCTION(grapheme_stripos) } /* do utf16 part of the strpos */ - ret_pos = grapheme_strpos_utf16(haystack, haystack_len, needle, needle_len, offset, NULL, 1 /* fIgnoreCase */, 0 /*last */ ); + ret_pos = grapheme_strpos_utf16(haystack, haystack_len, needle, needle_len, offset, NULL, 1 /* fIgnoreCase */, 0, locale /*last */ ); if ( ret_pos >= 0 ) { RETURN_LONG(ret_pos); @@ -200,6 +202,7 @@ PHP_FUNCTION(grapheme_stripos) PHP_FUNCTION(grapheme_strrpos) { char *haystack, *needle; + char *locale = ""; size_t haystack_len, needle_len; zend_long loffset = 0; int32_t offset = 0; @@ -242,7 +245,7 @@ PHP_FUNCTION(grapheme_strrpos) /* else we need to continue via utf16 */ } - ret_pos = grapheme_strpos_utf16(haystack, haystack_len, needle, needle_len, offset, NULL, 0 /* f_ignore_case */, 1/* last */); + ret_pos = grapheme_strpos_utf16(haystack, haystack_len, needle, needle_len, offset, NULL, 0 /* f_ignore_case */, 1, locale /* last */); if ( ret_pos >= 0 ) { RETURN_LONG(ret_pos); @@ -257,18 +260,19 @@ PHP_FUNCTION(grapheme_strrpos) /* {{{ Find position of last occurrence of a string within another, ignoring case */ PHP_FUNCTION(grapheme_strripos) { - char *haystack, *needle; - size_t haystack_len, needle_len; + char *haystack, *needle, *locale = ""; + size_t haystack_len, needle_len, locale_len = 0; zend_long loffset = 0; int32_t offset = 0; zend_long ret_pos; int is_ascii; - ZEND_PARSE_PARAMETERS_START(2, 3) + ZEND_PARSE_PARAMETERS_START(2, 4) Z_PARAM_STRING(haystack, haystack_len) Z_PARAM_STRING(needle, needle_len) Z_PARAM_OPTIONAL Z_PARAM_LONG(loffset) + Z_PARAM_STRING_OR_NULL(locale, locale_len) ZEND_PARSE_PARAMETERS_END(); if ( OUTSIDE_STRING(loffset, haystack_len) ) { @@ -309,7 +313,7 @@ PHP_FUNCTION(grapheme_strripos) /* else we need to continue via utf16 */ } - ret_pos = grapheme_strpos_utf16(haystack, haystack_len, needle, needle_len, offset, NULL, 1 /* f_ignore_case */, 1 /*last */); + ret_pos = grapheme_strpos_utf16(haystack, haystack_len, needle, needle_len, offset, NULL, 1 /* f_ignore_case */, 1, locale /*last */); if ( ret_pos >= 0 ) { RETURN_LONG(ret_pos); @@ -537,18 +541,29 @@ PHP_FUNCTION(grapheme_substr) /* {{{ strstr_common_handler */ static void strstr_common_handler(INTERNAL_FUNCTION_PARAMETERS, int f_ignore_case) { - char *haystack, *needle; + char *haystack, *needle, *locale = ""; const char *found; - size_t haystack_len, needle_len; + size_t haystack_len, needle_len, locale_len = 0; int32_t ret_pos, uchar_pos; bool part = false; - ZEND_PARSE_PARAMETERS_START(2, 3) - Z_PARAM_STRING(haystack, haystack_len) - Z_PARAM_STRING(needle, needle_len) - Z_PARAM_OPTIONAL - Z_PARAM_BOOL(part) - ZEND_PARSE_PARAMETERS_END(); + if (f_ignore_case == 1) { + ZEND_PARSE_PARAMETERS_START(2, 4) + Z_PARAM_STRING(haystack, haystack_len) + Z_PARAM_STRING(needle, needle_len) + Z_PARAM_OPTIONAL + Z_PARAM_BOOL(part) + Z_PARAM_STRING_OR_NULL(locale, locale_len) + ZEND_PARSE_PARAMETERS_END(); + } else { + ZEND_PARSE_PARAMETERS_START(2, 3) + Z_PARAM_STRING(haystack, haystack_len) + Z_PARAM_STRING(needle, needle_len) + Z_PARAM_OPTIONAL + Z_PARAM_BOOL(part) + Z_PARAM_STRING_OR_NULL(locale, locale_len) + ZEND_PARSE_PARAMETERS_END(); + } if ( !f_ignore_case ) { @@ -574,7 +589,7 @@ static void strstr_common_handler(INTERNAL_FUNCTION_PARAMETERS, int f_ignore_cas } /* need to work in utf16 */ - ret_pos = grapheme_strpos_utf16(haystack, haystack_len, needle, needle_len, 0, &uchar_pos, f_ignore_case, 0 /*last */ ); + ret_pos = grapheme_strpos_utf16(haystack, haystack_len, needle, needle_len, 0, &uchar_pos, f_ignore_case, 0, locale /*last */ ); if ( ret_pos < 0 ) { RETURN_FALSE; @@ -919,6 +934,8 @@ PHP_FUNCTION(grapheme_levenshtein) zend_long cost_ins = 1; zend_long cost_rep = 1; zend_long cost_del = 1; + char *locale = ""; + size_t locale_len = 0; ZEND_PARSE_PARAMETERS_START(2, 5) Z_PARAM_STR(string1) @@ -927,6 +944,7 @@ PHP_FUNCTION(grapheme_levenshtein) Z_PARAM_LONG(cost_ins) Z_PARAM_LONG(cost_rep) Z_PARAM_LONG(cost_del) + Z_PARAM_STRING_OR_NULL(locale, locale_len) ZEND_PARSE_PARAMETERS_END(); if (cost_ins <= 0 || cost_ins > UINT_MAX / 4) { @@ -1043,7 +1061,7 @@ PHP_FUNCTION(grapheme_levenshtein) RETVAL_FALSE; goto out_bi2; } - UCollator *collator = ucol_open("", &ustatus); + UCollator *collator = ucol_open(locale, &ustatus); if (U_FAILURE(ustatus)) { intl_error_set_code(NULL, ustatus); diff --git a/ext/intl/grapheme/grapheme_util.c b/ext/intl/grapheme/grapheme_util.c index 501b9dfb221d0..87facb9c35bbb 100644 --- a/ext/intl/grapheme/grapheme_util.c +++ b/ext/intl/grapheme/grapheme_util.c @@ -94,7 +94,7 @@ void grapheme_substr_ascii(char *str, size_t str_len, int32_t f, int32_t l, char /* {{{ grapheme_strpos_utf16 - strrpos using utf16*/ -int32_t grapheme_strpos_utf16(char *haystack, size_t haystack_len, char *needle, size_t needle_len, int32_t offset, int32_t *puchar_pos, int f_ignore_case, int last) +int32_t grapheme_strpos_utf16(char *haystack, size_t haystack_len, char *needle, size_t needle_len, int32_t offset, int32_t *puchar_pos, int f_ignore_case, int last, char* locale) { UChar *uhaystack = NULL, *uneedle = NULL; int32_t uhaystack_len = 0, uneedle_len = 0, char_pos, ret_pos, offset_pos = 0; @@ -136,7 +136,7 @@ int32_t grapheme_strpos_utf16(char *haystack, size_t haystack_len, char *needle, } status = U_ZERO_ERROR; - src = usearch_open(uneedle, uneedle_len, uhaystack, uhaystack_len, "", bi, &status); + src = usearch_open(uneedle, uneedle_len, uhaystack, uhaystack_len, locale, bi, &status); STRPOS_CHECK_STATUS(status, "Error creating search object"); if(f_ignore_case) { diff --git a/ext/intl/grapheme/grapheme_util.h b/ext/intl/grapheme/grapheme_util.h index d03194621acf3..00ef90cdffef0 100644 --- a/ext/intl/grapheme/grapheme_util.h +++ b/ext/intl/grapheme/grapheme_util.h @@ -26,7 +26,7 @@ void grapheme_substr_ascii(char *str, size_t str_len, int32_t f, int32_t l, char zend_long grapheme_strrpos_ascii(char *haystack, size_t haystack_len, char *needle, size_t needle_len, int32_t offset); int32_t grapheme_strrpos_utf16(char *haystack, size_t haystack_len, char *needle, size_t needle_len, int32_t offset, int f_ignore_case); -int32_t grapheme_strpos_utf16(char *haystack, size_t haystack_len, char *needle, size_t needle_len, int32_t offset, int *puchar_pos, int f_ignore_case, int last); +int32_t grapheme_strpos_utf16(char *haystack, size_t haystack_len, char *needle, size_t needle_len, int32_t offset, int *puchar_pos, int f_ignore_case, int last, char* locale); int32_t grapheme_split_string(const UChar *text, int32_t text_length, int boundary_array[], int boundary_array_len ); diff --git a/ext/intl/php_intl.stub.php b/ext/intl/php_intl.stub.php index dfb05a2b50ac5..6db2dfcf96dd4 100644 --- a/ext/intl/php_intl.stub.php +++ b/ext/intl/php_intl.stub.php @@ -433,21 +433,21 @@ function grapheme_strlen(string $string): int|false|null {} function grapheme_strpos(string $haystack, string $needle, int $offset = 0): int|false {} -function grapheme_stripos(string $haystack, string $needle, int $offset = 0): int|false {} +function grapheme_stripos(string $haystack, string $needle, int $offset = 0, ?string $locale = null): int|false {} function grapheme_strrpos(string $haystack, string $needle, int $offset = 0): int|false {} -function grapheme_strripos(string $haystack, string $needle, int $offset = 0): int|false {} +function grapheme_strripos(string $haystack, string $needle, int $offset = 0, ?string $locale = null): int|false {} function grapheme_substr(string $string, int $offset, ?int $length = null): string|false {} function grapheme_strstr(string $haystack, string $needle, bool $beforeNeedle = false): string|false {} -function grapheme_stristr(string $haystack, string $needle, bool $beforeNeedle = false): string|false {} +function grapheme_stristr(string $haystack, string $needle, bool $beforeNeedle = false, ?string $locale = null): string|false {} function grapheme_str_split(string $string, int $length = 1): array|false {} -function grapheme_levenshtein(string $string1, string $string2, int $insertion_cost = 1, int $replacement_cost = 1, int $deletion_cost = 1): int|false {} +function grapheme_levenshtein(string $string1, string $string2, int $insertion_cost = 1, int $replacement_cost = 1, int $deletion_cost = 1, ?string $locale = null): int|false {} /** @param int $next */ function grapheme_extract(string $haystack, int $size, int $type = GRAPHEME_EXTR_COUNT, int $offset = 0, &$next = null): string|false {} diff --git a/ext/intl/php_intl_arginfo.h b/ext/intl/php_intl_arginfo.h index b710084910733..e014c54b3aa15 100644 --- a/ext/intl/php_intl_arginfo.h +++ b/ext/intl/php_intl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 0d5b028a1ab8f35e8ee1b51ce3141b6ef782af28 */ + * Stub hash: b063534d9cc4b624fe742672858c30828db6a9b9 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_intlcal_create_instance, 0, 0, IntlCalendar, 1) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, timezone, "null") @@ -464,11 +464,16 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_grapheme_strpos, 0, 2, MAY_BE_LO ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, offset, IS_LONG, 0, "0") ZEND_END_ARG_INFO() -#define arginfo_grapheme_stripos arginfo_grapheme_strpos +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_grapheme_stripos, 0, 2, MAY_BE_LONG|MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, haystack, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, needle, IS_STRING, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, offset, IS_LONG, 0, "0") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, locale, IS_STRING, 1, "null") +ZEND_END_ARG_INFO() #define arginfo_grapheme_strrpos arginfo_grapheme_strpos -#define arginfo_grapheme_strripos arginfo_grapheme_strpos +#define arginfo_grapheme_strripos arginfo_grapheme_stripos ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_grapheme_substr, 0, 2, MAY_BE_STRING|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0) @@ -482,7 +487,12 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_grapheme_strstr, 0, 2, MAY_BE_ST ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, beforeNeedle, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() -#define arginfo_grapheme_stristr arginfo_grapheme_strstr +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_grapheme_stristr, 0, 2, MAY_BE_STRING|MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, haystack, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, needle, IS_STRING, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, beforeNeedle, _IS_BOOL, 0, "false") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, locale, IS_STRING, 1, "null") +ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_grapheme_str_split, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, string, IS_STRING, 0) @@ -495,6 +505,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_grapheme_levenshtein, 0, 2, MAY_ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, insertion_cost, IS_LONG, 0, "1") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, replacement_cost, IS_LONG, 0, "1") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, deletion_cost, IS_LONG, 0, "1") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, locale, IS_STRING, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_grapheme_extract, 0, 2, MAY_BE_STRING|MAY_BE_FALSE) diff --git a/ext/intl/tests/grapheme_levenshtein.phpt b/ext/intl/tests/grapheme_levenshtein.phpt index 4ff7dbb607bcd..719e177d7afc4 100644 --- a/ext/intl/tests/grapheme_levenshtein.phpt +++ b/ext/intl/tests/grapheme_levenshtein.phpt @@ -80,6 +80,10 @@ try { } catch (ValueError $e) { echo $e->getMessage() . PHP_EOL; } + +echo '--- Locale string ---' . \PHP_EOL; +var_dump(grapheme_stripos("i", "\u{0130}", 0, "tr_TR")); +var_dump(grapheme_stripos("i", "\u{0130}", 0, "en_US")); ?> --EXPECTF-- --- Equal --- @@ -126,3 +130,6 @@ int(0) grapheme_levenshtein(): Argument #3 ($insertion_cost) must be greater than 0 and less than or equal to %d grapheme_levenshtein(): Argument #4 ($replacement_cost) must be greater than 0 and less than or equal to %d grapheme_levenshtein(): Argument #5 ($deletion_cost) must be greater than 0 and less than or equal to %d +--- Locale string --- +int(0) +bool(false) diff --git a/ext/intl/tests/grapheme_stripos_locale_dependency.phpt b/ext/intl/tests/grapheme_stripos_locale_dependency.phpt new file mode 100644 index 0000000000000..e868e6f085c03 --- /dev/null +++ b/ext/intl/tests/grapheme_stripos_locale_dependency.phpt @@ -0,0 +1,14 @@ +--TEST-- +grapheme_stripos() function locale dependency test +--EXTENSIONS-- +intl +--FILE-- + +--EXPECT-- +int(0) +int(0) +bool(false) diff --git a/ext/intl/tests/grapheme_stristr_locale_dependency.phpt b/ext/intl/tests/grapheme_stristr_locale_dependency.phpt new file mode 100644 index 0000000000000..ea329f7d18c15 --- /dev/null +++ b/ext/intl/tests/grapheme_stristr_locale_dependency.phpt @@ -0,0 +1,15 @@ +--TEST-- +grapheme_stristr() function locale dependency test +--EXTENSIONS-- +intl +--FILE-- + +--EXPECT-- +string(3) "abc" +string(1) "i" +bool(false) + diff --git a/ext/intl/tests/grapheme_strripos_locale_dependency.phpt b/ext/intl/tests/grapheme_strripos_locale_dependency.phpt new file mode 100644 index 0000000000000..aecc74b5ab001 --- /dev/null +++ b/ext/intl/tests/grapheme_strripos_locale_dependency.phpt @@ -0,0 +1,14 @@ +--TEST-- +grapheme_strripos() function locale dependency test +--EXTENSIONS-- +intl +--FILE-- + +--EXPECT-- +int(0) +int(0) +bool(false)