diff options
Diffstat (limited to 'gl/nl_langinfo.c')
-rw-r--r-- | gl/nl_langinfo.c | 579 |
1 files changed, 440 insertions, 139 deletions
diff --git a/gl/nl_langinfo.c b/gl/nl_langinfo.c index 771c9533..b481f209 100644 --- a/gl/nl_langinfo.c +++ b/gl/nl_langinfo.c | |||
@@ -1,34 +1,278 @@ | |||
1 | /* nl_langinfo() replacement: query locale dependent information. | 1 | /* nl_langinfo() replacement: query locale dependent information. |
2 | 2 | ||
3 | Copyright (C) 2007-2013 Free Software Foundation, Inc. | 3 | Copyright (C) 2007-2021 Free Software Foundation, Inc. |
4 | 4 | ||
5 | This program is free software: you can redistribute it and/or modify | 5 | This file is free software: you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published by | 6 | it under the terms of the GNU Lesser General Public License as |
7 | the Free Software Foundation; either version 3 of the License, or | 7 | published by the Free Software Foundation; either version 2.1 of the |
8 | (at your option) any later version. | 8 | License, or (at your option) any later version. |
9 | 9 | ||
10 | This program is distributed in the hope that it will be useful, | 10 | This file is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. | 13 | GNU Lesser General Public License for more details. |
14 | 14 | ||
15 | You should have received a copy of the GNU General Public License | 15 | You should have received a copy of the GNU Lesser General Public License |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | 16 | along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
17 | 17 | ||
18 | #include <config.h> | 18 | #include <config.h> |
19 | 19 | ||
20 | /* Specification. */ | 20 | /* Specification. */ |
21 | #include <langinfo.h> | 21 | #include <langinfo.h> |
22 | 22 | ||
23 | #include <locale.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <string.h> | ||
26 | #if defined _WIN32 && ! defined __CYGWIN__ | ||
27 | # define WIN32_LEAN_AND_MEAN /* avoid including junk */ | ||
28 | # include <windows.h> | ||
29 | # include <stdio.h> | ||
30 | #endif | ||
31 | |||
32 | #if REPLACE_NL_LANGINFO && !NL_LANGINFO_MTSAFE | ||
33 | # if defined _WIN32 && !defined __CYGWIN__ | ||
34 | |||
35 | # define WIN32_LEAN_AND_MEAN /* avoid including junk */ | ||
36 | # include <windows.h> | ||
37 | |||
38 | # elif HAVE_PTHREAD_API | ||
39 | |||
40 | # include <pthread.h> | ||
41 | # if HAVE_THREADS_H && HAVE_WEAK_SYMBOLS | ||
42 | # include <threads.h> | ||
43 | # pragma weak thrd_exit | ||
44 | # define c11_threads_in_use() (thrd_exit != NULL) | ||
45 | # else | ||
46 | # define c11_threads_in_use() 0 | ||
47 | # endif | ||
48 | |||
49 | # elif HAVE_THREADS_H | ||
50 | |||
51 | # include <threads.h> | ||
52 | |||
53 | # endif | ||
54 | #endif | ||
55 | |||
56 | /* nl_langinfo() must be multithread-safe. To achieve this without using | ||
57 | thread-local storage: | ||
58 | 1. We use a specific static buffer for each possible argument. | ||
59 | So that different threads can call nl_langinfo with different arguments, | ||
60 | without interfering. | ||
61 | 2. We use a simple strcpy or memcpy to fill this static buffer. Filling it | ||
62 | through, for example, strcpy + strcat would not be guaranteed to leave | ||
63 | the buffer's contents intact if another thread is currently accessing | ||
64 | it. If necessary, the contents is first assembled in a stack-allocated | ||
65 | buffer. */ | ||
66 | |||
67 | #if !REPLACE_NL_LANGINFO || GNULIB_defined_CODESET | ||
68 | /* Return the codeset of the current locale, if this is easily deducible. | ||
69 | Otherwise, return "". */ | ||
70 | static char * | ||
71 | ctype_codeset (void) | ||
72 | { | ||
73 | static char result[2 + 10 + 1]; | ||
74 | char buf[2 + 10 + 1]; | ||
75 | char locale[SETLOCALE_NULL_MAX]; | ||
76 | char *codeset; | ||
77 | size_t codesetlen; | ||
78 | |||
79 | if (setlocale_null_r (LC_CTYPE, locale, sizeof (locale))) | ||
80 | locale[0] = '\0'; | ||
81 | |||
82 | codeset = buf; | ||
83 | codeset[0] = '\0'; | ||
84 | |||
85 | if (locale[0]) | ||
86 | { | ||
87 | /* If the locale name contains an encoding after the dot, return it. */ | ||
88 | char *dot = strchr (locale, '.'); | ||
89 | |||
90 | if (dot) | ||
91 | { | ||
92 | /* Look for the possible @... trailer and remove it, if any. */ | ||
93 | char *codeset_start = dot + 1; | ||
94 | char const *modifier = strchr (codeset_start, '@'); | ||
95 | |||
96 | if (! modifier) | ||
97 | codeset = codeset_start; | ||
98 | else | ||
99 | { | ||
100 | codesetlen = modifier - codeset_start; | ||
101 | if (codesetlen < sizeof buf) | ||
102 | { | ||
103 | codeset = memcpy (buf, codeset_start, codesetlen); | ||
104 | codeset[codesetlen] = '\0'; | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | } | ||
109 | |||
110 | # if defined _WIN32 && ! defined __CYGWIN__ | ||
111 | /* If setlocale is successful, it returns the number of the | ||
112 | codepage, as a string. Otherwise, fall back on Windows API | ||
113 | GetACP, which returns the locale's codepage as a number (although | ||
114 | this doesn't change according to what the 'setlocale' call specified). | ||
115 | Either way, prepend "CP" to make it a valid codeset name. */ | ||
116 | codesetlen = strlen (codeset); | ||
117 | if (0 < codesetlen && codesetlen < sizeof buf - 2) | ||
118 | memmove (buf + 2, codeset, codesetlen + 1); | ||
119 | else | ||
120 | sprintf (buf + 2, "%u", GetACP ()); | ||
121 | /* For a locale name such as "French_France.65001", in Windows 10, | ||
122 | setlocale now returns "French_France.utf8" instead. */ | ||
123 | if (strcmp (buf + 2, "65001") == 0 || strcmp (buf + 2, "utf8") == 0) | ||
124 | return (char *) "UTF-8"; | ||
125 | else | ||
126 | { | ||
127 | memcpy (buf, "CP", 2); | ||
128 | strcpy (result, buf); | ||
129 | return result; | ||
130 | } | ||
131 | # else | ||
132 | strcpy (result, codeset); | ||
133 | return result; | ||
134 | #endif | ||
135 | } | ||
136 | #endif | ||
137 | |||
138 | |||
23 | #if REPLACE_NL_LANGINFO | 139 | #if REPLACE_NL_LANGINFO |
24 | 140 | ||
25 | /* Override nl_langinfo with support for added nl_item values. */ | 141 | /* Override nl_langinfo with support for added nl_item values. */ |
26 | 142 | ||
27 | # include <locale.h> | ||
28 | # include <string.h> | ||
29 | |||
30 | # undef nl_langinfo | 143 | # undef nl_langinfo |
31 | 144 | ||
145 | /* Without locking, on Solaris 11.3, test-nl_langinfo-mt fails, with message | ||
146 | "thread5 disturbed by threadN!", even when threadN invokes only | ||
147 | nl_langinfo (CODESET); | ||
148 | nl_langinfo (CRNCYSTR); | ||
149 | Similarly on Solaris 10. */ | ||
150 | |||
151 | # if !NL_LANGINFO_MTSAFE /* Solaris */ | ||
152 | |||
153 | # define ITEMS (MAXSTRMSG + 1) | ||
154 | # define MAX_RESULT_LEN 80 | ||
155 | |||
156 | static char * | ||
157 | nl_langinfo_unlocked (nl_item item) | ||
158 | { | ||
159 | static char result[ITEMS][MAX_RESULT_LEN]; | ||
160 | |||
161 | /* The result of nl_langinfo is in storage that can be overwritten by | ||
162 | other calls to nl_langinfo. */ | ||
163 | char *tmp = nl_langinfo (item); | ||
164 | if (item >= 0 && item < ITEMS && tmp != NULL) | ||
165 | { | ||
166 | size_t tmp_len = strlen (tmp); | ||
167 | if (tmp_len < MAX_RESULT_LEN) | ||
168 | strcpy (result[item], tmp); | ||
169 | else | ||
170 | { | ||
171 | /* Produce a truncated result. Oh well... */ | ||
172 | result[item][MAX_RESULT_LEN - 1] = '\0'; | ||
173 | memcpy (result[item], tmp, MAX_RESULT_LEN - 1); | ||
174 | } | ||
175 | return result[item]; | ||
176 | } | ||
177 | else | ||
178 | return tmp; | ||
179 | } | ||
180 | |||
181 | /* Use a lock, so that no two threads can invoke nl_langinfo_unlocked | ||
182 | at the same time. */ | ||
183 | |||
184 | /* Prohibit renaming this symbol. */ | ||
185 | # undef gl_get_nl_langinfo_lock | ||
186 | |||
187 | # if defined _WIN32 && !defined __CYGWIN__ | ||
188 | |||
189 | extern __declspec(dllimport) CRITICAL_SECTION *gl_get_nl_langinfo_lock (void); | ||
190 | |||
191 | static char * | ||
192 | nl_langinfo_with_lock (nl_item item) | ||
193 | { | ||
194 | CRITICAL_SECTION *lock = gl_get_nl_langinfo_lock (); | ||
195 | char *ret; | ||
196 | |||
197 | EnterCriticalSection (lock); | ||
198 | ret = nl_langinfo_unlocked (item); | ||
199 | LeaveCriticalSection (lock); | ||
200 | |||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | # elif HAVE_PTHREAD_API | ||
205 | |||
206 | extern | ||
207 | # if defined _WIN32 || defined __CYGWIN__ | ||
208 | __declspec(dllimport) | ||
209 | # endif | ||
210 | pthread_mutex_t *gl_get_nl_langinfo_lock (void); | ||
211 | |||
212 | # if HAVE_WEAK_SYMBOLS /* musl libc, FreeBSD, NetBSD, OpenBSD, Haiku */ | ||
213 | |||
214 | /* Avoid the need to link with '-lpthread'. */ | ||
215 | # pragma weak pthread_mutex_lock | ||
216 | # pragma weak pthread_mutex_unlock | ||
217 | |||
218 | /* Determine whether libpthread is in use. */ | ||
219 | # pragma weak pthread_mutexattr_gettype | ||
220 | /* See the comments in lock.h. */ | ||
221 | # define pthread_in_use() \ | ||
222 | (pthread_mutexattr_gettype != NULL || c11_threads_in_use ()) | ||
223 | |||
224 | # else | ||
225 | # define pthread_in_use() 1 | ||
226 | # endif | ||
227 | |||
228 | static char * | ||
229 | nl_langinfo_with_lock (nl_item item) | ||
230 | { | ||
231 | if (pthread_in_use()) | ||
232 | { | ||
233 | pthread_mutex_t *lock = gl_get_nl_langinfo_lock (); | ||
234 | char *ret; | ||
235 | |||
236 | if (pthread_mutex_lock (lock)) | ||
237 | abort (); | ||
238 | ret = nl_langinfo_unlocked (item); | ||
239 | if (pthread_mutex_unlock (lock)) | ||
240 | abort (); | ||
241 | |||
242 | return ret; | ||
243 | } | ||
244 | else | ||
245 | return nl_langinfo_unlocked (item); | ||
246 | } | ||
247 | |||
248 | # elif HAVE_THREADS_H | ||
249 | |||
250 | extern mtx_t *gl_get_nl_langinfo_lock (void); | ||
251 | |||
252 | static char * | ||
253 | nl_langinfo_with_lock (nl_item item) | ||
254 | { | ||
255 | mtx_t *lock = gl_get_nl_langinfo_lock (); | ||
256 | char *ret; | ||
257 | |||
258 | if (mtx_lock (lock) != thrd_success) | ||
259 | abort (); | ||
260 | ret = nl_langinfo_unlocked (item); | ||
261 | if (mtx_unlock (lock) != thrd_success) | ||
262 | abort (); | ||
263 | |||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | # endif | ||
268 | |||
269 | # else | ||
270 | |||
271 | /* On other platforms, no lock is needed. */ | ||
272 | # define nl_langinfo_with_lock nl_langinfo | ||
273 | |||
274 | # endif | ||
275 | |||
32 | char * | 276 | char * |
33 | rpl_nl_langinfo (nl_item item) | 277 | rpl_nl_langinfo (nl_item item) |
34 | { | 278 | { |
@@ -36,47 +280,36 @@ rpl_nl_langinfo (nl_item item) | |||
36 | { | 280 | { |
37 | # if GNULIB_defined_CODESET | 281 | # if GNULIB_defined_CODESET |
38 | case CODESET: | 282 | case CODESET: |
39 | { | 283 | return ctype_codeset (); |
40 | const char *locale; | ||
41 | static char buf[2 + 10 + 1]; | ||
42 | |||
43 | locale = setlocale (LC_CTYPE, NULL); | ||
44 | if (locale != NULL && locale[0] != '\0') | ||
45 | { | ||
46 | /* If the locale name contains an encoding after the dot, return | ||
47 | it. */ | ||
48 | const char *dot = strchr (locale, '.'); | ||
49 | |||
50 | if (dot != NULL) | ||
51 | { | ||
52 | const char *modifier; | ||
53 | |||
54 | dot++; | ||
55 | /* Look for the possible @... trailer and remove it, if any. */ | ||
56 | modifier = strchr (dot, '@'); | ||
57 | if (modifier == NULL) | ||
58 | return dot; | ||
59 | if (modifier - dot < sizeof (buf)) | ||
60 | { | ||
61 | memcpy (buf, dot, modifier - dot); | ||
62 | buf [modifier - dot] = '\0'; | ||
63 | return buf; | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | return ""; | ||
68 | } | ||
69 | # endif | 284 | # endif |
70 | # if GNULIB_defined_T_FMT_AMPM | 285 | # if GNULIB_defined_T_FMT_AMPM |
71 | case T_FMT_AMPM: | 286 | case T_FMT_AMPM: |
72 | return "%I:%M:%S %p"; | 287 | return (char *) "%I:%M:%S %p"; |
288 | # endif | ||
289 | # if GNULIB_defined_ALTMON | ||
290 | case ALTMON_1: | ||
291 | case ALTMON_2: | ||
292 | case ALTMON_3: | ||
293 | case ALTMON_4: | ||
294 | case ALTMON_5: | ||
295 | case ALTMON_6: | ||
296 | case ALTMON_7: | ||
297 | case ALTMON_8: | ||
298 | case ALTMON_9: | ||
299 | case ALTMON_10: | ||
300 | case ALTMON_11: | ||
301 | case ALTMON_12: | ||
302 | /* We don't ship the appropriate localizations with gnulib. Therefore, | ||
303 | treat ALTMON_i like MON_i. */ | ||
304 | item = item - ALTMON_1 + MON_1; | ||
305 | break; | ||
73 | # endif | 306 | # endif |
74 | # if GNULIB_defined_ERA | 307 | # if GNULIB_defined_ERA |
75 | case ERA: | 308 | case ERA: |
76 | /* The format is not standardized. In glibc it is a sequence of strings | 309 | /* The format is not standardized. In glibc it is a sequence of strings |
77 | of the form "direction:offset:start_date:end_date:era_name:era_format" | 310 | of the form "direction:offset:start_date:end_date:era_name:era_format" |
78 | with an empty string at the end. */ | 311 | with an empty string at the end. */ |
79 | return ""; | 312 | return (char *) ""; |
80 | case ERA_D_FMT: | 313 | case ERA_D_FMT: |
81 | /* The %Ex conversion in strftime behaves like %x if the locale does not | 314 | /* The %Ex conversion in strftime behaves like %x if the locale does not |
82 | have an alternative time format. */ | 315 | have an alternative time format. */ |
@@ -95,176 +328,244 @@ rpl_nl_langinfo (nl_item item) | |||
95 | case ALT_DIGITS: | 328 | case ALT_DIGITS: |
96 | /* The format is not standardized. In glibc it is a sequence of 10 | 329 | /* The format is not standardized. In glibc it is a sequence of 10 |
97 | strings, appended in memory. */ | 330 | strings, appended in memory. */ |
98 | return "\0\0\0\0\0\0\0\0\0\0"; | 331 | return (char *) "\0\0\0\0\0\0\0\0\0\0"; |
99 | # endif | 332 | # endif |
100 | # if GNULIB_defined_YESEXPR || !FUNC_NL_LANGINFO_YESEXPR_WORKS | 333 | # if GNULIB_defined_YESEXPR || !FUNC_NL_LANGINFO_YESEXPR_WORKS |
101 | case YESEXPR: | 334 | case YESEXPR: |
102 | return "^[yY]"; | 335 | return (char *) "^[yY]"; |
103 | case NOEXPR: | 336 | case NOEXPR: |
104 | return "^[nN]"; | 337 | return (char *) "^[nN]"; |
105 | # endif | 338 | # endif |
106 | default: | 339 | default: |
107 | break; | 340 | break; |
108 | } | 341 | } |
109 | return nl_langinfo (item); | 342 | return nl_langinfo_with_lock (item); |
110 | } | 343 | } |
111 | 344 | ||
112 | #else | 345 | #else |
113 | 346 | ||
114 | /* Provide nl_langinfo from scratch. */ | 347 | /* Provide nl_langinfo from scratch, either for native MS-Windows, or |
115 | 348 | for old Unix platforms without locales, such as Linux libc5 or | |
116 | # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ | 349 | BeOS. */ |
117 | 350 | ||
118 | /* Native Windows platforms. */ | 351 | # include <time.h> |
119 | |||
120 | # define WIN32_LEAN_AND_MEAN /* avoid including junk */ | ||
121 | # include <windows.h> | ||
122 | |||
123 | # include <stdio.h> | ||
124 | |||
125 | # else | ||
126 | |||
127 | /* An old Unix platform without locales, such as Linux libc5 or BeOS. */ | ||
128 | |||
129 | # endif | ||
130 | |||
131 | # include <locale.h> | ||
132 | 352 | ||
133 | char * | 353 | char * |
134 | nl_langinfo (nl_item item) | 354 | nl_langinfo (nl_item item) |
135 | { | 355 | { |
356 | char buf[100]; | ||
357 | struct tm tmm = { 0 }; | ||
358 | |||
136 | switch (item) | 359 | switch (item) |
137 | { | 360 | { |
138 | /* nl_langinfo items of the LC_CTYPE category */ | 361 | /* nl_langinfo items of the LC_CTYPE category */ |
139 | case CODESET: | 362 | case CODESET: |
140 | # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ | ||
141 | { | 363 | { |
142 | static char buf[2 + 10 + 1]; | 364 | char *codeset = ctype_codeset (); |
143 | 365 | if (*codeset) | |
144 | /* The Windows API has a function returning the locale's codepage as | 366 | return codeset; |
145 | a number. */ | ||
146 | sprintf (buf, "CP%u", GetACP ()); | ||
147 | return buf; | ||
148 | } | 367 | } |
149 | # elif defined __BEOS__ | 368 | # ifdef __BEOS__ |
150 | return "UTF-8"; | 369 | return (char *) "UTF-8"; |
151 | # else | 370 | # else |
152 | return "ISO-8859-1"; | 371 | return (char *) "ISO-8859-1"; |
153 | # endif | 372 | # endif |
154 | /* nl_langinfo items of the LC_NUMERIC category */ | 373 | /* nl_langinfo items of the LC_NUMERIC category */ |
155 | case RADIXCHAR: | 374 | case RADIXCHAR: |
156 | return localeconv () ->decimal_point; | 375 | return localeconv () ->decimal_point; |
157 | case THOUSEP: | 376 | case THOUSEP: |
158 | return localeconv () ->thousands_sep; | 377 | return localeconv () ->thousands_sep; |
378 | # ifdef GROUPING | ||
379 | case GROUPING: | ||
380 | return localeconv () ->grouping; | ||
381 | # endif | ||
159 | /* nl_langinfo items of the LC_TIME category. | 382 | /* nl_langinfo items of the LC_TIME category. |
160 | TODO: Really use the locale. */ | 383 | TODO: Really use the locale. */ |
161 | case D_T_FMT: | 384 | case D_T_FMT: |
162 | case ERA_D_T_FMT: | 385 | case ERA_D_T_FMT: |
163 | return "%a %b %e %H:%M:%S %Y"; | 386 | return (char *) "%a %b %e %H:%M:%S %Y"; |
164 | case D_FMT: | 387 | case D_FMT: |
165 | case ERA_D_FMT: | 388 | case ERA_D_FMT: |
166 | return "%m/%d/%y"; | 389 | return (char *) "%m/%d/%y"; |
167 | case T_FMT: | 390 | case T_FMT: |
168 | case ERA_T_FMT: | 391 | case ERA_T_FMT: |
169 | return "%H:%M:%S"; | 392 | return (char *) "%H:%M:%S"; |
170 | case T_FMT_AMPM: | 393 | case T_FMT_AMPM: |
171 | return "%I:%M:%S %p"; | 394 | return (char *) "%I:%M:%S %p"; |
172 | case AM_STR: | 395 | case AM_STR: |
173 | return "AM"; | 396 | { |
397 | static char result[80]; | ||
398 | if (!strftime (buf, sizeof result, "%p", &tmm)) | ||
399 | return (char *) "AM"; | ||
400 | strcpy (result, buf); | ||
401 | return result; | ||
402 | } | ||
174 | case PM_STR: | 403 | case PM_STR: |
175 | return "PM"; | 404 | { |
405 | static char result[80]; | ||
406 | tmm.tm_hour = 12; | ||
407 | if (!strftime (buf, sizeof result, "%p", &tmm)) | ||
408 | return (char *) "PM"; | ||
409 | strcpy (result, buf); | ||
410 | return result; | ||
411 | } | ||
176 | case DAY_1: | 412 | case DAY_1: |
177 | return "Sunday"; | ||
178 | case DAY_2: | 413 | case DAY_2: |
179 | return "Monday"; | ||
180 | case DAY_3: | 414 | case DAY_3: |
181 | return "Tuesday"; | ||
182 | case DAY_4: | 415 | case DAY_4: |
183 | return "Wednesday"; | ||
184 | case DAY_5: | 416 | case DAY_5: |
185 | return "Thursday"; | ||
186 | case DAY_6: | 417 | case DAY_6: |
187 | return "Friday"; | ||
188 | case DAY_7: | 418 | case DAY_7: |
189 | return "Saturday"; | 419 | { |
420 | static char result[7][50]; | ||
421 | static char const days[][sizeof "Wednesday"] = { | ||
422 | "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", | ||
423 | "Friday", "Saturday" | ||
424 | }; | ||
425 | tmm.tm_wday = item - DAY_1; | ||
426 | if (!strftime (buf, sizeof result[0], "%A", &tmm)) | ||
427 | return (char *) days[item - DAY_1]; | ||
428 | strcpy (result[item - DAY_1], buf); | ||
429 | return result[item - DAY_1]; | ||
430 | } | ||
190 | case ABDAY_1: | 431 | case ABDAY_1: |
191 | return "Sun"; | ||
192 | case ABDAY_2: | 432 | case ABDAY_2: |
193 | return "Mon"; | ||
194 | case ABDAY_3: | 433 | case ABDAY_3: |
195 | return "Tue"; | ||
196 | case ABDAY_4: | 434 | case ABDAY_4: |
197 | return "Wed"; | ||
198 | case ABDAY_5: | 435 | case ABDAY_5: |
199 | return "Thu"; | ||
200 | case ABDAY_6: | 436 | case ABDAY_6: |
201 | return "Fri"; | ||
202 | case ABDAY_7: | 437 | case ABDAY_7: |
203 | return "Sat"; | 438 | { |
204 | case MON_1: | 439 | static char result[7][30]; |
205 | return "January"; | 440 | static char const abdays[][sizeof "Sun"] = { |
206 | case MON_2: | 441 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" |
207 | return "February"; | 442 | }; |
208 | case MON_3: | 443 | tmm.tm_wday = item - ABDAY_1; |
209 | return "March"; | 444 | if (!strftime (buf, sizeof result[0], "%a", &tmm)) |
210 | case MON_4: | 445 | return (char *) abdays[item - ABDAY_1]; |
211 | return "April"; | 446 | strcpy (result[item - ABDAY_1], buf); |
212 | case MON_5: | 447 | return result[item - ABDAY_1]; |
213 | return "May"; | 448 | } |
214 | case MON_6: | 449 | { |
215 | return "June"; | 450 | static char const months[][sizeof "September"] = { |
216 | case MON_7: | 451 | "January", "February", "March", "April", "May", "June", "July", |
217 | return "July"; | 452 | "September", "October", "November", "December" |
218 | case MON_8: | 453 | }; |
219 | return "August"; | 454 | case MON_1: |
220 | case MON_9: | 455 | case MON_2: |
221 | return "September"; | 456 | case MON_3: |
222 | case MON_10: | 457 | case MON_4: |
223 | return "October"; | 458 | case MON_5: |
224 | case MON_11: | 459 | case MON_6: |
225 | return "November"; | 460 | case MON_7: |
226 | case MON_12: | 461 | case MON_8: |
227 | return "December"; | 462 | case MON_9: |
463 | case MON_10: | ||
464 | case MON_11: | ||
465 | case MON_12: | ||
466 | { | ||
467 | static char result[12][50]; | ||
468 | tmm.tm_mon = item - MON_1; | ||
469 | if (!strftime (buf, sizeof result[0], "%B", &tmm)) | ||
470 | return (char *) months[item - MON_1]; | ||
471 | strcpy (result[item - MON_1], buf); | ||
472 | return result[item - MON_1]; | ||
473 | } | ||
474 | case ALTMON_1: | ||
475 | case ALTMON_2: | ||
476 | case ALTMON_3: | ||
477 | case ALTMON_4: | ||
478 | case ALTMON_5: | ||
479 | case ALTMON_6: | ||
480 | case ALTMON_7: | ||
481 | case ALTMON_8: | ||
482 | case ALTMON_9: | ||
483 | case ALTMON_10: | ||
484 | case ALTMON_11: | ||
485 | case ALTMON_12: | ||
486 | { | ||
487 | static char result[12][50]; | ||
488 | tmm.tm_mon = item - ALTMON_1; | ||
489 | /* The platforms without nl_langinfo() don't support strftime with | ||
490 | %OB. We don't even need to try. */ | ||
491 | #if 0 | ||
492 | if (!strftime (buf, sizeof result[0], "%OB", &tmm)) | ||
493 | #endif | ||
494 | if (!strftime (buf, sizeof result[0], "%B", &tmm)) | ||
495 | return (char *) months[item - ALTMON_1]; | ||
496 | strcpy (result[item - ALTMON_1], buf); | ||
497 | return result[item - ALTMON_1]; | ||
498 | } | ||
499 | } | ||
228 | case ABMON_1: | 500 | case ABMON_1: |
229 | return "Jan"; | ||
230 | case ABMON_2: | 501 | case ABMON_2: |
231 | return "Feb"; | ||
232 | case ABMON_3: | 502 | case ABMON_3: |
233 | return "Mar"; | ||
234 | case ABMON_4: | 503 | case ABMON_4: |
235 | return "Apr"; | ||
236 | case ABMON_5: | 504 | case ABMON_5: |
237 | return "May"; | ||
238 | case ABMON_6: | 505 | case ABMON_6: |
239 | return "Jun"; | ||
240 | case ABMON_7: | 506 | case ABMON_7: |
241 | return "Jul"; | ||
242 | case ABMON_8: | 507 | case ABMON_8: |
243 | return "Aug"; | ||
244 | case ABMON_9: | 508 | case ABMON_9: |
245 | return "Sep"; | ||
246 | case ABMON_10: | 509 | case ABMON_10: |
247 | return "Oct"; | ||
248 | case ABMON_11: | 510 | case ABMON_11: |
249 | return "Nov"; | ||
250 | case ABMON_12: | 511 | case ABMON_12: |
251 | return "Dec"; | 512 | { |
513 | static char result[12][30]; | ||
514 | static char const abmonths[][sizeof "Jan"] = { | ||
515 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", | ||
516 | "Sep", "Oct", "Nov", "Dec" | ||
517 | }; | ||
518 | tmm.tm_mon = item - ABMON_1; | ||
519 | if (!strftime (buf, sizeof result[0], "%b", &tmm)) | ||
520 | return (char *) abmonths[item - ABMON_1]; | ||
521 | strcpy (result[item - ABMON_1], buf); | ||
522 | return result[item - ABMON_1]; | ||
523 | } | ||
252 | case ERA: | 524 | case ERA: |
253 | return ""; | 525 | return (char *) ""; |
254 | case ALT_DIGITS: | 526 | case ALT_DIGITS: |
255 | return "\0\0\0\0\0\0\0\0\0\0"; | 527 | return (char *) "\0\0\0\0\0\0\0\0\0\0"; |
256 | /* nl_langinfo items of the LC_MONETARY category | 528 | /* nl_langinfo items of the LC_MONETARY category. */ |
257 | TODO: Really use the locale. */ | ||
258 | case CRNCYSTR: | 529 | case CRNCYSTR: |
259 | return "-"; | 530 | return localeconv () ->currency_symbol; |
531 | # ifdef INT_CURR_SYMBOL | ||
532 | case INT_CURR_SYMBOL: | ||
533 | return localeconv () ->int_curr_symbol; | ||
534 | case MON_DECIMAL_POINT: | ||
535 | return localeconv () ->mon_decimal_point; | ||
536 | case MON_THOUSANDS_SEP: | ||
537 | return localeconv () ->mon_thousands_sep; | ||
538 | case MON_GROUPING: | ||
539 | return localeconv () ->mon_grouping; | ||
540 | case POSITIVE_SIGN: | ||
541 | return localeconv () ->positive_sign; | ||
542 | case NEGATIVE_SIGN: | ||
543 | return localeconv () ->negative_sign; | ||
544 | case FRAC_DIGITS: | ||
545 | return & localeconv () ->frac_digits; | ||
546 | case INT_FRAC_DIGITS: | ||
547 | return & localeconv () ->int_frac_digits; | ||
548 | case P_CS_PRECEDES: | ||
549 | return & localeconv () ->p_cs_precedes; | ||
550 | case N_CS_PRECEDES: | ||
551 | return & localeconv () ->n_cs_precedes; | ||
552 | case P_SEP_BY_SPACE: | ||
553 | return & localeconv () ->p_sep_by_space; | ||
554 | case N_SEP_BY_SPACE: | ||
555 | return & localeconv () ->n_sep_by_space; | ||
556 | case P_SIGN_POSN: | ||
557 | return & localeconv () ->p_sign_posn; | ||
558 | case N_SIGN_POSN: | ||
559 | return & localeconv () ->n_sign_posn; | ||
560 | # endif | ||
260 | /* nl_langinfo items of the LC_MESSAGES category | 561 | /* nl_langinfo items of the LC_MESSAGES category |
261 | TODO: Really use the locale. */ | 562 | TODO: Really use the locale. */ |
262 | case YESEXPR: | 563 | case YESEXPR: |
263 | return "^[yY]"; | 564 | return (char *) "^[yY]"; |
264 | case NOEXPR: | 565 | case NOEXPR: |
265 | return "^[nN]"; | 566 | return (char *) "^[nN]"; |
266 | default: | 567 | default: |
267 | return ""; | 568 | return (char *) ""; |
268 | } | 569 | } |
269 | } | 570 | } |
270 | 571 | ||