From 777d14d9fb61c3d66512d69bb06c1e9fb7e1b20e Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Mon, 11 Sep 2023 22:37:05 -0500 Subject: [PATCH] feat: support ecma_intl.default_locale INI setting --- src/php/ecma_intl.c | 84 +++++++++++++++++++++++++- src/php/ecma_intl.h | 12 ++++ tests/phpt/ini-default_locale-001.phpt | 14 +++++ tests/phpt/ini-default_locale-002.phpt | 14 +++++ tests/phpt/ini-default_locale-003.phpt | 14 +++++ tests/phpt/ini-default_locale-004.phpt | 14 +++++ tests/phpt/ini-default_locale-005.phpt | 14 +++++ tests/phpt/ini-default_locale-006.phpt | 24 ++++++++ 8 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 tests/phpt/ini-default_locale-001.phpt create mode 100644 tests/phpt/ini-default_locale-002.phpt create mode 100644 tests/phpt/ini-default_locale-003.phpt create mode 100644 tests/phpt/ini-default_locale-004.phpt create mode 100644 tests/phpt/ini-default_locale-005.phpt create mode 100644 tests/phpt/ini-default_locale-006.phpt diff --git a/src/php/ecma_intl.c b/src/php/ecma_intl.c index 91ded7e..88538f1 100644 --- a/src/php/ecma_intl.c +++ b/src/php/ecma_intl.c @@ -16,6 +16,7 @@ #include "php/ecma_intl.h" +#include "ecma402/locale.h" #include "php/classes/category.h" #include "php/classes/collator.h" #include "php/classes/intl.h" @@ -28,18 +29,75 @@ #include "php/classes/supported_locales_options.h" #include +#include #include +#include + +ZEND_DECLARE_MODULE_GLOBALS(ecma_intl) + +/** + * Validates whether the locale provided in the ecma_intl.default_locale INI + * setting is supported by this implementation. If so, it stores the canonicalized + * BCP 47 version of the language tag to a global setting. + */ +ZEND_INI_MH(onUpdateLocale) +{ + if (!new_value || (new_value && !ZSTR_VAL(new_value)[0])) { + return FAILURE; + } + + char **p = (char **)ZEND_INI_GET_ADDR(); + char **available, *bestAvailable, *canonicalized; + size_t total, length; + zend_result result = FAILURE; + ecma402_errorStatus *status; + + available = (char **)emalloc(sizeof(char *) * uloc_countAvailable()); + bestAvailable = (char *)emalloc(sizeof(char) * ULOC_FULLNAME_CAPACITY); + total = ecma402_intlAvailableLocales(available); + + if (ecma402_bestAvailableLocale(available, total, ZSTR_VAL(new_value), bestAvailable, false) > 0) { + status = ecma402_initErrorStatus(); + canonicalized = (char *)emalloc(sizeof(char) * ULOC_FULLNAME_CAPACITY); + length = ecma402_canonicalizeUnicodeLocaleId(ZSTR_VAL(new_value), canonicalized, status); + + if (!ecma402_hasError(status) && length > 0) { + strcpy(*p, canonicalized); + result = SUCCESS; + } + + efree(canonicalized); + ecma402_freeErrorStatus(status); + } + + efree(bestAvailable); + efree(available); + + return result; +} + +PHP_INI_BEGIN() +STD_PHP_INI_ENTRY("ecma_intl.default_locale", NULL, PHP_INI_ALL, onUpdateLocale, defaultLocale, zend_ecma_intl_globals, + ecma_intl_globals) +PHP_INI_END() + +static PHP_GINIT_FUNCTION(ecma_intl); +static PHP_GSHUTDOWN_FUNCTION(ecma_intl); zend_module_entry ecma_intl_module_entry = {STANDARD_MODULE_HEADER, "ecma_intl", NULL, PHP_MINIT(ecma_intl_all), - NULL, + PHP_MSHUTDOWN(ecma_intl), PHP_RINIT(ecma_intl), NULL, PHP_MINFO(ecma_intl), PHP_ECMA_INTL_VERSION, - STANDARD_MODULE_PROPERTIES}; + PHP_MODULE_GLOBALS(ecma_intl), + PHP_GINIT(ecma_intl), + PHP_GSHUTDOWN(ecma_intl), + NULL, + STANDARD_MODULE_PROPERTIES_EX}; #ifdef COMPILE_DL_ECMA_INTL # ifdef ZTS @@ -48,8 +106,21 @@ ZEND_TSRMLS_CACHE_DEFINE() ZEND_GET_MODULE(ecma_intl) #endif +static PHP_GINIT_FUNCTION(ecma_intl) +{ + ZEND_SECURE_ZERO(ecma_intl_globals, sizeof(zend_ecma_intl_globals)); + ecma_intl_globals->defaultLocale = (char *)emalloc(sizeof(char) * ULOC_FULLNAME_CAPACITY); +} + +static PHP_GSHUTDOWN_FUNCTION(ecma_intl) +{ + efree(ecma_intl_globals->defaultLocale); +} + PHP_MINIT_FUNCTION(ecma_intl_all) { + REGISTER_INI_ENTRIES(); + PHP_MINIT(ecma_intl)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(ecma_intl_category)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(ecma_intl_collator)(INIT_FUNC_ARGS_PASSTHRU); @@ -64,6 +135,13 @@ PHP_MINIT_FUNCTION(ecma_intl_all) return SUCCESS; } +PHP_MSHUTDOWN_FUNCTION(ecma_intl) +{ + UNREGISTER_INI_ENTRIES(); + + return SUCCESS; +} + PHP_RINIT_FUNCTION(ecma_intl) { #if defined(ZTS) && defined(COMPILE_DL_ECMA_INTL) @@ -91,4 +169,6 @@ PHP_MINFO_FUNCTION(ecma_intl) php_info_print_table_row(2, "ICU TZData version", timeZoneDataVersion); php_info_print_table_row(2, "ICU Unicode version", U_UNICODE_VERSION); php_info_print_table_end(); + + DISPLAY_INI_ENTRIES(); } diff --git a/src/php/ecma_intl.h b/src/php/ecma_intl.h index eaa89ba..0c91435 100644 --- a/src/php/ecma_intl.h +++ b/src/php/ecma_intl.h @@ -20,11 +20,23 @@ extern zend_module_entry ecma_intl_module_entry; #define PHP_ECMA_INTL_VERSION "0.3.0-dev" +ZEND_BEGIN_MODULE_GLOBALS(ecma_intl) +char *defaultLocale; +ZEND_END_MODULE_GLOBALS(ecma_intl) + #if defined(ZTS) && defined(COMPILE_DL_ECMA_INTL) ZEND_TSRMLS_CACHE_EXTERN() #endif +ZEND_EXTERN_MODULE_GLOBALS(ecma_intl) +#ifdef ZTS +# define ECMA_INTL_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(ecma_intl, v) +#else +# define ECMA_INTL_G(v) (ecma_intl_globals.v) +#endif + PHP_MINIT_FUNCTION(ecma_intl_all); +PHP_MSHUTDOWN_FUNCTION(ecma_intl); PHP_RINIT_FUNCTION(ecma_intl); PHP_MINFO_FUNCTION(ecma_intl); diff --git a/tests/phpt/ini-default_locale-001.phpt b/tests/phpt/ini-default_locale-001.phpt new file mode 100644 index 0000000..89396a1 --- /dev/null +++ b/tests/phpt/ini-default_locale-001.phpt @@ -0,0 +1,14 @@ +--TEST-- +ecma_intl.default_locale has an empty string when set to empty +--EXTENSIONS-- +ecma_intl +--INI-- +ecma_intl.default_locale= +--FILE-- +