forked from OSchip/llvm-project
[SystemZ][z/OS] Missing locale functions libc++
The aim is to add the missing z/OS specific locale functions for libc++ (newlocale, freelocale and uselocale). Reviewed By: ldionne, #libc, curdeius Differential Revision: https://reviews.llvm.org/D98044
This commit is contained in:
parent
e4492b6f31
commit
ebe6161c54
|
@ -156,6 +156,7 @@ set(files
|
|||
__support/ibm/gettod_zos.h
|
||||
__support/ibm/limits.h
|
||||
__support/ibm/locale_mgmt_aix.h
|
||||
__support/ibm/locale_mgmt_zos.h
|
||||
__support/ibm/nanosleep.h
|
||||
__support/ibm/support.h
|
||||
__support/ibm/xlocale.h
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP_SUPPORT_IBM_LOCALE_MGMT_ZOS_H
|
||||
#define _LIBCPP_SUPPORT_IBM_LOCALE_MGMT_ZOS_H
|
||||
|
||||
#if defined(__MVS__)
|
||||
#include <locale.h>
|
||||
#include <string>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define _LC_MAX LC_MESSAGES /* highest real category */
|
||||
#define _NCAT (_LC_MAX + 1) /* maximum + 1 */
|
||||
|
||||
#define _CATMASK(n) (1 << (n))
|
||||
#define LC_COLLATE_MASK _CATMASK(LC_COLLATE)
|
||||
#define LC_CTYPE_MASK _CATMASK(LC_CTYPE)
|
||||
#define LC_MONETARY_MASK _CATMASK(LC_MONETARY)
|
||||
#define LC_NUMERIC_MASK _CATMASK(LC_NUMERIC)
|
||||
#define LC_TIME_MASK _CATMASK(LC_TIME)
|
||||
#define LC_MESSAGES_MASK _CATMASK(LC_MESSAGES)
|
||||
#define LC_ALL_MASK (_CATMASK(_NCAT) - 1)
|
||||
|
||||
typedef struct locale_struct {
|
||||
int category_mask;
|
||||
std::string lc_collate;
|
||||
std::string lc_ctype;
|
||||
std::string lc_monetary;
|
||||
std::string lc_numeric;
|
||||
std::string lc_time;
|
||||
std::string lc_messages;
|
||||
} * locale_t;
|
||||
|
||||
// z/OS does not have newlocale, freelocale and uselocale.
|
||||
// The functions below are workarounds in single thread mode.
|
||||
locale_t newlocale(int category_mask, const char* locale, locale_t base);
|
||||
void freelocale(locale_t locobj);
|
||||
locale_t uselocale(locale_t newloc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // defined(__MVS__)
|
||||
#endif // _LIBCPP_SUPPORT_IBM_LOCALE_MGMT_ZOS_H
|
|
@ -11,6 +11,7 @@
|
|||
#define _LIBCPP_SUPPORT_IBM_XLOCALE_H
|
||||
|
||||
#include <__support/ibm/locale_mgmt_aix.h>
|
||||
#include <__support/ibm/locale_mgmt_zos.h>
|
||||
|
||||
#include "cstdlib"
|
||||
|
||||
|
|
|
@ -90,6 +90,10 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS")
|
|||
support/solaris/wcsnrtombs.inc
|
||||
support/solaris/xlocale.cpp
|
||||
)
|
||||
elseif(ZOS)
|
||||
list(APPEND LIBCXX_SOURCES
|
||||
support/ibm/xlocale_zos.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LIBCXX_ENABLE_FILESYSTEM)
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <__support/ibm/xlocale.h>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
locale_t newlocale(int category_mask, const char* locale, locale_t base) {
|
||||
// Maintain current locale name(s) to restore later.
|
||||
std::string current_loc_name(setlocale(LC_ALL, 0));
|
||||
|
||||
// Check for errors.
|
||||
if (category_mask == LC_ALL_MASK && setlocale(LC_ALL, locale) == NULL) {
|
||||
errno = EINVAL;
|
||||
return (locale_t)0;
|
||||
} else {
|
||||
for (int _Cat = 0; _Cat <= _LC_MAX; ++_Cat) {
|
||||
if ((_CATMASK(_Cat) & category_mask) != 0 && setlocale(_Cat, locale) == NULL) {
|
||||
setlocale(LC_ALL, current_loc_name.c_str());
|
||||
errno = EINVAL;
|
||||
return (locale_t)0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create new locale.
|
||||
locale_t newloc = new locale_struct();
|
||||
|
||||
if (base) {
|
||||
if (category_mask != LC_ALL_MASK) {
|
||||
// Copy base when it will not be overwritten.
|
||||
memcpy(newloc, base, sizeof (locale_struct));
|
||||
newloc->category_mask = category_mask | base->category_mask;
|
||||
}
|
||||
delete base;
|
||||
} else {
|
||||
newloc->category_mask = category_mask;
|
||||
}
|
||||
|
||||
if (category_mask & LC_COLLATE_MASK)
|
||||
newloc->lc_collate = locale;
|
||||
if (category_mask & LC_CTYPE_MASK)
|
||||
newloc->lc_ctype = locale;
|
||||
if (category_mask & LC_MONETARY_MASK)
|
||||
newloc->lc_monetary = locale;
|
||||
if (category_mask & LC_NUMERIC_MASK)
|
||||
newloc->lc_numeric = locale;
|
||||
if (category_mask & LC_TIME_MASK)
|
||||
newloc->lc_time = locale;
|
||||
if (category_mask & LC_MESSAGES_MASK)
|
||||
newloc->lc_messages = locale;
|
||||
|
||||
// Restore current locale.
|
||||
setlocale(LC_ALL, current_loc_name.c_str());
|
||||
return (locale_t)newloc;
|
||||
}
|
||||
|
||||
void freelocale(locale_t locobj) {
|
||||
delete locobj;
|
||||
}
|
||||
|
||||
locale_t uselocale(locale_t newloc) {
|
||||
// Maintain current locale name(s).
|
||||
std::string current_loc_name(setlocale(LC_ALL, 0));
|
||||
|
||||
if (newloc) {
|
||||
// Set locales and check for errors.
|
||||
bool is_error =
|
||||
(newloc->category_mask & LC_COLLATE_MASK &&
|
||||
setlocale(LC_COLLATE, newloc->lc_collate.c_str()) == NULL) ||
|
||||
(newloc->category_mask & LC_CTYPE_MASK &&
|
||||
setlocale(LC_CTYPE, newloc->lc_ctype.c_str()) == NULL) ||
|
||||
(newloc->category_mask & LC_MONETARY_MASK &&
|
||||
setlocale(LC_MONETARY, newloc->lc_monetary.c_str()) == NULL) ||
|
||||
(newloc->category_mask & LC_NUMERIC_MASK &&
|
||||
setlocale(LC_NUMERIC, newloc->lc_numeric.c_str()) == NULL) ||
|
||||
(newloc->category_mask & LC_TIME_MASK &&
|
||||
setlocale(LC_TIME, newloc->lc_time.c_str()) == NULL) ||
|
||||
(newloc->category_mask & LC_MESSAGES_MASK &&
|
||||
setlocale(LC_MESSAGES, newloc->lc_messages.c_str()) == NULL);
|
||||
|
||||
if (is_error) {
|
||||
setlocale(LC_ALL, current_loc_name.c_str());
|
||||
errno = EINVAL;
|
||||
return (locale_t)0;
|
||||
}
|
||||
}
|
||||
|
||||
// Construct and return previous locale.
|
||||
locale_t previous_loc = new locale_struct();
|
||||
|
||||
// current_loc_name might be a comma-separated locale name list.
|
||||
if (current_loc_name.find(',') != std::string::npos) {
|
||||
// Tokenize locale name list.
|
||||
const char delimiter = ',';
|
||||
std::vector<std::string> tokenized;
|
||||
std::stringstream ss(current_loc_name);
|
||||
std::string s;
|
||||
|
||||
while (std::getline(ss, s, delimiter)) {
|
||||
tokenized.push_back(s);
|
||||
}
|
||||
|
||||
_LIBCPP_ASSERT(tokenized.size() >= _NCAT, "locale-name list is too short");
|
||||
|
||||
previous_loc->lc_collate = tokenized[LC_COLLATE];
|
||||
previous_loc->lc_ctype = tokenized[LC_CTYPE];
|
||||
previous_loc->lc_monetary = tokenized[LC_MONETARY];
|
||||
previous_loc->lc_numeric = tokenized[LC_NUMERIC];
|
||||
previous_loc->lc_time = tokenized[LC_TIME];
|
||||
// Skip LC_TOD.
|
||||
previous_loc->lc_messages = tokenized[LC_MESSAGES];
|
||||
} else {
|
||||
previous_loc->lc_collate = current_loc_name;
|
||||
previous_loc->lc_ctype = current_loc_name;
|
||||
previous_loc->lc_monetary = current_loc_name;
|
||||
previous_loc->lc_numeric = current_loc_name;
|
||||
previous_loc->lc_time = current_loc_name;
|
||||
previous_loc->lc_messages = current_loc_name;
|
||||
}
|
||||
|
||||
previous_loc->category_mask = LC_ALL_MASK;
|
||||
return previous_loc;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
Loading…
Reference in New Issue