176d0caaeSpatrick //===----------------------------------------------------------------------===//
276d0caaeSpatrick //
376d0caaeSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
476d0caaeSpatrick // See https://llvm.org/LICENSE.txt for license information.
576d0caaeSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
676d0caaeSpatrick //
776d0caaeSpatrick //===----------------------------------------------------------------------===//
876d0caaeSpatrick
9*4bdff4beSrobert #include <__assert>
1076d0caaeSpatrick #include <__support/ibm/xlocale.h>
1176d0caaeSpatrick #include <sstream>
1276d0caaeSpatrick #include <vector>
1376d0caaeSpatrick
1476d0caaeSpatrick #ifdef __cplusplus
1576d0caaeSpatrick extern "C" {
1676d0caaeSpatrick #endif // __cplusplus
1776d0caaeSpatrick
newlocale(int category_mask,const char * locale,locale_t base)1876d0caaeSpatrick locale_t newlocale(int category_mask, const char* locale, locale_t base) {
1976d0caaeSpatrick // Maintain current locale name(s) to restore later.
2076d0caaeSpatrick std::string current_loc_name(setlocale(LC_ALL, 0));
2176d0caaeSpatrick
2276d0caaeSpatrick // Check for errors.
2376d0caaeSpatrick if (category_mask == LC_ALL_MASK && setlocale(LC_ALL, locale) == NULL) {
2476d0caaeSpatrick errno = EINVAL;
2576d0caaeSpatrick return (locale_t)0;
2676d0caaeSpatrick } else {
2776d0caaeSpatrick for (int _Cat = 0; _Cat <= _LC_MAX; ++_Cat) {
2876d0caaeSpatrick if ((_CATMASK(_Cat) & category_mask) != 0 && setlocale(_Cat, locale) == NULL) {
2976d0caaeSpatrick setlocale(LC_ALL, current_loc_name.c_str());
3076d0caaeSpatrick errno = EINVAL;
3176d0caaeSpatrick return (locale_t)0;
3276d0caaeSpatrick }
3376d0caaeSpatrick }
3476d0caaeSpatrick }
3576d0caaeSpatrick
3676d0caaeSpatrick // Create new locale.
3776d0caaeSpatrick locale_t newloc = new locale_struct();
3876d0caaeSpatrick
3976d0caaeSpatrick if (base) {
4076d0caaeSpatrick if (category_mask != LC_ALL_MASK) {
4176d0caaeSpatrick // Copy base when it will not be overwritten.
4276d0caaeSpatrick memcpy(newloc, base, sizeof (locale_struct));
4376d0caaeSpatrick newloc->category_mask = category_mask | base->category_mask;
4476d0caaeSpatrick }
4576d0caaeSpatrick delete base;
4676d0caaeSpatrick } else {
4776d0caaeSpatrick newloc->category_mask = category_mask;
4876d0caaeSpatrick }
4976d0caaeSpatrick
5076d0caaeSpatrick if (category_mask & LC_COLLATE_MASK)
5176d0caaeSpatrick newloc->lc_collate = locale;
5276d0caaeSpatrick if (category_mask & LC_CTYPE_MASK)
5376d0caaeSpatrick newloc->lc_ctype = locale;
5476d0caaeSpatrick if (category_mask & LC_MONETARY_MASK)
5576d0caaeSpatrick newloc->lc_monetary = locale;
5676d0caaeSpatrick if (category_mask & LC_NUMERIC_MASK)
5776d0caaeSpatrick newloc->lc_numeric = locale;
5876d0caaeSpatrick if (category_mask & LC_TIME_MASK)
5976d0caaeSpatrick newloc->lc_time = locale;
6076d0caaeSpatrick if (category_mask & LC_MESSAGES_MASK)
6176d0caaeSpatrick newloc->lc_messages = locale;
6276d0caaeSpatrick
6376d0caaeSpatrick // Restore current locale.
6476d0caaeSpatrick setlocale(LC_ALL, current_loc_name.c_str());
6576d0caaeSpatrick return (locale_t)newloc;
6676d0caaeSpatrick }
6776d0caaeSpatrick
freelocale(locale_t locobj)6876d0caaeSpatrick void freelocale(locale_t locobj) {
6976d0caaeSpatrick delete locobj;
7076d0caaeSpatrick }
7176d0caaeSpatrick
uselocale(locale_t newloc)7276d0caaeSpatrick locale_t uselocale(locale_t newloc) {
7376d0caaeSpatrick // Maintain current locale name(s).
7476d0caaeSpatrick std::string current_loc_name(setlocale(LC_ALL, 0));
7576d0caaeSpatrick
7676d0caaeSpatrick if (newloc) {
7776d0caaeSpatrick // Set locales and check for errors.
7876d0caaeSpatrick bool is_error =
7976d0caaeSpatrick (newloc->category_mask & LC_COLLATE_MASK &&
8076d0caaeSpatrick setlocale(LC_COLLATE, newloc->lc_collate.c_str()) == NULL) ||
8176d0caaeSpatrick (newloc->category_mask & LC_CTYPE_MASK &&
8276d0caaeSpatrick setlocale(LC_CTYPE, newloc->lc_ctype.c_str()) == NULL) ||
8376d0caaeSpatrick (newloc->category_mask & LC_MONETARY_MASK &&
8476d0caaeSpatrick setlocale(LC_MONETARY, newloc->lc_monetary.c_str()) == NULL) ||
8576d0caaeSpatrick (newloc->category_mask & LC_NUMERIC_MASK &&
8676d0caaeSpatrick setlocale(LC_NUMERIC, newloc->lc_numeric.c_str()) == NULL) ||
8776d0caaeSpatrick (newloc->category_mask & LC_TIME_MASK &&
8876d0caaeSpatrick setlocale(LC_TIME, newloc->lc_time.c_str()) == NULL) ||
8976d0caaeSpatrick (newloc->category_mask & LC_MESSAGES_MASK &&
9076d0caaeSpatrick setlocale(LC_MESSAGES, newloc->lc_messages.c_str()) == NULL);
9176d0caaeSpatrick
9276d0caaeSpatrick if (is_error) {
9376d0caaeSpatrick setlocale(LC_ALL, current_loc_name.c_str());
9476d0caaeSpatrick errno = EINVAL;
9576d0caaeSpatrick return (locale_t)0;
9676d0caaeSpatrick }
9776d0caaeSpatrick }
9876d0caaeSpatrick
9976d0caaeSpatrick // Construct and return previous locale.
10076d0caaeSpatrick locale_t previous_loc = new locale_struct();
10176d0caaeSpatrick
10276d0caaeSpatrick // current_loc_name might be a comma-separated locale name list.
10376d0caaeSpatrick if (current_loc_name.find(',') != std::string::npos) {
10476d0caaeSpatrick // Tokenize locale name list.
10576d0caaeSpatrick const char delimiter = ',';
10676d0caaeSpatrick std::vector<std::string> tokenized;
10776d0caaeSpatrick std::stringstream ss(current_loc_name);
10876d0caaeSpatrick std::string s;
10976d0caaeSpatrick
11076d0caaeSpatrick while (std::getline(ss, s, delimiter)) {
11176d0caaeSpatrick tokenized.push_back(s);
11276d0caaeSpatrick }
11376d0caaeSpatrick
11476d0caaeSpatrick _LIBCPP_ASSERT(tokenized.size() >= _NCAT, "locale-name list is too short");
11576d0caaeSpatrick
11676d0caaeSpatrick previous_loc->lc_collate = tokenized[LC_COLLATE];
11776d0caaeSpatrick previous_loc->lc_ctype = tokenized[LC_CTYPE];
11876d0caaeSpatrick previous_loc->lc_monetary = tokenized[LC_MONETARY];
11976d0caaeSpatrick previous_loc->lc_numeric = tokenized[LC_NUMERIC];
12076d0caaeSpatrick previous_loc->lc_time = tokenized[LC_TIME];
12176d0caaeSpatrick // Skip LC_TOD.
12276d0caaeSpatrick previous_loc->lc_messages = tokenized[LC_MESSAGES];
12376d0caaeSpatrick } else {
12476d0caaeSpatrick previous_loc->lc_collate = current_loc_name;
12576d0caaeSpatrick previous_loc->lc_ctype = current_loc_name;
12676d0caaeSpatrick previous_loc->lc_monetary = current_loc_name;
12776d0caaeSpatrick previous_loc->lc_numeric = current_loc_name;
12876d0caaeSpatrick previous_loc->lc_time = current_loc_name;
12976d0caaeSpatrick previous_loc->lc_messages = current_loc_name;
13076d0caaeSpatrick }
13176d0caaeSpatrick
13276d0caaeSpatrick previous_loc->category_mask = LC_ALL_MASK;
13376d0caaeSpatrick return previous_loc;
13476d0caaeSpatrick }
13576d0caaeSpatrick
13676d0caaeSpatrick #ifdef __cplusplus
13776d0caaeSpatrick }
13876d0caaeSpatrick #endif // __cplusplus
139