File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lrzsz / lib / strftime.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Thu Oct 24 15:49:50 2019 UTC (4 years, 8 months ago) by misho
Branches: lrzsz, MAIN
CVS tags: v0_12_20p5, HEAD
lrzsz ver 0.12.20

    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>