1 1.1 christos /* $NetBSD: strftime.c,v 1.1.1.1 2016/01/13 03:15:30 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* Copyright (C) 1991-1999, 2000, 2001 Free Software Foundation, Inc. 4 1.1 christos 5 1.1 christos NOTE: The canonical source of this file is maintained with the GNU C Library. 6 1.1 christos Bugs can be reported to bug-glibc (at) prep.ai.mit.edu. 7 1.1 christos 8 1.1 christos This program is free software; you can redistribute it and/or modify it 9 1.1 christos under the terms of the GNU General Public License as published by the 10 1.1 christos Free Software Foundation; either version 2, or (at your option) any 11 1.1 christos later version. 12 1.1 christos 13 1.1 christos This program is distributed in the hope that it will be useful, 14 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 15 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 1.1 christos Library General Public License for more details. 17 1.1 christos 18 1.1 christos You should have received a copy of the GNU General Public License 19 1.1 christos along with this program; if not, write to the Free Software 20 1.1 christos Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 21 1.1 christos USA. */ 22 1.1 christos 23 1.1 christos #ifdef HAVE_CONFIG_H 24 1.1 christos # include <config.h> 25 1.1 christos #endif 26 1.1 christos 27 1.1 christos #ifdef _LIBC 28 1.1 christos # define HAVE_LIMITS_H 1 29 1.1 christos # define HAVE_MBLEN 1 30 1.1 christos # define HAVE_MBRLEN 1 31 1.1 christos # define HAVE_STRUCT_ERA_ENTRY 1 32 1.1 christos # define HAVE_TM_GMTOFF 1 33 1.1 christos # define HAVE_TM_ZONE 1 34 1.1 christos # define HAVE_TZNAME 1 35 1.1 christos # define HAVE_TZSET 1 36 1.1 christos # define MULTIBYTE_IS_FORMAT_SAFE 1 37 1.1 christos # define STDC_HEADERS 1 38 1.1 christos # include "../locale/localeinfo.h" 39 1.1 christos #endif 40 1.1 christos 41 1.1 christos #if defined emacs && !defined HAVE_BCOPY 42 1.1 christos # define HAVE_MEMCPY 1 43 1.1 christos #endif 44 1.1 christos 45 1.1 christos #include <ctype.h> 46 1.1 christos #include <sys/types.h> /* Some systems define `time_t' here. */ 47 1.1 christos 48 1.1 christos #ifdef TIME_WITH_SYS_TIME 49 1.1 christos # include <sys/time.h> 50 1.1 christos # include <time.h> 51 1.1 christos #else 52 1.1 christos # ifdef HAVE_SYS_TIME_H 53 1.1 christos # include <sys/time.h> 54 1.1 christos # else 55 1.1 christos # include <time.h> 56 1.1 christos # endif 57 1.1 christos #endif 58 1.1 christos #if HAVE_TZNAME 59 1.1 christos extern char *tzname[]; 60 1.1 christos #endif 61 1.1 christos 62 1.1 christos /* Do multibyte processing if multibytes are supported, unless 63 1.1 christos multibyte sequences are safe in formats. Multibyte sequences are 64 1.1 christos safe if they cannot contain byte sequences that look like format 65 1.1 christos conversion specifications. The GNU C Library uses UTF8 multibyte 66 1.1 christos encoding, which is safe for formats, but strftime.c can be used 67 1.1 christos with other C libraries that use unsafe encodings. */ 68 1.1 christos #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE) 69 1.1 christos 70 1.1 christos #if DO_MULTIBYTE 71 1.1 christos # if HAVE_MBRLEN 72 1.1 christos # include <wchar.h> 73 1.1 christos # else 74 1.1 christos /* Simulate mbrlen with mblen as best we can. */ 75 1.1 christos # define mbstate_t int 76 1.1 christos # define mbrlen(s, n, ps) mblen (s, n) 77 1.1 christos # define mbsinit(ps) (*(ps) == 0) 78 1.1 christos # endif 79 1.1 christos static const mbstate_t mbstate_zero; 80 1.1 christos #endif 81 1.1 christos 82 1.1 christos #if HAVE_LIMITS_H 83 1.1 christos # include <limits.h> 84 1.1 christos #endif 85 1.1 christos 86 1.1 christos #if STDC_HEADERS 87 1.1 christos # include <stddef.h> 88 1.1 christos # include <stdlib.h> 89 1.1 christos # include <string.h> 90 1.1 christos #else 91 1.1 christos # ifndef HAVE_MEMCPY 92 1.1 christos # define memcpy(d, s, n) bcopy ((s), (d), (n)) 93 1.1 christos # endif 94 1.1 christos #endif 95 1.1 christos 96 1.1 christos #ifdef COMPILE_WIDE 97 1.1 christos # include <endian.h> 98 1.1 christos # define CHAR_T wchar_t 99 1.1 christos # define UCHAR_T unsigned int 100 1.1 christos # define L_(Str) L##Str 101 1.1 christos # define NLW(Sym) _NL_W##Sym 102 1.1 christos 103 1.1 christos # define MEMCPY(d, s, n) __wmemcpy (d, s, n) 104 1.1 christos # define STRLEN(s) __wcslen (s) 105 1.1 christos 106 1.1 christos #else 107 1.1 christos # define CHAR_T char 108 1.1 christos # define UCHAR_T unsigned char 109 1.1 christos # define L_(Str) Str 110 1.1 christos # define NLW(Sym) Sym 111 1.1 christos 112 1.1 christos # if !defined STDC_HEADERS && !defined HAVE_MEMCPY 113 1.1 christos # define MEMCPY(d, s, n) bcopy ((s), (d), (n)) 114 1.1 christos # else 115 1.1 christos # define MEMCPY(d, s, n) memcpy ((d), (s), (n)) 116 1.1 christos # endif 117 1.1 christos # define STRLEN(s) strlen (s) 118 1.1 christos 119 1.1 christos # ifdef _LIBC 120 1.1 christos # define MEMPCPY(d, s, n) __mempcpy (d, s, n) 121 1.1 christos # else 122 1.1 christos # ifndef HAVE_MEMPCPY 123 1.1 christos # define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n))) 124 1.1 christos # endif 125 1.1 christos # endif 126 1.1 christos #endif 127 1.1 christos 128 1.1 christos #ifndef __P 129 1.1 christos # if defined __GNUC__ || (defined __STDC__ && __STDC__) 130 1.1 christos # define __P(args) args 131 1.1 christos # else 132 1.1 christos # define __P(args) () 133 1.1 christos # endif /* GCC. */ 134 1.1 christos #endif /* Not __P. */ 135 1.1 christos 136 1.1 christos #ifndef PTR 137 1.1 christos # ifdef __STDC__ 138 1.1 christos # define PTR void * 139 1.1 christos # else 140 1.1 christos # define PTR char * 141 1.1 christos # endif 142 1.1 christos #endif 143 1.1 christos 144 1.1 christos #ifndef CHAR_BIT 145 1.1 christos # define CHAR_BIT 8 146 1.1 christos #endif 147 1.1 christos 148 1.1 christos #ifndef NULL 149 1.1 christos # define NULL 0 150 1.1 christos #endif 151 1.1 christos 152 1.1 christos #define TYPE_SIGNED(t) ((t) -1 < 0) 153 1.1 christos 154 1.1 christos /* Bound on length of the string representing an integer value of type t. 155 1.1 christos Subtract one for the sign bit if t is signed; 156 1.1 christos 302 / 1000 is log10 (2) rounded up; 157 1.1 christos add one for integer division truncation; 158 1.1 christos add one more for a minus sign if t is signed. */ 159 1.1 christos #define INT_STRLEN_BOUND(t) \ 160 1.1 christos ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 + 1 + TYPE_SIGNED (t)) 161 1.1 christos 162 1.1 christos #define TM_YEAR_BASE 1900 163 1.1 christos 164 1.1 christos #ifndef __isleap 165 1.1 christos /* Nonzero if YEAR is a leap year (every 4 years, 166 1.1 christos except every 100th isn't, and every 400th is). */ 167 1.1 christos # define __isleap(year) \ 168 1.1 christos ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) 169 1.1 christos #endif 170 1.1 christos 171 1.1 christos 172 1.1 christos #ifdef _LIBC 173 1.1 christos # define my_strftime_gmtime_r __gmtime_r 174 1.1 christos # define my_strftime_localtime_r __localtime_r 175 1.1 christos # define tzname __tzname 176 1.1 christos # define tzset __tzset 177 1.1 christos #else 178 1.1 christos 179 1.1 christos /* If we're a strftime substitute in a GNU program, then prefer gmtime 180 1.1 christos to gmtime_r, since many gmtime_r implementations are buggy. 181 1.1 christos Similarly for localtime_r. */ 182 1.1 christos 183 1.1 christos # if ! HAVE_TM_GMTOFF 184 1.1 christos static struct tm *my_strftime_gmtime_r __P ((const time_t *, struct tm *)); 185 1.1 christos static struct tm * 186 1.1 christos my_strftime_gmtime_r (t, tp) 187 1.1 christos const time_t *t; 188 1.1 christos struct tm *tp; 189 1.1 christos { 190 1.1 christos struct tm *l = gmtime (t); 191 1.1 christos if (! l) 192 1.1 christos return 0; 193 1.1 christos *tp = *l; 194 1.1 christos return tp; 195 1.1 christos } 196 1.1 christos 197 1.1 christos static struct tm *my_strftime_localtime_r __P ((const time_t *, struct tm *)); 198 1.1 christos static struct tm * 199 1.1 christos my_strftime_localtime_r (t, tp) 200 1.1 christos const time_t *t; 201 1.1 christos struct tm *tp; 202 1.1 christos { 203 1.1 christos struct tm *l = localtime (t); 204 1.1 christos if (! l) 205 1.1 christos return 0; 206 1.1 christos *tp = *l; 207 1.1 christos return tp; 208 1.1 christos } 209 1.1 christos # endif /* ! HAVE_TM_GMTOFF */ 210 1.1 christos #endif /* ! defined _LIBC */ 211 1.1 christos 212 1.1 christos 213 1.1 christos #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC 214 1.1 christos /* Some systems lack the `memset' function and we don't want to 215 1.1 christos introduce additional dependencies. */ 216 1.1 christos /* The SGI compiler reportedly barfs on the trailing null 217 1.1 christos if we use a string constant as the initializer. 28 June 1997, rms. */ 218 1.1 christos static const CHAR_T spaces[16] = /* " " */ 219 1.1 christos { 220 1.1 christos L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '), 221 1.1 christos L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' ') 222 1.1 christos }; 223 1.1 christos static const CHAR_T zeroes[16] = /* "0000000000000000" */ 224 1.1 christos { 225 1.1 christos L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'), 226 1.1 christos L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0') 227 1.1 christos }; 228 1.1 christos 229 1.1 christos # define memset_space(P, Len) \ 230 1.1 christos do { \ 231 1.1 christos int _len = (Len); \ 232 1.1 christos \ 233 1.1 christos do \ 234 1.1 christos { \ 235 1.1 christos int _this = _len > 16 ? 16 : _len; \ 236 1.1 christos (P) = MEMPCPY ((P), spaces, _this * sizeof (CHAR_T)); \ 237 1.1 christos _len -= _this; \ 238 1.1 christos } \ 239 1.1 christos while (_len > 0); \ 240 1.1 christos } while (0) 241 1.1 christos 242 1.1 christos # define memset_zero(P, Len) \ 243 1.1 christos do { \ 244 1.1 christos int _len = (Len); \ 245 1.1 christos \ 246 1.1 christos do \ 247 1.1 christos { \ 248 1.1 christos int _this = _len > 16 ? 16 : _len; \ 249 1.1 christos (P) = MEMPCPY ((P), zeroes, _this * sizeof (CHAR_T)); \ 250 1.1 christos _len -= _this; \ 251 1.1 christos } \ 252 1.1 christos while (_len > 0); \ 253 1.1 christos } while (0) 254 1.1 christos #else 255 1.1 christos # ifdef COMPILE_WIDE 256 1.1 christos # define memset_space(P, Len) (wmemset ((P), L' ', (Len)), (P) += (Len)) 257 1.1 christos # define memset_zero(P, Len) (wmemset ((P), L'0', (Len)), (P) += (Len)) 258 1.1 christos # else 259 1.1 christos # define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len)) 260 1.1 christos # define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len)) 261 1.1 christos # endif 262 1.1 christos #endif 263 1.1 christos 264 1.1 christos #define add(n, f) \ 265 1.1 christos do \ 266 1.1 christos { \ 267 1.1 christos int _n = (n); \ 268 1.1 christos int _delta = width - _n; \ 269 1.1 christos int _incr = _n + (_delta > 0 ? _delta : 0); \ 270 1.1 christos if (i + _incr >= maxsize) \ 271 1.1 christos return 0; \ 272 1.1 christos if (p) \ 273 1.1 christos { \ 274 1.1 christos if (_delta > 0) \ 275 1.1 christos { \ 276 1.1 christos if (pad == L_('0')) \ 277 1.1 christos memset_zero (p, _delta); \ 278 1.1 christos else \ 279 1.1 christos memset_space (p, _delta); \ 280 1.1 christos } \ 281 1.1 christos f; \ 282 1.1 christos p += _n; \ 283 1.1 christos } \ 284 1.1 christos i += _incr; \ 285 1.1 christos } while (0) 286 1.1 christos 287 1.1 christos #define cpy(n, s) \ 288 1.1 christos add ((n), \ 289 1.1 christos if (to_lowcase) \ 290 1.1 christos memcpy_lowcase (p, (s), _n); \ 291 1.1 christos else if (to_uppcase) \ 292 1.1 christos memcpy_uppcase (p, (s), _n); \ 293 1.1 christos else \ 294 1.1 christos MEMCPY ((PTR) p, (const PTR) (s), _n)) 295 1.1 christos 296 1.1 christos #ifdef COMPILE_WIDE 297 1.1 christos # define widen(os, ws, l) \ 298 1.1 christos { \ 299 1.1 christos mbstate_t __st; \ 300 1.1 christos const char *__s = os; \ 301 1.1 christos memset (&__st, '\0', sizeof (__st)); \ 302 1.1 christos l = __mbsrtowcs (NULL, &__s, 0, &__st); \ 303 1.1 christos ws = alloca ((l + 1) * sizeof (wchar_t)); \ 304 1.1 christos (void) __mbsrtowcs (ws, &__s, l, &__st); \ 305 1.1 christos } 306 1.1 christos #endif 307 1.1 christos 308 1.1 christos 309 1.1 christos #ifdef COMPILE_WIDE 310 1.1 christos # define TOUPPER(Ch) towupper (Ch) 311 1.1 christos # define TOLOWER(Ch) towlower (Ch) 312 1.1 christos #else 313 1.1 christos # ifdef _LIBC 314 1.1 christos # define TOUPPER(Ch) toupper (Ch) 315 1.1 christos # define TOLOWER(Ch) tolower (Ch) 316 1.1 christos # else 317 1.1 christos # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch)) 318 1.1 christos # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch)) 319 1.1 christos # endif 320 1.1 christos #endif 321 1.1 christos /* We don't use `isdigit' here since the locale dependent 322 1.1 christos interpretation is not what we want here. We only need to accept 323 1.1 christos the arabic digits in the ASCII range. One day there is perhaps a 324 1.1 christos more reliable way to accept other sets of digits. */ 325 1.1 christos #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9) 326 1.1 christos 327 1.1 christos static CHAR_T *memcpy_lowcase __P ((CHAR_T *dest, const CHAR_T *src, 328 1.1 christos size_t len)); 329 1.1 christos 330 1.1 christos static CHAR_T * 331 1.1 christos memcpy_lowcase (dest, src, len) 332 1.1 christos CHAR_T *dest; 333 1.1 christos const CHAR_T *src; 334 1.1 christos size_t len; 335 1.1 christos { 336 1.1 christos while (len-- > 0) 337 1.1 christos dest[len] = TOLOWER ((UCHAR_T) src[len]); 338 1.1 christos return dest; 339 1.1 christos } 340 1.1 christos 341 1.1 christos static CHAR_T *memcpy_uppcase __P ((CHAR_T *dest, const CHAR_T *src, 342 1.1 christos size_t len)); 343 1.1 christos 344 1.1 christos static CHAR_T * 345 1.1 christos memcpy_uppcase (dest, src, len) 346 1.1 christos CHAR_T *dest; 347 1.1 christos const CHAR_T *src; 348 1.1 christos size_t len; 349 1.1 christos { 350 1.1 christos while (len-- > 0) 351 1.1 christos dest[len] = TOUPPER ((UCHAR_T) src[len]); 352 1.1 christos return dest; 353 1.1 christos } 354 1.1 christos 355 1.1 christos 356 1.1 christos #if ! HAVE_TM_GMTOFF 357 1.1 christos /* Yield the difference between *A and *B, 358 1.1 christos measured in seconds, ignoring leap seconds. */ 359 1.1 christos # define tm_diff ftime_tm_diff 360 1.1 christos static int tm_diff __P ((const struct tm *, const struct tm *)); 361 1.1 christos static int 362 1.1 christos tm_diff (a, b) 363 1.1 christos const struct tm *a; 364 1.1 christos const struct tm *b; 365 1.1 christos { 366 1.1 christos /* Compute intervening leap days correctly even if year is negative. 367 1.1 christos Take care to avoid int overflow in leap day calculations, 368 1.1 christos but it's OK to assume that A and B are close to each other. */ 369 1.1 christos int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3); 370 1.1 christos int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3); 371 1.1 christos int a100 = a4 / 25 - (a4 % 25 < 0); 372 1.1 christos int b100 = b4 / 25 - (b4 % 25 < 0); 373 1.1 christos int a400 = a100 >> 2; 374 1.1 christos int b400 = b100 >> 2; 375 1.1 christos int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); 376 1.1 christos int years = a->tm_year - b->tm_year; 377 1.1 christos int days = (365 * years + intervening_leap_days 378 1.1 christos + (a->tm_yday - b->tm_yday)); 379 1.1 christos return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour)) 380 1.1 christos + (a->tm_min - b->tm_min)) 381 1.1 christos + (a->tm_sec - b->tm_sec)); 382 1.1 christos } 383 1.1 christos #endif /* ! HAVE_TM_GMTOFF */ 384 1.1 christos 385 1.1 christos 386 1.1 christos 387 1.1 christos /* The number of days from the first day of the first ISO week of this 388 1.1 christos year to the year day YDAY with week day WDAY. ISO weeks start on 389 1.1 christos Monday; the first ISO week has the year's first Thursday. YDAY may 390 1.1 christos be as small as YDAY_MINIMUM. */ 391 1.1 christos #define ISO_WEEK_START_WDAY 1 /* Monday */ 392 1.1 christos #define ISO_WEEK1_WDAY 4 /* Thursday */ 393 1.1 christos #define YDAY_MINIMUM (-366) 394 1.1 christos static int iso_week_days __P ((int, int)); 395 1.1 christos #ifdef __GNUC__ 396 1.1 christos __inline__ 397 1.1 christos #endif 398 1.1 christos static int 399 1.1 christos iso_week_days (yday, wday) 400 1.1 christos int yday; 401 1.1 christos int wday; 402 1.1 christos { 403 1.1 christos /* Add enough to the first operand of % to make it nonnegative. */ 404 1.1 christos int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7; 405 1.1 christos return (yday 406 1.1 christos - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7 407 1.1 christos + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY); 408 1.1 christos } 409 1.1 christos 410 1.1 christos 411 1.1 christos #if !(defined _NL_CURRENT || HAVE_STRFTIME) 412 1.1 christos static CHAR_T const weekday_name[][10] = 413 1.1 christos { 414 1.1 christos L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"), 415 1.1 christos L_("Thursday"), L_("Friday"), L_("Saturday") 416 1.1 christos }; 417 1.1 christos static CHAR_T const month_name[][10] = 418 1.1 christos { 419 1.1 christos L_("January"), L_("February"), L_("March"), L_("April"), L_("May"), 420 1.1 christos L_("June"), L_("July"), L_("August"), L_("September"), L_("October"), 421 1.1 christos L_("November"), L_("December") 422 1.1 christos }; 423 1.1 christos #endif 424 1.1 christos 425 1.1 christos 426 1.1 christos /* When compiling this file, GNU applications can #define my_strftime 427 1.1 christos to a symbol (typically nstrftime) to get an extended strftime with 428 1.1 christos extra arguments UT and NS. Emacs is a special case for now, but 429 1.1 christos this Emacs-specific code can be removed once Emacs's config.h 430 1.1 christos defines my_strftime. */ 431 1.1 christos #if defined emacs && !defined my_strftime 432 1.1 christos # define my_strftime nstrftime 433 1.1 christos #endif 434 1.1 christos 435 1.1 christos #ifdef my_strftime 436 1.1 christos # define extra_args , ut, ns 437 1.1 christos # define extra_args_spec int ut; int ns; 438 1.1 christos # define extra_args_spec_iso , int ut, int ns 439 1.1 christos #else 440 1.1 christos # ifdef COMPILE_WIDE 441 1.1 christos # define my_strftime wcsftime 442 1.1 christos # else 443 1.1 christos # define my_strftime strftime 444 1.1 christos # endif 445 1.1 christos # define extra_args 446 1.1 christos # define extra_args_spec 447 1.1 christos # define extra_args_spec_iso 448 1.1 christos /* We don't have this information in general. */ 449 1.1 christos # define ut 0 450 1.1 christos # define ns 0 451 1.1 christos #endif 452 1.1 christos 453 1.1 christos #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET 454 1.1 christos /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime. 455 1.1 christos Work around this bug by copying *tp before it might be munged. */ 456 1.1 christos size_t _strftime_copytm __P ((char *, size_t, const char *, 457 1.1 christos const struct tm * extra_args_spec_iso)); 458 1.1 christos size_t 459 1.1 christos my_strftime (s, maxsize, format, tp extra_args) 460 1.1 christos CHAR_T *s; 461 1.1 christos size_t maxsize; 462 1.1 christos const CHAR_T *format; 463 1.1 christos const struct tm *tp; 464 1.1 christos extra_args_spec 465 1.1 christos { 466 1.1 christos struct tm tmcopy; 467 1.1 christos tmcopy = *tp; 468 1.1 christos return _strftime_copytm (s, maxsize, format, &tmcopy extra_args); 469 1.1 christos } 470 1.1 christos # undef my_strftime 471 1.1 christos # define my_strftime _strftime_copytm 472 1.1 christos #endif 473 1.1 christos 474 1.1 christos 475 1.1 christos /* Write information from TP into S according to the format 476 1.1 christos string FORMAT, writing no more that MAXSIZE characters 477 1.1 christos (including the terminating '\0') and returning number of 478 1.1 christos characters written. If S is NULL, nothing will be written 479 1.1 christos anywhere, so to determine how many characters would be 480 1.1 christos written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */ 481 1.1 christos size_t 482 1.1 christos my_strftime (s, maxsize, format, tp extra_args) 483 1.1 christos CHAR_T *s; 484 1.1 christos size_t maxsize; 485 1.1 christos const CHAR_T *format; 486 1.1 christos const struct tm *tp; 487 1.1 christos extra_args_spec 488 1.1 christos { 489 1.1 christos int hour12 = tp->tm_hour; 490 1.1 christos #ifdef _NL_CURRENT 491 1.1 christos /* We cannot make the following values variables since we must delay 492 1.1 christos the evaluation of these values until really needed since some 493 1.1 christos expressions might not be valid in every situation. The `struct tm' 494 1.1 christos might be generated by a strptime() call that initialized 495 1.1 christos only a few elements. Dereference the pointers only if the format 496 1.1 christos requires this. Then it is ok to fail if the pointers are invalid. */ 497 1.1 christos # define a_wkday \ 498 1.1 christos ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday)) 499 1.1 christos # define f_wkday \ 500 1.1 christos ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday)) 501 1.1 christos # define a_month \ 502 1.1 christos ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon)) 503 1.1 christos # define f_month \ 504 1.1 christos ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon)) 505 1.1 christos # define ampm \ 506 1.1 christos ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \ 507 1.1 christos ? NLW(PM_STR) : NLW(AM_STR))) 508 1.1 christos 509 1.1 christos # define aw_len STRLEN (a_wkday) 510 1.1 christos # define am_len STRLEN (a_month) 511 1.1 christos # define ap_len STRLEN (ampm) 512 1.1 christos #else 513 1.1 christos # if !HAVE_STRFTIME 514 1.1 christos # define f_wkday (weekday_name[tp->tm_wday]) 515 1.1 christos # define f_month (month_name[tp->tm_mon]) 516 1.1 christos # define a_wkday f_wkday 517 1.1 christos # define a_month f_month 518 1.1 christos # define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11)) 519 1.1 christos 520 1.1 christos size_t aw_len = 3; 521 1.1 christos size_t am_len = 3; 522 1.1 christos size_t ap_len = 2; 523 1.1 christos # endif 524 1.1 christos #endif 525 1.1 christos const char *zone; 526 1.1 christos size_t i = 0; 527 1.1 christos CHAR_T *p = s; 528 1.1 christos const CHAR_T *f; 529 1.1 christos #if DO_MULTIBYTE && !defined COMPILE_WIDE 530 1.1 christos const char *format_end = NULL; 531 1.1 christos #endif 532 1.1 christos 533 1.1 christos zone = NULL; 534 1.1 christos #if HAVE_TM_ZONE 535 1.1 christos /* The POSIX test suite assumes that setting 536 1.1 christos the environment variable TZ to a new value before calling strftime() 537 1.1 christos will influence the result (the %Z format) even if the information in 538 1.1 christos TP is computed with a totally different time zone. 539 1.1 christos This is bogus: though POSIX allows bad behavior like this, 540 1.1 christos POSIX does not require it. Do the right thing instead. */ 541 1.1 christos zone = (const char *) tp->tm_zone; 542 1.1 christos #endif 543 1.1 christos #if HAVE_TZNAME 544 1.1 christos if (ut) 545 1.1 christos { 546 1.1 christos if (! (zone && *zone)) 547 1.1 christos zone = "GMT"; 548 1.1 christos } 549 1.1 christos else 550 1.1 christos { 551 1.1 christos /* POSIX.1 8.1.1 requires that whenever strftime() is called, the 552 1.1 christos time zone names contained in the external variable `tzname' shall 553 1.1 christos be set as if the tzset() function had been called. */ 554 1.1 christos # if HAVE_TZSET 555 1.1 christos tzset (); 556 1.1 christos # endif 557 1.1 christos } 558 1.1 christos #endif 559 1.1 christos 560 1.1 christos if (hour12 > 12) 561 1.1 christos hour12 -= 12; 562 1.1 christos else 563 1.1 christos if (hour12 == 0) 564 1.1 christos hour12 = 12; 565 1.1 christos 566 1.1 christos for (f = format; *f != '\0'; ++f) 567 1.1 christos { 568 1.1 christos int pad = 0; /* Padding for number ('-', '_', or 0). */ 569 1.1 christos int modifier; /* Field modifier ('E', 'O', or 0). */ 570 1.1 christos int digits; /* Max digits for numeric format. */ 571 1.1 christos int number_value; /* Numeric value to be printed. */ 572 1.1 christos int negative_number; /* 1 if the number is negative. */ 573 1.1 christos const CHAR_T *subfmt; 574 1.1 christos CHAR_T *bufp; 575 1.1 christos CHAR_T buf[1 + (sizeof (int) < sizeof (time_t) 576 1.1 christos ? INT_STRLEN_BOUND (time_t) 577 1.1 christos : INT_STRLEN_BOUND (int))]; 578 1.1 christos int width = -1; 579 1.1 christos int to_lowcase = 0; 580 1.1 christos int to_uppcase = 0; 581 1.1 christos int change_case = 0; 582 1.1 christos int format_char; 583 1.1 christos 584 1.1 christos #if DO_MULTIBYTE && !defined COMPILE_WIDE 585 1.1 christos switch (*f) 586 1.1 christos { 587 1.1 christos case L_('%'): 588 1.1 christos break; 589 1.1 christos 590 1.1 christos case L_('\b'): case L_('\t'): case L_('\n'): 591 1.1 christos case L_('\v'): case L_('\f'): case L_('\r'): 592 1.1 christos case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'): 593 1.1 christos case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'): 594 1.1 christos case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'): 595 1.1 christos case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'): 596 1.1 christos case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'): 597 1.1 christos case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'): 598 1.1 christos case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'): 599 1.1 christos case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'): 600 1.1 christos case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'): 601 1.1 christos case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'): 602 1.1 christos case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'): 603 1.1 christos case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'): 604 1.1 christos case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'): 605 1.1 christos case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'): 606 1.1 christos case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'): 607 1.1 christos case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'): 608 1.1 christos case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'): 609 1.1 christos case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'): 610 1.1 christos case L_('~'): 611 1.1 christos /* The C Standard requires these 98 characters (plus '%') to 612 1.1 christos be in the basic execution character set. None of these 613 1.1 christos characters can start a multibyte sequence, so they need 614 1.1 christos not be analyzed further. */ 615 1.1 christos add (1, *p = *f); 616 1.1 christos continue; 617 1.1 christos 618 1.1 christos default: 619 1.1 christos /* Copy this multibyte sequence until we reach its end, find 620 1.1 christos an error, or come back to the initial shift state. */ 621 1.1 christos { 622 1.1 christos mbstate_t mbstate = mbstate_zero; 623 1.1 christos size_t len = 0; 624 1.1 christos size_t fsize; 625 1.1 christos 626 1.1 christos if (! format_end) 627 1.1 christos format_end = f + strlen (f) + 1; 628 1.1 christos fsize = format_end - f; 629 1.1 christos 630 1.1 christos do 631 1.1 christos { 632 1.1 christos size_t bytes = mbrlen (f + len, fsize - len, &mbstate); 633 1.1 christos 634 1.1 christos if (bytes == 0) 635 1.1 christos break; 636 1.1 christos 637 1.1 christos if (bytes == (size_t) -2) 638 1.1 christos { 639 1.1 christos len += strlen (f + len); 640 1.1 christos break; 641 1.1 christos } 642 1.1 christos 643 1.1 christos if (bytes == (size_t) -1) 644 1.1 christos { 645 1.1 christos len++; 646 1.1 christos break; 647 1.1 christos } 648 1.1 christos 649 1.1 christos len += bytes; 650 1.1 christos } 651 1.1 christos while (! mbsinit (&mbstate)); 652 1.1 christos 653 1.1 christos cpy (len, f); 654 1.1 christos f += len - 1; 655 1.1 christos continue; 656 1.1 christos } 657 1.1 christos } 658 1.1 christos 659 1.1 christos #else /* ! DO_MULTIBYTE */ 660 1.1 christos 661 1.1 christos /* Either multibyte encodings are not supported, they are 662 1.1 christos safe for formats, so any non-'%' byte can be copied through, 663 1.1 christos or this is the wide character version. */ 664 1.1 christos if (*f != L_('%')) 665 1.1 christos { 666 1.1 christos add (1, *p = *f); 667 1.1 christos continue; 668 1.1 christos } 669 1.1 christos 670 1.1 christos #endif /* ! DO_MULTIBYTE */ 671 1.1 christos 672 1.1 christos /* Check for flags that can modify a format. */ 673 1.1 christos while (1) 674 1.1 christos { 675 1.1 christos switch (*++f) 676 1.1 christos { 677 1.1 christos /* This influences the number formats. */ 678 1.1 christos case L_('_'): 679 1.1 christos case L_('-'): 680 1.1 christos case L_('0'): 681 1.1 christos pad = *f; 682 1.1 christos continue; 683 1.1 christos 684 1.1 christos /* This changes textual output. */ 685 1.1 christos case L_('^'): 686 1.1 christos to_uppcase = 1; 687 1.1 christos continue; 688 1.1 christos case L_('#'): 689 1.1 christos change_case = 1; 690 1.1 christos continue; 691 1.1 christos 692 1.1 christos default: 693 1.1 christos break; 694 1.1 christos } 695 1.1 christos break; 696 1.1 christos } 697 1.1 christos 698 1.1 christos /* As a GNU extension we allow to specify the field width. */ 699 1.1 christos if (ISDIGIT (*f)) 700 1.1 christos { 701 1.1 christos width = 0; 702 1.1 christos do 703 1.1 christos { 704 1.1 christos width *= 10; 705 1.1 christos width += *f - L_('0'); 706 1.1 christos ++f; 707 1.1 christos } 708 1.1 christos while (ISDIGIT (*f)); 709 1.1 christos } 710 1.1 christos 711 1.1 christos /* Check for modifiers. */ 712 1.1 christos switch (*f) 713 1.1 christos { 714 1.1 christos case L_('E'): 715 1.1 christos case L_('O'): 716 1.1 christos modifier = *f++; 717 1.1 christos break; 718 1.1 christos 719 1.1 christos default: 720 1.1 christos modifier = 0; 721 1.1 christos break; 722 1.1 christos } 723 1.1 christos 724 1.1 christos /* Now do the specified format. */ 725 1.1 christos format_char = *f; 726 1.1 christos switch (format_char) 727 1.1 christos { 728 1.1 christos #define DO_NUMBER(d, v) \ 729 1.1 christos digits = width == -1 ? d : width; \ 730 1.1 christos number_value = v; goto do_number 731 1.1 christos #define DO_NUMBER_SPACEPAD(d, v) \ 732 1.1 christos digits = width == -1 ? d : width; \ 733 1.1 christos number_value = v; goto do_number_spacepad 734 1.1 christos 735 1.1 christos case L_('%'): 736 1.1 christos if (modifier != 0) 737 1.1 christos goto bad_format; 738 1.1 christos add (1, *p = *f); 739 1.1 christos break; 740 1.1 christos 741 1.1 christos case L_('a'): 742 1.1 christos if (modifier != 0) 743 1.1 christos goto bad_format; 744 1.1 christos if (change_case) 745 1.1 christos { 746 1.1 christos to_uppcase = 1; 747 1.1 christos to_lowcase = 0; 748 1.1 christos } 749 1.1 christos #if defined _NL_CURRENT || !HAVE_STRFTIME 750 1.1 christos cpy (aw_len, a_wkday); 751 1.1 christos break; 752 1.1 christos #else 753 1.1 christos goto underlying_strftime; 754 1.1 christos #endif 755 1.1 christos 756 1.1 christos case 'A': 757 1.1 christos if (modifier != 0) 758 1.1 christos goto bad_format; 759 1.1 christos if (change_case) 760 1.1 christos { 761 1.1 christos to_uppcase = 1; 762 1.1 christos to_lowcase = 0; 763 1.1 christos } 764 1.1 christos #if defined _NL_CURRENT || !HAVE_STRFTIME 765 1.1 christos cpy (STRLEN (f_wkday), f_wkday); 766 1.1 christos break; 767 1.1 christos #else 768 1.1 christos goto underlying_strftime; 769 1.1 christos #endif 770 1.1 christos 771 1.1 christos case L_('b'): 772 1.1 christos case L_('h'): /* POSIX.2 extension. */ 773 1.1 christos if (change_case) 774 1.1 christos { 775 1.1 christos to_uppcase = 1; 776 1.1 christos to_lowcase = 0; 777 1.1 christos } 778 1.1 christos if (modifier != 0) 779 1.1 christos goto bad_format; 780 1.1 christos #if defined _NL_CURRENT || !HAVE_STRFTIME 781 1.1 christos cpy (am_len, a_month); 782 1.1 christos break; 783 1.1 christos #else 784 1.1 christos goto underlying_strftime; 785 1.1 christos #endif 786 1.1 christos 787 1.1 christos case L_('B'): 788 1.1 christos if (modifier != 0) 789 1.1 christos goto bad_format; 790 1.1 christos if (change_case) 791 1.1 christos { 792 1.1 christos to_uppcase = 1; 793 1.1 christos to_lowcase = 0; 794 1.1 christos } 795 1.1 christos #if defined _NL_CURRENT || !HAVE_STRFTIME 796 1.1 christos cpy (STRLEN (f_month), f_month); 797 1.1 christos break; 798 1.1 christos #else 799 1.1 christos goto underlying_strftime; 800 1.1 christos #endif 801 1.1 christos 802 1.1 christos case L_('c'): 803 1.1 christos if (modifier == L_('O')) 804 1.1 christos goto bad_format; 805 1.1 christos #ifdef _NL_CURRENT 806 1.1 christos if (! (modifier == 'E' 807 1.1 christos && (*(subfmt = 808 1.1 christos (const CHAR_T *) _NL_CURRENT (LC_TIME, 809 1.1 christos NLW(ERA_D_T_FMT))) 810 1.1 christos != '\0'))) 811 1.1 christos subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT)); 812 1.1 christos #else 813 1.1 christos # if HAVE_STRFTIME 814 1.1 christos goto underlying_strftime; 815 1.1 christos # else 816 1.1 christos subfmt = L_("%a %b %e %H:%M:%S %Y"); 817 1.1 christos # endif 818 1.1 christos #endif 819 1.1 christos 820 1.1 christos subformat: 821 1.1 christos { 822 1.1 christos CHAR_T *old_start = p; 823 1.1 christos size_t len = my_strftime (NULL, (size_t) -1, subfmt, 824 1.1 christos tp extra_args); 825 1.1 christos add (len, my_strftime (p, maxsize - i, subfmt, 826 1.1 christos tp extra_args)); 827 1.1 christos 828 1.1 christos if (to_uppcase) 829 1.1 christos while (old_start < p) 830 1.1 christos { 831 1.1 christos *old_start = TOUPPER ((UCHAR_T) *old_start); 832 1.1 christos ++old_start; 833 1.1 christos } 834 1.1 christos } 835 1.1 christos break; 836 1.1 christos 837 1.1 christos #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY) 838 1.1 christos underlying_strftime: 839 1.1 christos { 840 1.1 christos /* The relevant information is available only via the 841 1.1 christos underlying strftime implementation, so use that. */ 842 1.1 christos char ufmt[4]; 843 1.1 christos char *u = ufmt; 844 1.1 christos char ubuf[1024]; /* enough for any single format in practice */ 845 1.1 christos size_t len; 846 1.1 christos /* Make sure we're calling the actual underlying strftime. 847 1.1 christos In some cases, config.h contains something like 848 1.1 christos "#define strftime rpl_strftime". */ 849 1.1 christos # ifdef strftime 850 1.1 christos # undef strftime 851 1.1 christos size_t strftime (); 852 1.1 christos # endif 853 1.1 christos 854 1.1 christos *u++ = '%'; 855 1.1 christos if (modifier != 0) 856 1.1 christos *u++ = modifier; 857 1.1 christos *u++ = format_char; 858 1.1 christos *u = '\0'; 859 1.1 christos len = strftime (ubuf, sizeof ubuf, ufmt, tp); 860 1.1 christos if (len == 0 && ubuf[0] != '\0') 861 1.1 christos return 0; 862 1.1 christos cpy (len, ubuf); 863 1.1 christos } 864 1.1 christos break; 865 1.1 christos #endif 866 1.1 christos 867 1.1 christos case L_('C'): /* POSIX.2 extension. */ 868 1.1 christos if (modifier == L_('O')) 869 1.1 christos goto bad_format; 870 1.1 christos if (modifier == L_('E')) 871 1.1 christos { 872 1.1 christos #if HAVE_STRUCT_ERA_ENTRY 873 1.1 christos struct era_entry *era = _nl_get_era_entry (tp); 874 1.1 christos if (era) 875 1.1 christos { 876 1.1 christos # ifdef COMPILE_WIDE 877 1.1 christos size_t len = __wcslen (era->era_wname); 878 1.1 christos cpy (len, era->era_wname); 879 1.1 christos # else 880 1.1 christos size_t len = strlen (era->era_name); 881 1.1 christos cpy (len, era->era_name); 882 1.1 christos # endif 883 1.1 christos break; 884 1.1 christos } 885 1.1 christos #else 886 1.1 christos # if HAVE_STRFTIME 887 1.1 christos goto underlying_strftime; 888 1.1 christos # endif 889 1.1 christos #endif 890 1.1 christos } 891 1.1 christos 892 1.1 christos { 893 1.1 christos int year = tp->tm_year + TM_YEAR_BASE; 894 1.1 christos DO_NUMBER (1, year / 100 - (year % 100 < 0)); 895 1.1 christos } 896 1.1 christos 897 1.1 christos case L_('x'): 898 1.1 christos if (modifier == L_('O')) 899 1.1 christos goto bad_format; 900 1.1 christos #ifdef _NL_CURRENT 901 1.1 christos if (! (modifier == L_('E') 902 1.1 christos && (*(subfmt = 903 1.1 christos (const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT))) 904 1.1 christos != L_('\0')))) 905 1.1 christos subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT)); 906 1.1 christos goto subformat; 907 1.1 christos #else 908 1.1 christos # if HAVE_STRFTIME 909 1.1 christos goto underlying_strftime; 910 1.1 christos # else 911 1.1 christos /* Fall through. */ 912 1.1 christos # endif 913 1.1 christos #endif 914 1.1 christos case L_('D'): /* POSIX.2 extension. */ 915 1.1 christos if (modifier != 0) 916 1.1 christos goto bad_format; 917 1.1 christos subfmt = L_("%m/%d/%y"); 918 1.1 christos goto subformat; 919 1.1 christos 920 1.1 christos case L_('d'): 921 1.1 christos if (modifier == L_('E')) 922 1.1 christos goto bad_format; 923 1.1 christos 924 1.1 christos DO_NUMBER (2, tp->tm_mday); 925 1.1 christos 926 1.1 christos case L_('e'): /* POSIX.2 extension. */ 927 1.1 christos if (modifier == L_('E')) 928 1.1 christos goto bad_format; 929 1.1 christos 930 1.1 christos DO_NUMBER_SPACEPAD (2, tp->tm_mday); 931 1.1 christos 932 1.1 christos /* All numeric formats set DIGITS and NUMBER_VALUE and then 933 1.1 christos jump to one of these two labels. */ 934 1.1 christos 935 1.1 christos do_number_spacepad: 936 1.1 christos /* Force `_' flag unless overwritten by `0' flag. */ 937 1.1 christos if (pad != L_('0')) 938 1.1 christos pad = L_('_'); 939 1.1 christos 940 1.1 christos do_number: 941 1.1 christos /* Format the number according to the MODIFIER flag. */ 942 1.1 christos 943 1.1 christos if (modifier == L_('O') && 0 <= number_value) 944 1.1 christos { 945 1.1 christos #ifdef _NL_CURRENT 946 1.1 christos /* Get the locale specific alternate representation of 947 1.1 christos the number NUMBER_VALUE. If none exist NULL is returned. */ 948 1.1 christos # ifdef COMPILE_WIDE 949 1.1 christos const wchar_t *cp = _nl_get_walt_digit (number_value); 950 1.1 christos # else 951 1.1 christos const char *cp = _nl_get_alt_digit (number_value); 952 1.1 christos # endif 953 1.1 christos 954 1.1 christos if (cp != NULL) 955 1.1 christos { 956 1.1 christos size_t digitlen = STRLEN (cp); 957 1.1 christos if (digitlen != 0) 958 1.1 christos { 959 1.1 christos cpy (digitlen, cp); 960 1.1 christos break; 961 1.1 christos } 962 1.1 christos } 963 1.1 christos #else 964 1.1 christos # if HAVE_STRFTIME 965 1.1 christos goto underlying_strftime; 966 1.1 christos # endif 967 1.1 christos #endif 968 1.1 christos } 969 1.1 christos { 970 1.1 christos unsigned int u = number_value; 971 1.1 christos 972 1.1 christos bufp = buf + sizeof (buf) / sizeof (buf[0]); 973 1.1 christos negative_number = number_value < 0; 974 1.1 christos 975 1.1 christos if (negative_number) 976 1.1 christos u = -u; 977 1.1 christos 978 1.1 christos do 979 1.1 christos *--bufp = u % 10 + L_('0'); 980 1.1 christos while ((u /= 10) != 0); 981 1.1 christos } 982 1.1 christos 983 1.1 christos do_number_sign_and_padding: 984 1.1 christos if (negative_number) 985 1.1 christos *--bufp = L_('-'); 986 1.1 christos 987 1.1 christos if (pad != L_('-')) 988 1.1 christos { 989 1.1 christos int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0])) 990 1.1 christos - bufp); 991 1.1 christos 992 1.1 christos if (pad == L_('_')) 993 1.1 christos { 994 1.1 christos while (0 < padding--) 995 1.1 christos *--bufp = L_(' '); 996 1.1 christos } 997 1.1 christos else 998 1.1 christos { 999 1.1 christos bufp += negative_number; 1000 1.1 christos while (0 < padding--) 1001 1.1 christos *--bufp = L_('0'); 1002 1.1 christos if (negative_number) 1003 1.1 christos *--bufp = L_('-'); 1004 1.1 christos } 1005 1.1 christos } 1006 1.1 christos 1007 1.1 christos cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp); 1008 1.1 christos break; 1009 1.1 christos 1010 1.1 christos case L_('F'): 1011 1.1 christos if (modifier != 0) 1012 1.1 christos goto bad_format; 1013 1.1 christos subfmt = L_("%Y-%m-%d"); 1014 1.1 christos goto subformat; 1015 1.1 christos 1016 1.1 christos case L_('H'): 1017 1.1 christos if (modifier == L_('E')) 1018 1.1 christos goto bad_format; 1019 1.1 christos 1020 1.1 christos DO_NUMBER (2, tp->tm_hour); 1021 1.1 christos 1022 1.1 christos case L_('I'): 1023 1.1 christos if (modifier == L_('E')) 1024 1.1 christos goto bad_format; 1025 1.1 christos 1026 1.1 christos DO_NUMBER (2, hour12); 1027 1.1 christos 1028 1.1 christos case L_('k'): /* GNU extension. */ 1029 1.1 christos if (modifier == L_('E')) 1030 1.1 christos goto bad_format; 1031 1.1 christos 1032 1.1 christos DO_NUMBER_SPACEPAD (2, tp->tm_hour); 1033 1.1 christos 1034 1.1 christos case L_('l'): /* GNU extension. */ 1035 1.1 christos if (modifier == L_('E')) 1036 1.1 christos goto bad_format; 1037 1.1 christos 1038 1.1 christos DO_NUMBER_SPACEPAD (2, hour12); 1039 1.1 christos 1040 1.1 christos case L_('j'): 1041 1.1 christos if (modifier == L_('E')) 1042 1.1 christos goto bad_format; 1043 1.1 christos 1044 1.1 christos DO_NUMBER (3, 1 + tp->tm_yday); 1045 1.1 christos 1046 1.1 christos case L_('M'): 1047 1.1 christos if (modifier == L_('E')) 1048 1.1 christos goto bad_format; 1049 1.1 christos 1050 1.1 christos DO_NUMBER (2, tp->tm_min); 1051 1.1 christos 1052 1.1 christos case L_('m'): 1053 1.1 christos if (modifier == L_('E')) 1054 1.1 christos goto bad_format; 1055 1.1 christos 1056 1.1 christos DO_NUMBER (2, tp->tm_mon + 1); 1057 1.1 christos 1058 1.1 christos case L_('N'): /* GNU extension. */ 1059 1.1 christos if (modifier == L_('E')) 1060 1.1 christos goto bad_format; 1061 1.1 christos 1062 1.1 christos number_value = ns; 1063 1.1 christos if (width != -1) 1064 1.1 christos { 1065 1.1 christos /* Take an explicit width less than 9 as a precision. */ 1066 1.1 christos int j; 1067 1.1 christos for (j = width; j < 9; j++) 1068 1.1 christos number_value /= 10; 1069 1.1 christos } 1070 1.1 christos 1071 1.1 christos DO_NUMBER (9, number_value); 1072 1.1 christos 1073 1.1 christos case L_('n'): /* POSIX.2 extension. */ 1074 1.1 christos add (1, *p = L_('\n')); 1075 1.1 christos break; 1076 1.1 christos 1077 1.1 christos case L_('P'): 1078 1.1 christos to_lowcase = 1; 1079 1.1 christos #if !defined _NL_CURRENT && HAVE_STRFTIME 1080 1.1 christos format_char = L_('p'); 1081 1.1 christos #endif 1082 1.1 christos /* FALLTHROUGH */ 1083 1.1 christos 1084 1.1 christos case L_('p'): 1085 1.1 christos if (change_case) 1086 1.1 christos { 1087 1.1 christos to_uppcase = 0; 1088 1.1 christos to_lowcase = 1; 1089 1.1 christos } 1090 1.1 christos #if defined _NL_CURRENT || !HAVE_STRFTIME 1091 1.1 christos cpy (ap_len, ampm); 1092 1.1 christos break; 1093 1.1 christos #else 1094 1.1 christos goto underlying_strftime; 1095 1.1 christos #endif 1096 1.1 christos 1097 1.1 christos case L_('R'): /* ISO C99 extension. */ 1098 1.1 christos subfmt = L_("%H:%M"); 1099 1.1 christos goto subformat; 1100 1.1 christos 1101 1.1 christos case L_('r'): /* POSIX.2 extension. */ 1102 1.1 christos #ifdef _NL_CURRENT 1103 1.1 christos if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, 1104 1.1 christos NLW(T_FMT_AMPM))) 1105 1.1 christos == L_('\0')) 1106 1.1 christos #endif 1107 1.1 christos subfmt = L_("%I:%M:%S %p"); 1108 1.1 christos goto subformat; 1109 1.1 christos 1110 1.1 christos case L_('S'): 1111 1.1 christos if (modifier == L_('E')) 1112 1.1 christos goto bad_format; 1113 1.1 christos 1114 1.1 christos DO_NUMBER (2, tp->tm_sec); 1115 1.1 christos 1116 1.1 christos case L_('s'): /* GNU extension. */ 1117 1.1 christos { 1118 1.1 christos struct tm ltm; 1119 1.1 christos time_t t; 1120 1.1 christos 1121 1.1 christos ltm = *tp; 1122 1.1 christos t = mktime (<m); 1123 1.1 christos 1124 1.1 christos /* Generate string value for T using time_t arithmetic; 1125 1.1 christos this works even if sizeof (long) < sizeof (time_t). */ 1126 1.1 christos 1127 1.1 christos bufp = buf + sizeof (buf) / sizeof (buf[0]); 1128 1.1 christos negative_number = t < 0; 1129 1.1 christos 1130 1.1 christos do 1131 1.1 christos { 1132 1.1 christos int d = t % 10; 1133 1.1 christos t /= 10; 1134 1.1 christos 1135 1.1 christos if (negative_number) 1136 1.1 christos { 1137 1.1 christos d = -d; 1138 1.1 christos 1139 1.1 christos /* Adjust if division truncates to minus infinity. */ 1140 1.1 christos if (0 < -1 % 10 && d < 0) 1141 1.1 christos { 1142 1.1 christos t++; 1143 1.1 christos d += 10; 1144 1.1 christos } 1145 1.1 christos } 1146 1.1 christos 1147 1.1 christos *--bufp = d + L_('0'); 1148 1.1 christos } 1149 1.1 christos while (t != 0); 1150 1.1 christos 1151 1.1 christos digits = 1; 1152 1.1 christos goto do_number_sign_and_padding; 1153 1.1 christos } 1154 1.1 christos 1155 1.1 christos case L_('X'): 1156 1.1 christos if (modifier == L_('O')) 1157 1.1 christos goto bad_format; 1158 1.1 christos #ifdef _NL_CURRENT 1159 1.1 christos if (! (modifier == L_('E') 1160 1.1 christos && (*(subfmt = 1161 1.1 christos (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT))) 1162 1.1 christos != L_('\0')))) 1163 1.1 christos subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT)); 1164 1.1 christos goto subformat; 1165 1.1 christos #else 1166 1.1 christos # if HAVE_STRFTIME 1167 1.1 christos goto underlying_strftime; 1168 1.1 christos # else 1169 1.1 christos /* Fall through. */ 1170 1.1 christos # endif 1171 1.1 christos #endif 1172 1.1 christos case L_('T'): /* POSIX.2 extension. */ 1173 1.1 christos subfmt = L_("%H:%M:%S"); 1174 1.1 christos goto subformat; 1175 1.1 christos 1176 1.1 christos case L_('t'): /* POSIX.2 extension. */ 1177 1.1 christos add (1, *p = L_('\t')); 1178 1.1 christos break; 1179 1.1 christos 1180 1.1 christos case L_('u'): /* POSIX.2 extension. */ 1181 1.1 christos DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1); 1182 1.1 christos 1183 1.1 christos case L_('U'): 1184 1.1 christos if (modifier == L_('E')) 1185 1.1 christos goto bad_format; 1186 1.1 christos 1187 1.1 christos DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7); 1188 1.1 christos 1189 1.1 christos case L_('V'): 1190 1.1 christos case L_('g'): /* ISO C99 extension. */ 1191 1.1 christos case L_('G'): /* ISO C99 extension. */ 1192 1.1 christos if (modifier == L_('E')) 1193 1.1 christos goto bad_format; 1194 1.1 christos { 1195 1.1 christos int year = tp->tm_year + TM_YEAR_BASE; 1196 1.1 christos int days = iso_week_days (tp->tm_yday, tp->tm_wday); 1197 1.1 christos 1198 1.1 christos if (days < 0) 1199 1.1 christos { 1200 1.1 christos /* This ISO week belongs to the previous year. */ 1201 1.1 christos year--; 1202 1.1 christos days = iso_week_days (tp->tm_yday + (365 + __isleap (year)), 1203 1.1 christos tp->tm_wday); 1204 1.1 christos } 1205 1.1 christos else 1206 1.1 christos { 1207 1.1 christos int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)), 1208 1.1 christos tp->tm_wday); 1209 1.1 christos if (0 <= d) 1210 1.1 christos { 1211 1.1 christos /* This ISO week belongs to the next year. */ 1212 1.1 christos year++; 1213 1.1 christos days = d; 1214 1.1 christos } 1215 1.1 christos } 1216 1.1 christos 1217 1.1 christos switch (*f) 1218 1.1 christos { 1219 1.1 christos case L_('g'): 1220 1.1 christos DO_NUMBER (2, (year % 100 + 100) % 100); 1221 1.1 christos 1222 1.1 christos case L_('G'): 1223 1.1 christos DO_NUMBER (1, year); 1224 1.1 christos 1225 1.1 christos default: 1226 1.1 christos DO_NUMBER (2, days / 7 + 1); 1227 1.1 christos } 1228 1.1 christos } 1229 1.1 christos 1230 1.1 christos case L_('W'): 1231 1.1 christos if (modifier == L_('E')) 1232 1.1 christos goto bad_format; 1233 1.1 christos 1234 1.1 christos DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7); 1235 1.1 christos 1236 1.1 christos case L_('w'): 1237 1.1 christos if (modifier == L_('E')) 1238 1.1 christos goto bad_format; 1239 1.1 christos 1240 1.1 christos DO_NUMBER (1, tp->tm_wday); 1241 1.1 christos 1242 1.1 christos case L_('Y'): 1243 1.1 christos if (modifier == 'E') 1244 1.1 christos { 1245 1.1 christos #if HAVE_STRUCT_ERA_ENTRY 1246 1.1 christos struct era_entry *era = _nl_get_era_entry (tp); 1247 1.1 christos if (era) 1248 1.1 christos { 1249 1.1 christos # ifdef COMPILE_WIDE 1250 1.1 christos subfmt = era->era_wformat; 1251 1.1 christos # else 1252 1.1 christos subfmt = era->era_format; 1253 1.1 christos # endif 1254 1.1 christos goto subformat; 1255 1.1 christos } 1256 1.1 christos #else 1257 1.1 christos # if HAVE_STRFTIME 1258 1.1 christos goto underlying_strftime; 1259 1.1 christos # endif 1260 1.1 christos #endif 1261 1.1 christos } 1262 1.1 christos if (modifier == L_('O')) 1263 1.1 christos goto bad_format; 1264 1.1 christos else 1265 1.1 christos DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE); 1266 1.1 christos 1267 1.1 christos case L_('y'): 1268 1.1 christos if (modifier == L_('E')) 1269 1.1 christos { 1270 1.1 christos #if HAVE_STRUCT_ERA_ENTRY 1271 1.1 christos struct era_entry *era = _nl_get_era_entry (tp); 1272 1.1 christos if (era) 1273 1.1 christos { 1274 1.1 christos int delta = tp->tm_year - era->start_date[0]; 1275 1.1 christos DO_NUMBER (1, (era->offset 1276 1.1 christos + delta * era->absolute_direction)); 1277 1.1 christos } 1278 1.1 christos #else 1279 1.1 christos # if HAVE_STRFTIME 1280 1.1 christos goto underlying_strftime; 1281 1.1 christos # endif 1282 1.1 christos #endif 1283 1.1 christos } 1284 1.1 christos DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100); 1285 1.1 christos 1286 1.1 christos case L_('Z'): 1287 1.1 christos if (change_case) 1288 1.1 christos { 1289 1.1 christos to_uppcase = 0; 1290 1.1 christos to_lowcase = 1; 1291 1.1 christos } 1292 1.1 christos 1293 1.1 christos #if HAVE_TZNAME 1294 1.1 christos /* The tzset() call might have changed the value. */ 1295 1.1 christos if (!(zone && *zone) && tp->tm_isdst >= 0) 1296 1.1 christos zone = tzname[tp->tm_isdst]; 1297 1.1 christos #endif 1298 1.1 christos if (! zone) 1299 1.1 christos zone = ""; /* POSIX.2 requires the empty string here. */ 1300 1.1 christos 1301 1.1 christos #ifdef COMPILE_WIDE 1302 1.1 christos { 1303 1.1 christos /* The zone string is always given in multibyte form. We have 1304 1.1 christos to transform it first. */ 1305 1.1 christos wchar_t *wczone; 1306 1.1 christos size_t len; 1307 1.1 christos widen (zone, wczone, len); 1308 1.1 christos cpy (len, wczone); 1309 1.1 christos } 1310 1.1 christos #else 1311 1.1 christos cpy (strlen (zone), zone); 1312 1.1 christos #endif 1313 1.1 christos break; 1314 1.1 christos 1315 1.1 christos case L_('z'): /* ISO C99 extension. */ 1316 1.1 christos if (tp->tm_isdst < 0) 1317 1.1 christos break; 1318 1.1 christos 1319 1.1 christos { 1320 1.1 christos int diff; 1321 1.1 christos #if HAVE_TM_GMTOFF 1322 1.1 christos diff = tp->tm_gmtoff; 1323 1.1 christos #else 1324 1.1 christos if (ut) 1325 1.1 christos diff = 0; 1326 1.1 christos else 1327 1.1 christos { 1328 1.1 christos struct tm gtm; 1329 1.1 christos struct tm ltm; 1330 1.1 christos time_t lt; 1331 1.1 christos 1332 1.1 christos ltm = *tp; 1333 1.1 christos lt = mktime (<m); 1334 1.1 christos 1335 1.1 christos if (lt == (time_t) -1) 1336 1.1 christos { 1337 1.1 christos /* mktime returns -1 for errors, but -1 is also a 1338 1.1 christos valid time_t value. Check whether an error really 1339 1.1 christos occurred. */ 1340 1.1 christos struct tm tm; 1341 1.1 christos 1342 1.1 christos if (! my_strftime_localtime_r (<, &tm) 1343 1.1 christos || ((ltm.tm_sec ^ tm.tm_sec) 1344 1.1 christos | (ltm.tm_min ^ tm.tm_min) 1345 1.1 christos | (ltm.tm_hour ^ tm.tm_hour) 1346 1.1 christos | (ltm.tm_mday ^ tm.tm_mday) 1347 1.1 christos | (ltm.tm_mon ^ tm.tm_mon) 1348 1.1 christos | (ltm.tm_year ^ tm.tm_year))) 1349 1.1 christos break; 1350 1.1 christos } 1351 1.1 christos 1352 1.1 christos if (! my_strftime_gmtime_r (<, >m)) 1353 1.1 christos break; 1354 1.1 christos 1355 1.1 christos diff = tm_diff (<m, >m); 1356 1.1 christos } 1357 1.1 christos #endif 1358 1.1 christos 1359 1.1 christos if (diff < 0) 1360 1.1 christos { 1361 1.1 christos add (1, *p = L_('-')); 1362 1.1 christos diff = -diff; 1363 1.1 christos } 1364 1.1 christos else 1365 1.1 christos add (1, *p = L_('+')); 1366 1.1 christos 1367 1.1 christos diff /= 60; 1368 1.1 christos DO_NUMBER (4, (diff / 60) * 100 + diff % 60); 1369 1.1 christos } 1370 1.1 christos 1371 1.1 christos case L_('\0'): /* GNU extension: % at end of format. */ 1372 1.1 christos --f; 1373 1.1 christos /* Fall through. */ 1374 1.1 christos default: 1375 1.1 christos /* Unknown format; output the format, including the '%', 1376 1.1 christos since this is most likely the right thing to do if a 1377 1.1 christos multibyte string has been misparsed. */ 1378 1.1 christos bad_format: 1379 1.1 christos { 1380 1.1 christos int flen; 1381 1.1 christos for (flen = 1; f[1 - flen] != L_('%'); flen++) 1382 1.1 christos continue; 1383 1.1 christos cpy (flen, &f[1 - flen]); 1384 1.1 christos } 1385 1.1 christos break; 1386 1.1 christos } 1387 1.1 christos } 1388 1.1 christos 1389 1.1 christos if (p && maxsize != 0) 1390 1.1 christos *p = L_('\0'); 1391 1.1 christos return i; 1392 1.1 christos } 1393 1.1 christos 1394 1.1 christos 1395 1.1 christos #ifdef emacs 1396 1.1 christos /* For Emacs we have a separate interface which corresponds to the normal 1397 1.1 christos strftime function plus the ut argument, but without the ns argument. */ 1398 1.1 christos size_t 1399 1.1 christos emacs_strftimeu (s, maxsize, format, tp, ut) 1400 1.1 christos char *s; 1401 1.1 christos size_t maxsize; 1402 1.1 christos const char *format; 1403 1.1 christos const struct tm *tp; 1404 1.1 christos int ut; 1405 1.1 christos { 1406 1.1 christos return my_strftime (s, maxsize, format, tp, ut, 0); 1407 1.1 christos } 1408 1.1 christos #endif 1409