Annotation of embedaddon/lrzsz/lib/strftime.c, revision 1.1
1.1 ! misho 1: /* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
! 2:
! 3: NOTE: The canonical source of this file is maintained with the GNU C
! 4: Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
! 5:
! 6: This program is free software; you can redistribute it and/or modify it
! 7: under the terms of the GNU General Public License as published by the
! 8: Free Software Foundation; either version 2, or (at your option) any
! 9: later version.
! 10:
! 11: This program is distributed in the hope that it will be useful,
! 12: but WITHOUT ANY WARRANTY; without even the implied warranty of
! 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 14: GNU General Public License for more details.
! 15:
! 16: You should have received a copy of the GNU General Public License
! 17: along with this program; if not, write to the Free Software Foundation,
! 18: Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
! 19:
! 20: #ifdef HAVE_CONFIG_H
! 21: # include <config.h>
! 22: #endif
! 23:
! 24: #ifdef _LIBC
! 25: # define HAVE_LIMITS_H 1
! 26: # define HAVE_MBLEN 1
! 27: # define HAVE_MBRLEN 1
! 28: # define HAVE_STRUCT_ERA_ENTRY 1
! 29: # define HAVE_TM_GMTOFF 1
! 30: # define HAVE_TM_ZONE 1
! 31: # define MULTIBYTE_IS_FORMAT_SAFE 1
! 32: # define STDC_HEADERS 1
! 33: # include <ansidecl.h>
! 34: # include "../locale/localeinfo.h"
! 35: #endif
! 36:
! 37: #include <sys/types.h> /* Some systems define `time_t' here. */
! 38:
! 39: #ifdef TIME_WITH_SYS_TIME
! 40: # include <sys/time.h>
! 41: # include <time.h>
! 42: #else
! 43: # ifdef HAVE_SYS_TIME_H
! 44: # include <sys/time.h>
! 45: # else
! 46: # include <time.h>
! 47: # endif
! 48: #endif
! 49:
! 50: #if HAVE_TZNAME
! 51: extern char *tzname[];
! 52: #endif
! 53:
! 54: /* Do multibyte processing if multibytes are supported, unless
! 55: multibyte sequences are safe in formats. Multibyte sequences are
! 56: safe if they cannot contain byte sequences that look like format
! 57: conversion specifications. The GNU C Library uses UTF8 multibyte
! 58: encoding, which is safe for formats, but strftime.c can be used
! 59: with other C libraries that use unsafe encodings. */
! 60: #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
! 61:
! 62: #if DO_MULTIBYTE
! 63: # if HAVE_MBRLEN
! 64: # include <wchar.h>
! 65: # else
! 66: /* Simulate mbrlen with mblen as best we can. */
! 67: # define mbstate_t int
! 68: # define mbrlen(s, n, ps) mblen (s, n)
! 69: # define mbsinit(ps) (*(ps) == 0)
! 70: # endif
! 71: static const mbstate_t mbstate_zero;
! 72: #endif
! 73:
! 74: #if HAVE_LIMITS_H
! 75: # include <limits.h>
! 76: #endif
! 77:
! 78: #if STDC_HEADERS
! 79: # include <stddef.h>
! 80: # include <stdlib.h>
! 81: # include <string.h>
! 82: #else
! 83: # define memcpy(d, s, n) bcopy (s, d, n)
! 84: #endif
! 85:
! 86: #ifndef __P
! 87: #if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
! 88: #define __P(args) args
! 89: #else
! 90: #define __P(args) ()
! 91: #endif /* GCC. */
! 92: #endif /* Not __P. */
! 93:
! 94: #ifndef PTR
! 95: #ifdef __STDC__
! 96: #define PTR void *
! 97: #else
! 98: #define PTR char *
! 99: #endif
! 100: #endif
! 101:
! 102: #ifndef CHAR_BIT
! 103: #define CHAR_BIT 8
! 104: #endif
! 105:
! 106: #define TYPE_SIGNED(t) ((t) -1 < 0)
! 107:
! 108: /* Bound on length of the string representing an integer value of type t.
! 109: Subtract one for the sign bit if t is signed;
! 110: 302 / 1000 is log10 (2) rounded up;
! 111: add one for integer division truncation;
! 112: add one more for a minus sign if t is signed. */
! 113: #define INT_STRLEN_BOUND(t) \
! 114: ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
! 115:
! 116: #define TM_YEAR_BASE 1900
! 117:
! 118: #ifndef __isleap
! 119: /* Nonzero if YEAR is a leap year (every 4 years,
! 120: except every 100th isn't, and every 400th is). */
! 121: #define __isleap(year) \
! 122: ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
! 123: #endif
! 124:
! 125:
! 126: #ifdef _LIBC
! 127: # define gmtime_r __gmtime_r
! 128: # define localtime_r __localtime_r
! 129: #else
! 130: # if ! HAVE_LOCALTIME_R
! 131: # if ! HAVE_TM_GMTOFF
! 132: /* Approximate gmtime_r as best we can in its absence. */
! 133: #define gmtime_r my_gmtime_r
! 134: static struct tm *gmtime_r __P ((const time_t *, struct tm *));
! 135: static struct tm *
! 136: gmtime_r (t, tp)
! 137: const time_t *t;
! 138: struct tm *tp;
! 139: {
! 140: struct tm *l = gmtime (t);
! 141: if (! l)
! 142: return 0;
! 143: *tp = *l;
! 144: return tp;
! 145: }
! 146: # endif /* ! HAVE_TM_GMTOFF */
! 147:
! 148: /* Approximate localtime_r as best we can in its absence. */
! 149: #define localtime_r my_localtime_r
! 150: static struct tm *localtime_r __P ((const time_t *, struct tm *));
! 151: static struct tm *
! 152: localtime_r (t, tp)
! 153: const time_t *t;
! 154: struct tm *tp;
! 155: {
! 156: struct tm *l = localtime (t);
! 157: if (! l)
! 158: return 0;
! 159: *tp = *l;
! 160: return tp;
! 161: }
! 162: # endif /* ! HAVE_LOCALTIME_R */
! 163: #endif /* ! defined (_LIBC) */
! 164:
! 165:
! 166: #define add(n, f) \
! 167: do \
! 168: { \
! 169: i += (n); \
! 170: if (i >= maxsize) \
! 171: return 0; \
! 172: else \
! 173: if (p) \
! 174: { \
! 175: f; \
! 176: p += (n); \
! 177: } \
! 178: } while (0)
! 179: #define cpy(n, s) add ((n), memcpy((PTR) p, (PTR) (s), (n)))
! 180:
! 181: #if ! HAVE_TM_GMTOFF
! 182: /* Yield the difference between *A and *B,
! 183: measured in seconds, ignoring leap seconds. */
! 184: static int tm_diff __P ((const struct tm *, const struct tm *));
! 185: static int
! 186: tm_diff (a, b)
! 187: const struct tm *a;
! 188: const struct tm *b;
! 189: {
! 190: /* Compute intervening leap days correctly even if year is negative.
! 191: Take care to avoid int overflow in leap day calculations,
! 192: but it's OK to assume that A and B are close to each other. */
! 193: int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
! 194: int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
! 195: int a100 = a4 / 25 - (a4 % 25 < 0);
! 196: int b100 = b4 / 25 - (b4 % 25 < 0);
! 197: int a400 = a100 >> 2;
! 198: int b400 = b100 >> 2;
! 199: int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
! 200: int years = a->tm_year - b->tm_year;
! 201: int days = (365 * years + intervening_leap_days
! 202: + (a->tm_yday - b->tm_yday));
! 203: return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
! 204: + (a->tm_min - b->tm_min))
! 205: + (a->tm_sec - b->tm_sec));
! 206: }
! 207: #endif /* ! HAVE_TM_GMTOFF */
! 208:
! 209:
! 210:
! 211: /* The number of days from the first day of the first ISO week of this
! 212: year to the year day YDAY with week day WDAY. ISO weeks start on
! 213: Monday; the first ISO week has the year's first Thursday. YDAY may
! 214: be as small as YDAY_MINIMUM. */
! 215: #define ISO_WEEK_START_WDAY 1 /* Monday */
! 216: #define ISO_WEEK1_WDAY 4 /* Thursday */
! 217: #define YDAY_MINIMUM (-366)
! 218: static int iso_week_days __P ((int, int));
! 219: #ifdef __GNUC__
! 220: inline
! 221: #endif
! 222: static int
! 223: iso_week_days (yday, wday)
! 224: int yday;
! 225: int wday;
! 226: {
! 227: /* Add enough to the first operand of % to make it nonnegative. */
! 228: int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
! 229: return (yday
! 230: - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
! 231: + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
! 232: }
! 233:
! 234:
! 235: #ifndef _NL_CURRENT
! 236: static char const weekday_name[][10] =
! 237: {
! 238: "Sunday", "Monday", "Tuesday", "Wednesday",
! 239: "Thursday", "Friday", "Saturday"
! 240: };
! 241: static char const month_name[][10] =
! 242: {
! 243: "January", "February", "March", "April", "May", "June",
! 244: "July", "August", "September", "October", "November", "December"
! 245: };
! 246: #endif
! 247:
! 248: /* Write information from TP into S according to the format
! 249: string FORMAT, writing no more that MAXSIZE characters
! 250: (including the terminating '\0') and returning number of
! 251: characters written. If S is NULL, nothing will be written
! 252: anywhere, so to determine how many characters would be
! 253: written, use NULL for S and (size_t) UINT_MAX for MAXSIZE. */
! 254: size_t
! 255: strftime (s, maxsize, format, tp)
! 256: char *s;
! 257: size_t maxsize;
! 258: const char *format;
! 259: register const struct tm *tp;
! 260: {
! 261: int hour12 = tp->tm_hour;
! 262: #ifdef _NL_CURRENT
! 263: const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
! 264: const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
! 265: const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
! 266: const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
! 267: const char *const ampm = _NL_CURRENT (LC_TIME,
! 268: hour12 > 11 ? PM_STR : AM_STR);
! 269: size_t aw_len = strlen (a_wkday);
! 270: size_t am_len = strlen (a_month);
! 271: size_t ap_len = strlen (ampm);
! 272: #else
! 273: const char *const f_wkday = weekday_name[tp->tm_wday];
! 274: const char *const f_month = month_name[tp->tm_mon];
! 275: const char *const a_wkday = f_wkday;
! 276: const char *const a_month = f_month;
! 277: const char *const ampm = "AMPM" + 2 * (hour12 > 11);
! 278: size_t aw_len = 3;
! 279: size_t am_len = 3;
! 280: size_t ap_len = 2;
! 281: #endif
! 282: size_t wkday_len = strlen (f_wkday);
! 283: size_t month_len = strlen (f_month);
! 284: const char *zone;
! 285: size_t zonelen;
! 286: register size_t i = 0;
! 287: register char *p = s;
! 288: register const char *f;
! 289:
! 290: zone = 0;
! 291: #if HAVE_TM_ZONE
! 292: zone = (const char *) tp->tm_zone;
! 293: #endif
! 294: #if HAVE_TZNAME
! 295: if (!(zone && *zone) && tp->tm_isdst >= 0)
! 296: zone = tzname[tp->tm_isdst];
! 297: #endif
! 298: if (! zone)
! 299: zone = ""; /* POSIX.2 requires the empty string here. */
! 300:
! 301: zonelen = strlen (zone);
! 302:
! 303: if (hour12 > 12)
! 304: hour12 -= 12;
! 305: else
! 306: if (hour12 == 0) hour12 = 12;
! 307:
! 308: for (f = format; *f != '\0'; ++f)
! 309: {
! 310: int pad; /* Padding for number ('-', '_', or 0). */
! 311: int modifier; /* Field modifier ('E', 'O', or 0). */
! 312: int digits; /* Max digits for numeric format. */
! 313: int number_value; /* Numeric value to be printed. */
! 314: int negative_number; /* 1 if the number is negative. */
! 315: const char *subfmt;
! 316: char *bufp;
! 317: char buf[1 + (sizeof (int) < sizeof (time_t)
! 318: ? INT_STRLEN_BOUND (time_t)
! 319: : INT_STRLEN_BOUND (int))];
! 320:
! 321: #if DO_MULTIBYTE
! 322:
! 323: switch (*f)
! 324: {
! 325: case '%':
! 326: break;
! 327:
! 328: case '\a': case '\b': case '\t': case '\n':
! 329: case '\v': case '\f': case '\r':
! 330: case ' ': case '!': case '"': case '#': case '&': case'\'':
! 331: case '(': case ')': case '*': case '+': case ',': case '-':
! 332: case '.': case '/': case '0': case '1': case '2': case '3':
! 333: case '4': case '5': case '6': case '7': case '8': case '9':
! 334: case ':': case ';': case '<': case '=': case '>': case '?':
! 335: case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
! 336: case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
! 337: case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
! 338: case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
! 339: case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
! 340: case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
! 341: case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
! 342: case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
! 343: case 'r': case 's': case 't': case 'u': case 'v': case 'w':
! 344: case 'x': case 'y': case 'z': case '{': case '|': case '}':
! 345: case '~':
! 346: /* The C Standard requires these 98 characters (plus '%') to
! 347: be in the basic execution character set. None of these
! 348: characters can start a multibyte sequence, so they need
! 349: not be analyzed further. */
! 350: add (1, *p = *f);
! 351: continue;
! 352:
! 353: default:
! 354: /* Copy this multibyte sequence until we reach its end, find
! 355: an error, or come back to the initial shift state. */
! 356: {
! 357: mbstate_t mbstate = mbstate_zero;
! 358: size_t len = 0;
! 359:
! 360: do
! 361: {
! 362: size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
! 363:
! 364: if (bytes == 0)
! 365: break;
! 366:
! 367: if (bytes == (size_t) -2 || bytes == (size_t) -1)
! 368: {
! 369: len++;
! 370: break;
! 371: }
! 372:
! 373: len += bytes;
! 374: }
! 375: while (! mbsinit (&mbstate));
! 376:
! 377: cpy (len, f);
! 378: continue;
! 379: }
! 380: }
! 381:
! 382: #else /* ! DO_MULTIBYTE */
! 383:
! 384: /* Either multibyte encodings are not supported, or they are
! 385: safe for formats, so any non-'%' byte can be copied through. */
! 386: if (*f != '%')
! 387: {
! 388: add (1, *p = *f);
! 389: continue;
! 390: }
! 391:
! 392: #endif /* ! DO_MULTIBYTE */
! 393:
! 394: /* Check for flags that can modify a number format. */
! 395: ++f;
! 396: switch (*f)
! 397: {
! 398: case '_':
! 399: case '-':
! 400: pad = *f++;
! 401: break;
! 402:
! 403: default:
! 404: pad = 0;
! 405: break;
! 406: }
! 407:
! 408: /* Check for modifiers. */
! 409: switch (*f)
! 410: {
! 411: case 'E':
! 412: case 'O':
! 413: modifier = *f++;
! 414: break;
! 415:
! 416: default:
! 417: modifier = 0;
! 418: break;
! 419: }
! 420:
! 421: /* Now do the specified format. */
! 422: switch (*f)
! 423: {
! 424: #define DO_NUMBER(d, v) \
! 425: digits = d; number_value = v; goto do_number
! 426: #define DO_NUMBER_SPACEPAD(d, v) \
! 427: digits = d; number_value = v; goto do_number_spacepad
! 428:
! 429: case '%':
! 430: if (modifier != 0)
! 431: goto bad_format;
! 432: add (1, *p = *f);
! 433: break;
! 434:
! 435: case 'a':
! 436: if (modifier != 0)
! 437: goto bad_format;
! 438: cpy (aw_len, a_wkday);
! 439: break;
! 440:
! 441: case 'A':
! 442: if (modifier != 0)
! 443: goto bad_format;
! 444: cpy (wkday_len, f_wkday);
! 445: break;
! 446:
! 447: case 'b':
! 448: case 'h': /* POSIX.2 extension. */
! 449: if (modifier != 0)
! 450: goto bad_format;
! 451: cpy (am_len, a_month);
! 452: break;
! 453:
! 454: case 'B':
! 455: if (modifier != 0)
! 456: goto bad_format;
! 457: cpy (month_len, f_month);
! 458: break;
! 459:
! 460: case 'c':
! 461: if (modifier == 'O')
! 462: goto bad_format;
! 463: #ifdef _NL_CURRENT
! 464: if (! (modifier == 'E'
! 465: && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
! 466: subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
! 467: #else
! 468: subfmt = "%a %b %e %H:%M:%S %Y";
! 469: #endif
! 470:
! 471: subformat:
! 472: {
! 473: size_t len = strftime (p, maxsize - i, subfmt, tp);
! 474: if (len == 0 && *subfmt)
! 475: return 0;
! 476: add (len, ;);
! 477: }
! 478: break;
! 479:
! 480: case 'C': /* POSIX.2 extension. */
! 481: if (modifier == 'O')
! 482: goto bad_format;
! 483: #if HAVE_STRUCT_ERA_ENTRY
! 484: if (modifier == 'E')
! 485: {
! 486: struct era_entry *era = _nl_get_era_entry (tp);
! 487: if (era)
! 488: {
! 489: size_t len = strlen (era->name_fmt);
! 490: cpy (len, era->name_fmt);
! 491: break;
! 492: }
! 493: }
! 494: #endif
! 495: {
! 496: int year = tp->tm_year + TM_YEAR_BASE;
! 497: DO_NUMBER (1, year / 100 - (year % 100 < 0));
! 498: }
! 499:
! 500: case 'x':
! 501: if (modifier == 'O')
! 502: goto bad_format;
! 503: #ifdef _NL_CURRENT
! 504: if (! (modifier == 'E'
! 505: && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
! 506: subfmt = _NL_CURRENT (LC_TIME, D_FMT);
! 507: goto subformat;
! 508: #endif
! 509: /* Fall through. */
! 510: case 'D': /* POSIX.2 extension. */
! 511: if (modifier != 0)
! 512: goto bad_format;
! 513: subfmt = "%m/%d/%y";
! 514: goto subformat;
! 515:
! 516: case 'd':
! 517: if (modifier == 'E')
! 518: goto bad_format;
! 519:
! 520: DO_NUMBER (2, tp->tm_mday);
! 521:
! 522: case 'e': /* POSIX.2 extension. */
! 523: if (modifier == 'E')
! 524: goto bad_format;
! 525:
! 526: DO_NUMBER_SPACEPAD (2, tp->tm_mday);
! 527:
! 528: /* All numeric formats set DIGITS and NUMBER_VALUE and then
! 529: jump to one of these two labels. */
! 530:
! 531: do_number_spacepad:
! 532: /* Force `_' flag. */
! 533: pad = '_';
! 534:
! 535: do_number:
! 536: /* Format the number according to the MODIFIER flag. */
! 537:
! 538: #ifdef _NL_CURRENT
! 539: if (modifier == 'O' && 0 <= number_value)
! 540: {
! 541: /* Get the locale specific alternate representation of
! 542: the number NUMBER_VALUE. If none exist NULL is returned. */
! 543: const char *cp = _nl_get_alt_digit (number_value);
! 544:
! 545: if (cp != NULL)
! 546: {
! 547: size_t digitlen = strlen (cp);
! 548: if (digitlen != 0)
! 549: {
! 550: cpy (digitlen, cp);
! 551: break;
! 552: }
! 553: }
! 554: }
! 555: #endif
! 556: {
! 557: unsigned int u = number_value;
! 558:
! 559: bufp = buf + sizeof (buf);
! 560: negative_number = number_value < 0;
! 561:
! 562: if (negative_number)
! 563: u = -u;
! 564:
! 565: do
! 566: *--bufp = u % 10 + '0';
! 567: while ((u /= 10) != 0);
! 568: }
! 569:
! 570: do_number_sign_and_padding:
! 571: if (negative_number)
! 572: *--bufp = '-';
! 573:
! 574: if (pad != '-')
! 575: {
! 576: int padding = digits - (buf + sizeof (buf) - bufp);
! 577:
! 578: if (pad == '_')
! 579: {
! 580: while (0 < padding--)
! 581: *--bufp = ' ';
! 582: }
! 583: else
! 584: {
! 585: bufp += negative_number;
! 586: while (0 < padding--)
! 587: *--bufp = '0';
! 588: if (negative_number)
! 589: *--bufp = '-';
! 590: }
! 591: }
! 592:
! 593: cpy (buf + sizeof (buf) - bufp, bufp);
! 594: break;
! 595:
! 596:
! 597: case 'H':
! 598: if (modifier == 'E')
! 599: goto bad_format;
! 600:
! 601: DO_NUMBER (2, tp->tm_hour);
! 602:
! 603: case 'I':
! 604: if (modifier == 'E')
! 605: goto bad_format;
! 606:
! 607: DO_NUMBER (2, hour12);
! 608:
! 609: case 'k': /* GNU extension. */
! 610: if (modifier == 'E')
! 611: goto bad_format;
! 612:
! 613: DO_NUMBER_SPACEPAD (2, tp->tm_hour);
! 614:
! 615: case 'l': /* GNU extension. */
! 616: if (modifier == 'E')
! 617: goto bad_format;
! 618:
! 619: DO_NUMBER_SPACEPAD (2, hour12);
! 620:
! 621: case 'j':
! 622: if (modifier == 'E')
! 623: goto bad_format;
! 624:
! 625: DO_NUMBER (3, 1 + tp->tm_yday);
! 626:
! 627: case 'M':
! 628: if (modifier == 'E')
! 629: goto bad_format;
! 630:
! 631: DO_NUMBER (2, tp->tm_min);
! 632:
! 633: case 'm':
! 634: if (modifier == 'E')
! 635: goto bad_format;
! 636:
! 637: DO_NUMBER (2, tp->tm_mon + 1);
! 638:
! 639: case 'n': /* POSIX.2 extension. */
! 640: add (1, *p = '\n');
! 641: break;
! 642:
! 643: case 'p':
! 644: cpy (ap_len, ampm);
! 645: break;
! 646:
! 647: case 'R': /* GNU extension. */
! 648: subfmt = "%H:%M";
! 649: goto subformat;
! 650:
! 651: case 'r': /* POSIX.2 extension. */
! 652: #ifdef _NL_CURRENT
! 653: if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
! 654: #endif
! 655: subfmt = "%I:%M:%S %p";
! 656: goto subformat;
! 657:
! 658: case 'S':
! 659: if (modifier == 'E')
! 660: goto bad_format;
! 661:
! 662: DO_NUMBER (2, tp->tm_sec);
! 663:
! 664: case 's': /* GNU extension. */
! 665: {
! 666: struct tm ltm;
! 667: time_t t;
! 668:
! 669: ltm = *tp;
! 670: t = mktime (<m);
! 671:
! 672: /* Generate string value for T using time_t arithmetic;
! 673: this works even if sizeof (long) < sizeof (time_t). */
! 674:
! 675: bufp = buf + sizeof (buf);
! 676: negative_number = t < 0;
! 677:
! 678: do
! 679: {
! 680: int d = t % 10;
! 681: t /= 10;
! 682:
! 683: if (negative_number)
! 684: {
! 685: d = -d;
! 686:
! 687: /* Adjust if division truncates to minus infinity. */
! 688: if (0 < -1 % 10 && d < 0)
! 689: {
! 690: t++;
! 691: d += 10;
! 692: }
! 693: }
! 694:
! 695: *--bufp = d + '0';
! 696: }
! 697: while (t != 0);
! 698:
! 699: digits = 1;
! 700: goto do_number_sign_and_padding;
! 701: }
! 702:
! 703: case 'X':
! 704: if (modifier == 'O')
! 705: goto bad_format;
! 706: #ifdef _NL_CURRENT
! 707: if (! (modifier == 'E'
! 708: && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
! 709: subfmt = _NL_CURRENT (LC_TIME, T_FMT);
! 710: goto subformat;
! 711: #endif
! 712: /* Fall through. */
! 713: case 'T': /* POSIX.2 extension. */
! 714: subfmt = "%H:%M:%S";
! 715: goto subformat;
! 716:
! 717: case 't': /* POSIX.2 extension. */
! 718: add (1, *p = '\t');
! 719: break;
! 720:
! 721: case 'u': /* POSIX.2 extension. */
! 722: DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
! 723:
! 724: case 'U':
! 725: if (modifier == 'E')
! 726: goto bad_format;
! 727:
! 728: DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
! 729:
! 730: case 'V':
! 731: case 'g': /* GNU extension. */
! 732: case 'G': /* GNU extension. */
! 733: if (modifier == 'E')
! 734: goto bad_format;
! 735: {
! 736: int year = tp->tm_year + TM_YEAR_BASE;
! 737: int days = iso_week_days (tp->tm_yday, tp->tm_wday);
! 738:
! 739: if (days < 0)
! 740: {
! 741: /* This ISO week belongs to the previous year. */
! 742: year--;
! 743: days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
! 744: tp->tm_wday);
! 745: }
! 746: else
! 747: {
! 748: int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
! 749: tp->tm_wday);
! 750: if (0 <= d)
! 751: {
! 752: /* This ISO week belongs to the next year. */
! 753: year++;
! 754: days = d;
! 755: }
! 756: }
! 757:
! 758: switch (*f)
! 759: {
! 760: case 'g':
! 761: DO_NUMBER (2, (year % 100 + 100) % 100);
! 762:
! 763: case 'G':
! 764: DO_NUMBER (1, year);
! 765:
! 766: default:
! 767: DO_NUMBER (2, days / 7 + 1);
! 768: }
! 769: }
! 770:
! 771: case 'W':
! 772: if (modifier == 'E')
! 773: goto bad_format;
! 774:
! 775: DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
! 776:
! 777: case 'w':
! 778: if (modifier == 'E')
! 779: goto bad_format;
! 780:
! 781: DO_NUMBER (1, tp->tm_wday);
! 782:
! 783: case 'Y':
! 784: #if HAVE_STRUCT_ERA_ENTRY
! 785: if (modifier == 'E')
! 786: {
! 787: struct era_entry *era = _nl_get_era_entry (tp);
! 788: if (era)
! 789: {
! 790: subfmt = strchr (era->name_fmt, '\0') + 1;
! 791: goto subformat;
! 792: }
! 793: }
! 794: #endif
! 795: if (modifier == 'O')
! 796: goto bad_format;
! 797: else
! 798: DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
! 799:
! 800: case 'y':
! 801: #if HAVE_STRUCT_ERA_ENTRY
! 802: if (modifier == 'E')
! 803: {
! 804: struct era_entry *era = _nl_get_era_entry (tp);
! 805: if (era)
! 806: {
! 807: int delta = tp->tm_year - era->start_date[0];
! 808: DO_NUMBER (1, (era->offset
! 809: + (era->direction == '-' ? -delta : delta)));
! 810: }
! 811: }
! 812: #endif
! 813: DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
! 814:
! 815: case 'Z':
! 816: cpy (zonelen, zone);
! 817: break;
! 818:
! 819: case 'z': /* GNU extension. */
! 820: if (tp->tm_isdst < 0)
! 821: break;
! 822:
! 823: {
! 824: int diff;
! 825: #if HAVE_TM_GMTOFF
! 826: diff = tp->tm_gmtoff;
! 827: #else
! 828: struct tm gtm;
! 829: struct tm ltm;
! 830: time_t lt;
! 831:
! 832: ltm = *tp;
! 833: lt = mktime (<m);
! 834:
! 835: if (lt == (time_t) -1)
! 836: {
! 837: /* mktime returns -1 for errors, but -1 is also a
! 838: valid time_t value. Check whether an error really
! 839: occurred. */
! 840: struct tm tm;
! 841: localtime_r (<, &tm);
! 842:
! 843: if ((ltm.tm_sec ^ tm.tm_sec)
! 844: | (ltm.tm_min ^ tm.tm_min)
! 845: | (ltm.tm_hour ^ tm.tm_hour)
! 846: | (ltm.tm_mday ^ tm.tm_mday)
! 847: | (ltm.tm_mon ^ tm.tm_mon)
! 848: | (ltm.tm_year ^ tm.tm_year))
! 849: break;
! 850: }
! 851:
! 852: if (! gmtime_r (<, >m))
! 853: break;
! 854:
! 855: diff = tm_diff (<m, >m);
! 856: #endif
! 857:
! 858: if (diff < 0)
! 859: {
! 860: add (1, *p = '-');
! 861: diff = -diff;
! 862: }
! 863: else
! 864: add (1, *p = '+');
! 865:
! 866: diff /= 60;
! 867: DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
! 868: }
! 869:
! 870: case '\0': /* GNU extension: % at end of format. */
! 871: --f;
! 872: /* Fall through. */
! 873: default:
! 874: /* Unknown format; output the format, including the '%',
! 875: since this is most likely the right thing to do if a
! 876: multibyte string has been misparsed. */
! 877: bad_format:
! 878: {
! 879: int flen;
! 880: for (flen = 1; f[1 - flen] != '%'; flen++)
! 881: continue;
! 882: cpy (flen, &f[1 - flen]);
! 883: }
! 884: break;
! 885: }
! 886: }
! 887:
! 888: if (p)
! 889: *p = '\0';
! 890: return i;
! 891: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>