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 #define _CTYPE_H
#include <locale_t.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -27,6 +30,22 @@ int toascii(int);
int tolower(int); int tolower(int);
int toupper(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 { enum {
_ISblank = 0x0001, /* blank */ _ISblank = 0x0001, /* blank */
_IScntrl = 0x0002, /* control */ _IScntrl = 0x0002, /* control */
@@ -48,14 +67,19 @@ extern const unsigned short int *__ctype_b;
extern const int *__ctype_tolower; extern const int *__ctype_tolower;
extern const int *__ctype_toupper; 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) \ #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 isascii(c) (((c) & ~0x7f) == 0) /* ASCII characters have bit 8 cleared */
#define toascii(c) ((c) & 0x7f) /* Clear higher bits */ #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 _tolower(c) tolower(c)
#define _toupper(c) toupper(c) #define _toupper(c) toupper(c)
+1
View File
@@ -145,6 +145,7 @@ enum {
__BEGIN_DECLS __BEGIN_DECLS
extern char* nl_langinfo(nl_item item); extern char* nl_langinfo(nl_item item);
extern char* nl_langinfo_l(nl_item item, locale_t locale);
__END_DECLS __END_DECLS
+19
View File
@@ -6,6 +6,7 @@
#define _LOCALE_H_ #define _LOCALE_H_
#include <locale_t.h>
#include <null.h> #include <null.h>
struct lconv { struct lconv {
@@ -48,6 +49,19 @@ struct lconv {
*/ */
#define LC_LAST LC_MESSAGES #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 #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -55,6 +69,11 @@ extern "C" {
extern struct lconv *localeconv(void); extern struct lconv *localeconv(void);
extern char *setlocale(int category, const char *locale); 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 #ifdef __cplusplus
} }
#endif #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_ #define _MONETARY_H_
#include <locale.h> #include <locale_t.h>
#include <stddef.h> #include <stddef.h>
#include <sys/cdefs.h> #include <sys/cdefs.h>
#include <sys/types.h> #include <sys/types.h>
@@ -15,6 +15,7 @@
__BEGIN_DECLS __BEGIN_DECLS
extern ssize_t strfmon(char* s, size_t maxsize, const char* format, ...); 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 __END_DECLS
+6
View File
@@ -6,6 +6,7 @@
#define _STRING_H_ #define _STRING_H_
#include <locale_t.h>
#include <sys/types.h> #include <sys/types.h>
@@ -74,6 +75,11 @@ extern char *strupr(char *string);
extern const char *strsignal(int signum); 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 */ /* for compatibility, pull in functions declared in strings.h */
#include <strings.h> #include <strings.h>
+5
View File
@@ -6,6 +6,7 @@
#define _STRINGS_H_ #define _STRINGS_H_
#include <locale_t.h>
#include <sys/types.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, extern int strncasecmp(const char *string1, const char *string2,
size_t length); 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 */ /* legacy compatibility -- might be removed one day */
#define bcmp(a, b, length) memcmp((a), (b), (length)) #define bcmp(a, b, length) memcmp((a), (b), (length))
#define bcopy(source, dest, length) memmove((dest), (source), (length)) #define bcopy(source, dest, length) memmove((dest), (source), (length))
+3
View File
@@ -6,6 +6,7 @@
#define _TIME_H_ #define _TIME_H_
#include <locale_t.h>
#include <sys/types.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 int nanosleep(const struct timespec *, struct timespec *);
extern size_t strftime(char *buffer, size_t maxSize, const char *format, extern size_t strftime(char *buffer, size_t maxSize, const char *format,
const struct tm *tm); 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); extern char *strptime(const char *buf, const char *format, struct tm *tm);
/* clock functions */ /* clock functions */
+7
View File
@@ -7,6 +7,7 @@
#include <limits.h> #include <limits.h>
#include <locale.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <time.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 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 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(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 *wcscat(wchar_t *dest, const wchar_t *src);
extern wchar_t *wcschr(const wchar_t *wcs, wchar_t wc); extern wchar_t *wcschr(const wchar_t *wcs, wchar_t wc);
#ifdef _GNU_SOURCE #ifdef _GNU_SOURCE
@@ -100,6 +102,7 @@ extern wchar_t *wcschrnul(const wchar_t *wcs, wchar_t wc);
#endif #endif
extern int wcscmp(const wchar_t *wcs1, const wchar_t *wcs2); 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(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 wchar_t *wcscpy(wchar_t *dest, const wchar_t *src);
extern size_t wcscspn(const wchar_t *wcs, const wchar_t *reject); extern size_t wcscspn(const wchar_t *wcs, const wchar_t *reject);
extern wchar_t *wcsdup(const wchar_t *wcs); 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 size_t wcslen(const wchar_t *wcs);
extern int wcsncasecmp(const wchar_t *wcs1, const wchar_t *wcs2, extern int wcsncasecmp(const wchar_t *wcs1, const wchar_t *wcs2,
size_t maxLength); 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 wchar_t *wcsncat(wchar_t *dest, const wchar_t *src, size_t srcLength);
extern int wcsncmp(const wchar_t *wcs1, const wchar_t *wcs2, extern int wcsncmp(const wchar_t *wcs1, const wchar_t *wcs2,
size_t length); 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 wchar_t *wcswcs(const wchar_t *haystack, const wchar_t *needle);
extern int wcswidth(const wchar_t *wcs, size_t length); 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(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 wctob(wint_t wc);
extern int wcwidth(wchar_t wc); extern int wcwidth(wchar_t wc);
extern wchar_t *wmemchr(const wchar_t *wcs, wchar_t wc, size_t n); extern wchar_t *wmemchr(const wchar_t *wcs, wchar_t wc, size_t n);
+24
View File
@@ -6,6 +6,7 @@
#define _WCTYPE_H_ #define _WCTYPE_H_
#include <locale.h>
#include <wchar.h> #include <wchar.h>
typedef int wctrans_t; typedef int wctrans_t;
@@ -36,6 +37,29 @@ extern wint_t towupper(wint_t wc);
extern wctrans_t wctrans(const char *charClass); extern wctrans_t wctrans(const char *charClass);
extern wctype_t wctype(const char *property); 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 #ifdef __cplusplus
} }
#endif #endif
+53 -15
View File
@@ -8,11 +8,11 @@
#include <SupportDefs.h> #include <SupportDefs.h>
#include <locale.h>
#include <time.h> #include <time.h>
#include <wctype.h> #include <wctype.h>
struct lconv;
struct lc_time_t; struct lc_time_t;
struct locale_data; // glibc struct locale_data; // glibc
@@ -22,29 +22,38 @@ namespace Libroot {
struct LocaleCtypeDataBridge { struct LocaleCtypeDataBridge {
private:
const unsigned short* localClassInfoTable;
const int* localToLowerTable;
const int* localToUpperTable;
public:
const unsigned short** addrOfClassInfoTable; const unsigned short** addrOfClassInfoTable;
const int** addrOfToLowerTable; const int** addrOfToLowerTable;
const int** addrOfToUpperTable; const int** addrOfToUpperTable;
const unsigned short* posixClassInfo; const unsigned short* const posixClassInfo;
const int* posixToLowerMap; const int* const posixToLowerMap;
const int* posixToUpperMap; const int* const posixToUpperMap;
LocaleCtypeDataBridge(); bool isGlobal;
LocaleCtypeDataBridge(bool isGlobal);
void setMbCurMax(unsigned short mbCurMax); void setMbCurMax(unsigned short mbCurMax);
void ApplyToCurrentThread();
}; };
struct LocaleMessagesDataBridge { struct LocaleMessagesDataBridge {
const char** posixLanginfo; const char** const posixLanginfo;
LocaleMessagesDataBridge(); LocaleMessagesDataBridge();
}; };
struct LocaleMonetaryDataBridge { struct LocaleMonetaryDataBridge {
const struct lconv* posixLocaleConv; const struct lconv* const posixLocaleConv;
LocaleMonetaryDataBridge(); LocaleMonetaryDataBridge();
}; };
@@ -71,29 +80,42 @@ private:
values[6]; values[6];
}; };
locale_data* originalGlibcLocale; locale_data* originalGlibcLocale;
GlibcNumericLocale glibcNumericLocaleData;
public: public:
const struct lconv* posixLocaleConv; const struct lconv* const posixLocaleConv;
GlibcNumericLocale glibcNumericLocale; GlibcNumericLocale* glibcNumericLocale;
bool isGlobal;
LocaleNumericDataBridge(); LocaleNumericDataBridge(bool isGlobal);
~LocaleNumericDataBridge(); ~LocaleNumericDataBridge();
void ApplyToCurrentThread();
}; };
struct LocaleTimeDataBridge { struct LocaleTimeDataBridge {
const struct lc_time_t* posixLCTimeInfo; const struct lc_time_t* const posixLCTimeInfo;
LocaleTimeDataBridge(); LocaleTimeDataBridge();
}; };
struct TimeConversionDataBridge { struct TimeConversionDataBridge {
private:
int localDaylight;
long localTimezone;
char* localTZName[2];
char localTZName0[64];
char localTZName1[64];
public:
int* addrOfDaylight; int* addrOfDaylight;
long* addrOfTimezone; long* addrOfTimezone;
char** addrOfTZName; char** addrOfTZName;
bool isGlobal;
TimeConversionDataBridge(); TimeConversionDataBridge(bool isGlobal);
}; };
@@ -104,9 +126,12 @@ struct LocaleDataBridge {
LocaleNumericDataBridge numericDataBridge; LocaleNumericDataBridge numericDataBridge;
LocaleTimeDataBridge timeDataBridge; LocaleTimeDataBridge timeDataBridge;
TimeConversionDataBridge timeConversionDataBridge; 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; virtual void Initialize(LocaleDataBridge* dataBridge) = 0;
static status_t LoadBackend(); 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 Libroot
} // namespace BPrivate } // namespace BPrivate
@@ -0,0 +1,60 @@
/*
* Copyright 2022, Trung Nguyen, [email protected]
* 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_ #define _TIMELOCAL_H_
#include <locale.h>
#include <sys/cdefs.h> #include <sys/cdefs.h>
@@ -54,6 +55,7 @@ struct lc_time_t {
__BEGIN_DECLS __BEGIN_DECLS
const struct lc_time_t* __get_current_time_locale(void); const struct lc_time_t* __get_current_time_locale(void);
const struct lc_time_t* __get_time_locale(locale_t);
__END_DECLS __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 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 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(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 *__wcscat(wchar_t *dest, const wchar_t *src);
extern wchar_t *__wcschr(const wchar_t *wcs, wchar_t wc); extern wchar_t *__wcschr(const wchar_t *wcs, wchar_t wc);
extern wchar_t *__wcschrnul(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 __wcscmp(const wchar_t *wcs1, const wchar_t *wcs2);
extern int __wcscoll(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 wchar_t *__wcscpy(wchar_t *dest, const wchar_t *src);
extern size_t __wcscspn(const wchar_t *wcs, const wchar_t *reject); extern size_t __wcscspn(const wchar_t *wcs, const wchar_t *reject);
extern wchar_t *__wcsdup(const wchar_t *wcs); 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 size_t __wcslen(const wchar_t *wcs);
extern int __wcsncasecmp(const wchar_t *wcs1, const wchar_t *wcs2, extern int __wcsncasecmp(const wchar_t *wcs1, const wchar_t *wcs2,
size_t maxLength); 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 wchar_t *__wcsncat(wchar_t *dest, const wchar_t *src, size_t srcLength);
extern int __wcsncmp(const wchar_t *wcs1, const wchar_t *wcs2, extern int __wcsncmp(const wchar_t *wcs1, const wchar_t *wcs2,
size_t length); 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 wchar_t *__wcswcs(const wchar_t *haystack, const wchar_t *needle);
extern int __wcswidth(const wchar_t *wcs, size_t length); 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(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 __wctob(wint_t wc);
extern int __wcwidth(wchar_t wc); extern int __wcwidth(wchar_t wc);
extern wchar_t *__wmemchr(const wchar_t *wcs, wchar_t wc, size_t n); 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_ON_EXIT_THREAD_SLOT,
TLS_USER_THREAD_SLOT, TLS_USER_THREAD_SLOT,
TLS_DYNAMIC_THREAD_VECTOR, TLS_DYNAMIC_THREAD_VECTOR,
TLS_LOCALE_SLOT,
// Note: these entries can safely be changed between // Note: these entries can safely be changed between
// releases; 3rd party code always calls tls_allocate() // 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 ] ; = [ FDirName $(HAIKU_TOP) src system libroot posix glibc ] ;
SYSHDRS = SYSHDRS =
$(SUBDIR) $(SUBDIR)
[ FDirName $(glibcDir) ctype ]
[ FDirName $(glibcDir) libio ] [ FDirName $(glibcDir) libio ]
[ FDirName $(glibcDir) locale ]
[ FDirName $(glibcDir) stdlib ] [ FDirName $(glibcDir) stdlib ]
[ FDirName $(glibcDir) stdio-common ] [ FDirName $(glibcDir) stdio-common ]
[ FDirName $(glibcDir) include ] [ FDirName $(glibcDir) include ]
+2
View File
@@ -306,6 +306,8 @@ for platform in [ MultiBootSubDirSetup ] {
BootMergeObject boot_libroot_$(platform:G=).o : BootMergeObject boot_libroot_$(platform:G=).o :
abs.c abs.c
ctype_loc.cpp
ctype_l.cpp
ctype.cpp ctype.cpp
LocaleData.cpp LocaleData.cpp
qsort.c qsort.c
+2
View File
@@ -64,6 +64,8 @@ KernelMergeObject kernel_lib_posix.o :
poll.cpp poll.cpp
utime.c utime.c
# locale # locale
ctype_loc.cpp
ctype_l.cpp
ctype.cpp ctype.cpp
localeconv.cpp localeconv.cpp
LocaleData.cpp LocaleData.cpp
@@ -30,6 +30,13 @@ CreateInstance()
} }
extern "C" void
DestroyInstance(LocaleBackend* instance)
{
delete instance;
}
ICULocaleBackend::ICULocaleBackend() ICULocaleBackend::ICULocaleBackend()
: :
fThreadLocalStorageKey(_CreateThreadLocalStorageKey()), fThreadLocalStorageKey(_CreateThreadLocalStorageKey()),
@@ -34,9 +34,9 @@ ICUNumericData::ICUNumericData(pthread_key_t tlsKey, struct lconv& localeConv)
void void
ICUNumericData::Initialize(LocaleNumericDataBridge* dataBridge) ICUNumericData::Initialize(LocaleNumericDataBridge* dataBridge)
{ {
dataBridge->glibcNumericLocale.values[0].string = fDecimalPoint; dataBridge->glibcNumericLocale->values[0].string = fDecimalPoint;
dataBridge->glibcNumericLocale.values[1].string = fThousandsSep; dataBridge->glibcNumericLocale->values[1].string = fThousandsSep;
dataBridge->glibcNumericLocale.values[2].string = fGrouping; dataBridge->glibcNumericLocale->values[2].string = fGrouping;
fDataBridge = dataBridge; fDataBridge = dataBridge;
} }
@@ -62,13 +62,13 @@ ICUNumericData::SetTo(const Locale& locale, const char* posixLocaleName)
if (result == B_OK) { if (result == B_OK) {
result = _SetLocaleconvEntry(formatSymbols, fDecimalPoint, result = _SetLocaleconvEntry(formatSymbols, fDecimalPoint,
DecimalFormatSymbols::kDecimalSeparatorSymbol); DecimalFormatSymbols::kDecimalSeparatorSymbol);
fDataBridge->glibcNumericLocale.values[3].word fDataBridge->glibcNumericLocale->values[3].word
= (unsigned int)fDecimalPoint[0]; = (unsigned int)fDecimalPoint[0];
} }
if (result == B_OK) { if (result == B_OK) {
result = _SetLocaleconvEntry(formatSymbols, fThousandsSep, result = _SetLocaleconvEntry(formatSymbols, fThousandsSep,
DecimalFormatSymbols::kGroupingSeparatorSymbol); DecimalFormatSymbols::kGroupingSeparatorSymbol);
fDataBridge->glibcNumericLocale.values[4].word fDataBridge->glibcNumericLocale->values[4].word
= (unsigned int)fThousandsSep[0]; = (unsigned int)fThousandsSep[0];
} }
if (result == B_OK) { if (result == B_OK) {
@@ -104,9 +104,9 @@ ICUNumericData::SetToPosix()
strcpy(fDecimalPoint, fDataBridge->posixLocaleConv->decimal_point); strcpy(fDecimalPoint, fDataBridge->posixLocaleConv->decimal_point);
strcpy(fThousandsSep, fDataBridge->posixLocaleConv->thousands_sep); strcpy(fThousandsSep, fDataBridge->posixLocaleConv->thousands_sep);
strcpy(fGrouping, fDataBridge->posixLocaleConv->grouping); strcpy(fGrouping, fDataBridge->posixLocaleConv->grouping);
fDataBridge->glibcNumericLocale.values[3].word fDataBridge->glibcNumericLocale->values[3].word
= (unsigned int)fDecimalPoint[0]; = (unsigned int)fDecimalPoint[0];
fDataBridge->glibcNumericLocale.values[4].word fDataBridge->glibcNumericLocale->values[4].word
= (unsigned int)fThousandsSep[0]; = (unsigned int)fThousandsSep[0];
} }
@@ -47,6 +47,7 @@ status_t
ICUTimeConversion::TZSet(const char* timeZoneID, const char* tz) ICUTimeConversion::TZSet(const char* timeZoneID, const char* tz)
{ {
bool offsetHasBeenSet = false; bool offsetHasBeenSet = false;
bool timeZoneIdMatches = false;
// The given TZ environment variable's content overrides the default // The given TZ environment variable's content overrides the default
// system timezone. // system timezone.
@@ -55,8 +56,10 @@ ICUTimeConversion::TZSet(const char* timeZoneID, const char* tz)
// value is implementation specific, we expect a full timezone ID. // value is implementation specific, we expect a full timezone ID.
if (*tz == ':') { if (*tz == ':') {
// nothing to do if the given name matches the current timezone // nothing to do if the given name matches the current timezone
if (strcasecmp(fTimeZoneID, tz + 1) == 0) if (strcasecmp(fTimeZoneID, tz + 1) == 0) {
return B_OK; timeZoneIdMatches = true;
goto done;
}
strlcpy(fTimeZoneID, tz + 1, sizeof(fTimeZoneID)); strlcpy(fTimeZoneID, tz + 1, sizeof(fTimeZoneID));
} else { } else {
@@ -64,8 +67,10 @@ ICUTimeConversion::TZSet(const char* timeZoneID, const char* tz)
strlcpy(fTimeZoneID, tz, sizeof(fTimeZoneID)); strlcpy(fTimeZoneID, tz, sizeof(fTimeZoneID));
// nothing to do if the given name matches the current timezone // nothing to do if the given name matches the current timezone
if (strcasecmp(fTimeZoneID, fDataBridge->addrOfTZName[0]) == 0) if (strcasecmp(fTimeZoneID, fDataBridge->addrOfTZName[0]) == 0) {
return B_OK; timeZoneIdMatches = true;
goto done;
}
// parse TZ variable (only <std> and <offset> supported) // parse TZ variable (only <std> and <offset> supported)
const char* tzNameEnd = tz; const char* tzNameEnd = tz;
@@ -88,12 +93,21 @@ ICUTimeConversion::TZSet(const char* timeZoneID, const char* tz)
} }
} else { } else {
// nothing to do if the given name matches the current timezone // nothing to do if the given name matches the current timezone
if (strcasecmp(fTimeZoneID, timeZoneID) == 0) if (strcasecmp(fTimeZoneID, timeZoneID) == 0) {
return B_OK; timeZoneIdMatches = true;
goto done;
}
strlcpy(fTimeZoneID, timeZoneID, sizeof(fTimeZoneID)); 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; delete fTimeZone;
fTimeZone = TimeZone::createTimeZone(fTimeZoneID); fTimeZone = TimeZone::createTimeZone(fTimeZoneID);
if (fTimeZone == NULL) if (fTimeZone == NULL)
+15 -10
View File
@@ -64,6 +64,11 @@ enum
/* These are defined in ctype-info.c. /* These are defined in ctype-info.c.
The declarations here must match those in localeinfo.h. 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 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 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 [-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 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 doesn't fit into an `unsigned char'. But today more important is that
the arrays are also used for multi-byte character sets. */ the arrays are also used for multi-byte character sets. */
extern __const unsigned short int *__ctype_b; /* Characteristics. */ extern __const unsigned short int **__ctype_b_loc (void); /* Characteristics. */
extern __const __int32_t *__ctype_tolower; /* Case conversions. */ extern __const __int32_t **__ctype_tolower_loc (void); /* Case conversions. */
extern __const __int32_t *__ctype_toupper; /* Case conversions. */ extern __const __int32_t **__ctype_toupper_loc (void); /* Case conversions. */
#define __isctype(c, type) \ #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 __isascii(c) (((c) & ~0x7f) == 0) /* If C is a 7 bit value. */
#define __toascii(c) ((c) & 0x7f) /* Mask off high bits. */ #define __toascii(c) ((c) & 0x7f) /* Mask off high bits. */
@@ -167,27 +172,27 @@ __exctype (_tolower);
__extern_inline int __extern_inline int
tolower (int __c) __THROW 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 __extern_inline int
toupper (int __c) __THROW toupper (int __c) __THROW
{ {
return __c >= -128 && __c < 256 ? __ctype_toupper[__c] : __c; return __c >= -128 && __c < 256 ? (*__ctype_toupper_loc())[__c] : __c;
} }
# endif # endif
# if __GNUC__ >= 2 && defined __OPTIMIZE__ && !defined __cplusplus # if __GNUC__ >= 2 && defined __OPTIMIZE__ && !defined __cplusplus
# define tolower(c) __tobody (c, tolower, __ctype_tolower, (c)) # define tolower(c) __tobody (c, tolower, (*__ctype_tolower_loc()), (c))
# define toupper(c) __tobody (c, toupper, __ctype_toupper, (c)) # define toupper(c) __tobody (c, toupper, (*__ctype_toupper_loc()), (c))
# endif /* Optimizing gcc */ # endif /* Optimizing gcc */
# if defined __USE_SVID || defined __USE_MISC || defined __USE_XOPEN # if defined __USE_SVID || defined __USE_MISC || defined __USE_XOPEN
# define isascii(c) __isascii (c) # define isascii(c) __isascii (c)
# define toascii(c) __toascii (c) # define toascii(c) __toascii (c)
# define _tolower(c) ((int) __ctype_tolower[(int) (c)]) # define _tolower(c) ((int) (*__ctype_tolower_loc())[(int) (c)])
# define _toupper(c) ((int) __ctype_toupper[(int) (c)]) # define _toupper(c) ((int) (*__ctype_toupper_loc())[(int) (c)])
# endif # endif
#endif /* Not __NO_CTYPE. */ #endif /* Not __NO_CTYPE. */
@@ -10,6 +10,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include arch SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include arch
generic ; generic ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include ; 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 libio ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc locale ; SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc locale ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ; SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ;
@@ -13,6 +13,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
generic ; generic ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include ; 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 locale ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ctype ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ; SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ;
MergeObject <$(architecture)>posix_gnu_locale.o : MergeObject <$(architecture)>posix_gnu_locale.o :
@@ -24,6 +25,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
C-time.c C-time.c
C_name.c C_name.c
coll-lookup.c coll-lookup.c
global-locale.c
lc-collate.c lc-collate.c
lc-ctype.c lc-ctype.c
lc-messages.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); offset = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_CLASS_OFFSET);
for (cnt = 0; cnt < 12; cnt++) 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); offset = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_OFFSET);
for (cnt = 0; cnt < 2; cnt++) 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 <stdint.h>
#include <sys/types.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. */ /* This has to be changed whenever a new locale is defined. */
#define __LC_LAST 7 #define __LC_LAST 7
@@ -141,12 +146,6 @@ enum
(((((const uint32_t *) (desc)) - 8)[(c) >> 5] >> ((c) & 0x1f)) & 1) (((((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 char *const _nl_category_names[__LC_LAST];
extern const size_t _nl_category_name_sizes[__LC_LAST]; extern const size_t _nl_category_name_sizes[__LC_LAST];
extern struct locale_data * *const _nl_current[__LC_LAST]; extern struct locale_data * *const _nl_current[__LC_LAST];
@@ -158,22 +157,33 @@ extern const char _nl_POSIX_name[];
/* The standard codeset. */ /* The standard codeset. */
extern const char _nl_C_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. */ /* Extract the current CATEGORY locale's string for ITEM. */
#define _NL_CURRENT(category, 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. */ /* Extract the current CATEGORY locale's string for ITEM. */
#define _NL_CURRENT_WSTR(category, 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. */ /* Extract the current CATEGORY locale's word for ITEM. */
#define _NL_CURRENT_WORD(category, 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. */ /* This is used in lc-CATEGORY.c to define _nl_current_CATEGORY. */
#define _NL_CURRENT_DEFINE(category) \ #define _NL_CURRENT_DEFINE(category) \
extern struct locale_data _nl_C_##category; \ /* No per-category variable here. */
struct locale_data *_nl_current_##category = &_nl_C_##category
/* Load the locale data for CATEGORY from the file specified by *NAME. /* Load the locale data for CATEGORY from the file specified by *NAME.
If *NAME is "", use environment variables as specified by POSIX, 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 SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include arch
generic ; generic ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include ; 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 libio ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc misc ; SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc misc ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc locale ; SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc locale ;
@@ -14,6 +14,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
generic ; generic ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include ; 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 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 locale ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ; 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 SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include arch
generic ; generic ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc include ; 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 locale ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc stdlib ; SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc stdlib ;
SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ; SubDirSysHdrs $(HAIKU_TOP) src system libroot posix glibc ;
+10
View File
@@ -4,6 +4,7 @@ UsePrivateHeaders
[ FDirName libroot ] [ FDirName libroot ]
[ FDirName libroot locale ] [ FDirName libroot locale ]
[ FDirName libroot time ] [ FDirName libroot time ]
[ FDirName system ]
; ;
local architectureObject ; local architectureObject ;
@@ -12,14 +13,23 @@ for architectureObject in [ MultiArchSubDirSetup ] {
local architecture = $(TARGET_PACKAGING_ARCH) ; local architecture = $(TARGET_PACKAGING_ARCH) ;
MergeObject <$(architecture)>posix_locale.o : MergeObject <$(architecture)>posix_locale.o :
ctype_l.cpp
ctype.cpp ctype.cpp
LocaleBackend.cpp LocaleBackend.cpp
LocaleData.cpp LocaleData.cpp
LocaleDataBridge.cpp LocaleDataBridge.cpp
LocaleInternal.cpp
locale_t.cpp
localeconv.cpp localeconv.cpp
nl_langinfo.cpp nl_langinfo.cpp
setlocale.cpp setlocale.cpp
ThreadLocale.cpp
wctype_l.cpp
wctype.cpp wctype.cpp
; ;
MergeObject <$(architecture)>ctype_loc.o :
ctype_loc.cpp
;
} }
} }
@@ -10,37 +10,56 @@
#include <pthread.h> #include <pthread.h>
#include <string.h> #include <string.h>
#include <ThreadLocale.h>
namespace BPrivate { namespace BPrivate {
namespace Libroot { 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 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 static void
LoadBackend() LoadBackend()
{ {
void* imageHandle = dlopen("libroot-addon-icu.so", RTLD_LAZY); gGlobalLocaleBackend = LocaleBackend::CreateBackend();
if (imageHandle == NULL) if (gGlobalLocaleBackend != NULL) {
return; gGlobalLocaleBackend->Initialize(&gGlobalLocaleDataBridge);
typedef LocaleBackend* (*symbolType)();
symbolType createInstanceFunc
= (symbolType)dlsym(imageHandle, "CreateInstance");
if (createInstanceFunc == NULL) {
dlclose(imageHandle);
return;
} }
gLocaleBackend = createInstanceFunc();
} }
LocaleBackend::LocaleBackend() LocaleBackend::LocaleBackend()
{ {
} }
@@ -54,15 +73,60 @@ LocaleBackend::~LocaleBackend()
status_t status_t
LocaleBackend::LoadBackend() LocaleBackend::LoadBackend()
{ {
if (gLocaleBackend == NULL) { if (gGlobalLocaleBackend == NULL) {
pthread_once(&sBackendInitOnce, &BPrivate::Libroot::LoadBackend); 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 Libroot
} // namespace BPrivate } // namespace BPrivate
@@ -15,24 +15,45 @@
#include <PosixLanginfo.h> #include <PosixLanginfo.h>
#include <PosixLCTimeInfo.h> #include <PosixLCTimeInfo.h>
#include <PosixLocaleConv.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 BPrivate {
namespace Libroot { 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), localClassInfoTable(__ctype_b),
addrOfToLowerTable(&__ctype_tolower), localToLowerTable(__ctype_tolower),
addrOfToUpperTable(&__ctype_toupper), localToUpperTable(__ctype_toupper),
posixClassInfo(gPosixClassInfo), posixClassInfo(gPosixClassInfo),
posixToLowerMap(gPosixToLowerMap), 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() LocaleMessagesDataBridge::LocaleMessagesDataBridge()
: :
posixLanginfo(gPosixLanginfo) 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)); memcpy(glibcNumericLocale, _NL_GLOBAL_DATA(GLIBC_LC_NUMERIC),
_nl_current_LC_NUMERIC = (locale_data*)&glibcNumericLocale; sizeof(GlibcNumericLocale));
if (isGlobal) {
originalGlibcLocale = _NL_GLOBAL_DATA(GLIBC_LC_NUMERIC);
_NL_GLOBAL_DATA(GLIBC_LC_NUMERIC) = (locale_data*)glibcNumericLocale;
}
} }
LocaleNumericDataBridge::~LocaleNumericDataBridge() 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), localDaylight(daylight),
addrOfTimezone(&timezone), localTimezone(timezone),
addrOfTZName(tzname) 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() void
: LocaleDataBridge::ApplyToCurrentThread()
posixLanginfo(gPosixLanginfo)
{ {
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, [email protected]
* Copyright 2010, Oliver Tappe, [email protected]
* 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, [email protected]
* Copyright 2010, Oliver Tappe, [email protected]
* 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, [email protected]
* 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) isalnum(int c)
{ {
if (c >= -128 && c < 256) if (c >= -128 && c < 256)
return __ctype_b[c] & (_ISupper | _ISlower | _ISdigit); return (*__ctype_b_loc())[c] & (_ISupper | _ISlower | _ISdigit);
return 0; return 0;
} }
@@ -54,7 +54,7 @@ int
isalpha(int c) isalpha(int c)
{ {
if (c >= -128 && c < 256) if (c >= -128 && c < 256)
return __ctype_b[c] & (_ISupper | _ISlower); return (*__ctype_b_loc())[c] & (_ISupper | _ISlower);
return 0; return 0;
} }
@@ -72,7 +72,7 @@ int
isblank(int c) isblank(int c)
{ {
if (c >= -128 && c < 256) if (c >= -128 && c < 256)
return __ctype_b[c] & _ISblank; return (*__ctype_b_loc())[c] & _ISblank;
return 0; return 0;
} }
@@ -82,7 +82,7 @@ int
iscntrl(int c) iscntrl(int c)
{ {
if (c >= -128 && c < 256) if (c >= -128 && c < 256)
return __ctype_b[c] & _IScntrl; return (*__ctype_b_loc())[c] & _IScntrl;
return 0; return 0;
} }
@@ -92,7 +92,7 @@ int
isdigit(int c) isdigit(int c)
{ {
if (c >= -128 && c < 256) if (c >= -128 && c < 256)
return __ctype_b[c] & _ISdigit; return (*__ctype_b_loc())[c] & _ISdigit;
return 0; return 0;
} }
@@ -102,7 +102,7 @@ int
isgraph(int c) isgraph(int c)
{ {
if (c >= -128 && c < 256) if (c >= -128 && c < 256)
return __ctype_b[c] & _ISgraph; return (*__ctype_b_loc())[c] & _ISgraph;
return 0; return 0;
} }
@@ -112,7 +112,7 @@ int
islower(int c) islower(int c)
{ {
if (c >= -128 && c < 256) if (c >= -128 && c < 256)
return __ctype_b[c] & _ISlower; return (*__ctype_b_loc())[c] & _ISlower;
return 0; return 0;
} }
@@ -122,7 +122,7 @@ int
isprint(int c) isprint(int c)
{ {
if (c >= -128 && c < 256) if (c >= -128 && c < 256)
return __ctype_b[c] & _ISprint; return (*__ctype_b_loc())[c] & _ISprint;
return 0; return 0;
} }
@@ -132,7 +132,7 @@ int
ispunct(int c) ispunct(int c)
{ {
if (c >= -128 && c < 256) if (c >= -128 && c < 256)
return __ctype_b[c] & _ISpunct; return (*__ctype_b_loc())[c] & _ISpunct;
return 0; return 0;
} }
@@ -142,7 +142,7 @@ int
isspace(int c) isspace(int c)
{ {
if (c >= -128 && c < 256) if (c >= -128 && c < 256)
return __ctype_b[c] & _ISspace; return (*__ctype_b_loc())[c] & _ISspace;
return 0; return 0;
} }
@@ -152,7 +152,7 @@ int
isupper(int c) isupper(int c)
{ {
if (c >= -128 && c < 256) if (c >= -128 && c < 256)
return __ctype_b[c] & _ISupper; return (*__ctype_b_loc())[c] & _ISupper;
return 0; return 0;
} }
@@ -162,7 +162,7 @@ int
isxdigit(int c) isxdigit(int c)
{ {
if (c >= -128 && c < 256) if (c >= -128 && c < 256)
return __ctype_b[c] & _ISxdigit; return (*__ctype_b_loc())[c] & _ISxdigit;
return 0; return 0;
} }
@@ -180,7 +180,7 @@ int
tolower(int c) tolower(int c)
{ {
if (c >= -128 && c < 256) if (c >= -128 && c < 256)
return __ctype_tolower[c]; return (*__ctype_tolower_loc())[c];
return c; return c;
} }
@@ -190,7 +190,7 @@ int
toupper(int c) toupper(int c)
{ {
if (c >= -128 && c < 256) if (c >= -128 && c < 256)
return __ctype_toupper[c]; return (*__ctype_toupper_loc())[c];
return c; return c;
} }
+202
View File
@@ -0,0 +1,202 @@
/*
* Copyright 2022, Trung Nguyen, [email protected]
* 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, [email protected]
* 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, [email protected]
* 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> #include <PosixLocaleConv.h>
#ifndef _KERNEL_MODE #ifndef _KERNEL_MODE
#include <locale.h>
#include "LocaleBackend.h" #include "LocaleBackend.h"
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
#endif #endif
@@ -20,9 +24,25 @@ extern "C" struct lconv*
localeconv(void) localeconv(void)
{ {
#ifndef _KERNEL_MODE #ifndef _KERNEL_MODE
if (gLocaleBackend) LocaleBackend* backend = GetCurrentLocaleBackend();
return const_cast<lconv*>(gLocaleBackend->LocaleConv()); if (backend != NULL)
return const_cast<lconv*>(backend->LocaleConv());
#endif #endif
return &BPrivate::Libroot::gPosixLocaleConv; 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> #include <PosixLanginfo.h>
using BPrivate::Libroot::gLocaleBackend;
using BPrivate::Libroot::gPosixLanginfo; using BPrivate::Libroot::gPosixLanginfo;
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
extern "C" char* extern "C" char*
@@ -21,8 +23,23 @@ nl_langinfo(nl_item item)
if (item < 0 || item >= _NL_LANGINFO_LAST) if (item < 0 || item >= _NL_LANGINFO_LAST)
return const_cast<char*>(""); return const_cast<char*>("");
if (gLocaleBackend != NULL) if (GetCurrentLocaleBackend() != NULL)
return const_cast<char*>(gLocaleBackend->GetLanginfo(item)); 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]); return const_cast<char*>(gPosixLanginfo[item]);
} }
+9 -55
View File
@@ -7,65 +7,19 @@
#include <ctype.h> #include <ctype.h>
#include <locale.h> #include <locale.h>
#include <stdlib.h>
#include <strings.h> #include <strings.h>
#include <ErrnoMaintainer.h> #include <ErrnoMaintainer.h>
#include "LocaleBackend.h" #include "LocaleBackend.h"
#include "LocaleInternal.h"
using BPrivate::Libroot::gLocaleBackend; using BPrivate::Libroot::gGlobalLocaleBackend;
using BPrivate::Libroot::GetLocalesFromEnvironment;
using BPrivate::Libroot::LocaleBackend; 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* extern "C" char*
setlocale(int category, const char* locale) setlocale(int category, const char* locale)
{ {
@@ -76,8 +30,8 @@ setlocale(int category, const char* locale)
if (locale == NULL) { if (locale == NULL) {
// query the locale of the given category // query the locale of the given category
if (gLocaleBackend != NULL) if (gGlobalLocaleBackend != NULL)
return const_cast<char*>(gLocaleBackend->SetLocale(category, NULL)); return const_cast<char*>(gGlobalLocaleBackend->SetLocale(category, NULL));
else else
return const_cast<char*>("POSIX"); return const_cast<char*>("POSIX");
} }
@@ -93,7 +47,7 @@ setlocale(int category, const char* locale)
else else
locales[category] = locale; locales[category] = locale;
if (!gLocaleBackend) { if (gGlobalLocaleBackend == NULL) {
// for any locale other than POSIX/C, we try to activate the ICU // for any locale other than POSIX/C, we try to activate the ICU
// backend // backend
bool needBackend = false; bool needBackend = false;
@@ -108,17 +62,17 @@ setlocale(int category, const char* locale)
return NULL; return NULL;
} }
if (gLocaleBackend != NULL) { if (gGlobalLocaleBackend != NULL) {
for (int lc = 0; lc <= LC_LAST; lc++) { for (int lc = 0; lc <= LC_LAST; lc++) {
if (locales[lc] != NULL) { if (locales[lc] != NULL) {
locale = gLocaleBackend->SetLocale(lc, locales[lc]); locale = gGlobalLocaleBackend->SetLocale(lc, locales[lc]);
if (lc == LC_ALL) { if (lc == LC_ALL) {
// skip the rest, LC_ALL overrides // skip the rest, LC_ALL overrides
return const_cast<char*>(locale); 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"); return const_cast<char*>("POSIX");
+19 -9
View File
@@ -13,7 +13,9 @@
#include "LocaleBackend.h" #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 * In many of the following functions, we make use of the fact that with
@@ -26,13 +28,15 @@ using BPrivate::Libroot::gLocaleBackend;
int int
iswctype(wint_t wc, wctype_t charClass) iswctype(wint_t wc, wctype_t charClass)
{ {
if (gLocaleBackend == NULL) { LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend == NULL) {
if (wc < 0 || wc > 127) if (wc < 0 || wc > 127)
return 0; return 0;
return __isctype(wc, charClass); return __isctype(wc, charClass);
} }
return gLocaleBackend->IsWCType(wc, charClass); return backend->IsWCType(wc, charClass);
} }
@@ -123,14 +127,16 @@ iswxdigit(wint_t wc)
wint_t wint_t
towlower(wint_t wc) towlower(wint_t wc)
{ {
if (gLocaleBackend == NULL) { LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend == NULL) {
if (wc < 0 || wc > 127) if (wc < 0 || wc > 127)
return wc; return wc;
return tolower(wc); return tolower(wc);
} }
wint_t result = wc; wint_t result = wc;
gLocaleBackend->ToWCTrans(wc, _ISlower, result); backend->ToWCTrans(wc, _ISlower, result);
return result; return result;
} }
@@ -139,14 +145,16 @@ towlower(wint_t wc)
wint_t wint_t
towupper(wint_t wc) towupper(wint_t wc)
{ {
if (gLocaleBackend == NULL) { LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend == NULL) {
if (wc < 0 || wc > 127) if (wc < 0 || wc > 127)
return wc; return wc;
return toupper(wc); return toupper(wc);
} }
wint_t result = wc; wint_t result = wc;
gLocaleBackend->ToWCTrans(wc, _ISupper, result); backend->ToWCTrans(wc, _ISupper, result);
return result; return result;
} }
@@ -155,7 +163,9 @@ towupper(wint_t wc)
wint_t wint_t
towctrans(wint_t wc, wctrans_t transition) towctrans(wint_t wc, wctrans_t transition)
{ {
if (gLocaleBackend == NULL) { LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend == NULL) {
if (transition == _ISlower) if (transition == _ISlower)
return tolower(wc); return tolower(wc);
if (transition == _ISupper) if (transition == _ISupper)
@@ -166,7 +176,7 @@ towctrans(wint_t wc, wctrans_t transition)
} }
wint_t result = wc; wint_t result = wc;
status_t status = gLocaleBackend->ToWCTrans(wc, transition, result); status_t status = backend->ToWCTrans(wc, transition, result);
if (status != B_OK) if (status != B_OK)
__set_errno(EINVAL); __set_errno(EINVAL);
@@ -0,0 +1,236 @@
/*
* Copyright 2022, Trung Nguyen, [email protected]
* 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;
}
+34 -20
View File
@@ -89,19 +89,39 @@
} while (0) } while (0)
static void __setup_vars(int, char *, char *, char *, char **); extern struct lconv* localeconv_l(locale_t);
static int __calc_left_pad(int, char *);
static char *__format_grouped_double(double, int *, int, int, int); 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 ssize_t
strfmon(char *s, size_t maxsize, const char *format, strfmon(char *s, size_t maxsize, const char *format, ...)
...)
{ {
va_list ap; 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)
{
char *dst; /* output destination pointer */ char *dst; /* output destination pointer */
const char *fmt; /* current format poistion pointer */ const char *fmt; /* current format poistion pointer */
struct lconv *lc; /* pointer to lconv structure */
char *asciivalue; /* formatted double pointer */ char *asciivalue; /* formatted double pointer */
int flags; /* formatting options */ int flags; /* formatting options */
@@ -122,9 +142,6 @@ strfmon(char *s, size_t maxsize, const char *format,
char *tmpptr; /* temporary vars */ char *tmpptr; /* temporary vars */
int sverrno; int sverrno;
va_start(ap, format);
lc = localeconv();
dst = s; dst = s;
fmt = format; fmt = format;
asciivalue = NULL; asciivalue = NULL;
@@ -253,22 +270,22 @@ strfmon(char *s, size_t maxsize, const char *format,
/* fill left_prec with amount of padding chars */ /* fill left_prec with amount of padding chars */
if (left_prec >= 0) { if (left_prec >= 0) {
pad_size = __calc_left_pad((flags ^ IS_NEGATIVE), pad_size = __calc_left_pad((flags ^ IS_NEGATIVE), lc,
currency_symbol) - __calc_left_pad(flags, currency_symbol); currency_symbol) - __calc_left_pad(flags, lc, currency_symbol);
if (pad_size < 0) if (pad_size < 0)
pad_size = 0; pad_size = 0;
} }
if (asciivalue != NULL) if (asciivalue != NULL)
free(asciivalue); free(asciivalue);
asciivalue = __format_grouped_double(value, &flags, left_prec, asciivalue = __format_grouped_double(value, lc, &flags, left_prec,
right_prec, pad_char); right_prec, pad_char);
if (asciivalue == NULL) if (asciivalue == NULL)
goto end_error; /* errno already set */ goto end_error; /* errno already set */
/* to ENOMEM by malloc() */ /* to ENOMEM by malloc() */
/* set some variables for later use */ /* 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: * Description of some LC_MONETARY's values:
@@ -405,11 +422,9 @@ end_error:
static void 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) char **signstr)
{ {
struct lconv *lc = localeconv();
if ((flags & IS_NEGATIVE) && (flags & USE_INTL_CURRENCY)) { if ((flags & IS_NEGATIVE) && (flags & USE_INTL_CURRENCY)) {
*cs_precedes = lc->int_n_cs_precedes; *cs_precedes = lc->int_n_cs_precedes;
*sep_by_space = lc->int_n_sep_by_space; *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 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; char cs_precedes, sep_by_space, sign_posn, *signstr;
int left_chars = 0; 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) { if (cs_precedes != 0) {
left_chars += strlen(cur_symb); left_chars += strlen(cur_symb);
@@ -495,7 +510,7 @@ get_groups(int size, char *grouping)
/* convert double to ASCII */ /* convert double to ASCII */
static char * 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) int pad_char)
{ {
char *rslt; char *rslt;
@@ -508,7 +523,6 @@ __format_grouped_double(double value, int *flags, int left_prec, int right_prec,
int padded; int padded;
struct lconv *lc = localeconv();
char *grouping; char *grouping;
char decimal_point; char decimal_point;
char thousands_sep; char thousands_sep;
@@ -68,3 +68,35 @@ strncasecmp(const char *s1, const char *s2, size_t n)
return 0; 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" #include "LocaleBackend.h"
using BPrivate::Libroot::gLocaleBackend; using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
extern "C" int extern "C" int
strcoll(const char *a, const char *b) strcoll(const char *a, const char *b)
{ {
if (gLocaleBackend != NULL) { LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend != NULL) {
int result = 0; 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) if (status != B_OK)
__set_errno(EINVAL); __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 // 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" #include "LocaleBackend.h"
using BPrivate::Libroot::gLocaleBackend; using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
extern "C" size_t extern "C" size_t
strxfrm(char *out, const char *in, size_t size) strxfrm(char *out, const char *in, size_t size)
{ {
if (gLocaleBackend != NULL) { LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend != NULL) {
size_t outSize = 0; 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) if (status != B_OK)
__set_errno(EINVAL); __set_errno(EINVAL);
+23 -11
View File
@@ -17,7 +17,7 @@
#include "LocaleBackend.h" #include "LocaleBackend.h"
using BPrivate::Libroot::gLocaleBackend; using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend; using BPrivate::Libroot::LocaleBackend;
@@ -43,13 +43,13 @@ extern "C" time_t __timegm_fallback(struct tm* tmp);
extern "C" void extern "C" void
tzset(void) tzset(void)
{ {
if (gLocaleBackend == NULL && LocaleBackend::LoadBackend() != B_OK) if (GetCurrentLocaleBackend() == NULL && LocaleBackend::LoadBackend() != B_OK)
return; return;
char timeZoneID[B_FILE_NAME_LENGTH] = { "GMT" }; char timeZoneID[B_FILE_NAME_LENGTH] = { "GMT" };
_kern_get_timezone(NULL, timeZoneID, sizeof(timeZoneID)); _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(); 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) if (status != B_OK)
__set_errno(EOVERFLOW); __set_errno(EOVERFLOW);
@@ -104,8 +107,11 @@ gmtime_r(const time_t* inTime, struct tm* tmOut)
} }
tzset(); 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) if (status != B_OK)
__set_errno(EOVERFLOW); __set_errno(EOVERFLOW);
@@ -128,9 +134,12 @@ mktime(struct tm* inTm)
} }
tzset(); tzset();
if (gLocaleBackend != NULL) {
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend != NULL) {
time_t timeOut; time_t timeOut;
status_t status = gLocaleBackend->Mktime(inTm, timeOut); status_t status = backend->Mktime(inTm, timeOut);
if (status != B_OK) { if (status != B_OK) {
__set_errno(EOVERFLOW); __set_errno(EOVERFLOW);
@@ -154,9 +163,12 @@ timegm(struct tm* inTm)
return -1; return -1;
} }
tzset(); tzset();
if (gLocaleBackend != NULL) {
LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend != NULL) {
time_t timeOut; time_t timeOut;
status_t status = gLocaleBackend->Timegm(inTm, timeOut); status_t status = backend->Timegm(inTm, timeOut);
if (status != B_OK) { if (status != B_OK) {
__set_errno(EOVERFLOW); __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 "locale.h"
#include "timelocal.h" #include "timelocal.h"
#define Locale __get_current_time_locale()
static char * _add P((const char *, char *, const char *)); static char * _add P((const char *, char *, const char *));
static char * _conv P((int, 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 *, 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 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[]; extern char * tzname[];
@@ -60,18 +60,32 @@ extern char * tzname[];
#define NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU #define NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
size_t 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; char * const s;
const size_t maxsize; const size_t maxsize;
const char * const format; const char * const format;
const struct tm * const t; const struct tm * const t;
const struct lc_time_t* locale;
{ {
char * p; char * p;
int warn; int warn;
tzset(); tzset();
warn = IN_NONE; 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 #ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) { if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
(void) fprintf(stderr, "\n"); (void) fprintf(stderr, "\n");
@@ -95,12 +109,13 @@ const struct tm * const t;
} }
static char * static char *
_fmt(format, t, pt, ptlim, warnp) _fmt(format, t, pt, ptlim, warnp, Locale)
const char * format; const char * format;
const struct tm * const t; const struct tm * const t;
char * pt; char * pt;
const char * const ptlim; const char * const ptlim;
int * warnp; int * warnp;
const struct lc_time_t* Locale;
{ {
for ( ; *format; ++format) { for ( ; *format; ++format) {
if (*format == '%') { if (*format == '%') {
@@ -152,13 +167,13 @@ label:
{ {
int warn2 = IN_SOME; 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) if (warn2 > *warnp)
*warnp = warn2; *warnp = warn2;
} }
continue; continue;
case 'D': case 'D':
pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp); pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, Locale);
continue; continue;
case 'd': case 'd':
pt = _conv(t->tm_mday, "%02d", pt, ptlim); pt = _conv(t->tm_mday, "%02d", pt, ptlim);
@@ -179,7 +194,7 @@ label:
pt = _conv(t->tm_mday, "%2d", pt, ptlim); pt = _conv(t->tm_mday, "%2d", pt, ptlim);
continue; continue;
case 'F': case 'F':
pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp); pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, Locale);
continue; continue;
case 'H': case 'H':
pt = _conv(t->tm_hour, "%02d", pt, ptlim); pt = _conv(t->tm_hour, "%02d", pt, ptlim);
@@ -243,10 +258,10 @@ label:
pt, ptlim); pt, ptlim);
continue; continue;
case 'R': case 'R':
pt = _fmt("%H:%M", t, pt, ptlim, warnp); pt = _fmt("%H:%M", t, pt, ptlim, warnp, Locale);
continue; continue;
case 'r': case 'r':
pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp); pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp, Locale);
continue; continue;
case 'S': case 'S':
pt = _conv(t->tm_sec, "%02d", pt, ptlim); pt = _conv(t->tm_sec, "%02d", pt, ptlim);
@@ -269,7 +284,7 @@ label:
} }
continue; continue;
case 'T': case 'T':
pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp); pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, Locale);
continue; continue;
case 't': case 't':
pt = _add("\t", pt, ptlim); pt = _add("\t", pt, ptlim);
@@ -384,7 +399,7 @@ label:
** "date as dd-bbb-YYYY" ** "date as dd-bbb-YYYY"
** (ado, 1993-05-24) ** (ado, 1993-05-24)
*/ */
pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp); pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, Locale);
continue; continue;
case 'W': case 'W':
pt = _conv((t->tm_yday + DAYSPERWEEK - pt = _conv((t->tm_yday + DAYSPERWEEK -
@@ -397,13 +412,13 @@ label:
pt = _conv(t->tm_wday, "%d", pt, ptlim); pt = _conv(t->tm_wday, "%d", pt, ptlim);
continue; continue;
case 'X': case 'X':
pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp); pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp, Locale);
continue; continue;
case 'x': case 'x':
{ {
int warn2 = IN_SOME; 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) if (warn2 == IN_ALL)
warn2 = IN_THIS; warn2 = IN_THIS;
if (warn2 > *warnp) if (warn2 > *warnp)
@@ -489,7 +504,7 @@ label:
continue; continue;
case '+': case '+':
pt = _fmt(Locale->date_fmt, t, pt, ptlim, pt = _fmt(Locale->date_fmt, t, pt, ptlim,
warnp); warnp, Locale);
continue; continue;
case '%': case '%':
/* /*
+18 -3
View File
@@ -12,14 +12,29 @@
#include "PosixLCTimeInfo.h" #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* extern "C" const lc_time_t*
__get_current_time_locale(void) __get_current_time_locale(void)
{ {
if (gLocaleBackend) if (GetCurrentLocaleBackend() != NULL)
return gLocaleBackend->LCTimeInfo(); 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; return &BPrivate::Libroot::gPosixLCTimeInfo;
} }
+6 -4
View File
@@ -20,7 +20,8 @@
#endif #endif
using BPrivate::Libroot::gLocaleBackend; using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
extern "C" size_t extern "C" size_t
@@ -34,7 +35,9 @@ __mbrtowc(wchar_t* pwc, const char* s, size_t n, mbstate_t* ps)
if (s == NULL) if (s == NULL)
return __mbrtowc(NULL, "", 1, ps); return __mbrtowc(NULL, "", 1, ps);
if (gLocaleBackend == NULL) { LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend == NULL) {
if (*s == '\0') { if (*s == '\0') {
memset(ps, 0, sizeof(mbstate_t)); 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; size_t lengthUsed;
status_t status status_t status = backend->MultibyteToWchar(pwc, s, n, ps, lengthUsed);
= gLocaleBackend->MultibyteToWchar(pwc, s, n, ps, lengthUsed);
if (status == B_BAD_INDEX) if (status == B_BAD_INDEX)
return (size_t)-2; return (size_t)-2;
+9 -5
View File
@@ -20,22 +20,25 @@
#endif #endif
using BPrivate::Libroot::gLocaleBackend; using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
extern "C" size_t extern "C" size_t
__mbsnrtowcs(wchar_t* dst, const char** src, size_t nmc, size_t len, __mbsnrtowcs(wchar_t* dst, const char** src, size_t nmc, size_t len,
mbstate_t* ps) mbstate_t* ps)
{ {
LocaleBackend* backend = GetCurrentLocaleBackend();
TRACE(("mbsnrtowcs(%p, %p, %lu, %lu) - lb:%p\n", dst, *src, nmc, len, TRACE(("mbsnrtowcs(%p, %p, %lu, %lu) - lb:%p\n", dst, *src, nmc, len,
gLocaleBackend)); backend));
if (ps == NULL) { if (ps == NULL) {
static mbstate_t internalMbState; static mbstate_t internalMbState;
ps = &internalMbState; ps = &internalMbState;
} }
if (gLocaleBackend == NULL) { if (backend == NULL) {
/* /*
* The POSIX locale is active. Since the POSIX locale only contains * The POSIX locale is active. Since the POSIX locale only contains
* chars 0-127 and those ASCII chars are compatible with the UTF32 * 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; size_t result = 0;
status_t status = gLocaleBackend->MultibyteStringToWchar(dst, len, src, nmc, status_t status = backend->MultibyteStringToWchar(dst, len, src, nmc,
ps, result); ps, result);
if (status == B_BAD_DATA) { if (status == B_BAD_DATA) {
@@ -112,7 +115,8 @@ __mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps)
ps = &internalMbState; 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); return __mbsnrtowcs(dst, src, srcLen, len, ps);
} }
+6 -3
View File
@@ -20,12 +20,15 @@
#endif #endif
using BPrivate::Libroot::gLocaleBackend; using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
extern "C" size_t extern "C" size_t
__wcrtomb(char* s, wchar_t wc, mbstate_t* ps) __wcrtomb(char* s, wchar_t wc, mbstate_t* ps)
{ {
LocaleBackend* backend = GetCurrentLocaleBackend();
if (ps == NULL) { if (ps == NULL) {
static mbstate_t internalMbState; static mbstate_t internalMbState;
ps = &internalMbState; ps = &internalMbState;
@@ -34,7 +37,7 @@ __wcrtomb(char* s, wchar_t wc, mbstate_t* ps)
if (s == NULL) if (s == NULL)
wc = 0; wc = 0;
if (gLocaleBackend == NULL) { if (backend == NULL) {
/* /*
* The POSIX locale is active. Since the POSIX locale only contains * The POSIX locale is active. Since the POSIX locale only contains
* chars 0-127 and those ASCII chars are compatible with the UTF32 * 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; 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) if (status == B_BAD_INDEX)
return (size_t)-2; return (size_t)-2;
@@ -27,3 +27,22 @@ __wcscasecmp(const wchar_t* wcs1, const wchar_t* wcs2)
B_DEFINE_WEAK_ALIAS(__wcscasecmp, wcscasecmp); 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> #include <wchar_private.h>
using BPrivate::Libroot::gLocaleBackend; using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
extern "C" int extern "C" int
__wcscoll(const wchar_t* wcs1, const wchar_t* wcs2) __wcscoll(const wchar_t* wcs1, const wchar_t* wcs2)
{ {
if (gLocaleBackend != NULL) { LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend != NULL) {
int result = 0; int result = 0;
status_t status = gLocaleBackend->Wcscoll(wcs1, wcs2, result); status_t status = backend->Wcscoll(wcs1, wcs2, result);
if (status != B_OK) if (status != B_OK)
__set_errno(EINVAL); __set_errno(EINVAL);
@@ -29,3 +33,26 @@ __wcscoll(const wchar_t* wcs1, const wchar_t* wcs2)
B_DEFINE_WEAK_ALIAS(__wcscoll, wcscoll); 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); 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 #endif
using BPrivate::Libroot::gLocaleBackend; using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
extern "C" size_t extern "C" size_t
__wcsnrtombs(char* dst, const wchar_t** src, size_t nwc, size_t len, __wcsnrtombs(char* dst, const wchar_t** src, size_t nwc, size_t len,
mbstate_t* ps) mbstate_t* ps)
{ {
LocaleBackend* backend = GetCurrentLocaleBackend();
TRACE(("wcsnrtombs(%p, %p, %lu, %lu) - lb:%p\n", dst, *src, nwc, len, TRACE(("wcsnrtombs(%p, %p, %lu, %lu) - lb:%p\n", dst, *src, nwc, len,
gLocaleBackend)); backend));
if (ps == NULL) { if (ps == NULL) {
static mbstate_t internalMbState; static mbstate_t internalMbState;
ps = &internalMbState; ps = &internalMbState;
} }
if (gLocaleBackend == NULL) { if (backend == NULL) {
/* /*
* The POSIX locale is active. Since the POSIX locale only contains * The POSIX locale is active. Since the POSIX locale only contains
* chars 0-127 and those ASCII chars are compatible with the UTF32 * 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; size_t result = 0;
status_t status = gLocaleBackend->WcharStringToMultibyte(dst, len, src, nwc, status_t status = backend->WcharStringToMultibyte(dst, len, src, nwc,
ps, result); ps, result);
if (status == B_BAD_DATA) { if (status == B_BAD_DATA) {
+30 -3
View File
@@ -10,15 +10,19 @@
#include <wchar_private.h> #include <wchar_private.h>
using BPrivate::Libroot::gLocaleBackend; using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
extern "C" size_t extern "C" size_t
__wcsxfrm(wchar_t* dest, const wchar_t* src, size_t destSize) __wcsxfrm(wchar_t* dest, const wchar_t* src, size_t destSize)
{ {
if (gLocaleBackend != NULL) { LocaleBackend* backend = GetCurrentLocaleBackend();
if (backend != NULL) {
size_t outSize = 0; 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) if (status != B_OK)
__set_errno(EINVAL); __set_errno(EINVAL);
@@ -31,3 +35,26 @@ __wcsxfrm(wchar_t* dest, const wchar_t* src, size_t destSize)
B_DEFINE_WEAK_ALIAS(__wcsxfrm, wcsxfrm); 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!$(architecture)>fcntl.o
<src!system!libroot!posix!locale!$(architecture)>ctype.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!locale!$(architecture)>LocaleData.o
<src!system!libroot!posix!string!$(architecture)>memchr.o <src!system!libroot!posix!string!$(architecture)>memchr.o