From c59325be44cc2ce4197eeebb24f3c5c0e383cfa9 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Mon, 30 Mar 2026 20:28:03 +0300 Subject: [PATCH 1/3] added test --- runtime-light/k2-platform/k2-api.h | 3 + .../stdlib/string/string-functions.h | 2 +- tests/phpt/dl/1048_setlocale.php | 94 +++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 tests/phpt/dl/1048_setlocale.php diff --git a/runtime-light/k2-platform/k2-api.h b/runtime-light/k2-platform/k2-api.h index 1bbf21333b..45e1f179b3 100644 --- a/runtime-light/k2-platform/k2-api.h +++ b/runtime-light/k2-platform/k2-api.h @@ -332,6 +332,9 @@ inline struct tm* localtime_r(const time_t* timer, struct tm* result) noexcept { } inline int32_t uselocale(int32_t category, std::string_view locale) noexcept { + if (locale == "0") { + return k2::errno_ok; + } return k2_uselocale(category, locale.data()); } diff --git a/runtime-light/stdlib/string/string-functions.h b/runtime-light/stdlib/string/string-functions.h index aa6b147dde..6a1ff24440 100644 --- a/runtime-light/stdlib/string/string-functions.h +++ b/runtime-light/stdlib/string/string-functions.h @@ -24,5 +24,5 @@ inline Optional f$setlocale(int64_t category, const string& locale) noex if (!opt_locale_name.has_value()) [[unlikely]] { return false; } - return opt_locale_name->data(); + return string{opt_locale_name->data(), static_cast(opt_locale_name->size())}; } diff --git a/tests/phpt/dl/1048_setlocale.php b/tests/phpt/dl/1048_setlocale.php new file mode 100644 index 0000000000..8d55e989f4 --- /dev/null +++ b/tests/phpt/dl/1048_setlocale.php @@ -0,0 +1,94 @@ +@ok + " . setlocale(LC_CTYPE, "0")); + var_dump("LC_NUMERIC 0 -> " . setlocale(LC_NUMERIC, "0")); + var_dump("LC_TIME 0 -> " . setlocale(LC_TIME, "0")); + var_dump("LC_COLLATE 0 -> " . setlocale(LC_COLLATE, "0")); + var_dump("LC_MONETARY 0 -> " . setlocale(LC_MONETARY, "0")); + var_dump("LC_ALL 0 -> " . setlocale(LC_ALL, "0")); +} + +function setlocale_return_empty() { + var_dump("setlocale_empty"); + + var_dump("LC_CTYPE \"\" -> " . setlocale(LC_CTYPE, "")); + var_dump("LC_NUMERIC \"\" -> " . setlocale(LC_NUMERIC, "")); + var_dump("LC_TIME \"\" -> " . setlocale(LC_TIME, "")); + var_dump("LC_COLLATE \"\" -> " . setlocale(LC_COLLATE, "")); + var_dump("LC_MONETARY \"\" -> " . setlocale(LC_MONETARY, "")); + var_dump("LC_ALL \"\" -> " . setlocale(LC_ALL, "")); + + var_dump("check other (1)"); + setlocale_zero(); +} + +function setlocale_return_set_ru_RU_CP1251() { + var_dump("setlocale_set_ru_RU_CP1251"); + + var_dump("LC_ALL \"\" -> " . setlocale(LC_ALL, "")); // unset all + + var_dump("LC_CTYPE ru_RU.CP1251 -> " . setlocale(LC_CTYPE, "ru_RU.CP1251")); + var_dump("LC_CTYPE 0 -> " . setlocale(LC_CTYPE, "0")); + + var_dump("LC_NUMERIC ru_RU.CP1251 -> " . setlocale(LC_NUMERIC, "ru_RU.CP1251")); + var_dump("LC_NUMERIC 0 -> " . setlocale(LC_NUMERIC, "0")); + + var_dump("LC_TIME ru_RU.CP1251 -> " . setlocale(LC_TIME, "ru_RU.CP1251")); + var_dump("LC_TIME 0 -> " . setlocale(LC_TIME, "0")); + + var_dump("LC_COLLATE ru_RU.CP1251 -> " . setlocale(LC_COLLATE, "ru_RU.CP1251")); + var_dump("LC_COLLATE 0 -> " . setlocale(LC_COLLATE, "0")); + + var_dump("LC_MONETARY ru_RU.CP1251 -> " . setlocale(LC_MONETARY, "ru_RU.CP1251")); + var_dump("LC_MONETARY 0 -> " . setlocale(LC_MONETARY, "0")); + + var_dump("LC_ALL 0 -> " . setlocale(LC_ALL, "0")); + + var_dump("LC_ALL \"\" -> " . setlocale(LC_ALL, "")); // unset all + + var_dump("check other (2)"); + setlocale_zero(); + + var_dump("LC_ALL ru_RU.CP1251 -> " . setlocale(LC_ALL, "ru_RU.CP1251")); + + var_dump("check other (3)"); + setlocale_zero(); + + var_dump("LC_ALL \"\" -> " . setlocale(LC_ALL, "")); // unset all +} + +function setlocale_return_correct_LC_ALL_changes() { + var_dump("setlocale_correct_LC_ALL_changes"); + + var_dump("LC_ALL en_US.UTF-8 -> " . setlocale(LC_ALL, "en_US.UTF-8")); + var_dump("LC_ALL 0 -> " . setlocale(LC_ALL, "0")); + + var_dump("LC_COLLATE ru_RU.CP1251 -> " . setlocale(LC_COLLATE, "ru_RU.CP1251")); + var_dump("LC_ALL 0 -> " . setlocale(LC_ALL, "0")); + + var_dump("LC_COLLATE en_US.UTF-8 -> " . setlocale(LC_COLLATE, "en_US.UTF-8")); + var_dump("LC_ALL 0 -> " . setlocale(LC_ALL, "0")); +} + + +function setlocale_numeric_cp1251() { + function printf_numeric() { + printf("%.2f\n", 1234.56); + } + + var_dump("setlocale_numeric_cp1251"); + setlocale(LC_NUMERIC, 'ru_RU.CP1251'); + printf_numeric(); + setlocale(LC_NUMERIC, 'C'); + printf_numeric(); +} + + +setlocale_return_empty(); +setlocale_return_set_ru_RU_CP1251(); +setlocale_return_correct_LC_ALL_changes(); +setlocale_numeric_cp1251(); From 7fc176072188bacef3c6d4dcb1c6203d6fea2654 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 31 Mar 2026 12:58:36 +0300 Subject: [PATCH 2/3] minor fix --- runtime-light/k2-platform/k2-api.h | 3 --- runtime-light/stdlib/string/string-functions.h | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/runtime-light/k2-platform/k2-api.h b/runtime-light/k2-platform/k2-api.h index 45e1f179b3..1bbf21333b 100644 --- a/runtime-light/k2-platform/k2-api.h +++ b/runtime-light/k2-platform/k2-api.h @@ -332,9 +332,6 @@ inline struct tm* localtime_r(const time_t* timer, struct tm* result) noexcept { } inline int32_t uselocale(int32_t category, std::string_view locale) noexcept { - if (locale == "0") { - return k2::errno_ok; - } return k2_uselocale(category, locale.data()); } diff --git a/runtime-light/stdlib/string/string-functions.h b/runtime-light/stdlib/string/string-functions.h index 6a1ff24440..deab114b9d 100644 --- a/runtime-light/stdlib/string/string-functions.h +++ b/runtime-light/stdlib/string/string-functions.h @@ -17,7 +17,7 @@ inline string f$prepare_search_query(const string& query) noexcept { inline Optional f$setlocale(int64_t category, const string& locale) noexcept { const int32_t i32category{static_cast(category)}; - if (k2::uselocale(i32category, {locale.c_str(), locale.size()}) != k2::errno_ok) { + if ((locale.size() != 1 || locale[0] != '0') && k2::uselocale(i32category, {locale.c_str(), locale.size()}) != k2::errno_ok) { return false; } const auto opt_locale_name{k2::current_locale_name(i32category)}; From 3cfcf568bf4c977f53d44f2e643033ac7dbfac24 Mon Sep 17 00:00:00 2001 From: Denis Zubarev Date: Tue, 31 Mar 2026 14:11:33 +0300 Subject: [PATCH 3/3] minor fix --- runtime-light/stdlib/string/string-functions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime-light/stdlib/string/string-functions.h b/runtime-light/stdlib/string/string-functions.h index deab114b9d..38e13702d7 100644 --- a/runtime-light/stdlib/string/string-functions.h +++ b/runtime-light/stdlib/string/string-functions.h @@ -17,7 +17,7 @@ inline string f$prepare_search_query(const string& query) noexcept { inline Optional f$setlocale(int64_t category, const string& locale) noexcept { const int32_t i32category{static_cast(category)}; - if ((locale.size() != 1 || locale[0] != '0') && k2::uselocale(i32category, {locale.c_str(), locale.size()}) != k2::errno_ok) { + if (const std::string_view sv_locale{locale.c_str(), locale.size()}; sv_locale != "0" && k2::uselocale(i32category, sv_locale) != k2::errno_ok) { return false; } const auto opt_locale_name{k2::current_locale_name(i32category)};