Skip to content

Update stringshims to always use clocale #1427

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/FoundationEssentials/JSON/JSON5Scanner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1081,7 +1081,7 @@ extension JSON5Scanner {
jsonBytes.formIndex(after: &index)
}

let cmp = jsonBytes[index..<endIndex].prefix(2).withUnsafePointer({ _stringshims_strncasecmp_l($0, "0x", $1, nil) })
let cmp = jsonBytes[index..<endIndex].prefix(2).withUnsafePointer({ _stringshims_strncasecmp_clocale($0, "0x", $1) })
if cmp == 0 {
jsonBytes.formIndex(&index, offsetBy: 2)

Expand Down
4 changes: 2 additions & 2 deletions Sources/FoundationEssentials/JSON/JSONScanner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1179,7 +1179,7 @@ extension Double : PrevalidatedJSONNumberBufferConvertible {
init?(prevalidatedBuffer buffer: BufferView<UInt8>) {
let decodedValue = buffer.withUnsafePointer { nptr, count -> Double? in
var endPtr: UnsafeMutablePointer<CChar>? = nil
let decodedValue = _stringshims_strtod_l(nptr, &endPtr, nil)
let decodedValue = _stringshims_strtod_clocale(nptr, &endPtr)
if let endPtr, nptr.advanced(by: count) == endPtr {
return decodedValue
} else {
Expand All @@ -1195,7 +1195,7 @@ extension Float : PrevalidatedJSONNumberBufferConvertible {
init?(prevalidatedBuffer buffer: BufferView<UInt8>) {
let decodedValue = buffer.withUnsafePointer { nptr, count -> Float? in
var endPtr: UnsafeMutablePointer<CChar>? = nil
let decodedValue = _stringshims_strtof_l(nptr, &endPtr, nil)
let decodedValue = _stringshims_strtof_clocale(nptr, &endPtr)
if let endPtr, nptr.advanced(by: count) == endPtr {
return decodedValue
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ open class PropertyListDecoder {
}

return try buffer[unchecked: baseIdx..<idx].withUnsafePointer { ptr, encodingLength in
if encodingLength == 5, _stringshims_strncasecmp_l(ptr, "utf-8", 5, nil) == 0 {
if encodingLength == 5, _stringshims_strncasecmp_clocale(ptr, "utf-8", 5) == 0 {
return .utf8
}

Expand Down
10 changes: 5 additions & 5 deletions Sources/FoundationEssentials/PropertyList/XMLPlistScanner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ extension XMLPlistMap.Value {
return .nan
}
case (UInt8(ascii: "+"), 9):
if _stringshims_strncasecmp_l(buf.baseAddress, "+infinity", 9, nil) == 0 {
if _stringshims_strncasecmp_clocale(buf.baseAddress, "+infinity", 9) == 0 {
return .infinity
}
case (UInt8(ascii: "+"), 4):
Expand All @@ -655,7 +655,7 @@ extension XMLPlistMap.Value {
return .infinity
}
case (UInt8(ascii: "-"), 9):
if _stringshims_strncasecmp_l(buf.baseAddress, "-infinity", 9, nil) == 0 {
if _stringshims_strncasecmp_clocale(buf.baseAddress, "-infinity", 9) == 0 {
return .infinity * -1
}
case (UInt8(ascii: "-"), 4):
Expand All @@ -665,7 +665,7 @@ extension XMLPlistMap.Value {
return .infinity * -1
}
case (UInt8(ascii: "i"), 8), (UInt8(ascii: "I"), 8):
if _stringshims_strncasecmp_l(buf.baseAddress, "infinity", 8, nil) == 0 {
if _stringshims_strncasecmp_clocale(buf.baseAddress, "infinity", 8) == 0 {
return .infinity
}
case (.none, 0):
Expand Down Expand Up @@ -728,9 +728,9 @@ extension XMLPlistMap.Value {
var parseEndPtr : UnsafeMutablePointer<CChar>?
let res : T
if MemoryLayout<T>.size == MemoryLayout<Float>.size {
res = T(_stringshims_strtof_l(ptr, &parseEndPtr, nil))
res = T(_stringshims_strtof_clocale(ptr, &parseEndPtr))
} else if MemoryLayout<T>.size == MemoryLayout<Double>.size {
res = T(_stringshims_strtod_l(ptr, &parseEndPtr, nil))
res = T(_stringshims_strtod_clocale(ptr, &parseEndPtr))
} else {
preconditionFailure("Only Float and Double are currently supported by PropertyListDecoder, not \(type))")
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/_FoundationCShims/include/string_shims.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ extern "C" {
#define locale_t void *
#endif

INTERNAL int _stringshims_strncasecmp_l(const char * _Nullable s1, const char * _Nullable s2, size_t n, locale_t _Nullable loc);
INTERNAL int _stringshims_strncasecmp_clocale(const char * _Nullable s1, const char * _Nullable s2, size_t n);

INTERNAL double _stringshims_strtod_l(const char * _Nullable __restrict nptr, char * _Nullable * _Nullable __restrict endptr, locale_t _Nullable loc);
INTERNAL double _stringshims_strtod_clocale(const char * _Nullable __restrict nptr, char * _Nullable * _Nullable __restrict endptr);

INTERNAL float _stringshims_strtof_l(const char * _Nullable __restrict nptr, char * _Nullable * _Nullable __restrict endptr, locale_t _Nullable loc);
INTERNAL float _stringshims_strtof_clocale(const char * _Nullable __restrict nptr, char * _Nullable * _Nullable __restrict endptr);

#define _STRINGSHIMS_MACROMAN_MAP_SIZE 129
INTERNAL const uint8_t _stringshims_macroman_mapping[_STRINGSHIMS_MACROMAN_MAP_SIZE][3];
Expand Down
97 changes: 46 additions & 51 deletions Sources/_FoundationCShims/string_shims.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,80 +23,75 @@
#include <strings.h>
#endif

int _stringshims_strncasecmp_l(const char * _Nullable s1,
const char * _Nullable s2,
size_t n,
locale_t _Nullable loc)
{
#if TARGET_OS_WINDOWS
static _locale_t storage;
static _locale_t *cloc = NULL;
if (cloc == NULL) {
storage = _create_locale(LC_ALL, "C");
cloc = &storage;
}
return _strnicmp_l(s1, s2, n, loc ? loc : *cloc);
#else
if (loc != NULL) {
#if (defined(TARGET_OS_EXCLAVEKIT) && TARGET_OS_EXCLAVEKIT) || \
(defined(TARGET_OS_ANDROID) && TARGET_OS_ANDROID && __ANDROID_API__ < 23)
abort();
#define FOUNDATION_C_LOCALE (_clocale())
static _locale_t _clocale() {
static _locale_t storage;
static bool once = false;
if (!once) {
storage = _create_locale(LC_ALL, "C");
once = true;
}
return storage;
}
#elif TARGET_OS_MAC
#define FOUNDATION_C_LOCALE LC_C_LOCALE
#else
return strncasecmp_l(s1, s2, n, loc);
#endif
#define FOUNDATION_C_LOCALE (_clocale())
static locale_t _clocale() {
static locale_t storage;
static bool once = false;
if (!once) {
storage = newlocale(LC_ALL_MASK, "C", (locale_t)0);
once = true;
}
// On Darwin, NULL loc means unlocalized compare.
// Uses the standard C locale for Linux in this case
#if (defined(TARGET_OS_EXCLAVEKIT) && TARGET_OS_EXCLAVEKIT) || \
return storage;
}
#endif


int _stringshims_strncasecmp_clocale(const char * _Nullable s1,
const char * _Nullable s2,
size_t n)
{
#if TARGET_OS_WINDOWS
return _strnicmp_l(s1, s2, n, FOUNDATION_C_LOCALE);
#elif (defined(TARGET_OS_EXCLAVEKIT) && TARGET_OS_EXCLAVEKIT) || \
(defined(TARGET_OS_ANDROID) && TARGET_OS_ANDROID && __ANDROID_API__ < 23)
return strncasecmp(s1, s2, n);
#elif TARGET_OS_MAC
return strncasecmp_l(s1, s2, n, NULL);
#else
locale_t clocale = newlocale(LC_ALL_MASK, "C", (locale_t)0);
return strncasecmp_l(s1, s2, n, clocale);
#endif // TARGET_OS_MAC
#endif // TARGET_OS_WINDOWS
return strncasecmp_l(s1, s2, n, FOUNDATION_C_LOCALE);
#endif
}

double _stringshims_strtod_l(const char * _Nullable restrict nptr,
char * _Nullable * _Nullable restrict endptr,
locale_t _Nullable loc)
double _stringshims_strtod_clocale(const char * _Nullable restrict nptr,
char * _Nullable * _Nullable restrict endptr)
{
#if defined(TARGET_OS_EXCLAVEKIT) && TARGET_OS_EXCLAVEKIT
assert(loc == NULL);
return strtod_l(nptr, endptr, NULL);
#elif TARGET_OS_MAC
return strtod_l(nptr, endptr, loc);
#if TARGET_OS_MAC
return strtod_l(nptr, endptr, FOUNDATION_C_LOCALE);
#elif TARGET_OS_WINDOWS
return _strtod_l(nptr, endptr, loc);
return _strtod_l(nptr, endptr, FOUNDATION_C_LOCALE);
#else
// Use the C locale
locale_t clocale = newlocale(LC_ALL_MASK, "C", (locale_t)0);
locale_t oldLocale = uselocale(clocale);
locale_t oldLocale = uselocale(FOUNDATION_C_LOCALE);
double result = strtod(nptr, endptr);
// Restore locale
uselocale(oldLocale);
return result;
#endif
}

float _stringshims_strtof_l(const char * _Nullable restrict nptr,
char * _Nullable * _Nullable restrict endptr,
locale_t _Nullable loc)
float _stringshims_strtof_clocale(const char * _Nullable restrict nptr,
char * _Nullable * _Nullable restrict endptr)
{
#if defined(TARGET_OS_EXCLAVEKIT) && TARGET_OS_EXCLAVEKIT
assert(loc == NULL);
return strtof_l(nptr, endptr, NULL);
#elif TARGET_OS_MAC
return strtof_l(nptr, endptr, loc);
#if TARGET_OS_MAC
return strtof_l(nptr, endptr, FOUNDATION_C_LOCALE);
#elif TARGET_OS_WINDOWS
return _strtof_l(nptr, endptr, loc);
return _strtof_l(nptr, endptr, FOUNDATION_C_LOCALE);
#else
// Use the C locale
locale_t clocale = newlocale(LC_ALL_MASK, "C", (locale_t)0);
locale_t oldLocale = uselocale(clocale);
float result = strtof(nptr, endptr);
locale_t oldLocale = uselocale(FOUNDATION_C_LOCALE);
double result = strtof(nptr, endptr);
// Restore locale
uselocale(oldLocale);
return result;
Expand Down