Skip to content

Commit

Permalink
feat: support ecma_intl.default_locale INI setting
Browse files Browse the repository at this point in the history
  • Loading branch information
ramsey committed Sep 12, 2023
1 parent 3b50906 commit 777d14d
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 2 deletions.
84 changes: 82 additions & 2 deletions src/php/ecma_intl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -28,18 +29,75 @@
#include "php/classes/supported_locales_options.h"

#include <ext/standard/info.h>
#include <php_ini.h>
#include <unicode/ucal.h>
#include <unicode/uloc.h>

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
Expand All @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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();
}
12 changes: 12 additions & 0 deletions src/php/ecma_intl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
14 changes: 14 additions & 0 deletions tests/phpt/ini-default_locale-001.phpt
Original file line number Diff line number Diff line change
@@ -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--
<?php
declare(strict_types=1);

var_dump(ini_get('ecma_intl.default_locale'));

--EXPECT--
string(0) ""
14 changes: 14 additions & 0 deletions tests/phpt/ini-default_locale-002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
ecma_intl.default_locale has an empty string when set to an invalid value
--EXTENSIONS--
ecma_intl
--INI--
ecma_intl.default_locale=foobar
--FILE--
<?php
declare(strict_types=1);

var_dump(ini_get('ecma_intl.default_locale'));

--EXPECT--
string(0) ""
14 changes: 14 additions & 0 deletions tests/phpt/ini-default_locale-003.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
ecma_intl.default_locale has a value when set to a valid value
--EXTENSIONS--
ecma_intl
--INI--
ecma_intl.default_locale=en-US
--FILE--
<?php
declare(strict_types=1);

var_dump(ini_get('ecma_intl.default_locale'));

--EXPECT--
string(5) "en-US"
14 changes: 14 additions & 0 deletions tests/phpt/ini-default_locale-004.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
ecma_intl.default_locale can be set to en-US-POSIX
--EXTENSIONS--
ecma_intl
--INI--
ecma_intl.default_locale=en-US-POSIX
--FILE--
<?php
declare(strict_types=1);

var_dump(ini_get('ecma_intl.default_locale'));

--EXPECT--
string(11) "en-US-POSIX"
14 changes: 14 additions & 0 deletions tests/phpt/ini-default_locale-005.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
ecma_intl.default_locale cannot recognize underscores in locale IDs
--EXTENSIONS--
ecma_intl
--INI--
ecma_intl.default_locale=en_US_POSIX
--FILE--
<?php
declare(strict_types=1);

var_dump(ini_get('ecma_intl.default_locale'));

--EXPECT--
string(0) ""
24 changes: 24 additions & 0 deletions tests/phpt/ini-default_locale-006.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
ecma_intl.default_locale can be set from the application
--EXTENSIONS--
ecma_intl
--INI--
ecma_intl.default_locale=
--FILE--
<?php
declare(strict_types=1);

var_dump(ini_set('ecma_intl.default_locale', 'en-US'));
var_dump(ini_set('ecma_intl.default_locale', 'foobar'));
var_dump(ini_set('ecma_intl.default_locale', 'en-Latn-US'));
var_dump(ini_set('ecma_intl.default_locale', 'en-US-POSIX'));
var_dump(ini_set('ecma_intl.default_locale', 'de'));
var_dump(ini_get('ecma_intl.default_locale'));

--EXPECT--
string(0) ""
bool(false)
string(5) "en-US"
string(10) "en-Latn-US"
string(11) "en-US-POSIX"
string(2) "de"

0 comments on commit 777d14d

Please sign in to comment.