1/*
2 * Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "LocaleBackend.h"
8
9#include <ctype.h>
10#include <langinfo.h>
11#include <string.h>
12#include <time.h>
13
14#include <PosixCtype.h>
15#include <PosixLanginfo.h>
16#include <PosixLCTimeInfo.h>
17#include <PosixLocaleConv.h>
18#include <ThreadLocale.h>
19
20
21extern const unsigned short* __ctype_b;
22extern const int* __ctype_tolower;
23extern const int* __ctype_toupper;
24
25
26namespace BPrivate {
27namespace Libroot {
28
29
30extern "C" GlibcLocaleStruct* _nl_current_locale();
31extern "C" GlibcLocaleStruct _nl_global_locale;
32#define _NL_CURRENT_DATA(category) \
33	((locale_data*&)(_nl_current_locale()->__locales[category]))
34#define _NL_GLOBAL_DATA(category) \
35	((locale_data*&)(_nl_global_locale.__locales[category]))
36
37
38LocaleCtypeDataBridge::LocaleCtypeDataBridge(bool isGlobal)
39	:
40	localClassInfoTable(__ctype_b),
41	localToLowerTable(__ctype_tolower),
42	localToUpperTable(__ctype_toupper),
43	posixClassInfo(gPosixClassInfo),
44	posixToLowerMap(gPosixToLowerMap),
45	posixToUpperMap(gPosixToUpperMap),
46	isGlobal(isGlobal)
47{
48	if (isGlobal) {
49		addrOfClassInfoTable = &__ctype_b;
50		addrOfToLowerTable = &__ctype_tolower;
51		addrOfToUpperTable = &__ctype_toupper;
52	} else {
53		addrOfClassInfoTable = &localClassInfoTable;
54		addrOfToLowerTable = &localToLowerTable;
55		addrOfToUpperTable = &localToUpperTable;
56	}
57}
58
59
60void LocaleCtypeDataBridge::setMbCurMax(unsigned short mbCurMax)
61{
62	__ctype_mb_cur_max = mbCurMax;
63}
64
65
66void
67LocaleCtypeDataBridge::ApplyToCurrentThread()
68{
69	*__ctype_b_loc() = *addrOfClassInfoTable;
70	*__ctype_tolower_loc() = *addrOfToLowerTable;
71	*__ctype_toupper_loc() = *addrOfToUpperTable;
72}
73
74
75LocaleMessagesDataBridge::LocaleMessagesDataBridge()
76	:
77	posixLanginfo(gPosixLanginfo)
78{
79}
80
81
82LocaleMonetaryDataBridge::LocaleMonetaryDataBridge()
83	:
84	posixLocaleConv(&gPosixLocaleConv)
85{
86}
87
88
89LocaleNumericDataBridge::LocaleNumericDataBridge(bool isGlobal)
90	:
91	posixLocaleConv(&gPosixLocaleConv),
92	glibcNumericLocale(&glibcNumericLocaleData),
93	isGlobal(isGlobal)
94{
95
96	memcpy(glibcNumericLocale, _NL_GLOBAL_DATA(GLIBC_LC_NUMERIC),
97		sizeof(GlibcNumericLocale));
98
99	if (isGlobal) {
100		originalGlibcLocale = _NL_GLOBAL_DATA(GLIBC_LC_NUMERIC);
101		_NL_GLOBAL_DATA(GLIBC_LC_NUMERIC) = (locale_data*)glibcNumericLocale;
102	}
103}
104
105
106LocaleNumericDataBridge::~LocaleNumericDataBridge()
107{
108	if (isGlobal) {
109		_NL_GLOBAL_DATA(GLIBC_LC_NUMERIC) = originalGlibcLocale;
110	} else if (_NL_CURRENT_DATA(GLIBC_LC_NUMERIC) == (locale_data*)glibcNumericLocale) {
111		_NL_CURRENT_DATA(GLIBC_LC_NUMERIC) = _NL_GLOBAL_DATA(GLIBC_LC_NUMERIC);
112	}
113}
114
115
116void
117LocaleNumericDataBridge::ApplyToCurrentThread()
118{
119	_NL_CURRENT_DATA(GLIBC_LC_NUMERIC) = (locale_data*)glibcNumericLocale;
120}
121
122
123LocaleTimeDataBridge::LocaleTimeDataBridge()
124	:
125	posixLCTimeInfo(&gPosixLCTimeInfo)
126{
127}
128
129
130TimeConversionDataBridge::TimeConversionDataBridge(bool isGlobal)
131	:
132	localDaylight(daylight),
133	localTimezone(timezone),
134	isGlobal(isGlobal)
135{
136	if (isGlobal) {
137		addrOfDaylight = &daylight;
138		addrOfTimezone = &timezone;
139		addrOfTZName = tzname;
140	} else {
141		addrOfDaylight = &localDaylight;
142		addrOfTimezone = &localTimezone;
143		addrOfTZName = localTZName;
144		addrOfTZName[0] = localTZName0;
145		addrOfTZName[1] = localTZName1;
146		strlcpy(localTZName0, tzname[0], sizeof(localTZName0));
147		strlcpy(localTZName1, tzname[1], sizeof(localTZName1));
148	}
149}
150
151
152LocaleDataBridge::LocaleDataBridge(bool isGlobal)
153	:
154	ctypeDataBridge(isGlobal),
155	numericDataBridge(isGlobal),
156	timeConversionDataBridge(isGlobal),
157	posixLanginfo(gPosixLanginfo),
158	isGlobal(isGlobal)
159{
160}
161
162
163void
164LocaleDataBridge::ApplyToCurrentThread()
165{
166	ctypeDataBridge.ApplyToCurrentThread();
167	numericDataBridge.ApplyToCurrentThread();
168	// While timeConverstionDataBridge stores read-write variables,
169	// these variables are global (by POSIX definition). Furthermore,
170	// none of the backends seem to access these variables
171	// directly. The values are set in the bridge mostly for
172	// synchronization purposes. Therefore, don't call
173	// ApplyToCurrentThread for this object.
174}
175
176
177}	// namespace Libroot
178}	// namespace BPrivate
179