1ebe6161cSMuiez Ahmed //===----------------------------------------------------------------------===// 2ebe6161cSMuiez Ahmed // 3ebe6161cSMuiez Ahmed // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4ebe6161cSMuiez Ahmed // See https://llvm.org/LICENSE.txt for license information. 5ebe6161cSMuiez Ahmed // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ebe6161cSMuiez Ahmed // 7ebe6161cSMuiez Ahmed //===----------------------------------------------------------------------===// 8ebe6161cSMuiez Ahmed 9f87aa19bSLouis Dionne #include <__assert> 10ebe6161cSMuiez Ahmed #include <__support/ibm/xlocale.h> 11ebe6161cSMuiez Ahmed #include <sstream> 12ebe6161cSMuiez Ahmed #include <vector> 13ebe6161cSMuiez Ahmed 14ebe6161cSMuiez Ahmed #ifdef __cplusplus 15ebe6161cSMuiez Ahmed extern "C" { 16ebe6161cSMuiez Ahmed #endif // __cplusplus 17ebe6161cSMuiez Ahmed 18ebe6161cSMuiez Ahmed locale_t newlocale(int category_mask, const char* locale, locale_t base) { 19ebe6161cSMuiez Ahmed // Maintain current locale name(s) to restore later. 20ebe6161cSMuiez Ahmed std::string current_loc_name(setlocale(LC_ALL, 0)); 21ebe6161cSMuiez Ahmed 22ebe6161cSMuiez Ahmed // Check for errors. 23*d0438d2dSLouis Dionne if (category_mask == LC_ALL_MASK && setlocale(LC_ALL, locale) == nullptr) { 24ebe6161cSMuiez Ahmed errno = EINVAL; 25ebe6161cSMuiez Ahmed return (locale_t)0; 26ebe6161cSMuiez Ahmed } else { 27ebe6161cSMuiez Ahmed for (int _Cat = 0; _Cat <= _LC_MAX; ++_Cat) { 28*d0438d2dSLouis Dionne if ((_CATMASK(_Cat) & category_mask) != 0 && setlocale(_Cat, locale) == nullptr) { 29ebe6161cSMuiez Ahmed setlocale(LC_ALL, current_loc_name.c_str()); 30ebe6161cSMuiez Ahmed errno = EINVAL; 31ebe6161cSMuiez Ahmed return (locale_t)0; 32ebe6161cSMuiez Ahmed } 33ebe6161cSMuiez Ahmed } 34ebe6161cSMuiez Ahmed } 35ebe6161cSMuiez Ahmed 36ebe6161cSMuiez Ahmed // Create new locale. 37ebe6161cSMuiez Ahmed locale_t newloc = new locale_struct(); 38ebe6161cSMuiez Ahmed 39ebe6161cSMuiez Ahmed if (base) { 40ebe6161cSMuiez Ahmed if (category_mask != LC_ALL_MASK) { 41ebe6161cSMuiez Ahmed // Copy base when it will not be overwritten. 42ebe6161cSMuiez Ahmed memcpy(newloc, base, sizeof(locale_struct)); 43ebe6161cSMuiez Ahmed newloc->category_mask = category_mask | base->category_mask; 44ebe6161cSMuiez Ahmed } 45ebe6161cSMuiez Ahmed delete base; 46ebe6161cSMuiez Ahmed } else { 47ebe6161cSMuiez Ahmed newloc->category_mask = category_mask; 48ebe6161cSMuiez Ahmed } 49ebe6161cSMuiez Ahmed 50ebe6161cSMuiez Ahmed if (category_mask & LC_COLLATE_MASK) 51ebe6161cSMuiez Ahmed newloc->lc_collate = locale; 52ebe6161cSMuiez Ahmed if (category_mask & LC_CTYPE_MASK) 53ebe6161cSMuiez Ahmed newloc->lc_ctype = locale; 54ebe6161cSMuiez Ahmed if (category_mask & LC_MONETARY_MASK) 55ebe6161cSMuiez Ahmed newloc->lc_monetary = locale; 56ebe6161cSMuiez Ahmed if (category_mask & LC_NUMERIC_MASK) 57ebe6161cSMuiez Ahmed newloc->lc_numeric = locale; 58ebe6161cSMuiez Ahmed if (category_mask & LC_TIME_MASK) 59ebe6161cSMuiez Ahmed newloc->lc_time = locale; 60ebe6161cSMuiez Ahmed if (category_mask & LC_MESSAGES_MASK) 61ebe6161cSMuiez Ahmed newloc->lc_messages = locale; 62ebe6161cSMuiez Ahmed 63ebe6161cSMuiez Ahmed // Restore current locale. 64ebe6161cSMuiez Ahmed setlocale(LC_ALL, current_loc_name.c_str()); 65ebe6161cSMuiez Ahmed return (locale_t)newloc; 66ebe6161cSMuiez Ahmed } 67ebe6161cSMuiez Ahmed 689783f28cSLouis Dionne void freelocale(locale_t locobj) { delete locobj; } 69ebe6161cSMuiez Ahmed 70ebe6161cSMuiez Ahmed locale_t uselocale(locale_t newloc) { 71ebe6161cSMuiez Ahmed // Maintain current locale name(s). 72ebe6161cSMuiez Ahmed std::string current_loc_name(setlocale(LC_ALL, 0)); 73ebe6161cSMuiez Ahmed 74ebe6161cSMuiez Ahmed if (newloc) { 75ebe6161cSMuiez Ahmed // Set locales and check for errors. 76ebe6161cSMuiez Ahmed bool is_error = 77*d0438d2dSLouis Dionne (newloc->category_mask & LC_COLLATE_MASK && setlocale(LC_COLLATE, newloc->lc_collate.c_str()) == nullptr) || 78*d0438d2dSLouis Dionne (newloc->category_mask & LC_CTYPE_MASK && setlocale(LC_CTYPE, newloc->lc_ctype.c_str()) == nullptr) || 79*d0438d2dSLouis Dionne (newloc->category_mask & LC_MONETARY_MASK && setlocale(LC_MONETARY, newloc->lc_monetary.c_str()) == nullptr) || 80*d0438d2dSLouis Dionne (newloc->category_mask & LC_NUMERIC_MASK && setlocale(LC_NUMERIC, newloc->lc_numeric.c_str()) == nullptr) || 81*d0438d2dSLouis Dionne (newloc->category_mask & LC_TIME_MASK && setlocale(LC_TIME, newloc->lc_time.c_str()) == nullptr) || 82*d0438d2dSLouis Dionne (newloc->category_mask & LC_MESSAGES_MASK && setlocale(LC_MESSAGES, newloc->lc_messages.c_str()) == nullptr); 83ebe6161cSMuiez Ahmed 84ebe6161cSMuiez Ahmed if (is_error) { 85ebe6161cSMuiez Ahmed setlocale(LC_ALL, current_loc_name.c_str()); 86ebe6161cSMuiez Ahmed errno = EINVAL; 87ebe6161cSMuiez Ahmed return (locale_t)0; 88ebe6161cSMuiez Ahmed } 89ebe6161cSMuiez Ahmed } 90ebe6161cSMuiez Ahmed 91ebe6161cSMuiez Ahmed // Construct and return previous locale. 92ebe6161cSMuiez Ahmed locale_t previous_loc = new locale_struct(); 93ebe6161cSMuiez Ahmed 94ebe6161cSMuiez Ahmed // current_loc_name might be a comma-separated locale name list. 95ebe6161cSMuiez Ahmed if (current_loc_name.find(',') != std::string::npos) { 96ebe6161cSMuiez Ahmed // Tokenize locale name list. 97ebe6161cSMuiez Ahmed const char delimiter = ','; 98ebe6161cSMuiez Ahmed std::vector<std::string> tokenized; 99ebe6161cSMuiez Ahmed std::stringstream ss(current_loc_name); 100ebe6161cSMuiez Ahmed std::string s; 101ebe6161cSMuiez Ahmed 102ebe6161cSMuiez Ahmed while (std::getline(ss, s, delimiter)) { 103ebe6161cSMuiez Ahmed tokenized.push_back(s); 104ebe6161cSMuiez Ahmed } 105ebe6161cSMuiez Ahmed 1061638657dSKonstantin Varlamov _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(tokenized.size() >= _NCAT, "locale-name list is too short"); 107ebe6161cSMuiez Ahmed 108ebe6161cSMuiez Ahmed previous_loc->lc_collate = tokenized[LC_COLLATE]; 109ebe6161cSMuiez Ahmed previous_loc->lc_ctype = tokenized[LC_CTYPE]; 110ebe6161cSMuiez Ahmed previous_loc->lc_monetary = tokenized[LC_MONETARY]; 111ebe6161cSMuiez Ahmed previous_loc->lc_numeric = tokenized[LC_NUMERIC]; 112ebe6161cSMuiez Ahmed previous_loc->lc_time = tokenized[LC_TIME]; 113ebe6161cSMuiez Ahmed // Skip LC_TOD. 114ebe6161cSMuiez Ahmed previous_loc->lc_messages = tokenized[LC_MESSAGES]; 115ebe6161cSMuiez Ahmed } else { 116ebe6161cSMuiez Ahmed previous_loc->lc_collate = current_loc_name; 117ebe6161cSMuiez Ahmed previous_loc->lc_ctype = current_loc_name; 118ebe6161cSMuiez Ahmed previous_loc->lc_monetary = current_loc_name; 119ebe6161cSMuiez Ahmed previous_loc->lc_numeric = current_loc_name; 120ebe6161cSMuiez Ahmed previous_loc->lc_time = current_loc_name; 121ebe6161cSMuiez Ahmed previous_loc->lc_messages = current_loc_name; 122ebe6161cSMuiez Ahmed } 123ebe6161cSMuiez Ahmed 124ebe6161cSMuiez Ahmed previous_loc->category_mask = LC_ALL_MASK; 125ebe6161cSMuiez Ahmed return previous_loc; 126ebe6161cSMuiez Ahmed } 127ebe6161cSMuiez Ahmed 128ebe6161cSMuiez Ahmed #ifdef __cplusplus 129ebe6161cSMuiez Ahmed } 130ebe6161cSMuiez Ahmed #endif // __cplusplus 131