diff options
| author | Andreas Baumann <mail@andreasbaumann.cc> | 2023-02-11 07:20:24 +0100 |
|---|---|---|
| committer | Andreas Baumann <mail@andreasbaumann.cc> | 2023-02-11 07:20:24 +0100 |
| commit | f867d7b44080fa9716deeff4476275f9a489879f (patch) | |
| tree | bc964662fc3300dc626fb6d833d8ed5c8f46eca7 /gl/nl_langinfo.c | |
| parent | 9734c439cba0a02b087e50789e94ec9b07754608 (diff) | |
| parent | c07206f2ccc2356aa74bc6813a94c2190017d44e (diff) | |
| download | monitoring-plugins-f867d7b44080fa9716deeff4476275f9a489879f.tar.gz | |
Merge branch 'master' into curlfixes
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..131166fd 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-2023 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 | ||
