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