1 | /* |
---|
2 | FUNCTION |
---|
3 | <<newlocale>>---create or modify a locale object |
---|
4 | |
---|
5 | INDEX |
---|
6 | newlocale |
---|
7 | |
---|
8 | INDEX |
---|
9 | _newlocale_r |
---|
10 | |
---|
11 | SYNOPSIS |
---|
12 | #include <locale.h> |
---|
13 | locale_t newlocale(int <[category_mask]>, const char *<[locale]>, |
---|
14 | locale_t <[locobj]>); |
---|
15 | |
---|
16 | locale_t _newlocale_r(void *<[reent]>, int <[category_mask]>, |
---|
17 | const char *<[locale]>, locale_t <[locobj]>); |
---|
18 | |
---|
19 | DESCRIPTION |
---|
20 | The <<newlocale>> function shall create a new locale object or modify an |
---|
21 | existing one. If the base argument is (locale_t) <<0>>, a new locale |
---|
22 | object shall be created. It is unspecified whether the locale object |
---|
23 | pointed to by base shall be modified, or freed and a new locale object |
---|
24 | created. |
---|
25 | |
---|
26 | The category_mask argument specifies the locale categories to be set or |
---|
27 | modified. Values for category_mask shall be constructed by a |
---|
28 | bitwise-inclusive OR of the symbolic constants LC_CTYPE_MASK, |
---|
29 | LC_NUMERIC_MASK, LC_TIME_MASK, LC_COLLATE_MASK, LC_MONETARY_MASK, and |
---|
30 | LC_MESSAGES_MASK, or any of the other implementation-defined LC_*_MASK |
---|
31 | values defined in <locale.h>. |
---|
32 | |
---|
33 | For each category with the corresponding bit set in category_mask the |
---|
34 | data from the locale named by locale shall be used. In the case of |
---|
35 | modifying an existing locale object, the data from the locale named by |
---|
36 | locale shall replace the existing data within the locale object. If a |
---|
37 | completely new locale object is created, the data for all sections not |
---|
38 | requested by category_mask shall be taken from the default locale. |
---|
39 | |
---|
40 | The following preset values of locale are defined for all settings of |
---|
41 | category_mask: |
---|
42 | |
---|
43 | "POSIX" Specifies the minimal environment for C-language translation |
---|
44 | called the POSIX locale. |
---|
45 | |
---|
46 | "C" Equivalent to "POSIX". |
---|
47 | |
---|
48 | "" Specifies an implementation-defined native environment. This |
---|
49 | corresponds to the value of the associated environment variables, |
---|
50 | LC_* and LANG; see the Base Definitions volume of POSIX.1‐2008, |
---|
51 | Chapter 7, Locale and Chapter 8, Environment Variables. |
---|
52 | |
---|
53 | If the base argument is not (locale_t) <<0>> and the <<newlocale>> |
---|
54 | function call succeeds, the contents of base are unspecified. |
---|
55 | Applications shall ensure that they stop using base as a locale object |
---|
56 | before calling <<newlocale>>. If the function call fails and the base |
---|
57 | argument is not (locale_t) <<0>>, the contents of base shall remain |
---|
58 | valid and unchanged. |
---|
59 | |
---|
60 | The behavior is undefined if the base argument is the special locale |
---|
61 | object LC_GLOBAL_LOCALE, or is not a valid locale object handle and is |
---|
62 | not (locale_t) <<0>>. |
---|
63 | |
---|
64 | RETURNS |
---|
65 | Upon successful completion, the <<newlocale>> function shall return a |
---|
66 | handle which the caller may use on subsequent calls to <<duplocale>>, |
---|
67 | <<freelocale>>, and other functions taking a locale_t argument. |
---|
68 | |
---|
69 | Upon failure, the <<newlocale>> function shall return (locale_t) <<0>> |
---|
70 | and set errno to indicate the error. |
---|
71 | |
---|
72 | PORTABILITY |
---|
73 | <<newlocale>> is POSIX-1.2008. |
---|
74 | */ |
---|
75 | |
---|
76 | #include <newlib.h> |
---|
77 | #include <errno.h> |
---|
78 | #include <reent.h> |
---|
79 | #include <stdlib.h> |
---|
80 | #include "setlocale.h" |
---|
81 | |
---|
82 | #define LC_VALID_MASK (LC_COLLATE_MASK | LC_CTYPE_MASK | LC_MONETARY_MASK \ |
---|
83 | | LC_NUMERIC_MASK | LC_TIME_MASK | LC_MESSAGES_MASK) |
---|
84 | |
---|
85 | struct __locale_t * |
---|
86 | _newlocale_r (struct _reent *p, int category_mask, const char *locale, |
---|
87 | struct __locale_t *base) |
---|
88 | { |
---|
89 | #ifndef _MB_CAPABLE |
---|
90 | return __get_C_locale (); |
---|
91 | #else /* _MB_CAPABLE */ |
---|
92 | char new_categories[_LC_LAST][ENCODING_LEN + 1]; |
---|
93 | struct __locale_t tmp_locale, *new_locale; |
---|
94 | int i; |
---|
95 | |
---|
96 | /* Convert LC_ALL_MASK to a mask containing all valid MASK values. |
---|
97 | This simplifies the code below. */ |
---|
98 | if (category_mask & LC_ALL_MASK) |
---|
99 | { |
---|
100 | category_mask &= ~LC_ALL_MASK; |
---|
101 | category_mask |= LC_VALID_MASK; |
---|
102 | } |
---|
103 | /* Check for invalid mask values and valid locale ptr. */ |
---|
104 | if ((category_mask & ~LC_VALID_MASK) || !locale) |
---|
105 | { |
---|
106 | p->_errno = EINVAL; |
---|
107 | return NULL; |
---|
108 | } |
---|
109 | /* If the new locale is supposed to be all default locale, just return |
---|
110 | a pointer to the default locale. */ |
---|
111 | if ((!base && category_mask == 0) |
---|
112 | || (category_mask == LC_VALID_MASK |
---|
113 | && (!strcmp (locale, "C") || !strcmp (locale, "POSIX")))) |
---|
114 | return __get_C_locale (); |
---|
115 | /* Start with setting all values to the default locale values. */ |
---|
116 | tmp_locale = *__get_C_locale (); |
---|
117 | /* Fill out new category strings. */ |
---|
118 | for (i = 1; i < _LC_LAST; ++i) |
---|
119 | { |
---|
120 | if (((1 << i) & category_mask) != 0) |
---|
121 | { |
---|
122 | /* If locale is "", fetch from environment. Otherwise use locale |
---|
123 | name verbatim. */ |
---|
124 | const char *cat = (locale[0] == '\0') ? __get_locale_env (p, i) |
---|
125 | : locale; |
---|
126 | if (strlen (cat) > ENCODING_LEN) |
---|
127 | { |
---|
128 | p->_errno = EINVAL; |
---|
129 | return NULL; |
---|
130 | } |
---|
131 | strcpy (new_categories[i], cat); |
---|
132 | } |
---|
133 | else |
---|
134 | strcpy (new_categories[i], base ? base->categories[i] : "C"); |
---|
135 | } |
---|
136 | /* Now go over all categories and set them. */ |
---|
137 | for (i = 1; i < _LC_LAST; ++i) |
---|
138 | { |
---|
139 | /* If we have a base locale, and the category is not in category_mask |
---|
140 | or the new category is the base categroy, just copy over. */ |
---|
141 | if (base && (((1 << i) & category_mask) == 0 |
---|
142 | || !strcmp (base->categories[i], new_categories[i]))) |
---|
143 | { |
---|
144 | strcpy (tmp_locale.categories[i], new_categories[i]); |
---|
145 | if (i == LC_CTYPE) |
---|
146 | { |
---|
147 | tmp_locale.wctomb = base->wctomb; |
---|
148 | tmp_locale.mbtowc = base->mbtowc; |
---|
149 | tmp_locale.cjk_lang = base->cjk_lang; |
---|
150 | tmp_locale.ctype_ptr - base->ctype_ptr; |
---|
151 | } |
---|
152 | #ifdef __HAVE_LOCALE_INFO__ |
---|
153 | /* Mark the values as "has still to be copied". We do this in |
---|
154 | two steps to simplify freeing new locale types in case of a |
---|
155 | subsequent error. */ |
---|
156 | tmp_locale.lc_cat[i].ptr = base->lc_cat[i].ptr; |
---|
157 | tmp_locale.lc_cat[i].buf = (void *) -1; |
---|
158 | #else /* !__HAVE_LOCALE_INFO__ */ |
---|
159 | if (i == LC_CTYPE) |
---|
160 | strcpy (tmp_locale.ctype_codeset, base->ctype_codeset); |
---|
161 | else if (i == LC_MESSAGES) |
---|
162 | strcpy (tmp_locale.message_codeset, base->message_codeset); |
---|
163 | #endif /* !__HAVE_LOCALE_INFO__ */ |
---|
164 | } |
---|
165 | /* Otherwise, if the category is in category_mask, create entry. */ |
---|
166 | else if (((1 << i) & category_mask) != 0) |
---|
167 | { |
---|
168 | /* Nothing to do for "C"/"POSIX" locale. */ |
---|
169 | if (!strcmp (new_categories[i], "C") |
---|
170 | || !strcmp (new_categories[i], "POSIX")) |
---|
171 | continue; |
---|
172 | /* Otherwise load locale data. */ |
---|
173 | else if (!__loadlocale (&tmp_locale, i, new_categories[i])) |
---|
174 | goto error; |
---|
175 | } |
---|
176 | } |
---|
177 | /* Allocate new locale_t. */ |
---|
178 | new_locale = (struct __locale_t *) _calloc_r (p, 1, sizeof *new_locale); |
---|
179 | if (!new_locale) |
---|
180 | goto error; |
---|
181 | if (base) |
---|
182 | { |
---|
183 | #ifdef __HAVE_LOCALE_INFO__ |
---|
184 | /* Step 2 of copying over.. Make sure to invalidate the copied buffer |
---|
185 | pointers in base, so the subsequent _freelocale_r (base) doesn't free |
---|
186 | the buffers now used in the new locale. */ |
---|
187 | for (i = 1; i < _LC_LAST; ++i) |
---|
188 | if (tmp_locale.lc_cat[i].buf == (const void *) -1) |
---|
189 | { |
---|
190 | tmp_locale.lc_cat[i].buf = base->lc_cat[i].buf; |
---|
191 | base->lc_cat[i].ptr = base->lc_cat[i].buf = NULL; |
---|
192 | } |
---|
193 | #endif /* __HAVE_LOCALE_INFO__ */ |
---|
194 | _freelocale_r (p, base); |
---|
195 | } |
---|
196 | |
---|
197 | *new_locale = tmp_locale; |
---|
198 | return new_locale; |
---|
199 | |
---|
200 | error: |
---|
201 | /* An error occured while we had already (potentially) allocated memory. |
---|
202 | Free memory and return NULL. errno is supposed to be set already. */ |
---|
203 | #ifdef __HAVE_LOCALE_INFO__ |
---|
204 | for (i = 1; i < _LC_LAST; ++i) |
---|
205 | if (((1 << i) & category_mask) != 0 |
---|
206 | && tmp_locale.lc_cat[i].buf |
---|
207 | && tmp_locale.lc_cat[i].buf != (const void *) -1) |
---|
208 | { |
---|
209 | _free_r (p, (void *) tmp_locale.lc_cat[i].ptr); |
---|
210 | _free_r (p, tmp_locale.lc_cat[i].buf); |
---|
211 | } |
---|
212 | #endif /* __HAVE_LOCALE_INFO__ */ |
---|
213 | |
---|
214 | return NULL; |
---|
215 | #endif /* _MB_CAPABLE */ |
---|
216 | } |
---|
217 | |
---|
218 | struct __locale_t * |
---|
219 | newlocale (int category_mask, const char *locale, struct __locale_t *base) |
---|
220 | { |
---|
221 | return _newlocale_r (_REENT, category_mask, locale, base); |
---|
222 | } |
---|