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