| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 | /* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.This file is part of the GNU C Library.The GNU C Library is free software; you can redistribute it and/ormodify it under the terms of the GNU Library General Public License aspublished by the Free Software Foundation; either version 2 of theLicense, or (at your option) any later version.The GNU C Library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNULibrary General Public License for more details.You should have received a copy of the GNU Library General PublicLicense along with the GNU C Library; see the file COPYING.LIB.  Ifnot, write to the Free Software Foundation, Inc., 675 Mass Ave,Cambridge, MA 02139, USA.  */#include <stddef.h>#include <stdlib.h>#include <string.h>#include <stdio.h>#include <sys/types.h>		/* Some systems define `time_t' here.  */#include <sys/time.h>#include <time.h>#include <ctype.h>#include <limits.h>static unsigned int week (const struct tm *const, int, int);#define	add(n, f)							      \  do									      \    {									      \      i += (n);								      \      if (i >= maxsize)							      \	return 0;							      \      else								      \	if (p)								      \	  {								      \	    f;								      \	    p += (n);							      \	  }								      \    } while (0)#define	cpy(n, s)	add((n), memcpy((void *) p, (void *) (s), (n)))#ifdef _LIBC#define	fmt(n, args)	add((n), if (sprintf args != (n)) return 0)#else#define	fmt(n, args)	add((n), sprintf args; if (strlen (p) != (n)) return 0)#endif/* Return the week in the year specified by TP,   with weeks starting on STARTING_DAY.  */static unsigned int week(const struct tm *const tp , int starting_day , int max_preceding ){  int wday, dl, base;  wday = tp->tm_wday - starting_day;  if (wday < 0)    wday += 7;  /* Set DL to the day in the year of the first day of the week     containing the day specified in TP.  */  dl = tp->tm_yday - wday;  /* For the computation following ISO 8601:1988 we set the number of     the week containing January 1st to 1 if this week has more than     MAX_PRECEDING days in the new year.  For ISO 8601 this number is     3, for the other representation it is 7 (i.e., not to be     fulfilled).  */  base = ((dl + 7) % 7) > max_preceding ? 1 : 0;  /* If DL is negative we compute the result as 0 unless we have to     compute it according ISO 8601.  In this case we have to return 53     or 1 if the week containing January 1st has less than 4 days in     the new year or not.  If DL is not negative we calculate the     number of complete weeks for our week (DL / 7) plus 1 (because     only for DL < 0 we are in week 0/53 and plus the number of the     first week computed in the last step.  */  return dl < 0 ? (dl < -max_preceding ? 53 : base)		: base + 1 + dl / 7;}#ifndef _NL_CURRENTstatic char const weekday_name[][10] =  {    "Sunday", "Monday", "Tuesday", "Wednesday",    "Thursday", "Friday", "Saturday"  };static char const month_name[][10] =  {    "January", "February", "March", "April", "May", "June",    "July", "August", "September", "October", "November", "December"  };#endif/* Write information from TP into S according to the format   string FORMAT, writing no more that MAXSIZE characters   (including the terminating '\0') and returning number of   characters written.  If S is NULL, nothing will be written   anywhere, so to determine how many characters would be   written, use NULL for S and (size_t) UINT_MAX for MAXSIZE.  */size_t strftime( char *s , size_t maxsize , const char *format , register const struct tm *tp){  int hour12 = tp->tm_hour;#ifdef _NL_CURRENT  const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);  const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);  const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);  const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);  const char *const ampm = _NL_CURRENT (LC_TIME,					hour12 > 11 ? PM_STR : AM_STR);  size_t aw_len = strlen(a_wkday);  size_t am_len = strlen(a_month);  size_t ap_len = strlen (ampm);#else  const char *const f_wkday = weekday_name[tp->tm_wday];  const char *const f_month = month_name[tp->tm_mon];  const char *const a_wkday = f_wkday;  const char *const a_month = f_month;  const char *const ampm = "AMPM" + 2 * (hour12 > 11);  size_t aw_len = 3;  size_t am_len = 3;  size_t ap_len = 2;#endif  size_t wkday_len = strlen(f_wkday);  size_t month_len = strlen(f_month);  const unsigned int y_week0 = week (tp, 0, 7);  const unsigned int y_week1 = week (tp, 1, 7);  const unsigned int y_week2 = week (tp, 1, 3);  const char *zone;  size_t zonelen;  register size_t i = 0;  register char *p = s;  register const char *f;  char number_fmt[5];  /* Initialize the buffer we will use for the sprintf format for numbers.  */  number_fmt[0] = '%';  zone = 0;#if HAVE_TM_ZONE  zone = (const char *) tp->tm_zone;#endif  if (!(zone && *zone) && tp->tm_isdst >= 0)    zone = tzname[tp->tm_isdst];  if (!(zone && *zone))    zone = "???";  zonelen = strlen (zone);  if (hour12 > 12)    hour12 -= 12;  else    if (hour12 == 0) hour12 = 12;  for (f = format; *f != '\0'; ++f)    {      enum { pad_zero, pad_space, pad_none } pad; /* Padding for number.  */      unsigned int maxdigits;	/* Max digits for numeric format.  */      unsigned int number_value; /* Numeric value to be printed.  */      const char *subfmt;#if HAVE_MBLEN      if (!isascii(*f))	{	  /* Non-ASCII, may be a multibyte.  */	  int len = mblen(f, strlen(f));	  if (len > 0)	    {	      cpy(len, f);	      continue;	    }	}#endif      if (*f != '%')	{	  add(1, *p = *f);	  continue;	}      /* Check for flags that can modify a number format.  */      ++f;      switch (*f)	{	case '_':	  pad = pad_space;	  ++f;	  break;	case '-':	  pad = pad_none;	  ++f;	  break;	default:	  pad = pad_zero;	  break;	}      /* Now do the specified format.  */      switch (*f)	{	case '\0':	case '%':	  add(1, *p = *f);	  break;	case 'a':	  cpy(aw_len, a_wkday);	  break;	case 'A':	  cpy(wkday_len, f_wkday);	  break;	case 'b':	case 'h':		/* GNU extension.  */	  cpy(am_len, a_month);	  break;	case 'B':	  cpy(month_len, f_month);	  break;	case 'c':#ifdef _NL_CURRENT	  subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);#else	  subfmt = "%a %b %d %H:%M:%S %Z %Y";#endif	subformat:	  {	    size_t len = strftime (p, maxsize - i, subfmt, tp);	    if (len == 0 && *subfmt)	      return 0;	    add(len, );	  }	  break;#define DO_NUMBER(digits, value) \	  maxdigits = digits; number_value = value; goto do_number#define DO_NUMBER_NOPAD(digits, value) \	  maxdigits = digits; number_value = value; goto do_number_nopad	case 'C':	  DO_NUMBER (2, (1900 + tp->tm_year) / 100);	case 'x':#ifdef _NL_CURRENT	  subfmt = _NL_CURRENT (LC_TIME, D_FMT);	  goto subformat;#endif	  /* Fall through.  */	case 'D':		/* GNU extension.  */	  subfmt = "%m/%d/%y";	  goto subformat;	case 'd':	  DO_NUMBER (2, tp->tm_mday);	case 'e':		/* GNU extension: %d, but blank-padded.  */#if 0	  DO_NUMBER_NOPAD (2, tp->tm_mday);#else	  DO_NUMBER (2, tp->tm_mday);#endif	  /* All numeric formats set MAXDIGITS and NUMBER_VALUE and then	     jump to one of these two labels.  */	do_number_nopad:	  /* Force `-' flag.  */	  pad = pad_none;	do_number:	  {	    /* Format the number according to the PAD flag.  */	    register char *nf = &number_fmt[1];	    int printed;	    switch (pad)	      {	      case pad_zero:		*nf++ = '0';	      case pad_space:		*nf++ = '0' + maxdigits;	      case pad_none:		*nf++ = 'u';		*nf = '\0';	      }#ifdef _LIBC	    if (i + maxdigits >= maxsize)		return 0;	    printed = sprintf (p, number_fmt, number_value);	    i += printed;	    p += printed;#else	    add (maxdigits, sprintf (p, number_fmt, number_value);		 printed = strlen (p));#endif	    break;	  }	case 'H':	  DO_NUMBER (2, tp->tm_hour);	case 'I':	  DO_NUMBER (2, hour12);	case 'k':		/* GNU extension.  */	  DO_NUMBER_NOPAD (2, tp->tm_hour);	case 'l':		/* GNU extension.  */	  DO_NUMBER_NOPAD (2, hour12);	case 'j':	  DO_NUMBER (3, 1 + tp->tm_yday);	case 'M':	  DO_NUMBER (2, tp->tm_min);	case 'm':	  DO_NUMBER (2, tp->tm_mon + 1);	case 'n':		/* GNU extension.  */	  add (1, *p = '\n');	  break;	case 'p':	  cpy(ap_len, ampm);	  break;	case 'R':		/* GNU extension.  */	  subfmt = "%H:%M";	  goto subformat;	case 'r':		/* GNU extension.  */	  subfmt = "%I:%M:%S %p";	  goto subformat;	case 'S':	  DO_NUMBER (2, tp->tm_sec);	case 'X':#ifdef _NL_CURRENT	  subfmt = _NL_CURRENT (LC_TIME, T_FMT);	  goto subformat;#endif	  /* Fall through.  */	case 'T':		/* GNU extenstion.  */	  subfmt = "%H:%M:%S";	  goto subformat;	case 't':		/* GNU extenstion.  */	  add (1, *p = '\t');	  break;	case 'U':	  DO_NUMBER (2, y_week0);	case 'V':	  DO_NUMBER (2, y_week2);	case 'W':	  DO_NUMBER (2, y_week1);	case 'w':	  DO_NUMBER (1, tp->tm_wday);	case 'Y':	  DO_NUMBER (4, 1900 + tp->tm_year);	case 'y':	  DO_NUMBER (2, tp->tm_year % 100);	case 'Z':	  cpy(zonelen, zone);	  break;	default:	  /* Bad format.  */	  break;	}    }  if (p)    *p = '\0';  return i;}
 |