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:
committed by
waddlesplash
parent
86fa1c21e1
commit
d338200e2b
+27
-3
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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,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>
|
||||||
|
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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,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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
const unsigned short** addrOfClassInfoTable;
|
private:
|
||||||
const int** addrOfToLowerTable;
|
const unsigned short* localClassInfoTable;
|
||||||
const int** addrOfToUpperTable;
|
const int* localToLowerTable;
|
||||||
|
const int* localToUpperTable;
|
||||||
|
|
||||||
const unsigned short* posixClassInfo;
|
public:
|
||||||
const int* posixToLowerMap;
|
const unsigned short** addrOfClassInfoTable;
|
||||||
const int* posixToUpperMap;
|
const int** addrOfToLowerTable;
|
||||||
|
const int** addrOfToUpperTable;
|
||||||
|
|
||||||
LocaleCtypeDataBridge();
|
const unsigned short* const posixClassInfo;
|
||||||
|
const int* const posixToLowerMap;
|
||||||
|
const int* const posixToUpperMap;
|
||||||
|
|
||||||
|
bool isGlobal;
|
||||||
|
|
||||||
|
LocaleCtypeDataBridge(bool isGlobal);
|
||||||
|
|
||||||
void setMbCurMax(unsigned short mbCurMax);
|
void 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
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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 ]
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 ;
|
||||||
|
|||||||
@@ -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, axeld@pinc-software.de
|
||||||
|
* Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "LocaleInternal.h"
|
||||||
|
|
||||||
|
#include <locale.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
|
#include <Debug.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
namespace Libroot {
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
GetLocalesFromEnvironment(int category, const char** locales)
|
||||||
|
{
|
||||||
|
if (category > LC_LAST) {
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* locale = getenv("LC_ALL");
|
||||||
|
if (locale != NULL && *locale != '\0')
|
||||||
|
locales[category] = locale;
|
||||||
|
else {
|
||||||
|
// the order of the names must match the one specified in locale.h
|
||||||
|
const char* const categoryNames[] = {
|
||||||
|
"LC_ALL",
|
||||||
|
"LC_COLLATE",
|
||||||
|
"LC_CTYPE",
|
||||||
|
"LC_MONETARY",
|
||||||
|
"LC_NUMERIC",
|
||||||
|
"LC_TIME",
|
||||||
|
"LC_MESSAGES"
|
||||||
|
};
|
||||||
|
|
||||||
|
STATIC_ASSERT(B_COUNT_OF(categoryNames) == LC_LAST + 1);
|
||||||
|
|
||||||
|
int from, to;
|
||||||
|
if (category == LC_ALL) {
|
||||||
|
// we need to check each real category if all of them should be set
|
||||||
|
from = 1;
|
||||||
|
to = LC_LAST;
|
||||||
|
} else
|
||||||
|
from = to = category;
|
||||||
|
bool haveDifferentLocales = false;
|
||||||
|
locale = NULL;
|
||||||
|
for (int lc = from; lc <= to; lc++) {
|
||||||
|
const char* lastLocale = locale;
|
||||||
|
locale = getenv(categoryNames[lc]);
|
||||||
|
if (locale == NULL || *locale == '\0')
|
||||||
|
locale = getenv("LANG");
|
||||||
|
if (locale == NULL || *locale == '\0')
|
||||||
|
locale = "POSIX";
|
||||||
|
locales[lc] = locale;
|
||||||
|
if (lastLocale != NULL && strcasecmp(locale, lastLocale) != 0)
|
||||||
|
haveDifferentLocales = true;
|
||||||
|
}
|
||||||
|
if (!haveDifferentLocales) {
|
||||||
|
// we can set all locales at once
|
||||||
|
locales[LC_ALL] = locale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Libroot
|
||||||
|
} // namespace BPrivate
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de
|
||||||
|
* Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define LOCALE_T_MAGIC 'LOCA'
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
namespace Libroot {
|
||||||
|
|
||||||
|
|
||||||
|
status_t GetLocalesFromEnvironment(int category, const char** locales);
|
||||||
|
|
||||||
|
} // namespace Libroot
|
||||||
|
} // namespace BPrivate
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022, Trung Nguyen, trungnt282910@gmail.com
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <tls.h>
|
||||||
|
#include <kernel/OS.h>
|
||||||
|
#include <ThreadLocale.h>
|
||||||
|
|
||||||
|
|
||||||
|
// From glibc's localeinfo.h
|
||||||
|
extern BPrivate::Libroot::GlibcLocaleStruct _nl_global_locale;
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
namespace Libroot {
|
||||||
|
|
||||||
|
|
||||||
|
static void DestroyThreadLocale(void* ptr)
|
||||||
|
{
|
||||||
|
ThreadLocale* threadLocale = (ThreadLocale*)ptr;
|
||||||
|
delete threadLocale;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ThreadLocale*
|
||||||
|
GetCurrentThreadLocale()
|
||||||
|
{
|
||||||
|
ThreadLocale* threadLocale = (ThreadLocale*)tls_get(TLS_LOCALE_SLOT);
|
||||||
|
if (threadLocale == NULL) {
|
||||||
|
threadLocale = new ThreadLocale();
|
||||||
|
threadLocale->glibcLocaleStruct = _nl_global_locale;
|
||||||
|
threadLocale->threadLocaleInfo = NULL;
|
||||||
|
on_exit_thread(DestroyThreadLocale, threadLocale);
|
||||||
|
tls_set(TLS_LOCALE_SLOT, threadLocale);
|
||||||
|
}
|
||||||
|
return threadLocale;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Exported so that glibc could also use.
|
||||||
|
extern "C" GlibcLocaleStruct*
|
||||||
|
_nl_current_locale()
|
||||||
|
{
|
||||||
|
return &GetCurrentThreadLocale()->glibcLocaleStruct;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" const unsigned short**
|
||||||
|
__ctype_b_loc()
|
||||||
|
{
|
||||||
|
return &GetCurrentThreadLocale()->glibcLocaleStruct.__ctype_b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" const int**
|
||||||
|
__ctype_tolower_loc()
|
||||||
|
{
|
||||||
|
return &GetCurrentThreadLocale()->glibcLocaleStruct.__ctype_tolower;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" const int**
|
||||||
|
__ctype_toupper_loc()
|
||||||
|
{
|
||||||
|
return &GetCurrentThreadLocale()->glibcLocaleStruct.__ctype_toupper;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Libroot
|
||||||
|
} // namespace BPrivate
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022, Trung Nguyen, trungnt282910@gmail.com
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <locale.h>
|
||||||
|
|
||||||
|
#include <LocaleBackend.h>
|
||||||
|
#include <PosixCtype.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
namespace Libroot {
|
||||||
|
|
||||||
|
|
||||||
|
// A NULL databridge means that the object represents the POSIX locale.
|
||||||
|
static const unsigned short*
|
||||||
|
GetClassInfoTable(locale_t l)
|
||||||
|
{
|
||||||
|
LocaleBackendData* locale = (LocaleBackendData*)l;
|
||||||
|
|
||||||
|
if (locale->databridge == NULL) {
|
||||||
|
return &gPosixClassInfo[128];
|
||||||
|
}
|
||||||
|
return *locale->databridge->ctypeDataBridge.addrOfClassInfoTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const int*
|
||||||
|
GetToUpperTable(locale_t l)
|
||||||
|
{
|
||||||
|
LocaleBackendData* locale = (LocaleBackendData*)l;
|
||||||
|
|
||||||
|
if (locale->databridge == NULL) {
|
||||||
|
return &gPosixToUpperMap[128];
|
||||||
|
}
|
||||||
|
return *locale->databridge->ctypeDataBridge.addrOfToUpperTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const int*
|
||||||
|
GetToLowerTable(locale_t l)
|
||||||
|
{
|
||||||
|
LocaleBackendData* locale = (LocaleBackendData*)l;
|
||||||
|
|
||||||
|
if (locale->databridge == NULL) {
|
||||||
|
return &gPosixToLowerMap[128];
|
||||||
|
}
|
||||||
|
return *locale->databridge->ctypeDataBridge.addrOfToLowerTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
isalnum_l(int c, locale_t l)
|
||||||
|
{
|
||||||
|
if (c >= -128 && c < 256)
|
||||||
|
return GetClassInfoTable(l)[c] & (_ISupper | _ISlower | _ISdigit);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
isalpha_l(int c, locale_t l)
|
||||||
|
{
|
||||||
|
if (c >= -128 && c < 256)
|
||||||
|
return GetClassInfoTable(l)[c] & (_ISupper | _ISlower);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
isblank_l(int c, locale_t l)
|
||||||
|
{
|
||||||
|
if (c >= -128 && c < 256)
|
||||||
|
return GetClassInfoTable(l)[c] & _ISblank;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
iscntrl_l(int c, locale_t l)
|
||||||
|
{
|
||||||
|
if (c >= -128 && c < 256)
|
||||||
|
return GetClassInfoTable(l)[c] & _IScntrl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
isdigit_l(int c, locale_t l)
|
||||||
|
{
|
||||||
|
if (c >= -128 && c < 256)
|
||||||
|
return GetClassInfoTable(l)[c] & _ISdigit;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
isgraph_l(int c, locale_t l)
|
||||||
|
{
|
||||||
|
if (c >= -128 && c < 256)
|
||||||
|
return GetClassInfoTable(l)[c] & _ISgraph;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
islower_l(int c, locale_t l)
|
||||||
|
{
|
||||||
|
if (c >= -128 && c < 256)
|
||||||
|
return GetClassInfoTable(l)[c] & _ISlower;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
isprint_l(int c, locale_t l)
|
||||||
|
{
|
||||||
|
if (c >= -128 && c < 256)
|
||||||
|
return GetClassInfoTable(l)[c] & _ISprint;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ispunct_l(int c, locale_t l)
|
||||||
|
{
|
||||||
|
if (c >= -128 && c < 256)
|
||||||
|
return GetClassInfoTable(l)[c] & _ISpunct;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
isspace_l(int c, locale_t l)
|
||||||
|
{
|
||||||
|
if (c >= -128 && c < 256)
|
||||||
|
return GetClassInfoTable(l)[c] & _ISspace;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
isupper_l(int c, locale_t l)
|
||||||
|
{
|
||||||
|
if (c >= -128 && c < 256)
|
||||||
|
return GetClassInfoTable(l)[c] & _ISupper;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
isxdigit_l(int c, locale_t l)
|
||||||
|
{
|
||||||
|
if (c >= -128 && c < 256)
|
||||||
|
return GetClassInfoTable(l)[c] & _ISxdigit;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
tolower_l(int c, locale_t l)
|
||||||
|
{
|
||||||
|
if (c >= -128 && c < 256)
|
||||||
|
return GetToLowerTable(l)[c];
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
toupper_l(int c, locale_t l)
|
||||||
|
{
|
||||||
|
if (c >= -128 && c < 256)
|
||||||
|
return GetToUpperTable(l)[c];
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Libroot
|
||||||
|
} // namespace BPrivate
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022, Trung Nguyen, trungnt282910@gmail.com
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
|
||||||
|
// These functions are intended for scenarios where we cannot
|
||||||
|
// link to the whole libroot and access pthread functions;
|
||||||
|
// for example, when we're in the bootloader, kernel or the
|
||||||
|
// runtime_loader.
|
||||||
|
|
||||||
|
extern "C" const unsigned short**
|
||||||
|
__ctype_b_loc()
|
||||||
|
{
|
||||||
|
return &__ctype_b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" const int**
|
||||||
|
__ctype_tolower_loc()
|
||||||
|
{
|
||||||
|
return &__ctype_tolower;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" const int**
|
||||||
|
__ctype_toupper_loc()
|
||||||
|
{
|
||||||
|
return &__ctype_toupper;
|
||||||
|
}
|
||||||
@@ -0,0 +1,238 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022, Trung Nguyen, trungnt282910@gmail.com
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
|
#include <ErrnoMaintainer.h>
|
||||||
|
|
||||||
|
#include "LocaleBackend.h"
|
||||||
|
#include "LocaleInternal.h"
|
||||||
|
|
||||||
|
|
||||||
|
using BPrivate::Libroot::gGlobalLocaleBackend;
|
||||||
|
using BPrivate::Libroot::gGlobalLocaleDataBridge;
|
||||||
|
using BPrivate::Libroot::GetCurrentLocaleInfo;
|
||||||
|
using BPrivate::Libroot::GetLocalesFromEnvironment;
|
||||||
|
using BPrivate::Libroot::LocaleBackend;
|
||||||
|
using BPrivate::Libroot::LocaleBackendData;
|
||||||
|
using BPrivate::Libroot::LocaleDataBridge;
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" locale_t
|
||||||
|
duplocale(locale_t l)
|
||||||
|
{
|
||||||
|
LocaleBackendData* locObj = (LocaleBackendData*)l;
|
||||||
|
|
||||||
|
LocaleBackendData* newObj = new (std::nothrow) LocaleBackendData;
|
||||||
|
if (newObj == NULL) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return (locale_t)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocaleBackend* backend = (l == LC_GLOBAL_LOCALE) ?
|
||||||
|
gGlobalLocaleBackend : (LocaleBackend*)locObj->backend;
|
||||||
|
|
||||||
|
if (backend == NULL) {
|
||||||
|
newObj->backend = NULL;
|
||||||
|
return (locale_t)newObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if everything is set to "C" or "POSIX",
|
||||||
|
// and avoid making a backend.
|
||||||
|
const char* localeDescription = backend->SetLocale(LC_ALL, NULL);
|
||||||
|
|
||||||
|
if ((strcasecmp(localeDescription, "POSIX") == 0)
|
||||||
|
|| (strcasecmp(localeDescription, "C") == 0)) {
|
||||||
|
newObj->backend = NULL;
|
||||||
|
return (locale_t)newObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
BPrivate::ErrnoMaintainer errnoMaintainer;
|
||||||
|
|
||||||
|
LocaleBackend*& newBackend = newObj->backend;
|
||||||
|
LocaleDataBridge*& newDataBridge = newObj->databridge;
|
||||||
|
newBackend = LocaleBackend::CreateBackend();
|
||||||
|
|
||||||
|
if (newBackend == NULL) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
delete newObj;
|
||||||
|
return (locale_t)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
newDataBridge = new (std::nothrow) LocaleDataBridge(false);
|
||||||
|
|
||||||
|
if (newDataBridge == NULL) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
delete newBackend;
|
||||||
|
delete newObj;
|
||||||
|
return (locale_t)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
newBackend->Initialize(newDataBridge);
|
||||||
|
|
||||||
|
// Skipping LC_ALL. Asking for LC_ALL would force the backend
|
||||||
|
// to query each other value once, anyway.
|
||||||
|
for (int lc = 1; lc <= LC_LAST; ++lc) {
|
||||||
|
newBackend->SetLocale(lc, backend->SetLocale(lc, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (locale_t)newObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void
|
||||||
|
freelocale(locale_t l)
|
||||||
|
{
|
||||||
|
LocaleBackendData* locobj = (LocaleBackendData*)l;
|
||||||
|
|
||||||
|
if (locobj->backend) {
|
||||||
|
LocaleBackend::DestroyBackend(locobj->backend);
|
||||||
|
LocaleDataBridge* databridge = locobj->databridge;
|
||||||
|
delete databridge;
|
||||||
|
}
|
||||||
|
delete locobj;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" locale_t
|
||||||
|
newlocale(int category_mask, const char* locale, locale_t base)
|
||||||
|
{
|
||||||
|
if (((category_mask | LC_ALL_MASK) != LC_ALL_MASK) || (locale == NULL)) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return (locale_t)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool newObject = false;
|
||||||
|
LocaleBackendData* localeObject = (LocaleBackendData*)base;
|
||||||
|
|
||||||
|
if (localeObject == NULL) {
|
||||||
|
localeObject = new (std::nothrow) LocaleBackendData;
|
||||||
|
if (localeObject == NULL) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return (locale_t)0;
|
||||||
|
}
|
||||||
|
localeObject->magic = LOCALE_T_MAGIC;
|
||||||
|
localeObject->backend = NULL;
|
||||||
|
localeObject->databridge = NULL;
|
||||||
|
|
||||||
|
newObject = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocaleBackend*& backend = localeObject->backend;
|
||||||
|
LocaleDataBridge*& databridge = localeObject->databridge;
|
||||||
|
|
||||||
|
const char* locales[LC_LAST + 1];
|
||||||
|
for (int lc = 0; lc <= LC_LAST; lc++)
|
||||||
|
locales[lc] = NULL;
|
||||||
|
|
||||||
|
if (*locale == '\0') {
|
||||||
|
if (category_mask == LC_ALL_MASK) {
|
||||||
|
GetLocalesFromEnvironment(LC_ALL, locales);
|
||||||
|
} else {
|
||||||
|
for (int lc = 1; lc <= LC_LAST; ++lc) {
|
||||||
|
if (category_mask & (1 << (lc - 1))) {
|
||||||
|
GetLocalesFromEnvironment(lc, locales);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (category_mask == LC_ALL_MASK) {
|
||||||
|
locales[LC_ALL] = locale;
|
||||||
|
}
|
||||||
|
for (int lc = 1; lc <= LC_LAST; ++lc) {
|
||||||
|
if (category_mask & (1 << (lc - 1))) {
|
||||||
|
locales[lc] = locale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (backend == NULL) {
|
||||||
|
// for any locale other than POSIX/C, we try to activate the ICU
|
||||||
|
// backend
|
||||||
|
bool needBackend = false;
|
||||||
|
for (int lc = 0; lc <= LC_LAST; lc++) {
|
||||||
|
if (locales[lc] != NULL && strcasecmp(locales[lc], "POSIX") != 0
|
||||||
|
&& strcasecmp(locales[lc], "C") != 0) {
|
||||||
|
needBackend = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needBackend) {
|
||||||
|
backend = LocaleBackend::CreateBackend();
|
||||||
|
if (backend == NULL) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
if (newObject) {
|
||||||
|
delete localeObject;
|
||||||
|
}
|
||||||
|
return (locale_t)0;
|
||||||
|
}
|
||||||
|
databridge = new (std::nothrow) LocaleDataBridge(false);
|
||||||
|
if (databridge == NULL) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
delete backend;
|
||||||
|
if (newObject) {
|
||||||
|
delete localeObject;
|
||||||
|
}
|
||||||
|
return (locale_t)0;
|
||||||
|
}
|
||||||
|
backend->Initialize(databridge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BPrivate::ErrnoMaintainer errnoMaintainer;
|
||||||
|
|
||||||
|
if (backend != NULL) {
|
||||||
|
for (int lc = 0; lc <= LC_LAST; lc++) {
|
||||||
|
if (locales[lc] != NULL) {
|
||||||
|
locale = backend->SetLocale(lc, locales[lc]);
|
||||||
|
if (lc == LC_ALL) {
|
||||||
|
// skip the rest, LC_ALL overrides
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (locale_t)localeObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" locale_t
|
||||||
|
uselocale(locale_t newLoc)
|
||||||
|
{
|
||||||
|
locale_t oldLoc = (locale_t)GetCurrentLocaleInfo();
|
||||||
|
if (oldLoc == NULL) {
|
||||||
|
oldLoc = LC_GLOBAL_LOCALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newLoc != (locale_t)0) {
|
||||||
|
// Avoid expensive TLS reads with a local variable.
|
||||||
|
locale_t appliedLoc = oldLoc;
|
||||||
|
|
||||||
|
if (newLoc == LC_GLOBAL_LOCALE) {
|
||||||
|
appliedLoc = NULL;
|
||||||
|
} else {
|
||||||
|
if (((LocaleBackendData*)newLoc)->magic != LOCALE_T_MAGIC) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return (locale_t)0;
|
||||||
|
}
|
||||||
|
appliedLoc = newLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetCurrentLocaleInfo((LocaleBackendData*)appliedLoc);
|
||||||
|
|
||||||
|
if (appliedLoc != NULL) {
|
||||||
|
((LocaleBackendData*)appliedLoc)->databridge->ApplyToCurrentThread();
|
||||||
|
} else {
|
||||||
|
gGlobalLocaleDataBridge.ApplyToCurrentThread();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return oldLoc;
|
||||||
|
}
|
||||||
@@ -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]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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, trungnt282910@gmail.com
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <wctype.h>
|
||||||
|
|
||||||
|
#include <errno_private.h>
|
||||||
|
|
||||||
|
#include "LocaleBackend.h"
|
||||||
|
|
||||||
|
|
||||||
|
using BPrivate::Libroot::GetCurrentLocaleBackend;
|
||||||
|
using BPrivate::Libroot::LocaleBackend;
|
||||||
|
using BPrivate::Libroot::LocaleBackendData;
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
iswctype_l(wint_t wc, wctype_t charClass, locale_t l)
|
||||||
|
{
|
||||||
|
LocaleBackendData* locale = (LocaleBackendData*)l;
|
||||||
|
LocaleBackend* backend = locale->backend;
|
||||||
|
|
||||||
|
if (backend == NULL) {
|
||||||
|
if (wc < 0 || wc > 127)
|
||||||
|
return 0;
|
||||||
|
return __isctype(wc, charClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
return backend->IsWCType(wc, charClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
iswalnum_l(wint_t wc, locale_t locale)
|
||||||
|
{
|
||||||
|
return iswctype_l(wc, _ISalnum, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
iswalpha_l(wint_t wc, locale_t locale)
|
||||||
|
{
|
||||||
|
return iswctype_l(wc, _ISalpha, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
iswblank_l(wint_t wc, locale_t locale)
|
||||||
|
{
|
||||||
|
return iswctype_l(wc, _ISblank, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
iswcntrl_l(wint_t wc, locale_t locale)
|
||||||
|
{
|
||||||
|
return iswctype_l(wc, _IScntrl, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
iswdigit_l(wint_t wc, locale_t locale)
|
||||||
|
{
|
||||||
|
return iswctype_l(wc, _ISdigit, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
iswgraph_l(wint_t wc, locale_t locale)
|
||||||
|
{
|
||||||
|
return iswctype_l(wc, _ISgraph, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
iswlower_l(wint_t wc, locale_t locale)
|
||||||
|
{
|
||||||
|
return iswctype_l(wc, _ISlower, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
iswprint_l(wint_t wc, locale_t locale)
|
||||||
|
{
|
||||||
|
return iswctype_l(wc, _ISprint, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
iswpunct_l(wint_t wc, locale_t locale)
|
||||||
|
{
|
||||||
|
return iswctype_l(wc, _ISpunct, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
iswspace_l(wint_t wc, locale_t locale)
|
||||||
|
{
|
||||||
|
return iswctype_l(wc, _ISspace, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
iswupper_l(wint_t wc, locale_t locale)
|
||||||
|
{
|
||||||
|
return iswctype_l(wc, _ISupper, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
iswxdigit_l(wint_t wc, locale_t locale)
|
||||||
|
{
|
||||||
|
return iswctype_l(wc, _ISxdigit, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wint_t
|
||||||
|
towlower_l(wint_t wc, locale_t l)
|
||||||
|
{
|
||||||
|
LocaleBackendData* locale = (LocaleBackendData*)l;
|
||||||
|
LocaleBackend* backend = locale->backend;
|
||||||
|
|
||||||
|
if (backend == NULL) {
|
||||||
|
if (wc < 0 || wc > 127)
|
||||||
|
return wc;
|
||||||
|
return tolower(wc);
|
||||||
|
}
|
||||||
|
|
||||||
|
wint_t result = wc;
|
||||||
|
backend->ToWCTrans(wc, _ISlower, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wint_t
|
||||||
|
towupper_l(wint_t wc, locale_t l)
|
||||||
|
{
|
||||||
|
LocaleBackendData* locale = (LocaleBackendData*)l;
|
||||||
|
LocaleBackend* backend = locale->backend;
|
||||||
|
|
||||||
|
if (backend == NULL) {
|
||||||
|
if (wc < 0 || wc > 127)
|
||||||
|
return wc;
|
||||||
|
return toupper(wc);
|
||||||
|
}
|
||||||
|
|
||||||
|
wint_t result = wc;
|
||||||
|
backend->ToWCTrans(wc, _ISupper, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wint_t
|
||||||
|
towctrans_l(wint_t wc, wctrans_t transition, locale_t l)
|
||||||
|
{
|
||||||
|
LocaleBackendData* locale = (LocaleBackendData*)l;
|
||||||
|
LocaleBackend* backend = locale->backend;
|
||||||
|
|
||||||
|
if (backend == NULL) {
|
||||||
|
if (transition == _ISlower)
|
||||||
|
return tolower(wc);
|
||||||
|
if (transition == _ISupper)
|
||||||
|
return toupper(wc);
|
||||||
|
|
||||||
|
__set_errno(EINVAL);
|
||||||
|
return wc;
|
||||||
|
}
|
||||||
|
|
||||||
|
wint_t result = wc;
|
||||||
|
status_t status = backend->ToWCTrans(wc, transition, result);
|
||||||
|
if (status != B_OK)
|
||||||
|
__set_errno(EINVAL);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wctrans_t
|
||||||
|
wctrans_l(const char *charClass, locale_t locale)
|
||||||
|
{
|
||||||
|
(void)locale;
|
||||||
|
|
||||||
|
if (charClass != NULL) {
|
||||||
|
// we do not know any locale-specific character classes
|
||||||
|
if (strcmp(charClass, "tolower") == 0)
|
||||||
|
return _ISlower;
|
||||||
|
if (strcmp(charClass, "toupper") == 0)
|
||||||
|
return _ISupper;
|
||||||
|
}
|
||||||
|
|
||||||
|
__set_errno(EINVAL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wctype_t
|
||||||
|
wctype_l(const char *property, locale_t locale)
|
||||||
|
{
|
||||||
|
(void)locale;
|
||||||
|
|
||||||
|
// currently, we do not support any locale-specific properties
|
||||||
|
if (strcmp(property, "alnum") == 0)
|
||||||
|
return _ISalnum;
|
||||||
|
if (strcmp(property, "alpha") == 0)
|
||||||
|
return _ISalpha;
|
||||||
|
if (strcmp(property, "blank") == 0)
|
||||||
|
return _ISblank;
|
||||||
|
if (strcmp(property, "cntrl") == 0)
|
||||||
|
return _IScntrl;
|
||||||
|
if (strcmp(property, "digit") == 0)
|
||||||
|
return _ISdigit;
|
||||||
|
if (strcmp(property, "graph") == 0)
|
||||||
|
return _ISgraph;
|
||||||
|
if (strcmp(property, "lower") == 0)
|
||||||
|
return _ISlower;
|
||||||
|
if (strcmp(property, "print") == 0)
|
||||||
|
return _ISprint;
|
||||||
|
if (strcmp(property, "punct") == 0)
|
||||||
|
return _ISpunct;
|
||||||
|
if (strcmp(property, "space") == 0)
|
||||||
|
return _ISspace;
|
||||||
|
if (strcmp(property, "upper") == 0)
|
||||||
|
return _ISupper;
|
||||||
|
if (strcmp(property, "xdigit") == 0)
|
||||||
|
return _ISxdigit;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
struct lconv* lc = localeconv();
|
||||||
|
va_start(ap, format);
|
||||||
|
return __strfmon(s, maxsize, lc, format, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
strfmon_l(char *s, size_t maxsize, locale_t locale, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
struct lconv* lc = localeconv_l(locale);
|
||||||
|
va_start(ap, format);
|
||||||
|
return __strfmon(s, maxsize, lc, format, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
__strfmon(char *s, size_t maxsize, struct lconv* lc, const char *format, va_list ap)
|
||||||
{
|
{
|
||||||
va_list ap;
|
|
||||||
char *dst; /* output destination pointer */
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 '%':
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user