Annotation of embedaddon/lrzsz/lib/strftime.c, revision 1.1.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 (&ltm);
                    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 (&ltm);
                    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 (&lt, &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 (&lt, &gtm))
                    853:              break;
                    854: 
                    855:            diff = tm_diff (&ltm, &gtm);
                    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>