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