brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.4 KiB · 136999e Raw
131 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include <__assert>10#include <__support/ibm/xlocale.h>11#include <sstream>12#include <vector>13 14#ifdef __cplusplus15extern "C" {16#endif // __cplusplus17 18locale_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));21 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;32      }33    }34  }35 36  // Create new locale.37  locale_t newloc = new locale_struct();38 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;44    }45    delete base;46  } else {47    newloc->category_mask = category_mask;48  }49 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;62 63  // Restore current locale.64  setlocale(LC_ALL, current_loc_name.c_str());65  return (locale_t)newloc;66}67 68void freelocale(locale_t locobj) { delete locobj; }69 70locale_t uselocale(locale_t newloc) {71  // Maintain current locale name(s).72  std::string current_loc_name(setlocale(LC_ALL, 0));73 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);83 84    if (is_error) {85      setlocale(LC_ALL, current_loc_name.c_str());86      errno = EINVAL;87      return (locale_t)0;88    }89  }90 91  // Construct and return previous locale.92  locale_t previous_loc = new locale_struct();93 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;101 102    while (std::getline(ss, s, delimiter)) {103      tokenized.push_back(s);104    }105 106    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(tokenized.size() >= _NCAT, "locale-name list is too short");107 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;122  }123 124  previous_loc->category_mask = LC_ALL_MASK;125  return previous_loc;126}127 128#ifdef __cplusplus129}130#endif // __cplusplus131