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 (&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>