libs/posix: Implemented new locale functions

Implemented the missing POSIX functions in <locale.h>:
newlocale, duplocale, uselocale, and freelocale, and also
provided missing type definitions for <locale.h>.

Implemented missing POSIX locale-based function variants.

Modified LocaleBackend so that it could support thread-local
locales.

Some glibc-like locale-related variables supporting
ctype and printf family of functions have also been updated
to reflect the thread-local variables present in the latest
glibc sources.

As there have been some modifications to global symbols
in libroot, libroot_stubs.c has been regenerated.

Bug: #17168
Change-Id: Ibf296c58c47d42d1d1dfb2ce64042442f2679431
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5351
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
Trung Nguyen
2022-07-11 16:30:16 +00:00
committed by waddlesplash
parent 86fa1c21e1
commit d338200e2b
64 changed files with 2116 additions and 965 deletions
+27 -3
View File
@@ -6,6 +6,9 @@
#define _CTYPE_H
#include <locale_t.h>
#ifdef __cplusplus
extern "C" {
#endif
@@ -27,6 +30,22 @@ int toascii(int);
int tolower(int);
int toupper(int);
int isalnum_l(int, locale_t);
int isalpha_l(int, locale_t);
int isblank_l(int, locale_t);
int iscntrl_l(int, locale_t);
int isdigit_l(int, locale_t);
int isgraph_l(int, locale_t);
int islower_l(int, locale_t);
int isprint_l(int, locale_t);
int ispunct_l(int, locale_t);
int isspace_l(int, locale_t);
int isupper_l(int, locale_t);
int isxdigit_l(int, locale_t);
int tolower_l(int, locale_t);
int toupper_l(int, locale_t);
enum {
_ISblank = 0x0001, /* blank */
_IScntrl = 0x0002, /* control */
@@ -48,14 +67,19 @@ extern const unsigned short int *__ctype_b;
extern const int *__ctype_tolower;
extern const int *__ctype_toupper;
extern const unsigned short int **__ctype_b_loc();
extern const int **__ctype_tolower_loc();
extern const int **__ctype_toupper_loc();
#define __isctype(c, type) \
(__ctype_b[(int)(c)] & (unsigned short int)type)
((*__ctype_b_loc())[(int)(c)] & (unsigned short int)type)
#define tolower(c) ((int)(*__ctype_tolower_loc())[(int)(c)])
#define toupper(c) ((int)(*__ctype_toupper_loc())[(int)(c)])
#define isascii(c) (((c) & ~0x7f) == 0) /* ASCII characters have bit 8 cleared */
#define toascii(c) ((c) & 0x7f) /* Clear higher bits */
#define tolower(c) ((int)__ctype_tolower[(int)(c)])
#define toupper(c) ((int)__ctype_toupper[(int)(c)])
#define _tolower(c) tolower(c)
#define _toupper(c) toupper(c)
+1
View File
@@ -145,6 +145,7 @@ enum {
__BEGIN_DECLS
extern char* nl_langinfo(nl_item item);
extern char* nl_langinfo_l(nl_item item, locale_t locale);
__END_DECLS
+19
View File
@@ -6,6 +6,7 @@
#define _LOCALE_H_
#include <locale_t.h>
#include <null.h>
struct lconv {
@@ -48,6 +49,19 @@ struct lconv {
*/
#define LC_LAST LC_MESSAGES
#define LC_COLLATE_MASK (1 << (LC_COLLATE - 1))
#define LC_CTYPE_MASK (1 << (LC_CTYPE - 1))
#define LC_MONETARY_MASK (1 << (LC_MONETARY - 1))
#define LC_NUMERIC_MASK (1 << (LC_NUMERIC - 1))
#define LC_TIME_MASK (1 << (LC_TIME - 1))
#define LC_MESSAGES_MASK (1 << (LC_MESSAGES - 1))
#define LC_ALL_MASK (LC_COLLATE_MASK | LC_CTYPE_MASK | \
LC_MONETARY_MASK | LC_NUMERIC_MASK | \
LC_TIME_MASK | LC_MESSAGES_MASK)
#define LC_GLOBAL_LOCALE ((locale_t)-1)
#ifdef __cplusplus
extern "C" {
#endif
@@ -55,6 +69,11 @@ extern "C" {
extern struct lconv *localeconv(void);
extern char *setlocale(int category, const char *locale);
extern locale_t duplocale(locale_t);
extern void freelocale(locale_t);
extern locale_t newlocale(int, const char *, locale_t);
extern locale_t uselocale(locale_t);
#ifdef __cplusplus
}
#endif
+12
View File
@@ -0,0 +1,12 @@
/*
* Copyright 2022 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _LOCALE_T_H_
#define _LOCALE_T_H_
typedef void* locale_t;
#endif
+2 -1
View File
@@ -6,7 +6,7 @@
#define _MONETARY_H_
#include <locale.h>
#include <locale_t.h>
#include <stddef.h>
#include <sys/cdefs.h>
#include <sys/types.h>
@@ -15,6 +15,7 @@
__BEGIN_DECLS
extern ssize_t strfmon(char* s, size_t maxsize, const char* format, ...);
extern ssize_t strfmon_l(char* s, size_t maxsize, locale_t locale, const char* format, ...);
__END_DECLS
+6
View File
@@ -6,6 +6,7 @@
#define _STRING_H_
#include <locale_t.h>
#include <sys/types.h>
@@ -74,6 +75,11 @@ extern char *strupr(char *string);
extern const char *strsignal(int signum);
/* locale versions of string functions */
extern int strcoll_l(const char *string1, const char *string2, locale_t locale);
extern char *strerror_l(int errorCode, locale_t locale);
extern size_t strxfrm_l(char *string1, const char *string2, size_t length, locale_t locale);
/* for compatibility, pull in functions declared in strings.h */
#include <strings.h>
+5
View File
@@ -6,6 +6,7 @@
#define _STRINGS_H_
#include <locale_t.h>
#include <sys/types.h>
@@ -19,6 +20,10 @@ extern int strcasecmp(const char *string1, const char *string2);
extern int strncasecmp(const char *string1, const char *string2,
size_t length);
extern int strcasecmp_l(const char *string1, const char *string2, locale_t locale);
extern int strncasecmp_l(const char *string1, const char *string2,
size_t length, locale_t locale);
/* legacy compatibility -- might be removed one day */
#define bcmp(a, b, length) memcmp((a), (b), (length))
#define bcopy(source, dest, length) memmove((dest), (source), (length))
+3
View File
@@ -6,6 +6,7 @@
#define _TIME_H_
#include <locale_t.h>
#include <sys/types.h>
@@ -92,6 +93,8 @@ extern struct tm *localtime_r(const time_t *timer, struct tm *tm);
extern int nanosleep(const struct timespec *, struct timespec *);
extern size_t strftime(char *buffer, size_t maxSize, const char *format,
const struct tm *tm);
extern size_t strftime_l(char *buffer, size_t maxSize, const char *format,
const struct tm *tm, locale_t locale);
extern char *strptime(const char *buf, const char *format, struct tm *tm);
/* clock functions */
+7
View File
@@ -7,6 +7,7 @@
#include <limits.h>
#include <locale.h>
#include <stddef.h>
#include <stdio.h>
#include <time.h>
@@ -93,6 +94,7 @@ extern wchar_t *wcpcpy(wchar_t *dest, const wchar_t *src);
extern wchar_t *wcpncpy(wchar_t *dest, const wchar_t *src, size_t srcLength);
extern size_t wcrtomb(char *dest, wchar_t wc, mbstate_t *mbState);
extern int wcscasecmp(const wchar_t *wcs1, const wchar_t *wcs2);
extern int wcscasecmp_l(const wchar_t *wcs1, const wchar_t *wcs2, locale_t locale);
extern wchar_t *wcscat(wchar_t *dest, const wchar_t *src);
extern wchar_t *wcschr(const wchar_t *wcs, wchar_t wc);
#ifdef _GNU_SOURCE
@@ -100,6 +102,7 @@ extern wchar_t *wcschrnul(const wchar_t *wcs, wchar_t wc);
#endif
extern int wcscmp(const wchar_t *wcs1, const wchar_t *wcs2);
extern int wcscoll(const wchar_t *wcs1, const wchar_t *wcs2);
extern int wcscoll_l(const wchar_t *wcs1, const wchar_t *wcs2, locale_t locale);
extern wchar_t *wcscpy(wchar_t *dest, const wchar_t *src);
extern size_t wcscspn(const wchar_t *wcs, const wchar_t *reject);
extern wchar_t *wcsdup(const wchar_t *wcs);
@@ -110,6 +113,8 @@ extern size_t wcslcpy(wchar_t *dest, const wchar_t *src, size_t maxLength);
extern size_t wcslen(const wchar_t *wcs);
extern int wcsncasecmp(const wchar_t *wcs1, const wchar_t *wcs2,
size_t maxLength);
extern int wcsncasecmp_l(const wchar_t *wcs1, const wchar_t *wcs2,
size_t maxLength, locale_t locale);
extern wchar_t *wcsncat(wchar_t *dest, const wchar_t *src, size_t srcLength);
extern int wcsncmp(const wchar_t *wcs1, const wchar_t *wcs2,
size_t length);
@@ -136,6 +141,8 @@ extern unsigned long long wcstoull(const wchar_t *wcs, wchar_t **endPtr,
extern wchar_t *wcswcs(const wchar_t *haystack, const wchar_t *needle);
extern int wcswidth(const wchar_t *wcs, size_t length);
extern size_t wcsxfrm(wchar_t *dest, const wchar_t *src, size_t destLength);
extern size_t wcsxfrm_l(wchar_t *dest, const wchar_t *src, size_t destLength,
locale_t locale);
extern int wctob(wint_t wc);
extern int wcwidth(wchar_t wc);
extern wchar_t *wmemchr(const wchar_t *wcs, wchar_t wc, size_t n);
+24
View File
@@ -6,6 +6,7 @@
#define _WCTYPE_H_
#include <locale.h>
#include <wchar.h>
typedef int wctrans_t;
@@ -36,6 +37,29 @@ extern wint_t towupper(wint_t wc);
extern wctrans_t wctrans(const char *charClass);
extern wctype_t wctype(const char *property);
extern int iswalnum_l(wint_t wc, locale_t locale);
extern int iswalpha_l(wint_t wc, locale_t locale);
extern int iswcntrl_l(wint_t wc, locale_t locale);
extern int iswctype_l(wint_t wc, wctype_t desc, locale_t locale);
extern int iswdigit_l(wint_t wc, locale_t locale);
extern int iswgraph_l(wint_t wc, locale_t locale);
extern int iswlower_l(wint_t wc, locale_t locale);
extern int iswprint_l(wint_t wc, locale_t locale);
extern int iswpunct_l(wint_t wc, locale_t locale);
extern int iswspace_l(wint_t wc, locale_t locale);
extern int iswupper_l(wint_t wc, locale_t locale);
extern int iswxdigit_l(wint_t wc, locale_t locale);
extern int iswblank_l(wint_t wc, locale_t locale);
extern wint_t towctrans_l(wint_t wc, wctrans_t transition, locale_t locale);
extern wint_t towlower_l(wint_t wc, locale_t locale);
extern wint_t towupper_l(wint_t wc, locale_t locale);
extern wctrans_t wctrans_l(const char *charClass, locale_t locale);
extern wctype_t wctype_l(const char *property, locale_t locale);
#ifdef __cplusplus
}
#endif
+56 -18
View File
@@ -8,11 +8,11 @@
#include <SupportDefs.h>
#include <locale.h>
#include <time.h>
#include <wctype.h>
struct lconv;
struct lc_time_t;
struct locale_data; // glibc
@@ -22,29 +22,38 @@ namespace Libroot {
struct LocaleCtypeDataBridge {
const unsigned short** addrOfClassInfoTable;
const int** addrOfToLowerTable;
const int** addrOfToUpperTable;
private:
const unsigned short* localClassInfoTable;
const int* localToLowerTable;
const int* localToUpperTable;
const unsigned short* posixClassInfo;
const int* posixToLowerMap;
const int* posixToUpperMap;
public:
const unsigned short** addrOfClassInfoTable;
const int** addrOfToLowerTable;
const int** addrOfToUpperTable;
LocaleCtypeDataBridge();
const unsigned short* const posixClassInfo;
const int* const posixToLowerMap;
const int* const posixToUpperMap;
bool isGlobal;
LocaleCtypeDataBridge(bool isGlobal);
void setMbCurMax(unsigned short mbCurMax);
void ApplyToCurrentThread();
};
struct LocaleMessagesDataBridge {
const char** posixLanginfo;
const char** const posixLanginfo;
LocaleMessagesDataBridge();
};
struct LocaleMonetaryDataBridge {
const struct lconv* posixLocaleConv;
const struct lconv* const posixLocaleConv;
LocaleMonetaryDataBridge();
};
@@ -71,29 +80,42 @@ private:
values[6];
};
locale_data* originalGlibcLocale;
GlibcNumericLocale glibcNumericLocaleData;
public:
const struct lconv* posixLocaleConv;
GlibcNumericLocale glibcNumericLocale;
const struct lconv* const posixLocaleConv;
GlibcNumericLocale* glibcNumericLocale;
bool isGlobal;
LocaleNumericDataBridge();
LocaleNumericDataBridge(bool isGlobal);
~LocaleNumericDataBridge();
void ApplyToCurrentThread();
};
struct LocaleTimeDataBridge {
const struct lc_time_t* posixLCTimeInfo;
const struct lc_time_t* const posixLCTimeInfo;
LocaleTimeDataBridge();
};
struct TimeConversionDataBridge {
private:
int localDaylight;
long localTimezone;
char* localTZName[2];
char localTZName0[64];
char localTZName1[64];
public:
int* addrOfDaylight;
long* addrOfTimezone;
char** addrOfTZName;
bool isGlobal;
TimeConversionDataBridge();
TimeConversionDataBridge(bool isGlobal);
};
@@ -104,9 +126,12 @@ struct LocaleDataBridge {
LocaleNumericDataBridge numericDataBridge;
LocaleTimeDataBridge timeDataBridge;
TimeConversionDataBridge timeConversionDataBridge;
const char** posixLanginfo;
const char** const posixLanginfo;
bool isGlobal;
LocaleDataBridge();
LocaleDataBridge(bool isGlobal);
void ApplyToCurrentThread();
};
@@ -162,12 +187,25 @@ public:
virtual void Initialize(LocaleDataBridge* dataBridge) = 0;
static status_t LoadBackend();
static LocaleBackend* CreateBackend();
static void DestroyBackend(LocaleBackend* instance);
};
extern LocaleBackend* gLocaleBackend;
// The real struct behind locale_t
struct LocaleBackendData {
int magic;
LocaleBackend* backend;
LocaleDataBridge* databridge;
};
LocaleBackendData* GetCurrentLocaleInfo();
void SetCurrentLocaleInfo(LocaleBackendData* newLocale);
LocaleBackend* GetCurrentLocaleBackend();
extern LocaleBackend* gGlobalLocaleBackend;
extern LocaleDataBridge gGlobalLocaleDataBridge;
} // namespace Libroot
} // namespace BPrivate
@@ -0,0 +1,60 @@
/*
* Copyright 2022, Trung Nguyen, trungnt282910@gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _THREAD_LOCALE_H
#define _THREAD_LOCALE_H
#include "LocaleBackend.h"
namespace BPrivate {
namespace Libroot {
// This struct is taken from glibc's __locale_struct
// from xlocale.h.
// It will also be used by glibc so it should have the same
// layout.
struct GlibcLocaleStruct {
void *__locales[7]; /* 7 = __LC_LAST. */
const unsigned short int *__ctype_b;
const int *__ctype_tolower;
const int *__ctype_toupper;
};
// Taken from glibc's bits/locale.h
// glibc uses different codes from our the native locale.h.
// This should be the values used for the indexes
// in GlibcLocaleStruct.
enum {
GLIBC_LC_CTYPE = 0,
GLIBC_LC_NUMERIC = 1,
GLIBC_LC_TIME = 2,
GLIBC_LC_COLLATE = 3,
GLIBC_LC_MONETARY = 4,
GLIBC_LC_MESSAGES = 5,
GLIBC_LC_ALL = 6,
};
// The pointer in the TLS will point to this struct.
struct ThreadLocale {
GlibcLocaleStruct glibcLocaleStruct;
LocaleBackendData* threadLocaleInfo;
};
ThreadLocale* GetCurrentThreadLocale();
} // namespace Libroot
} // namespace BPrivate
#endif // _THREAD_LOCALE_H
+2
View File
@@ -29,6 +29,7 @@
#define _TIMELOCAL_H_
#include <locale.h>
#include <sys/cdefs.h>
@@ -54,6 +55,7 @@ struct lc_time_t {
__BEGIN_DECLS
const struct lc_time_t* __get_current_time_locale(void);
const struct lc_time_t* __get_time_locale(locale_t);
__END_DECLS
+8
View File
@@ -33,11 +33,15 @@ extern wchar_t *__wcpcpy(wchar_t *dest, const wchar_t *src);
extern wchar_t *__wcpncpy(wchar_t *dest, const wchar_t *src, size_t srcLength);
extern size_t __wcrtomb(char *dest, wchar_t wc, mbstate_t *mbState);
extern int __wcscasecmp(const wchar_t *wcs1, const wchar_t *wcs2);
extern int __wcscasecmp_l(const wchar_t *wcs1, const wchar_t *wcs2,
locale_t locale);
extern wchar_t *__wcscat(wchar_t *dest, const wchar_t *src);
extern wchar_t *__wcschr(const wchar_t *wcs, wchar_t wc);
extern wchar_t *__wcschrnul(const wchar_t *wcs, wchar_t wc);
extern int __wcscmp(const wchar_t *wcs1, const wchar_t *wcs2);
extern int __wcscoll(const wchar_t *wcs1, const wchar_t *wcs2);
extern int __wcscoll_l(const wchar_t *wcs1, const wchar_t *wcs2,
locale_t locale);
extern wchar_t *__wcscpy(wchar_t *dest, const wchar_t *src);
extern size_t __wcscspn(const wchar_t *wcs, const wchar_t *reject);
extern wchar_t *__wcsdup(const wchar_t *wcs);
@@ -48,6 +52,8 @@ extern size_t __wcslcpy(wchar_t *dest, const wchar_t *src, size_t maxLength);
extern size_t __wcslen(const wchar_t *wcs);
extern int __wcsncasecmp(const wchar_t *wcs1, const wchar_t *wcs2,
size_t maxLength);
extern int __wcsncasecmp_l(const wchar_t *wcs1, const wchar_t *wcs2,
size_t maxLength, locale_t locale);
extern wchar_t *__wcsncat(wchar_t *dest, const wchar_t *src, size_t srcLength);
extern int __wcsncmp(const wchar_t *wcs1, const wchar_t *wcs2,
size_t length);
@@ -76,6 +82,8 @@ extern int __wctomb(char *string, wchar_t wc);
extern wchar_t *__wcswcs(const wchar_t *haystack, const wchar_t *needle);
extern int __wcswidth(const wchar_t *wcs, size_t length);
extern size_t __wcsxfrm(wchar_t *dest, const wchar_t *src, size_t destLength);
extern size_t __wcsxfrm_l(wchar_t *dest, const wchar_t *src, size_t destLength,
locale_t locale);
extern int __wctob(wint_t wc);
extern int __wcwidth(wchar_t wc);
extern wchar_t *__wmemchr(const wchar_t *wcs, wchar_t wc, size_t n);
+1
View File
@@ -21,6 +21,7 @@ enum {
TLS_ON_EXIT_THREAD_SLOT,
TLS_USER_THREAD_SLOT,
TLS_DYNAMIC_THREAD_VECTOR,
TLS_LOCALE_SLOT,
// Note: these entries can safely be changed between
// releases; 3rd party code always calls tls_allocate()
+2
View File
@@ -21,7 +21,9 @@ for architectureObject in [ MultiArchSubDirSetup x86_gcc2 ] {
= [ FDirName $(HAIKU_TOP) src system libroot posix glibc ] ;
SYSHDRS =
$(SUBDIR)
[ FDirName $(glibcDir) ctype ]
[ FDirName $(glibcDir) libio ]
[ FDirName $(glibcDir) locale ]
[ FDirName $(glibcDir) stdlib ]
[ FDirName $(glibcDir) stdio-common ]
[ FDirName $(glibcDir) include ]
+2
View File
@@ -306,6 +306,8 @@ for platform in [ MultiBootSubDirSetup ] {
BootMergeObject boot_libroot_$(platform:G=).o :
abs.c
ctype_loc.cpp
ctype_l.cpp
ctype.cpp
LocaleData.cpp
qsort.c
+2
View File
@@ -64,6 +64,8 @@ KernelMergeObject kernel_lib_posix.o :
poll.cpp
utime.c
# locale
ctype_loc.cpp
ctype_l.cpp
ctype.cpp
localeconv.cpp
LocaleData.cpp
@@ -30,6 +30,13 @@ CreateInstance()
}
extern "C" void
DestroyInstance(LocaleBackend* instance)
{
delete instance;
}
ICULocaleBackend::ICULocaleBackend()
:
fThreadLocalStorageKey(_CreateThreadLocalStorageKey()),
@@ -34,9 +34,9 @@ ICUNumericData::ICUNumericData(pthread_key_t tlsKey, struct lconv& localeConv)
void
ICUNumericData::Initialize(LocaleNumericDataBridge* dataBridge)
{
dataBridge->glibcNumericLocale.values[0].string = fDecimalPoint;
dataBridge->glibcNumericLocale.values[1].string = fThousandsSep;
dataBridge->glibcNumericLocale.values[2].string = fGrouping;
dataBridge->glibcNumericLocale->values[0].string = fDecimalPoint;
dataBridge->glibcNumericLocale->values[1].string = fThousandsSep;
dataBridge->glibcNumericLocale->values[2].string = fGrouping;
fDataBridge = dataBridge;
}
@@ -62,13 +62,13 @@ ICUNumericData::SetTo(const Locale& locale, const char* posixLocaleName)
if (result == B_OK) {
result = _SetLocaleconvEntry(formatSymbols, fDecimalPoint,
DecimalFormatSymbols::kDecimalSeparatorSymbol);
fDataBridge->glibcNumericLocale.values[3].word
fDataBridge->glibcNumericLocale->values[3].word
= (unsigned int)fDecimalPoint[0];
}
if (result == B_OK) {
result = _SetLocaleconvEntry(formatSymbols, fThousandsSep,
DecimalFormatSymbols::kGroupingSeparatorSymbol);
fDataBridge->glibcNumericLocale.values[4].word
fDataBridge->glibcNumericLocale->values[4].word
= (unsigned int)fThousandsSep[0];
}
if (result == B_OK) {
@@ -104,9 +104,9 @@ ICUNumericData::SetToPosix()
strcpy(fDecimalPoint, fDataBridge->posixLocaleConv->decimal_point);
strcpy(fThousandsSep, fDataBridge->posixLocaleConv->thousands_sep);
strcpy(fGrouping, fDataBridge->posixLocaleConv->grouping);
fDataBridge->glibcNumericLocale.values[3].word
fDataBridge->glibcNumericLocale->values[3].word
= (unsigned int)fDecimalPoint[0];
fDataBridge->glibcNumericLocale.values[4].word
fDataBridge->glibcNumericLocale->values[4].word
= (unsigned int)fThousandsSep[0];
}
@@ -47,6 +47,7 @@ status_t
ICUTimeConversion::TZSet(const char* timeZoneID, const char* tz)
{
bool offsetHasBeenSet = false;
bool timeZoneIdMatches = false;
// The given TZ environment variable's content overrides the default
// system timezone.
@@ -55,8 +56,10 @@ ICUTimeConversion::TZSet(const char* timeZoneID, const char* tz)
// value is implementation specific, we expect a full timezone ID.
if (*tz == ':') {
// nothing to do if the given name matches the current timezone
if (strcasecmp(fTimeZoneID, tz + 1) == 0)
return B_OK;
if (strcasecmp(fTimeZoneID, tz + 1) == 0) {
timeZoneIdMatches = true;
goto done;
}
strlcpy(fTimeZoneID, tz + 1, sizeof(fTimeZoneID));
} else {
@@ -64,8 +67,10 @@ ICUTimeConversion::TZSet(const char* timeZoneID, const char* tz)
strlcpy(fTimeZoneID, tz, sizeof(fTimeZoneID));
// nothing to do if the given name matches the current timezone
if (strcasecmp(fTimeZoneID, fDataBridge->addrOfTZName[0]) == 0)
return B_OK;
if (strcasecmp(fTimeZoneID, fDataBridge->addrOfTZName[0]) == 0) {
timeZoneIdMatches = true;
goto done;
}
// parse TZ variable (only <std> and <offset> supported)
const char* tzNameEnd = tz;
@@ -88,12 +93,21 @@ ICUTimeConversion::TZSet(const char* timeZoneID, const char* tz)
}
} else {
// nothing to do if the given name matches the current timezone
if (strcasecmp(fTimeZoneID, timeZoneID) == 0)
return B_OK;
if (strcasecmp(fTimeZoneID, timeZoneID) == 0) {
timeZoneIdMatches = true;
goto done;
}
strlcpy(fTimeZoneID, timeZoneID, sizeof(fTimeZoneID));
}
done:
// fTimeZone can still be NULL if we don't initialize it
// in the first TZSet, causing problems for future
// Localtime invocations.
if (fTimeZone != NULL && timeZoneIdMatches)
return B_OK;
delete fTimeZone;
fTimeZone = TimeZone::createTimeZone(fTimeZoneID);
if (fTimeZone == NULL)
+15 -10
View File
@@ -64,6 +64,11 @@ enum
/* These are defined in ctype-info.c.
The declarations here must match those in localeinfo.h.
In the thread-specific locale model (see `uselocale' in <locale.h>)
we cannot use global variables for these as was done in the past.
Instead, the following accessor functions return the address of
each variable, which is local to the current thread if multithreaded.
These point into arrays of 384, so they can be indexed by any `unsigned
char' value [0,255]; by EOF (-1); or by any `signed char' value
[-128,-1). ISO C requires that the ctype functions work for `unsigned
@@ -72,12 +77,12 @@ enum
rather than `unsigned char's because tolower (EOF) must be EOF, which
doesn't fit into an `unsigned char'. But today more important is that
the arrays are also used for multi-byte character sets. */
extern __const unsigned short int *__ctype_b; /* Characteristics. */
extern __const __int32_t *__ctype_tolower; /* Case conversions. */
extern __const __int32_t *__ctype_toupper; /* Case conversions. */
extern __const unsigned short int **__ctype_b_loc (void); /* Characteristics. */
extern __const __int32_t **__ctype_tolower_loc (void); /* Case conversions. */
extern __const __int32_t **__ctype_toupper_loc (void); /* Case conversions. */
#define __isctype(c, type) \
(__ctype_b[(int) (c)] & (unsigned short int) type)
((*__ctype_b_loc())[(int) (c)] & (unsigned short int) type)
#define __isascii(c) (((c) & ~0x7f) == 0) /* If C is a 7 bit value. */
#define __toascii(c) ((c) & 0x7f) /* Mask off high bits. */
@@ -167,27 +172,27 @@ __exctype (_tolower);
__extern_inline int
tolower (int __c) __THROW
{
return __c >= -128 && __c < 256 ? __ctype_tolower[__c] : __c;
return __c >= -128 && __c < 256 ? (*__ctype_tolower_loc())[__c] : __c;
}
__extern_inline int
toupper (int __c) __THROW
{
return __c >= -128 && __c < 256 ? __ctype_toupper[__c] : __c;
return __c >= -128 && __c < 256 ? (*__ctype_toupper_loc())[__c] : __c;
}
# endif
# if __GNUC__ >= 2 && defined __OPTIMIZE__ && !defined __cplusplus
# define tolower(c) __tobody (c, tolower, __ctype_tolower, (c))
# define toupper(c) __tobody (c, toupper, __ctype_toupper, (c))
# define tolower(c) __tobody (c, tolower, (*__ctype_tolower_loc()), (c))
# define toupper(c) __tobody (c, toupper, (*__ctype_toupper_loc()), (c))
# endif /* Optimizing gcc */
# if defined __USE_SVID || defined __USE_MISC || defined __USE_XOPEN
# define isascii(c) __isascii (c)
# define toascii(c) __toascii (c)
# define _tolower(c) ((int) __ctype_tolower[(int) (c)])
# define _toupper(c) ((int) __ctype_toupper[(int) (c)])
# define _tolower(c) ((int) (*__ctype_tolower_loc())[(int) (c)])
# define _toupper(c) ((int) (*__ctype_toupper_loc())[(int) (c)])
# endif
#endif /* Not __NO_CTYPE. */
@@ -10,6 +10,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include arch
generic ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ctype ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc libio ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc locale ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ;
@@ -13,6 +13,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
generic ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc locale ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ctype ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ;
MergeObject <$(architecture)>posix_gnu_locale.o :
@@ -24,6 +25,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
C-time.c
C_name.c
coll-lookup.c
global-locale.c
lc-collate.c
lc-ctype.c
lc-messages.c
@@ -0,0 +1,48 @@
/* Locale object representing the global locale controlled by setlocale.
Copyright (C) 2002-2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <locale.h>
#include "localeinfo.h"
#define DEFINE_CATEGORY(category, category_name, items, a) \
extern struct locale_data _nl_C_##category;
#include "categories.def"
#undef DEFINE_CATEGORY
/* Defined in locale/C-ctype.c. */
extern const char _nl_C_LC_CTYPE_class[];
extern const char _nl_C_LC_CTYPE_toupper[];
extern const char _nl_C_LC_CTYPE_tolower[];
/* Here we define the locale object maintained by setlocale.
The references in the initializer are weak, so the parts of
the structure that are never referred to will be zero. */
struct __locale_struct _nl_global_locale =
{
.__locales =
{
#define DEFINE_CATEGORY(category, category_name, items, a) \
[category] = &_nl_C_##category,
#include "categories.def"
#undef DEFINE_CATEGORY
},
.__ctype_b = (const unsigned short int *) _nl_C_LC_CTYPE_class + 128,
.__ctype_tolower = (const int *) _nl_C_LC_CTYPE_tolower + 128,
.__ctype_toupper = (const int *) _nl_C_LC_CTYPE_toupper + 128
};
@@ -47,9 +47,9 @@ _nl_postload_ctype (void)
offset = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_CLASS_OFFSET);
for (cnt = 0; cnt < 12; cnt++)
__ctype32_wctype[cnt] = _nl_current_LC_CTYPE->values[offset + cnt].string;
__ctype32_wctype[cnt] = _nl_global_locale.__locales[LC_CTYPE]->values[offset + cnt].string;
offset = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_OFFSET);
for (cnt = 0; cnt < 2; cnt++)
__ctype32_wctrans[cnt] = _nl_current_LC_CTYPE->values[offset + cnt].string;
__ctype32_wctrans[cnt] = _nl_global_locale.__locales[LC_CTYPE]->values[offset + cnt].string;
}
@@ -27,6 +27,11 @@
#include <stdint.h>
#include <sys/types.h>
// __locale_struct
#include <xlocale.h>
// LC_* values
#include <locale.h>
/* This has to be changed whenever a new locale is defined. */
#define __LC_LAST 7
@@ -141,12 +146,6 @@ enum
(((((const uint32_t *) (desc)) - 8)[(c) >> 5] >> ((c) & 0x1f)) & 1)
/* For each category declare the variable for the current locale data. */
#define DEFINE_CATEGORY(category, category_name, items, a) \
extern struct locale_data *_nl_current_##category;
#include "categories.def"
#undef DEFINE_CATEGORY
extern const char *const _nl_category_names[__LC_LAST];
extern const size_t _nl_category_name_sizes[__LC_LAST];
extern struct locale_data * *const _nl_current[__LC_LAST];
@@ -158,22 +157,33 @@ extern const char _nl_POSIX_name[];
/* The standard codeset. */
extern const char _nl_C_codeset[];
/* This is the internal locale_t object that holds the global locale
controlled by calls to setlocale. A thread's TSD locale pointer
points to this when `uselocale (LC_GLOBAL_LOCALE)' is in effect. */
extern struct __locale_struct _nl_global_locale;
extern struct __locale_struct* _nl_current_locale();
#define _NL_CURRENT_LOCALE (_nl_current_locale())
/* Return a pointer to the current `struct __locale_data' for CATEGORY. */
#define _NL_CURRENT_DATA(category) \
(_NL_CURRENT_LOCALE->__locales[category])
/* Extract the current CATEGORY locale's string for ITEM. */
#define _NL_CURRENT(category, item) \
(_nl_current_##category->values[_NL_ITEM_INDEX (item)].string)
(_NL_CURRENT_DATA (category)->values[_NL_ITEM_INDEX (item)].string)
/* Extract the current CATEGORY locale's string for ITEM. */
#define _NL_CURRENT_WSTR(category, item) \
((wchar_t *) (_nl_current_##category->values[_NL_ITEM_INDEX (item)].wstr))
((wchar_t *) _NL_CURRENT_DATA (category)->values[_NL_ITEM_INDEX (item)].wstr)
/* Extract the current CATEGORY locale's word for ITEM. */
#define _NL_CURRENT_WORD(category, item) \
(_nl_current_##category->values[_NL_ITEM_INDEX (item)].word)
((uint32_t) _NL_CURRENT_DATA (category)->values[_NL_ITEM_INDEX (item)].word)
/* This is used in lc-CATEGORY.c to define _nl_current_CATEGORY. */
#define _NL_CURRENT_DEFINE(category) \
extern struct locale_data _nl_C_##category; \
struct locale_data *_nl_current_##category = &_nl_C_##category
/* No per-category variable here. */
/* Load the locale data for CATEGORY from the file specified by *NAME.
If *NAME is "", use environment variables as specified by POSIX,
@@ -12,6 +12,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include arch
generic ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ctype ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc libio ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc misc ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc locale ;
@@ -14,6 +14,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
generic ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc stdio-common ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ctype ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc locale ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ;
@@ -12,6 +12,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include arch
generic ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ctype ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc locale ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc stdlib ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ;
+10
View File
@@ -4,6 +4,7 @@ UsePrivateHeaders
[ FDirName libroot ]
[ FDirName libroot locale ]
[ FDirName libroot time ]
[ FDirName system ]
;
local architectureObject ;
@@ -12,14 +13,23 @@ for architectureObject in [ MultiArchSubDirSetup ] {
local architecture = $(TARGET_PACKAGING_ARCH) ;
MergeObject <$(architecture)>posix_locale.o :
ctype_l.cpp
ctype.cpp
LocaleBackend.cpp
LocaleData.cpp
LocaleDataBridge.cpp
LocaleInternal.cpp
locale_t.cpp
localeconv.cpp
nl_langinfo.cpp
setlocale.cpp
ThreadLocale.cpp
wctype_l.cpp
wctype.cpp
;
MergeObject <$(architecture)>ctype_loc.o :
ctype_loc.cpp
;
}
}
@@ -10,37 +10,56 @@
#include <pthread.h>
#include <string.h>
#include <ThreadLocale.h>
namespace BPrivate {
namespace Libroot {
LocaleBackend* gLocaleBackend = NULL;
LocaleBackend* gGlobalLocaleBackend = NULL;
LocaleDataBridge gGlobalLocaleDataBridge = LocaleDataBridge(true);
static void* sImageHandle = NULL;
typedef LocaleBackend* (*create_instance_t)();
typedef void (*destroy_instance_t)(LocaleBackend*);
static create_instance_t sCreateInstanceFunc = NULL;
static destroy_instance_t sDestroyInstanceFunc = NULL;
static LocaleDataBridge sLocaleDataBridge;
static pthread_once_t sBackendInitOnce = PTHREAD_ONCE_INIT;
static pthread_once_t sFunctionsInitOnce = PTHREAD_ONCE_INIT;
static void
LoadFunctions()
{
sImageHandle = dlopen("libroot-addon-icu.so", RTLD_LAZY);
if (sImageHandle == NULL)
return;
sCreateInstanceFunc = (create_instance_t)dlsym(sImageHandle, "CreateInstance");
sDestroyInstanceFunc = (destroy_instance_t)dlsym(sImageHandle, "DestroyInstance");
if ((sCreateInstanceFunc == NULL) || (sDestroyInstanceFunc == NULL)) {
dlclose(sImageHandle);
return;
}
}
static void
LoadBackend()
{
void* imageHandle = dlopen("libroot-addon-icu.so", RTLD_LAZY);
if (imageHandle == NULL)
return;
typedef LocaleBackend* (*symbolType)();
symbolType createInstanceFunc
= (symbolType)dlsym(imageHandle, "CreateInstance");
if (createInstanceFunc == NULL) {
dlclose(imageHandle);
return;
gGlobalLocaleBackend = LocaleBackend::CreateBackend();
if (gGlobalLocaleBackend != NULL) {
gGlobalLocaleBackend->Initialize(&gGlobalLocaleDataBridge);
}
gLocaleBackend = createInstanceFunc();
}
LocaleBackend::LocaleBackend()
{
}
@@ -54,15 +73,60 @@ LocaleBackend::~LocaleBackend()
status_t
LocaleBackend::LoadBackend()
{
if (gLocaleBackend == NULL) {
if (gGlobalLocaleBackend == NULL) {
pthread_once(&sBackendInitOnce, &BPrivate::Libroot::LoadBackend);
if (gLocaleBackend != NULL)
gLocaleBackend->Initialize(&sLocaleDataBridge);
}
return gLocaleBackend != NULL ? B_OK : B_ERROR;
return gGlobalLocaleBackend != NULL ? B_OK : B_ERROR;
}
LocaleBackend*
LocaleBackend::CreateBackend()
{
if (sCreateInstanceFunc == NULL) {
pthread_once(&sFunctionsInitOnce, &BPrivate::Libroot::LoadFunctions);
}
if (sCreateInstanceFunc != NULL) {
LocaleBackend* backend = sCreateInstanceFunc();
return backend;
}
return NULL;
}
void
LocaleBackend::DestroyBackend(LocaleBackend* instance)
{
if (sDestroyInstanceFunc != NULL) {
sDestroyInstanceFunc(instance);
}
}
LocaleBackendData* GetCurrentLocaleInfo()
{
return GetCurrentThreadLocale()->threadLocaleInfo;
}
void
SetCurrentLocaleInfo(LocaleBackendData* newLocale)
{
GetCurrentThreadLocale()->threadLocaleInfo = newLocale;
}
LocaleBackend* GetCurrentLocaleBackend()
{
LocaleBackendData* info = GetCurrentThreadLocale()->threadLocaleInfo;
if (info != NULL && info->backend != NULL) {
return info->backend;
}
return gGlobalLocaleBackend;
}
} // namespace Libroot
} // namespace BPrivate
@@ -15,24 +15,45 @@
#include <PosixLanginfo.h>
#include <PosixLCTimeInfo.h>
#include <PosixLocaleConv.h>
#include <ThreadLocale.h>
extern locale_data* _nl_current_LC_NUMERIC;
extern const unsigned short* __ctype_b;
extern const int* __ctype_tolower;
extern const int* __ctype_toupper;
namespace BPrivate {
namespace Libroot {
LocaleCtypeDataBridge::LocaleCtypeDataBridge()
extern "C" GlibcLocaleStruct* _nl_current_locale();
extern "C" GlibcLocaleStruct _nl_global_locale;
#define _NL_CURRENT_DATA(category) \
((locale_data*&)(_nl_current_locale()->__locales[category]))
#define _NL_GLOBAL_DATA(category) \
((locale_data*&)(_nl_global_locale.__locales[category]))
LocaleCtypeDataBridge::LocaleCtypeDataBridge(bool isGlobal)
:
addrOfClassInfoTable(&__ctype_b),
addrOfToLowerTable(&__ctype_tolower),
addrOfToUpperTable(&__ctype_toupper),
localClassInfoTable(__ctype_b),
localToLowerTable(__ctype_tolower),
localToUpperTable(__ctype_toupper),
posixClassInfo(gPosixClassInfo),
posixToLowerMap(gPosixToLowerMap),
posixToUpperMap(gPosixToUpperMap)
posixToUpperMap(gPosixToUpperMap),
isGlobal(isGlobal)
{
if (isGlobal) {
addrOfClassInfoTable = &__ctype_b;
addrOfToLowerTable = &__ctype_tolower;
addrOfToUpperTable = &__ctype_toupper;
} else {
addrOfClassInfoTable = &localClassInfoTable;
addrOfToLowerTable = &localToLowerTable;
addrOfToUpperTable = &localToUpperTable;
}
}
@@ -42,6 +63,15 @@ void LocaleCtypeDataBridge::setMbCurMax(unsigned short mbCurMax)
}
void
LocaleCtypeDataBridge::ApplyToCurrentThread()
{
*__ctype_b_loc() = *addrOfClassInfoTable;
*__ctype_tolower_loc() = *addrOfToLowerTable;
*__ctype_toupper_loc() = *addrOfToUpperTable;
}
LocaleMessagesDataBridge::LocaleMessagesDataBridge()
:
posixLanginfo(gPosixLanginfo)
@@ -56,20 +86,36 @@ LocaleMonetaryDataBridge::LocaleMonetaryDataBridge()
}
LocaleNumericDataBridge::LocaleNumericDataBridge()
LocaleNumericDataBridge::LocaleNumericDataBridge(bool isGlobal)
:
originalGlibcLocale(_nl_current_LC_NUMERIC),
posixLocaleConv(&gPosixLocaleConv)
posixLocaleConv(&gPosixLocaleConv),
glibcNumericLocale(&glibcNumericLocaleData)
{
memcpy(&glibcNumericLocale, _nl_current_LC_NUMERIC,
sizeof(glibcNumericLocale));
_nl_current_LC_NUMERIC = (locale_data*)&glibcNumericLocale;
memcpy(glibcNumericLocale, _NL_GLOBAL_DATA(GLIBC_LC_NUMERIC),
sizeof(GlibcNumericLocale));
if (isGlobal) {
originalGlibcLocale = _NL_GLOBAL_DATA(GLIBC_LC_NUMERIC);
_NL_GLOBAL_DATA(GLIBC_LC_NUMERIC) = (locale_data*)glibcNumericLocale;
}
}
LocaleNumericDataBridge::~LocaleNumericDataBridge()
{
_nl_current_LC_NUMERIC = originalGlibcLocale;
if (isGlobal) {
_NL_GLOBAL_DATA(GLIBC_LC_NUMERIC) = originalGlibcLocale;
} else if (_NL_CURRENT_DATA(GLIBC_LC_NUMERIC) == (locale_data*)glibcNumericLocale) {
_NL_CURRENT_DATA(GLIBC_LC_NUMERIC) = _NL_GLOBAL_DATA(GLIBC_LC_NUMERIC);
}
}
void
LocaleNumericDataBridge::ApplyToCurrentThread()
{
_NL_CURRENT_DATA(GLIBC_LC_NUMERIC) = (locale_data*)glibcNumericLocale;
}
@@ -80,19 +126,50 @@ LocaleTimeDataBridge::LocaleTimeDataBridge()
}
TimeConversionDataBridge::TimeConversionDataBridge()
TimeConversionDataBridge::TimeConversionDataBridge(bool isGlobal)
:
addrOfDaylight(&daylight),
addrOfTimezone(&timezone),
addrOfTZName(tzname)
localDaylight(daylight),
localTimezone(timezone),
isGlobal(isGlobal)
{
if (isGlobal) {
addrOfDaylight = &daylight;
addrOfTimezone = &timezone;
addrOfTZName = tzname;
} else {
addrOfDaylight = &localDaylight;
addrOfTimezone = &localTimezone;
addrOfTZName = localTZName;
addrOfTZName[0] = localTZName0;
addrOfTZName[1] = localTZName1;
strlcpy(localTZName0, tzname[0], sizeof(localTZName0));
strlcpy(localTZName1, tzname[1], sizeof(localTZName1));
}
}
LocaleDataBridge::LocaleDataBridge(bool isGlobal)
:
ctypeDataBridge(isGlobal),
numericDataBridge(isGlobal),
timeConversionDataBridge(isGlobal),
posixLanginfo(gPosixLanginfo),
isGlobal(isGlobal)
{
}
LocaleDataBridge::LocaleDataBridge()
:
posixLanginfo(gPosixLanginfo)
void
LocaleDataBridge::ApplyToCurrentThread()
{
ctypeDataBridge.ApplyToCurrentThread();
numericDataBridge.ApplyToCurrentThread();
// While timeConverstionDataBridge stores read-write variables,
// these variables are global (by POSIX definition). Furthermore,
// none of the backends seem to access these variables
// directly. The values are set in the bridge mostly for
// synchronization purposes. Therefore, don't call
// ApplyToCurrentThread for this object.
}
@@ -0,0 +1,75 @@
/*
* Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de
* Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "LocaleInternal.h"
#include <locale.h>
#include <stdlib.h>
#include <strings.h>
#include <Debug.h>
namespace BPrivate {
namespace Libroot {
status_t
GetLocalesFromEnvironment(int category, const char** locales)
{
if (category > LC_LAST) {
return B_BAD_VALUE;
}
const char* locale = getenv("LC_ALL");
if (locale != NULL && *locale != '\0')
locales[category] = locale;
else {
// the order of the names must match the one specified in locale.h
const char* const categoryNames[] = {
"LC_ALL",
"LC_COLLATE",
"LC_CTYPE",
"LC_MONETARY",
"LC_NUMERIC",
"LC_TIME",
"LC_MESSAGES"
};
STATIC_ASSERT(B_COUNT_OF(categoryNames) == LC_LAST + 1);
int from, to;
if (category == LC_ALL) {
// we need to check each real category if all of them should be set
from = 1;
to = LC_LAST;
} else
from = to = category;
bool haveDifferentLocales = false;
locale = NULL;
for (int lc = from; lc <= to; lc++) {
const char* lastLocale = locale;
locale = getenv(categoryNames[lc]);
if (locale == NULL || *locale == '\0')
locale = getenv("LANG");
if (locale == NULL || *locale == '\0')
locale = "POSIX";
locales[lc] = locale;
if (lastLocale != NULL && strcasecmp(locale, lastLocale) != 0)
haveDifferentLocales = true;
}
if (!haveDifferentLocales) {
// we can set all locales at once
locales[LC_ALL] = locale;
}
}
return B_OK;
}
} // namespace Libroot
} // namespace BPrivate
@@ -0,0 +1,21 @@
/*
* Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de
* Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <SupportDefs.h>
#define LOCALE_T_MAGIC 'LOCA'
namespace BPrivate {
namespace Libroot {
status_t GetLocalesFromEnvironment(int category, const char** locales);
} // namespace Libroot
} // namespace BPrivate
@@ -0,0 +1,74 @@
/*
* Copyright 2022, Trung Nguyen, trungnt282910@gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <ctype.h>
#include <tls.h>
#include <kernel/OS.h>
#include <ThreadLocale.h>
// From glibc's localeinfo.h
extern BPrivate::Libroot::GlibcLocaleStruct _nl_global_locale;
namespace BPrivate {
namespace Libroot {
static void DestroyThreadLocale(void* ptr)
{
ThreadLocale* threadLocale = (ThreadLocale*)ptr;
delete threadLocale;
}
ThreadLocale*
GetCurrentThreadLocale()
{
ThreadLocale* threadLocale = (ThreadLocale*)tls_get(TLS_LOCALE_SLOT);
if (threadLocale == NULL) {
threadLocale = new ThreadLocale();
threadLocale->glibcLocaleStruct = _nl_global_locale;
threadLocale->threadLocaleInfo = NULL;
on_exit_thread(DestroyThreadLocale, threadLocale);
tls_set(TLS_LOCALE_SLOT, threadLocale);
}
return threadLocale;
}
// Exported so that glibc could also use.
extern "C" GlibcLocaleStruct*
_nl_current_locale()
{
return &GetCurrentThreadLocale()->glibcLocaleStruct;
}
extern "C" const unsigned short**
__ctype_b_loc()
{
return &GetCurrentThreadLocale()->glibcLocaleStruct.__ctype_b;
}
extern "C" const int**
__ctype_tolower_loc()
{
return &GetCurrentThreadLocale()->glibcLocaleStruct.__ctype_tolower;
}
extern "C" const int**
__ctype_toupper_loc()
{
return &GetCurrentThreadLocale()->glibcLocaleStruct.__ctype_toupper;
}
} // namespace Libroot
} // namespace BPrivate
+14 -14
View File
@@ -44,7 +44,7 @@ int
isalnum(int c)
{
if (c >= -128 && c < 256)
return __ctype_b[c] & (_ISupper | _ISlower | _ISdigit);
return (*__ctype_b_loc())[c] & (_ISupper | _ISlower | _ISdigit);
return 0;
}
@@ -54,7 +54,7 @@ int
isalpha(int c)
{
if (c >= -128 && c < 256)
return __ctype_b[c] & (_ISupper | _ISlower);
return (*__ctype_b_loc())[c] & (_ISupper | _ISlower);
return 0;
}
@@ -72,7 +72,7 @@ int
isblank(int c)
{
if (c >= -128 && c < 256)
return __ctype_b[c] & _ISblank;
return (*__ctype_b_loc())[c] & _ISblank;
return 0;
}
@@ -82,7 +82,7 @@ int
iscntrl(int c)
{
if (c >= -128 && c < 256)
return __ctype_b[c] & _IScntrl;
return (*__ctype_b_loc())[c] & _IScntrl;
return 0;
}
@@ -92,7 +92,7 @@ int
isdigit(int c)
{
if (c >= -128 && c < 256)
return __ctype_b[c] & _ISdigit;
return (*__ctype_b_loc())[c] & _ISdigit;
return 0;
}
@@ -102,7 +102,7 @@ int
isgraph(int c)
{
if (c >= -128 && c < 256)
return __ctype_b[c] & _ISgraph;
return (*__ctype_b_loc())[c] & _ISgraph;
return 0;
}
@@ -112,7 +112,7 @@ int
islower(int c)
{
if (c >= -128 && c < 256)
return __ctype_b[c] & _ISlower;
return (*__ctype_b_loc())[c] & _ISlower;
return 0;
}
@@ -122,7 +122,7 @@ int
isprint(int c)
{
if (c >= -128 && c < 256)
return __ctype_b[c] & _ISprint;
return (*__ctype_b_loc())[c] & _ISprint;
return 0;
}
@@ -132,7 +132,7 @@ int
ispunct(int c)
{
if (c >= -128 && c < 256)
return __ctype_b[c] & _ISpunct;
return (*__ctype_b_loc())[c] & _ISpunct;
return 0;
}
@@ -142,7 +142,7 @@ int
isspace(int c)
{
if (c >= -128 && c < 256)
return __ctype_b[c] & _ISspace;
return (*__ctype_b_loc())[c] & _ISspace;
return 0;
}
@@ -152,7 +152,7 @@ int
isupper(int c)
{
if (c >= -128 && c < 256)
return __ctype_b[c] & _ISupper;
return (*__ctype_b_loc())[c] & _ISupper;
return 0;
}
@@ -162,7 +162,7 @@ int
isxdigit(int c)
{
if (c >= -128 && c < 256)
return __ctype_b[c] & _ISxdigit;
return (*__ctype_b_loc())[c] & _ISxdigit;
return 0;
}
@@ -180,7 +180,7 @@ int
tolower(int c)
{
if (c >= -128 && c < 256)
return __ctype_tolower[c];
return (*__ctype_tolower_loc())[c];
return c;
}
@@ -190,7 +190,7 @@ int
toupper(int c)
{
if (c >= -128 && c < 256)
return __ctype_toupper[c];
return (*__ctype_toupper_loc())[c];
return c;
}
+202
View File
@@ -0,0 +1,202 @@
/*
* Copyright 2022, Trung Nguyen, trungnt282910@gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <ctype.h>
#include <locale.h>
#include <LocaleBackend.h>
#include <PosixCtype.h>
namespace BPrivate {
namespace Libroot {
// A NULL databridge means that the object represents the POSIX locale.
static const unsigned short*
GetClassInfoTable(locale_t l)
{
LocaleBackendData* locale = (LocaleBackendData*)l;
if (locale->databridge == NULL) {
return &gPosixClassInfo[128];
}
return *locale->databridge->ctypeDataBridge.addrOfClassInfoTable;
}
static const int*
GetToUpperTable(locale_t l)
{
LocaleBackendData* locale = (LocaleBackendData*)l;
if (locale->databridge == NULL) {
return &gPosixToUpperMap[128];
}
return *locale->databridge->ctypeDataBridge.addrOfToUpperTable;
}
static const int*
GetToLowerTable(locale_t l)
{
LocaleBackendData* locale = (LocaleBackendData*)l;
if (locale->databridge == NULL) {
return &gPosixToLowerMap[128];
}
return *locale->databridge->ctypeDataBridge.addrOfToLowerTable;
}
extern "C" {
int
isalnum_l(int c, locale_t l)
{
if (c >= -128 && c < 256)
return GetClassInfoTable(l)[c] & (_ISupper | _ISlower | _ISdigit);
return 0;
}
int
isalpha_l(int c, locale_t l)
{
if (c >= -128 && c < 256)
return GetClassInfoTable(l)[c] & (_ISupper | _ISlower);
return 0;
}
int
isblank_l(int c, locale_t l)
{
if (c >= -128 && c < 256)
return GetClassInfoTable(l)[c] & _ISblank;
return 0;
}
int
iscntrl_l(int c, locale_t l)
{
if (c >= -128 && c < 256)
return GetClassInfoTable(l)[c] & _IScntrl;
return 0;
}
int
isdigit_l(int c, locale_t l)
{
if (c >= -128 && c < 256)
return GetClassInfoTable(l)[c] & _ISdigit;
return 0;
}
int
isgraph_l(int c, locale_t l)
{
if (c >= -128 && c < 256)
return GetClassInfoTable(l)[c] & _ISgraph;
return 0;
}
int
islower_l(int c, locale_t l)
{
if (c >= -128 && c < 256)
return GetClassInfoTable(l)[c] & _ISlower;
return 0;
}
int
isprint_l(int c, locale_t l)
{
if (c >= -128 && c < 256)
return GetClassInfoTable(l)[c] & _ISprint;
return 0;
}
int
ispunct_l(int c, locale_t l)
{
if (c >= -128 && c < 256)
return GetClassInfoTable(l)[c] & _ISpunct;
return 0;
}
int
isspace_l(int c, locale_t l)
{
if (c >= -128 && c < 256)
return GetClassInfoTable(l)[c] & _ISspace;
return 0;
}
int
isupper_l(int c, locale_t l)
{
if (c >= -128 && c < 256)
return GetClassInfoTable(l)[c] & _ISupper;
return 0;
}
int
isxdigit_l(int c, locale_t l)
{
if (c >= -128 && c < 256)
return GetClassInfoTable(l)[c] & _ISxdigit;
return 0;
}
int
tolower_l(int c, locale_t l)
{
if (c >= -128 && c < 256)
return GetToLowerTable(l)[c];
return c;
}
int
toupper_l(int c, locale_t l)
{
if (c >= -128 && c < 256)
return GetToUpperTable(l)[c];
return c;
}
}
} // namespace Libroot
} // namespace BPrivate
@@ -0,0 +1,33 @@
/*
* Copyright 2022, Trung Nguyen, trungnt282910@gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <ctype.h>
// These functions are intended for scenarios where we cannot
// link to the whole libroot and access pthread functions;
// for example, when we're in the bootloader, kernel or the
// runtime_loader.
extern "C" const unsigned short**
__ctype_b_loc()
{
return &__ctype_b;
}
extern "C" const int**
__ctype_tolower_loc()
{
return &__ctype_tolower;
}
extern "C" const int**
__ctype_toupper_loc()
{
return &__ctype_toupper;
}
@@ -0,0 +1,238 @@
/*
* Copyright 2022, Trung Nguyen, trungnt282910@gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <new>
#include <errno.h>
#include <locale.h>
#include <strings.h>
#include <ErrnoMaintainer.h>
#include "LocaleBackend.h"
#include "LocaleInternal.h"
using BPrivate::Libroot::gGlobalLocaleBackend;
using BPrivate::Libroot::gGlobalLocaleDataBridge;
using BPrivate::Libroot::GetCurrentLocaleInfo;
using BPrivate::Libroot::GetLocalesFromEnvironment;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
using BPrivate::Libroot::LocaleDataBridge;
extern "C" locale_t
duplocale(locale_t l)
{
LocaleBackendData* locObj = (LocaleBackendData*)l;
LocaleBackendData* newObj = new (std::nothrow) LocaleBackendData;
if (newObj == NULL) {
errno = ENOMEM;
return (locale_t)0;
}
LocaleBackend* backend = (l == LC_GLOBAL_LOCALE) ?
gGlobalLocaleBackend : (LocaleBackend*)locObj->backend;
if (backend == NULL) {
newObj->backend = NULL;
return (locale_t)newObj;
}
// Check if everything is set to "C" or "POSIX",
// and avoid making a backend.
const char* localeDescription = backend->SetLocale(LC_ALL, NULL);
if ((strcasecmp(localeDescription, "POSIX") == 0)
|| (strcasecmp(localeDescription, "C") == 0)) {
newObj->backend = NULL;
return (locale_t)newObj;
}
BPrivate::ErrnoMaintainer errnoMaintainer;
LocaleBackend*& newBackend = newObj->backend;
LocaleDataBridge*& newDataBridge = newObj->databridge;
newBackend = LocaleBackend::CreateBackend();
if (newBackend == NULL) {
errno = ENOMEM;
delete newObj;
return (locale_t)0;
}
newDataBridge = new (std::nothrow) LocaleDataBridge(false);
if (newDataBridge == NULL) {
errno = ENOMEM;
delete newBackend;
delete newObj;
return (locale_t)0;
}
newBackend->Initialize(newDataBridge);
// Skipping LC_ALL. Asking for LC_ALL would force the backend
// to query each other value once, anyway.
for (int lc = 1; lc <= LC_LAST; ++lc) {
newBackend->SetLocale(lc, backend->SetLocale(lc, NULL));
}
return (locale_t)newObj;
}
extern "C" void
freelocale(locale_t l)
{
LocaleBackendData* locobj = (LocaleBackendData*)l;
if (locobj->backend) {
LocaleBackend::DestroyBackend(locobj->backend);
LocaleDataBridge* databridge = locobj->databridge;
delete databridge;
}
delete locobj;
}
extern "C" locale_t
newlocale(int category_mask, const char* locale, locale_t base)
{
if (((category_mask | LC_ALL_MASK) != LC_ALL_MASK) || (locale == NULL)) {
errno = EINVAL;
return (locale_t)0;
}
bool newObject = false;
LocaleBackendData* localeObject = (LocaleBackendData*)base;
if (localeObject == NULL) {
localeObject = new (std::nothrow) LocaleBackendData;
if (localeObject == NULL) {
errno = ENOMEM;
return (locale_t)0;
}
localeObject->magic = LOCALE_T_MAGIC;
localeObject->backend = NULL;
localeObject->databridge = NULL;
newObject = true;
}
LocaleBackend*& backend = localeObject->backend;
LocaleDataBridge*& databridge = localeObject->databridge;
const char* locales[LC_LAST + 1];
for (int lc = 0; lc <= LC_LAST; lc++)
locales[lc] = NULL;
if (*locale == '\0') {
if (category_mask == LC_ALL_MASK) {
GetLocalesFromEnvironment(LC_ALL, locales);
} else {
for (int lc = 1; lc <= LC_LAST; ++lc) {
if (category_mask & (1 << (lc - 1))) {
GetLocalesFromEnvironment(lc, locales);
}
}
}
} else {
if (category_mask == LC_ALL_MASK) {
locales[LC_ALL] = locale;
}
for (int lc = 1; lc <= LC_LAST; ++lc) {
if (category_mask & (1 << (lc - 1))) {
locales[lc] = locale;
}
}
}
if (backend == NULL) {
// for any locale other than POSIX/C, we try to activate the ICU
// backend
bool needBackend = false;
for (int lc = 0; lc <= LC_LAST; lc++) {
if (locales[lc] != NULL && strcasecmp(locales[lc], "POSIX") != 0
&& strcasecmp(locales[lc], "C") != 0) {
needBackend = true;
break;
}
}
if (needBackend) {
backend = LocaleBackend::CreateBackend();
if (backend == NULL) {
errno = ENOMEM;
if (newObject) {
delete localeObject;
}
return (locale_t)0;
}
databridge = new (std::nothrow) LocaleDataBridge(false);
if (databridge == NULL) {
errno = ENOMEM;
delete backend;
if (newObject) {
delete localeObject;
}
return (locale_t)0;
}
backend->Initialize(databridge);
}
}
BPrivate::ErrnoMaintainer errnoMaintainer;
if (backend != NULL) {
for (int lc = 0; lc <= LC_LAST; lc++) {
if (locales[lc] != NULL) {
locale = backend->SetLocale(lc, locales[lc]);
if (lc == LC_ALL) {
// skip the rest, LC_ALL overrides
break;
}
}
}
}
return (locale_t)localeObject;
}
extern "C" locale_t
uselocale(locale_t newLoc)
{
locale_t oldLoc = (locale_t)GetCurrentLocaleInfo();
if (oldLoc == NULL) {
oldLoc = LC_GLOBAL_LOCALE;
}
if (newLoc != (locale_t)0) {
// Avoid expensive TLS reads with a local variable.
locale_t appliedLoc = oldLoc;
if (newLoc == LC_GLOBAL_LOCALE) {
appliedLoc = NULL;
} else {
if (((LocaleBackendData*)newLoc)->magic != LOCALE_T_MAGIC) {
errno = EINVAL;
return (locale_t)0;
}
appliedLoc = newLoc;
}
SetCurrentLocaleInfo((LocaleBackendData*)appliedLoc);
if (appliedLoc != NULL) {
((LocaleBackendData*)appliedLoc)->databridge->ApplyToCurrentThread();
} else {
gGlobalLocaleDataBridge.ApplyToCurrentThread();
}
}
return oldLoc;
}
+23 -3
View File
@@ -11,8 +11,12 @@
#include <PosixLocaleConv.h>
#ifndef _KERNEL_MODE
#include <locale.h>
#include "LocaleBackend.h"
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
#endif
@@ -20,9 +24,25 @@ extern "C" struct lconv*
localeconv(void)
{
#ifndef _KERNEL_MODE
if (gLocaleBackend)
return const_cast<lconv*>(gLocaleBackend->LocaleConv());
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend != NULL)
return const_cast<lconv*>(backend->LocaleConv());
#endif
return &BPrivate::Libroot::gPosixLocaleConv;
}
#ifndef _KERNEL_MODE
extern "C" struct lconv*
localeconv_l(locale_t l)
{
LocaleBackendData* locale = (LocaleBackendData*)l;
LocaleBackend* backend = locale->backend;
if (backend != NULL)
return const_cast<lconv*>(backend->LocaleConv());
return &BPrivate::Libroot::gPosixLocaleConv;
}
#endif
@@ -11,8 +11,10 @@
#include <PosixLanginfo.h>
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::gPosixLanginfo;
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
extern "C" char*
@@ -21,8 +23,23 @@ nl_langinfo(nl_item item)
if (item < 0 || item >= _NL_LANGINFO_LAST)
return const_cast<char*>("");
if (gLocaleBackend != NULL)
return const_cast<char*>(gLocaleBackend->GetLanginfo(item));
if (GetCurrentLocaleBackend() != NULL)
return const_cast<char*>(GetCurrentLocaleBackend()->GetLanginfo(item));
return const_cast<char*>(gPosixLanginfo[item]);
}
extern "C" char*
nl_langinfo_l(nl_item item, locale_t locale)
{
if (item < 0 || item >= _NL_LANGINFO_LAST)
return const_cast<char*>("");
LocaleBackend* backend = ((LocaleBackendData*)locale)->backend;
if (backend != NULL)
return const_cast<char*>(backend->GetLanginfo(item));
return const_cast<char*>(gPosixLanginfo[item]);
}
+9 -55
View File
@@ -7,65 +7,19 @@
#include <ctype.h>
#include <locale.h>
#include <stdlib.h>
#include <strings.h>
#include <ErrnoMaintainer.h>
#include "LocaleBackend.h"
#include "LocaleInternal.h"
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::gGlobalLocaleBackend;
using BPrivate::Libroot::GetLocalesFromEnvironment;
using BPrivate::Libroot::LocaleBackend;
static status_t
GetLocalesFromEnvironment(int category, const char** locales)
{
const char* locale = getenv("LC_ALL");
if (locale && *locale)
locales[category] = locale;
else {
// the order of the names must match the one specified in locale.h
const char* categoryNames[] = {
"LC_ALL",
"LC_COLLATE",
"LC_CTYPE",
"LC_MONETARY",
"LC_NUMERIC",
"LC_TIME",
"LC_MESSAGES"
};
int from, to;
if (category == LC_ALL) {
// we need to check each real category if all of them should be set
from = 1;
to = LC_LAST;
} else
from = to = category;
bool haveDifferentLocales = false;
locale = NULL;
for (int lc = from; lc <= to; lc++) {
const char* lastLocale = locale;
locale = getenv(categoryNames[lc]);
if (!locale || *locale == '\0')
locale = getenv("LANG");
if (!locale || *locale == '\0')
locale = "POSIX";
locales[lc] = locale;
if (lastLocale && strcasecmp(locale, lastLocale) != 0)
haveDifferentLocales = true;
}
if (!haveDifferentLocales) {
// we can set all locales at once
locales[LC_ALL] = locale;
}
}
return B_OK;
}
extern "C" char*
setlocale(int category, const char* locale)
{
@@ -76,8 +30,8 @@ setlocale(int category, const char* locale)
if (locale == NULL) {
// query the locale of the given category
if (gLocaleBackend != NULL)
return const_cast<char*>(gLocaleBackend->SetLocale(category, NULL));
if (gGlobalLocaleBackend != NULL)
return const_cast<char*>(gGlobalLocaleBackend->SetLocale(category, NULL));
else
return const_cast<char*>("POSIX");
}
@@ -93,7 +47,7 @@ setlocale(int category, const char* locale)
else
locales[category] = locale;
if (!gLocaleBackend) {
if (gGlobalLocaleBackend == NULL) {
// for any locale other than POSIX/C, we try to activate the ICU
// backend
bool needBackend = false;
@@ -108,17 +62,17 @@ setlocale(int category, const char* locale)
return NULL;
}
if (gLocaleBackend != NULL) {
if (gGlobalLocaleBackend != NULL) {
for (int lc = 0; lc <= LC_LAST; lc++) {
if (locales[lc] != NULL) {
locale = gLocaleBackend->SetLocale(lc, locales[lc]);
locale = gGlobalLocaleBackend->SetLocale(lc, locales[lc]);
if (lc == LC_ALL) {
// skip the rest, LC_ALL overrides
return const_cast<char*>(locale);
}
}
}
return const_cast<char*>(gLocaleBackend->SetLocale(category, NULL));
return const_cast<char*>(gGlobalLocaleBackend->SetLocale(category, NULL));
}
return const_cast<char*>("POSIX");
+19 -9
View File
@@ -13,7 +13,9 @@
#include "LocaleBackend.h"
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
/*
* In many of the following functions, we make use of the fact that with
@@ -26,13 +28,15 @@ using BPrivate::Libroot::gLocaleBackend;
int
iswctype(wint_t wc, wctype_t charClass)
{
if (gLocaleBackend == NULL) {
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend == NULL) {
if (wc < 0 || wc > 127)
return 0;
return __isctype(wc, charClass);
}
return gLocaleBackend->IsWCType(wc, charClass);
return backend->IsWCType(wc, charClass);
}
@@ -123,14 +127,16 @@ iswxdigit(wint_t wc)
wint_t
towlower(wint_t wc)
{
if (gLocaleBackend == NULL) {
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend == NULL) {
if (wc < 0 || wc > 127)
return wc;
return tolower(wc);
}
wint_t result = wc;
gLocaleBackend->ToWCTrans(wc, _ISlower, result);
backend->ToWCTrans(wc, _ISlower, result);
return result;
}
@@ -139,14 +145,16 @@ towlower(wint_t wc)
wint_t
towupper(wint_t wc)
{
if (gLocaleBackend == NULL) {
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend == NULL) {
if (wc < 0 || wc > 127)
return wc;
return toupper(wc);
}
wint_t result = wc;
gLocaleBackend->ToWCTrans(wc, _ISupper, result);
backend->ToWCTrans(wc, _ISupper, result);
return result;
}
@@ -155,7 +163,9 @@ towupper(wint_t wc)
wint_t
towctrans(wint_t wc, wctrans_t transition)
{
if (gLocaleBackend == NULL) {
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend == NULL) {
if (transition == _ISlower)
return tolower(wc);
if (transition == _ISupper)
@@ -166,7 +176,7 @@ towctrans(wint_t wc, wctrans_t transition)
}
wint_t result = wc;
status_t status = gLocaleBackend->ToWCTrans(wc, transition, result);
status_t status = backend->ToWCTrans(wc, transition, result);
if (status != B_OK)
__set_errno(EINVAL);
@@ -0,0 +1,236 @@
/*
* Copyright 2022, Trung Nguyen, trungnt282910@gmail.com
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <ctype.h>
#include <errno.h>
#include <locale.h>
#include <string.h>
#include <wctype.h>
#include <errno_private.h>
#include "LocaleBackend.h"
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
int
iswctype_l(wint_t wc, wctype_t charClass, locale_t l)
{
LocaleBackendData* locale = (LocaleBackendData*)l;
LocaleBackend* backend = locale->backend;
if (backend == NULL) {
if (wc < 0 || wc > 127)
return 0;
return __isctype(wc, charClass);
}
return backend->IsWCType(wc, charClass);
}
int
iswalnum_l(wint_t wc, locale_t locale)
{
return iswctype_l(wc, _ISalnum, locale);
}
int
iswalpha_l(wint_t wc, locale_t locale)
{
return iswctype_l(wc, _ISalpha, locale);
}
int
iswblank_l(wint_t wc, locale_t locale)
{
return iswctype_l(wc, _ISblank, locale);
}
int
iswcntrl_l(wint_t wc, locale_t locale)
{
return iswctype_l(wc, _IScntrl, locale);
}
int
iswdigit_l(wint_t wc, locale_t locale)
{
return iswctype_l(wc, _ISdigit, locale);
}
int
iswgraph_l(wint_t wc, locale_t locale)
{
return iswctype_l(wc, _ISgraph, locale);
}
int
iswlower_l(wint_t wc, locale_t locale)
{
return iswctype_l(wc, _ISlower, locale);
}
int
iswprint_l(wint_t wc, locale_t locale)
{
return iswctype_l(wc, _ISprint, locale);
}
int
iswpunct_l(wint_t wc, locale_t locale)
{
return iswctype_l(wc, _ISpunct, locale);
}
int
iswspace_l(wint_t wc, locale_t locale)
{
return iswctype_l(wc, _ISspace, locale);
}
int
iswupper_l(wint_t wc, locale_t locale)
{
return iswctype_l(wc, _ISupper, locale);
}
int
iswxdigit_l(wint_t wc, locale_t locale)
{
return iswctype_l(wc, _ISxdigit, locale);
}
wint_t
towlower_l(wint_t wc, locale_t l)
{
LocaleBackendData* locale = (LocaleBackendData*)l;
LocaleBackend* backend = locale->backend;
if (backend == NULL) {
if (wc < 0 || wc > 127)
return wc;
return tolower(wc);
}
wint_t result = wc;
backend->ToWCTrans(wc, _ISlower, result);
return result;
}
wint_t
towupper_l(wint_t wc, locale_t l)
{
LocaleBackendData* locale = (LocaleBackendData*)l;
LocaleBackend* backend = locale->backend;
if (backend == NULL) {
if (wc < 0 || wc > 127)
return wc;
return toupper(wc);
}
wint_t result = wc;
backend->ToWCTrans(wc, _ISupper, result);
return result;
}
wint_t
towctrans_l(wint_t wc, wctrans_t transition, locale_t l)
{
LocaleBackendData* locale = (LocaleBackendData*)l;
LocaleBackend* backend = locale->backend;
if (backend == NULL) {
if (transition == _ISlower)
return tolower(wc);
if (transition == _ISupper)
return toupper(wc);
__set_errno(EINVAL);
return wc;
}
wint_t result = wc;
status_t status = backend->ToWCTrans(wc, transition, result);
if (status != B_OK)
__set_errno(EINVAL);
return result;
}
wctrans_t
wctrans_l(const char *charClass, locale_t locale)
{
(void)locale;
if (charClass != NULL) {
// we do not know any locale-specific character classes
if (strcmp(charClass, "tolower") == 0)
return _ISlower;
if (strcmp(charClass, "toupper") == 0)
return _ISupper;
}
__set_errno(EINVAL);
return 0;
}
wctype_t
wctype_l(const char *property, locale_t locale)
{
(void)locale;
// currently, we do not support any locale-specific properties
if (strcmp(property, "alnum") == 0)
return _ISalnum;
if (strcmp(property, "alpha") == 0)
return _ISalpha;
if (strcmp(property, "blank") == 0)
return _ISblank;
if (strcmp(property, "cntrl") == 0)
return _IScntrl;
if (strcmp(property, "digit") == 0)
return _ISdigit;
if (strcmp(property, "graph") == 0)
return _ISgraph;
if (strcmp(property, "lower") == 0)
return _ISlower;
if (strcmp(property, "print") == 0)
return _ISprint;
if (strcmp(property, "punct") == 0)
return _ISpunct;
if (strcmp(property, "space") == 0)
return _ISspace;
if (strcmp(property, "upper") == 0)
return _ISupper;
if (strcmp(property, "xdigit") == 0)
return _ISxdigit;
return 0;
}
+35 -21
View File
@@ -89,19 +89,39 @@
} while (0)
static void __setup_vars(int, char *, char *, char *, char **);
static int __calc_left_pad(int, char *);
static char *__format_grouped_double(double, int *, int, int, int);
extern struct lconv* localeconv_l(locale_t);
static ssize_t __strfmon(char*, size_t, struct lconv*, const char*, va_list ap);
static void __setup_vars(int, struct lconv*, char *, char *, char *, char **);
static int __calc_left_pad(int, struct lconv*, char *);
static char *__format_grouped_double(double, struct lconv*, int *, int, int, int);
ssize_t
strfmon(char *s, size_t maxsize, const char *format,
...)
strfmon(char *s, size_t maxsize, const char *format, ...)
{
va_list ap;
struct lconv* lc = localeconv();
va_start(ap, format);
return __strfmon(s, maxsize, lc, format, ap);
}
ssize_t
strfmon_l(char *s, size_t maxsize, locale_t locale, const char *format, ...)
{
va_list ap;
struct lconv* lc = localeconv_l(locale);
va_start(ap, format);
return __strfmon(s, maxsize, lc, format, ap);
}
static ssize_t
__strfmon(char *s, size_t maxsize, struct lconv* lc, const char *format, va_list ap)
{
va_list ap;
char *dst; /* output destination pointer */
const char *fmt; /* current format poistion pointer */
struct lconv *lc; /* pointer to lconv structure */
char *asciivalue; /* formatted double pointer */
int flags; /* formatting options */
@@ -122,9 +142,6 @@ strfmon(char *s, size_t maxsize, const char *format,
char *tmpptr; /* temporary vars */
int sverrno;
va_start(ap, format);
lc = localeconv();
dst = s;
fmt = format;
asciivalue = NULL;
@@ -253,22 +270,22 @@ strfmon(char *s, size_t maxsize, const char *format,
/* fill left_prec with amount of padding chars */
if (left_prec >= 0) {
pad_size = __calc_left_pad((flags ^ IS_NEGATIVE),
currency_symbol) - __calc_left_pad(flags, currency_symbol);
pad_size = __calc_left_pad((flags ^ IS_NEGATIVE), lc,
currency_symbol) - __calc_left_pad(flags, lc, currency_symbol);
if (pad_size < 0)
pad_size = 0;
}
if (asciivalue != NULL)
free(asciivalue);
asciivalue = __format_grouped_double(value, &flags, left_prec,
asciivalue = __format_grouped_double(value, lc, &flags, left_prec,
right_prec, pad_char);
if (asciivalue == NULL)
goto end_error; /* errno already set */
/* to ENOMEM by malloc() */
/* set some variables for later use */
__setup_vars(flags, &cs_precedes, &sep_by_space, &sign_posn, &signstr);
__setup_vars(flags, lc, &cs_precedes, &sep_by_space, &sign_posn, &signstr);
/*
* Description of some LC_MONETARY's values:
@@ -405,11 +422,9 @@ end_error:
static void
__setup_vars(int flags, char *cs_precedes, char *sep_by_space, char *sign_posn,
__setup_vars(int flags, struct lconv* lc, char *cs_precedes, char *sep_by_space, char *sign_posn,
char **signstr)
{
struct lconv *lc = localeconv();
if ((flags & IS_NEGATIVE) && (flags & USE_INTL_CURRENCY)) {
*cs_precedes = lc->int_n_cs_precedes;
*sep_by_space = lc->int_n_sep_by_space;
@@ -443,12 +458,12 @@ __setup_vars(int flags, char *cs_precedes, char *sep_by_space, char *sign_posn,
static int
__calc_left_pad(int flags, char *cur_symb)
__calc_left_pad(int flags, struct lconv* lc, char *cur_symb)
{
char cs_precedes, sep_by_space, sign_posn, *signstr;
int left_chars = 0;
__setup_vars(flags, &cs_precedes, &sep_by_space, &sign_posn, &signstr);
__setup_vars(flags, lc, &cs_precedes, &sep_by_space, &sign_posn, &signstr);
if (cs_precedes != 0) {
left_chars += strlen(cur_symb);
@@ -495,7 +510,7 @@ get_groups(int size, char *grouping)
/* convert double to ASCII */
static char *
__format_grouped_double(double value, int *flags, int left_prec, int right_prec,
__format_grouped_double(double value, struct lconv* lc, int *flags, int left_prec, int right_prec,
int pad_char)
{
char *rslt;
@@ -508,7 +523,6 @@ __format_grouped_double(double value, int *flags, int left_prec, int right_prec,
int padded;
struct lconv *lc = localeconv();
char *grouping;
char decimal_point;
char thousands_sep;
@@ -68,3 +68,35 @@ strncasecmp(const char *s1, const char *s2, size_t n)
return 0;
}
int
strcasecmp_l(const char *s1, const char *s2, locale_t locale)
{
const u_char *us1 = (const u_char *)s1;
const u_char *us2 = (const u_char *)s2;
while (tolower_l(*us1, locale) == tolower_l(*us2++, locale)) {
if (*us1++ == '\0')
return 0;
}
return tolower_l(*us1, locale) - tolower_l(*--us2, locale);
}
int
strncasecmp_l(const char *s1, const char *s2, size_t n, locale_t locale)
{
if (n != 0) {
const u_char *us1 = (const u_char *)s1;
const u_char *us2 = (const u_char *)s2;
do {
if (tolower_l(*us1, locale) != tolower_l(*us2++, locale))
return tolower_l(*us1, locale) - tolower_l(*--us2, locale);
if (*us1++ == '\0')
break;
} while (--n != 0);
}
return 0;
}
+27 -3
View File
@@ -11,15 +11,39 @@
#include "LocaleBackend.h"
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
extern "C" int
strcoll(const char *a, const char *b)
{
if (gLocaleBackend != NULL) {
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend != NULL) {
int result = 0;
status_t status = gLocaleBackend->Strcoll(a, b, result);
status_t status = backend->Strcoll(a, b, result);
if (status != B_OK)
__set_errno(EINVAL);
return result;
}
return strcmp(a, b);
}
extern "C" int
strcoll_l(const char *a, const char *b, locale_t l)
{
LocaleBackendData* locale = (LocaleBackendData*)l;
LocaleBackend* backend = locale->backend;
if (backend != NULL) {
int result = 0;
status_t status = backend->Strcoll(a, b, result);
if (status != B_OK)
__set_errno(EINVAL);
@@ -583,3 +583,11 @@ strerror_r(int error, char *buffer, size_t bufferSize)
// TODO: could return ERANGE if buffer is too small
}
char *
strerror_l(int error, locale_t locale)
{
// Don't have error messages in other locales yet.
(void)locale;
return strerror(error);
}
+27 -3
View File
@@ -11,15 +11,39 @@
#include "LocaleBackend.h"
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
extern "C" size_t
strxfrm(char *out, const char *in, size_t size)
{
if (gLocaleBackend != NULL) {
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend != NULL) {
size_t outSize = 0;
status_t status = gLocaleBackend->Strxfrm(out, in, size, outSize);
status_t status = backend->Strxfrm(out, in, size, outSize);
if (status != B_OK)
__set_errno(EINVAL);
return outSize;
}
return strlcpy(out, in, size);
}
extern "C" size_t
strxfrm_l(char *out, const char *in, size_t size, locale_t l)
{
LocaleBackendData* locale = (LocaleBackendData*)l;
LocaleBackend* backend = locale->backend;
if (backend != NULL) {
size_t outSize = 0;
status_t status = backend->Strxfrm(out, in, size, outSize);
if (status != B_OK)
__set_errno(EINVAL);
+23 -11
View File
@@ -17,7 +17,7 @@
#include "LocaleBackend.h"
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
@@ -43,13 +43,13 @@ extern "C" time_t __timegm_fallback(struct tm* tmp);
extern "C" void
tzset(void)
{
if (gLocaleBackend == NULL && LocaleBackend::LoadBackend() != B_OK)
if (GetCurrentLocaleBackend() == NULL && LocaleBackend::LoadBackend() != B_OK)
return;
char timeZoneID[B_FILE_NAME_LENGTH] = { "GMT" };
_kern_get_timezone(NULL, timeZoneID, sizeof(timeZoneID));
gLocaleBackend->TZSet(timeZoneID, getenv("TZ"));
GetCurrentLocaleBackend()->TZSet(timeZoneID, getenv("TZ"));
}
@@ -71,8 +71,11 @@ localtime_r(const time_t* inTime, struct tm* tmOut)
}
tzset();
if (gLocaleBackend != NULL) {
status_t status = gLocaleBackend->Localtime(inTime, tmOut);
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend != NULL) {
status_t status = backend->Localtime(inTime, tmOut);
if (status != B_OK)
__set_errno(EOVERFLOW);
@@ -104,8 +107,11 @@ gmtime_r(const time_t* inTime, struct tm* tmOut)
}
tzset();
if (gLocaleBackend != NULL) {
status_t status = gLocaleBackend->Gmtime(inTime, tmOut);
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend != NULL) {
status_t status = backend->Gmtime(inTime, tmOut);
if (status != B_OK)
__set_errno(EOVERFLOW);
@@ -128,9 +134,12 @@ mktime(struct tm* inTm)
}
tzset();
if (gLocaleBackend != NULL) {
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend != NULL) {
time_t timeOut;
status_t status = gLocaleBackend->Mktime(inTm, timeOut);
status_t status = backend->Mktime(inTm, timeOut);
if (status != B_OK) {
__set_errno(EOVERFLOW);
@@ -154,9 +163,12 @@ timegm(struct tm* inTm)
return -1;
}
tzset();
if (gLocaleBackend != NULL) {
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend != NULL) {
time_t timeOut;
status_t status = gLocaleBackend->Timegm(inTm, timeOut);
status_t status = backend->Timegm(inTm, timeOut);
if (status != B_OK) {
__set_errno(EOVERFLOW);
+31 -16
View File
@@ -38,13 +38,13 @@ static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89";
#include "locale.h"
#include "timelocal.h"
#define Locale __get_current_time_locale()
static char * _add P((const char *, char *, const char *));
static char * _conv P((int, const char *, char *, const char *));
static char * _fmt P((const char *, const struct tm *, char *, const char *,
int *));
int *, const struct lc_time_t*));
static char * _yconv P((int, int, int, int, char *, const char *));
static size_t __strftime(char * const, const size_t, const char * const,
const struct tm * const, const struct lc_time_t*);
extern char * tzname[];
@@ -60,18 +60,32 @@ extern char * tzname[];
#define NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
size_t
strftime(s, maxsize, format, t)
strftime(char* const s, const size_t maxsize, const char* const format, const struct tm* const t)
{
return __strftime(s, maxsize, format, t, __get_current_time_locale());
}
size_t
strftime_l(char* const s, const size_t maxsize, const char* const format, const struct tm* const t,
locale_t locale)
{
return __strftime(s, maxsize, format, t, __get_time_locale(locale));
}
static size_t
__strftime(s, maxsize, format, t, locale)
char * const s;
const size_t maxsize;
const char * const format;
const struct tm * const t;
const struct lc_time_t* locale;
{
char * p;
int warn;
tzset();
warn = IN_NONE;
p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn);
p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, locale);
#ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
(void) fprintf(stderr, "\n");
@@ -95,12 +109,13 @@ const struct tm * const t;
}
static char *
_fmt(format, t, pt, ptlim, warnp)
_fmt(format, t, pt, ptlim, warnp, Locale)
const char * format;
const struct tm * const t;
char * pt;
const char * const ptlim;
int * warnp;
const struct lc_time_t* Locale;
{
for ( ; *format; ++format) {
if (*format == '%') {
@@ -152,13 +167,13 @@ label:
{
int warn2 = IN_SOME;
pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp);
pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp, Locale);
if (warn2 > *warnp)
*warnp = warn2;
}
continue;
case 'D':
pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, Locale);
continue;
case 'd':
pt = _conv(t->tm_mday, "%02d", pt, ptlim);
@@ -179,7 +194,7 @@ label:
pt = _conv(t->tm_mday, "%2d", pt, ptlim);
continue;
case 'F':
pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, Locale);
continue;
case 'H':
pt = _conv(t->tm_hour, "%02d", pt, ptlim);
@@ -243,10 +258,10 @@ label:
pt, ptlim);
continue;
case 'R':
pt = _fmt("%H:%M", t, pt, ptlim, warnp);
pt = _fmt("%H:%M", t, pt, ptlim, warnp, Locale);
continue;
case 'r':
pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp);
pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp, Locale);
continue;
case 'S':
pt = _conv(t->tm_sec, "%02d", pt, ptlim);
@@ -269,7 +284,7 @@ label:
}
continue;
case 'T':
pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, Locale);
continue;
case 't':
pt = _add("\t", pt, ptlim);
@@ -384,7 +399,7 @@ label:
** "date as dd-bbb-YYYY"
** (ado, 1993-05-24)
*/
pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, Locale);
continue;
case 'W':
pt = _conv((t->tm_yday + DAYSPERWEEK -
@@ -397,13 +412,13 @@ label:
pt = _conv(t->tm_wday, "%d", pt, ptlim);
continue;
case 'X':
pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp);
pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp, Locale);
continue;
case 'x':
{
int warn2 = IN_SOME;
pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2);
pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2, Locale);
if (warn2 == IN_ALL)
warn2 = IN_THIS;
if (warn2 > *warnp)
@@ -489,7 +504,7 @@ label:
continue;
case '+':
pt = _fmt(Locale->date_fmt, t, pt, ptlim,
warnp);
warnp, Locale);
continue;
case '%':
/*
+18 -3
View File
@@ -12,14 +12,29 @@
#include "PosixLCTimeInfo.h"
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
extern "C" const lc_time_t*
__get_current_time_locale(void)
{
if (gLocaleBackend)
return gLocaleBackend->LCTimeInfo();
if (GetCurrentLocaleBackend() != NULL)
return GetCurrentLocaleBackend()->LCTimeInfo();
return &BPrivate::Libroot::gPosixLCTimeInfo;
}
extern "C" const lc_time_t*
__get_time_locale(locale_t l)
{
LocaleBackendData* locale = (LocaleBackendData*)l;
LocaleBackend* backend = locale->backend;
if (backend != NULL)
return backend->LCTimeInfo();
return &BPrivate::Libroot::gPosixLCTimeInfo;
}
+6 -4
View File
@@ -20,7 +20,8 @@
#endif
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
extern "C" size_t
@@ -34,7 +35,9 @@ __mbrtowc(wchar_t* pwc, const char* s, size_t n, mbstate_t* ps)
if (s == NULL)
return __mbrtowc(NULL, "", 1, ps);
if (gLocaleBackend == NULL) {
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend == NULL) {
if (*s == '\0') {
memset(ps, 0, sizeof(mbstate_t));
@@ -63,8 +66,7 @@ __mbrtowc(wchar_t* pwc, const char* s, size_t n, mbstate_t* ps)
}
size_t lengthUsed;
status_t status
= gLocaleBackend->MultibyteToWchar(pwc, s, n, ps, lengthUsed);
status_t status = backend->MultibyteToWchar(pwc, s, n, ps, lengthUsed);
if (status == B_BAD_INDEX)
return (size_t)-2;
+9 -5
View File
@@ -20,22 +20,25 @@
#endif
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
extern "C" size_t
__mbsnrtowcs(wchar_t* dst, const char** src, size_t nmc, size_t len,
mbstate_t* ps)
{
LocaleBackend* backend = GetCurrentLocaleBackend();
TRACE(("mbsnrtowcs(%p, %p, %lu, %lu) - lb:%p\n", dst, *src, nmc, len,
gLocaleBackend));
backend));
if (ps == NULL) {
static mbstate_t internalMbState;
ps = &internalMbState;
}
if (gLocaleBackend == NULL) {
if (backend == NULL) {
/*
* The POSIX locale is active. Since the POSIX locale only contains
* chars 0-127 and those ASCII chars are compatible with the UTF32
@@ -82,7 +85,7 @@ __mbsnrtowcs(wchar_t* dst, const char** src, size_t nmc, size_t len,
}
size_t result = 0;
status_t status = gLocaleBackend->MultibyteStringToWchar(dst, len, src, nmc,
status_t status = backend->MultibyteStringToWchar(dst, len, src, nmc,
ps, result);
if (status == B_BAD_DATA) {
@@ -112,7 +115,8 @@ __mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps)
ps = &internalMbState;
}
size_t srcLen = gLocaleBackend == NULL ? strlen(*src) + 1 : (size_t)-1;
LocaleBackend* backend = GetCurrentLocaleBackend();
size_t srcLen = backend == NULL ? strlen(*src) + 1 : (size_t)-1;
return __mbsnrtowcs(dst, src, srcLen, len, ps);
}
+6 -3
View File
@@ -20,12 +20,15 @@
#endif
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
extern "C" size_t
__wcrtomb(char* s, wchar_t wc, mbstate_t* ps)
{
LocaleBackend* backend = GetCurrentLocaleBackend();
if (ps == NULL) {
static mbstate_t internalMbState;
ps = &internalMbState;
@@ -34,7 +37,7 @@ __wcrtomb(char* s, wchar_t wc, mbstate_t* ps)
if (s == NULL)
wc = 0;
if (gLocaleBackend == NULL) {
if (backend == NULL) {
/*
* The POSIX locale is active. Since the POSIX locale only contains
* chars 0-127 and those ASCII chars are compatible with the UTF32
@@ -54,7 +57,7 @@ __wcrtomb(char* s, wchar_t wc, mbstate_t* ps)
}
size_t lengthUsed;
status_t status = gLocaleBackend->WcharToMultibyte(s, wc, ps, lengthUsed);
status_t status = backend->WcharToMultibyte(s, wc, ps, lengthUsed);
if (status == B_BAD_INDEX)
return (size_t)-2;
@@ -27,3 +27,22 @@ __wcscasecmp(const wchar_t* wcs1, const wchar_t* wcs2)
B_DEFINE_WEAK_ALIAS(__wcscasecmp, wcscasecmp);
int
__wcscasecmp_l(const wchar_t* wcs1, const wchar_t* wcs2, locale_t locale)
{
int cmp;
for (;;) {
cmp = towlower_l(*wcs1, locale) - towlower_l(*wcs2++, locale);
if (cmp != 0 || *wcs1++ == L'\0')
break;
}
return cmp;
}
B_DEFINE_WEAK_ALIAS(__wcscasecmp_l, wcscasecmp_l);
+30 -3
View File
@@ -8,15 +8,19 @@
#include <wchar_private.h>
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
extern "C" int
__wcscoll(const wchar_t* wcs1, const wchar_t* wcs2)
{
if (gLocaleBackend != NULL) {
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend != NULL) {
int result = 0;
status_t status = gLocaleBackend->Wcscoll(wcs1, wcs2, result);
status_t status = backend->Wcscoll(wcs1, wcs2, result);
if (status != B_OK)
__set_errno(EINVAL);
@@ -29,3 +33,26 @@ __wcscoll(const wchar_t* wcs1, const wchar_t* wcs2)
B_DEFINE_WEAK_ALIAS(__wcscoll, wcscoll);
extern "C" int
__wcscoll_l(const wchar_t* wcs1, const wchar_t* wcs2, locale_t l)
{
LocaleBackendData* locale = (LocaleBackendData*)l;
LocaleBackend* backend = locale->backend;
if (backend != NULL) {
int result = 0;
status_t status = backend->Wcscoll(wcs1, wcs2, result);
if (status != B_OK)
__set_errno(EINVAL);
return result;
}
return wcscmp(wcs1, wcs2);
}
B_DEFINE_WEAK_ALIAS(__wcscoll_l, wcscoll_l);
@@ -27,3 +27,24 @@ __wcsncasecmp(const wchar_t* wcs1, const wchar_t* wcs2, size_t count)
B_DEFINE_WEAK_ALIAS(__wcsncasecmp, wcsncasecmp);
int
__wcsncasecmp_l(const wchar_t* wcs1, const wchar_t* wcs2, size_t count, locale_t locale)
{
int cmp = 0;
while (count-- > 0) {
cmp = towlower_l(*wcs1, locale) - towlower_l(*wcs2++, locale);
/* note: won't overflow, since our wchar_t is guaranteed to never
have the highest bit set */
if (cmp != 0 || *wcs1++ == L'\0')
break;
}
return cmp;
}
B_DEFINE_WEAK_ALIAS(__wcsncasecmp_l, wcsncasecmp_l);
+7 -4
View File
@@ -21,22 +21,25 @@
#endif
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
extern "C" size_t
__wcsnrtombs(char* dst, const wchar_t** src, size_t nwc, size_t len,
mbstate_t* ps)
{
LocaleBackend* backend = GetCurrentLocaleBackend();
TRACE(("wcsnrtombs(%p, %p, %lu, %lu) - lb:%p\n", dst, *src, nwc, len,
gLocaleBackend));
backend));
if (ps == NULL) {
static mbstate_t internalMbState;
ps = &internalMbState;
}
if (gLocaleBackend == NULL) {
if (backend == NULL) {
/*
* The POSIX locale is active. Since the POSIX locale only contains
* chars 0-127 and those ASCII chars are compatible with the UTF32
@@ -83,7 +86,7 @@ __wcsnrtombs(char* dst, const wchar_t** src, size_t nwc, size_t len,
}
size_t result = 0;
status_t status = gLocaleBackend->WcharStringToMultibyte(dst, len, src, nwc,
status_t status = backend->WcharStringToMultibyte(dst, len, src, nwc,
ps, result);
if (status == B_BAD_DATA) {
+30 -3
View File
@@ -10,15 +10,19 @@
#include <wchar_private.h>
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
extern "C" size_t
__wcsxfrm(wchar_t* dest, const wchar_t* src, size_t destSize)
{
if (gLocaleBackend != NULL) {
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend != NULL) {
size_t outSize = 0;
status_t status = gLocaleBackend->Wcsxfrm(dest, src, destSize, outSize);
status_t status = backend->Wcsxfrm(dest, src, destSize, outSize);
if (status != B_OK)
__set_errno(EINVAL);
@@ -31,3 +35,26 @@ __wcsxfrm(wchar_t* dest, const wchar_t* src, size_t destSize)
B_DEFINE_WEAK_ALIAS(__wcsxfrm, wcsxfrm);
extern "C" size_t
__wcsxfrm_l(wchar_t* dest, const wchar_t* src, size_t destSize, locale_t l)
{
LocaleBackendData* locale = (LocaleBackendData*)l;
LocaleBackend* backend = locale->backend;
if (backend != NULL) {
size_t outSize = 0;
status_t status = backend->Wcsxfrm(dest, src, destSize, outSize);
if (status != B_OK)
__set_errno(EINVAL);
return outSize;
}
return wcslcpy(dest, src, destSize);
}
B_DEFINE_WEAK_ALIAS(__wcsxfrm_l, wcsxfrm_l);
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1
View File
@@ -51,6 +51,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
<src!system!libroot!posix!$(architecture)>fcntl.o
<src!system!libroot!posix!locale!$(architecture)>ctype.o
<src!system!libroot!posix!locale!$(architecture)>ctype_loc.o
<src!system!libroot!posix!locale!$(architecture)>LocaleData.o
<src!system!libroot!posix!string!$(architecture)>memchr.o