mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-01-31 11:30:56 +08:00
* libc/time/strftime.c: Add support for era and alt_digits data from
LC_TIME locale category. Conditionalize using _WANT_C99_TIME_FORMATS flag. (STRTOUL): Define differently for building strftime or wcsftime. (STRCPY): Ditto. (STRCHR): Ditto. (STRLEN): Ditto. (CHECK_LENGTH): Define to simplify code. (era_info_t): New type to store era info. (get_era_info): New function to fetch era info matching incoming struct tm. (free_era_info): New function to free era info. (alt_digits_t): New type to store alternative digits. (get_alt_digits): New function to convert alt_digits string into alt_digits_t structure. (free_alt_digits): New function to free alt_digits info. (conv_to_alt_digits): New function to convert unsigned value into alternative digits. (strftime): Conditionalize on _WANT_C99_TIME_FORMATS. If _WANT_C99_TIME_FORMATS is defined, define as just a wrapper function providing era_info and alt_digits pointers and call ... (__strftime): Rename from strftime and make static if _WANT_C99_TIME_FORMATS is defined. Add parameters for era_info and alt_digits pointers. Handle conversion modifiers according to POSIX-1.2008. Redefine %F and %Y according to POSIX. Add default case to allow to bail out on invalid conversion specifiers. * libc/include/sys/config.h: Move Cygwin build flags to Cygwin's config.h. * libc/include/stdio.h: Remove __CYGWIN_USE_BIG_TYPES__ condition.
This commit is contained in:
parent
d91ab868e1
commit
be7f7a7503
@ -1,3 +1,36 @@
|
||||
2010-02-26 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* libc/time/strftime.c: Add support for era and alt_digits data from
|
||||
LC_TIME locale category. Conditionalize using _WANT_C99_TIME_FORMATS
|
||||
flag.
|
||||
(STRTOUL): Define differently for building strftime or wcsftime.
|
||||
(STRCPY): Ditto.
|
||||
(STRCHR): Ditto.
|
||||
(STRLEN): Ditto.
|
||||
(CHECK_LENGTH): Define to simplify code.
|
||||
(era_info_t): New type to store era info.
|
||||
(get_era_info): New function to fetch era info matching incoming
|
||||
struct tm.
|
||||
(free_era_info): New function to free era info.
|
||||
(alt_digits_t): New type to store alternative digits.
|
||||
(get_alt_digits): New function to convert alt_digits string into
|
||||
alt_digits_t structure.
|
||||
(free_alt_digits): New function to free alt_digits info.
|
||||
(conv_to_alt_digits): New function to convert unsigned value into
|
||||
alternative digits.
|
||||
(strftime): Conditionalize on _WANT_C99_TIME_FORMATS. If
|
||||
_WANT_C99_TIME_FORMATS is defined, define as just a wrapper function
|
||||
providing era_info and alt_digits pointers and call ...
|
||||
(__strftime): Rename from strftime and make static if
|
||||
_WANT_C99_TIME_FORMATS is defined. Add parameters for era_info and
|
||||
alt_digits pointers. Handle conversion modifiers according to
|
||||
POSIX-1.2008. Redefine %F and %Y according to POSIX. Add default case
|
||||
to allow to bail out on invalid conversion specifiers.
|
||||
* libc/include/sys/config.h: Move Cygwin build flags to Cygwin's
|
||||
config.h.
|
||||
|
||||
* libc/include/stdio.h: Remove __CYGWIN_USE_BIG_TYPES__ condition.
|
||||
|
||||
2010-02-25 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* libc/locale/locale.c (loadlocale): Fix typo in comment.
|
||||
|
@ -50,13 +50,9 @@ _BEGIN_STD_C
|
||||
typedef __FILE FILE;
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
#ifdef __CYGWIN_USE_BIG_TYPES__
|
||||
typedef _fpos64_t fpos_t;
|
||||
#else
|
||||
typedef _fpos_t fpos_t;
|
||||
#endif
|
||||
#else
|
||||
typedef _fpos_t fpos_t;
|
||||
#ifdef __LARGE64_FILES
|
||||
typedef _fpos64_t fpos64_t;
|
||||
#endif
|
||||
|
@ -188,9 +188,6 @@
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
#include <cygwin/config.h>
|
||||
#define __LINUX_ERRNO_EXTENSIONS__ 1
|
||||
#define _MB_EXTENDED_CHARSETS_ALL 1
|
||||
#define __HAVE_LOCALE_INFO__ 1
|
||||
#if !defined (__STRICT_ANSI__) || (__STDC_VERSION__ >= 199901L)
|
||||
#define __USE_XOPEN2K 1
|
||||
#endif
|
||||
|
@ -284,6 +284,10 @@ the "C" locale settings.
|
||||
# define SFLG /* %s flag (null for normal char) */
|
||||
# define _ctloc(x) (ctloclen = strlen (ctloc = _CurrentTimeLocale->x), ctloc)
|
||||
# define TOLOWER(c) tolower((int)(unsigned char)(c))
|
||||
# define STRTOUL(c,p,b) strtoul((c),(p),(b))
|
||||
# define STRCPY(a,b) strcpy((a),(b))
|
||||
# define STRCHR(a,b) strchr((a),(b))
|
||||
# define STRLEN(a) strlen(a)
|
||||
# else
|
||||
# define strftime wcsftime /* Alternate function name */
|
||||
# define CHAR wchar_t /* string type basis */
|
||||
@ -291,6 +295,10 @@ the "C" locale settings.
|
||||
# define snprintf swprintf /* wide-char equivalent function name */
|
||||
# define strncmp wcsncmp /* wide-char equivalent function name */
|
||||
# define TOLOWER(c) towlower((wint_t)(c))
|
||||
# define STRTOUL(c,p,b) wcstoul((c),(p),(b))
|
||||
# define STRCPY(a,b) wcscpy((a),(b))
|
||||
# define STRCHR(a,b) wcschr((a),(b))
|
||||
# define STRLEN(a) wcslen(a)
|
||||
# define SFLG "l" /* %s flag (l for wide char) */
|
||||
# define CTLOCBUFLEN 256 /* Arbitrary big buffer size */
|
||||
const wchar_t *
|
||||
@ -306,6 +314,9 @@ the "C" locale settings.
|
||||
&ctloclen))
|
||||
#endif /* MAKE_WCSFTIME */
|
||||
|
||||
#define CHECK_LENGTH() if (len < 0 || (count += len) >= maxsize) \
|
||||
return 0
|
||||
|
||||
/* Enforce the coding assumptions that YEAR_BASE is positive. (%C, %Y, etc.) */
|
||||
#if YEAR_BASE < 0
|
||||
# error "YEAR_BASE < 0"
|
||||
@ -361,12 +372,288 @@ _DEFUN (iso_year_adjust, (tim_p),
|
||||
#undef PACK
|
||||
}
|
||||
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
typedef struct {
|
||||
int year;
|
||||
CHAR *era_C;
|
||||
CHAR *era_Y;
|
||||
} era_info_t;
|
||||
|
||||
static era_info_t *
|
||||
get_era_info (const struct tm *tim_p, const char *era)
|
||||
{
|
||||
char *c;
|
||||
const char *dir;
|
||||
long offset;
|
||||
struct tm stm, etm;
|
||||
era_info_t *ei;
|
||||
|
||||
ei = (era_info_t *) calloc (1, sizeof (era_info_t));
|
||||
if (!ei)
|
||||
return NULL;
|
||||
|
||||
stm.tm_isdst = etm.tm_isdst = 0;
|
||||
while (era)
|
||||
{
|
||||
dir = era;
|
||||
era += 2;
|
||||
offset = strtol (era, &c, 10);
|
||||
era = c + 1;
|
||||
stm.tm_year = strtol (era, &c, 10) - YEAR_BASE;
|
||||
/* Adjust offset for negative gregorian dates. */
|
||||
if (stm.tm_year <= -YEAR_BASE)
|
||||
++stm.tm_year;
|
||||
stm.tm_mon = strtol (c + 1, &c, 10);
|
||||
stm.tm_mday = strtol (c + 1, &c, 10);
|
||||
stm.tm_hour = stm.tm_min = stm.tm_sec = 0;
|
||||
era = c + 1;
|
||||
if (era[0] == '-' && era[1] == '*')
|
||||
{
|
||||
etm = stm;
|
||||
stm.tm_year = INT_MIN;
|
||||
stm.tm_mon = stm.tm_mday = stm.tm_hour = stm.tm_min = stm.tm_sec = 0;
|
||||
era += 3;
|
||||
}
|
||||
else if (era[0] == '+' && era[1] == '*')
|
||||
{
|
||||
etm.tm_year = INT_MAX;
|
||||
etm.tm_mon = 12;
|
||||
etm.tm_mday = 31;
|
||||
etm.tm_hour = 23;
|
||||
etm.tm_min = etm.tm_sec = 59;
|
||||
era += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
etm.tm_year = strtol (era, &c, 10) - YEAR_BASE;
|
||||
/* Adjust offset for negative gregorian dates. */
|
||||
if (etm.tm_year <= -YEAR_BASE)
|
||||
++etm.tm_year;
|
||||
etm.tm_mon = strtol (c + 1, &c, 10);
|
||||
etm.tm_mday = strtol (c + 1, &c, 10);
|
||||
etm.tm_mday = 31;
|
||||
etm.tm_hour = 23;
|
||||
etm.tm_min = etm.tm_sec = 59;
|
||||
era = c + 1;
|
||||
}
|
||||
if ((tim_p->tm_year > stm.tm_year
|
||||
|| (tim_p->tm_year == stm.tm_year
|
||||
&& (tim_p->tm_mon > stm.tm_mon
|
||||
|| (tim_p->tm_mon == stm.tm_mon
|
||||
&& tim_p->tm_mday >= stm.tm_mday))))
|
||||
&& (tim_p->tm_year < etm.tm_year
|
||||
|| (tim_p->tm_year == etm.tm_year
|
||||
&& (tim_p->tm_mon < etm.tm_mon
|
||||
|| (tim_p->tm_mon == etm.tm_mon
|
||||
&& tim_p->tm_mday <= etm.tm_mday)))))
|
||||
{
|
||||
/* Gotcha */
|
||||
size_t len;
|
||||
|
||||
/* year */
|
||||
if (*dir == '+' && stm.tm_year != INT_MIN)
|
||||
ei->year = tim_p->tm_year - stm.tm_year + offset;
|
||||
else
|
||||
ei->year = etm.tm_year - tim_p->tm_year + offset;
|
||||
/* era_C */
|
||||
c = strchr (era, ':');
|
||||
#ifdef MAKE_WCSFTIME
|
||||
len = mbsnrtowcs (NULL, &era, c - era, 0, NULL);
|
||||
if (len == (size_t) -1)
|
||||
{
|
||||
free (ei);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
len = c - era;
|
||||
#endif
|
||||
ei->era_C = (CHAR *) malloc ((len + 1) * sizeof (CHAR));
|
||||
if (!ei->era_C)
|
||||
{
|
||||
free (ei);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef MAKE_WCSFTIME
|
||||
len = mbsnrtowcs (ei->era_C, &era, c - era, len + 1, NULL);
|
||||
#else
|
||||
strncpy (ei->era_C, era, len);
|
||||
era += len;
|
||||
#endif
|
||||
ei->era_C[len] = CQ('\0');
|
||||
/* era_Y */
|
||||
++era;
|
||||
c = strchr (era, ';');
|
||||
if (!c)
|
||||
c = strchr (era, '\0');
|
||||
#ifdef MAKE_WCSFTIME
|
||||
len = mbsnrtowcs (NULL, &era, c - era, 0, NULL);
|
||||
if (len == (size_t) -1)
|
||||
{
|
||||
free (ei->era_C);
|
||||
free (ei);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
len = c - era;
|
||||
#endif
|
||||
ei->era_Y = (CHAR *) malloc ((len + 1) * sizeof (CHAR));
|
||||
if (!ei->era_Y)
|
||||
{
|
||||
free (ei->era_C);
|
||||
free (ei);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef MAKE_WCSFTIME
|
||||
len = mbsnrtowcs (ei->era_Y, &era, c - era, len + 1, NULL);
|
||||
#else
|
||||
strncpy (ei->era_Y, era, len);
|
||||
era += len;
|
||||
#endif
|
||||
ei->era_Y[len] = CQ('\0');
|
||||
return ei;
|
||||
}
|
||||
else
|
||||
era = strchr (era, ';');
|
||||
if (era)
|
||||
++era;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
free_era_info (era_info_t *ei)
|
||||
{
|
||||
free (ei->era_C);
|
||||
free (ei->era_Y);
|
||||
free (ei);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
size_t num;
|
||||
CHAR **digit;
|
||||
CHAR *buffer;
|
||||
} alt_digits_t;
|
||||
|
||||
static alt_digits_t *
|
||||
get_alt_digits (const char *alt_digits)
|
||||
{
|
||||
alt_digits_t *adi;
|
||||
const char *a, *e;
|
||||
CHAR *aa, *ae;
|
||||
size_t len;
|
||||
|
||||
adi = (alt_digits_t *) calloc (1, sizeof (alt_digits_t));
|
||||
if (!adi)
|
||||
return NULL;
|
||||
|
||||
/* Compute number of alt_digits. */
|
||||
adi->num = 1;
|
||||
for (a = alt_digits; (e = strchr (a, ';')) != NULL; a = e + 1)
|
||||
++adi->num;
|
||||
/* Allocate the `digit' array, which is an array of `num' pointers into
|
||||
`buffer'. */
|
||||
adi->digit = (CHAR **) calloc (adi->num, sizeof (CHAR **));
|
||||
if (!adi->digit)
|
||||
{
|
||||
free (adi);
|
||||
return NULL;
|
||||
}
|
||||
/* Compute memory required for `buffer'. */
|
||||
#ifdef MAKE_WCSFTIME
|
||||
len = mbstowcs (NULL, alt_digits, 0);
|
||||
if (len == (size_t) -1)
|
||||
{
|
||||
free (adi->digit);
|
||||
free (adi);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
len = strlen (alt_digits);
|
||||
#endif
|
||||
/* Allocate it. */
|
||||
adi->buffer = (CHAR *) malloc ((len + 1) * sizeof (CHAR));
|
||||
if (!adi->buffer)
|
||||
{
|
||||
free (adi->digit);
|
||||
free (adi);
|
||||
return NULL;
|
||||
}
|
||||
/* Store digits in it. */
|
||||
#ifdef MAKE_WCSFTIME
|
||||
mbstowcs (adi->buffer, alt_digits, len + 1);
|
||||
#else
|
||||
strcpy (adi->buffer, alt_digits);
|
||||
#endif
|
||||
/* Store the pointers into `buffer' into the appropriate `digit' slot. */
|
||||
for (len = 0, aa = adi->buffer; (ae = STRCHR (aa, CQ(';'))) != NULL;
|
||||
++len, aa = ae + 1)
|
||||
{
|
||||
*ae = '\0';
|
||||
adi->digit[len] = aa;
|
||||
}
|
||||
adi->digit[len] = aa;
|
||||
return adi;
|
||||
}
|
||||
|
||||
static void
|
||||
free_alt_digits (alt_digits_t *adi)
|
||||
{
|
||||
free (adi->digit);
|
||||
free (adi->buffer);
|
||||
free (adi);
|
||||
}
|
||||
|
||||
/* Return 0 if no alt_digit is available for a number.
|
||||
Return -1 if buffer size isn't sufficient to hold alternative digit.
|
||||
Return length of new digit otherwise. */
|
||||
static int
|
||||
conv_to_alt_digits (CHAR *buf, size_t bufsiz, unsigned num, alt_digits_t *adi)
|
||||
{
|
||||
if (num < adi->num)
|
||||
{
|
||||
size_t len = STRLEN (adi->digit[num]);
|
||||
if (bufsiz < len)
|
||||
return -1;
|
||||
STRCPY (buf, adi->digit[num]);
|
||||
return (int) len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t __strftime (CHAR *, size_t, const CHAR *, const struct tm *,
|
||||
era_info_t **, alt_digits_t **);
|
||||
|
||||
size_t
|
||||
_DEFUN (strftime, (s, maxsize, format, tim_p),
|
||||
CHAR *s _AND
|
||||
size_t maxsize _AND
|
||||
_CONST CHAR *format _AND
|
||||
_CONST struct tm *tim_p)
|
||||
{
|
||||
era_info_t *era_info = NULL;
|
||||
alt_digits_t *alt_digits = NULL;
|
||||
size_t ret = __strftime (s, maxsize, format, tim_p, &era_info, &alt_digits);
|
||||
if (era_info)
|
||||
free_era_info (era_info);
|
||||
if (alt_digits)
|
||||
free_alt_digits (alt_digits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t
|
||||
__strftime (CHAR *s, size_t maxsize, const CHAR *format,
|
||||
const struct tm *tim_p, era_info_t **era_info,
|
||||
alt_digits_t **alt_digits)
|
||||
#else /* !_WANT_C99_TIME_FORMATS */
|
||||
# define __strftime(s,m,f,t,e,a) strftime((s),(m),(f),(t))
|
||||
|
||||
size_t
|
||||
_DEFUN (strftime, (s, maxsize, format, tim_p),
|
||||
CHAR *s _AND
|
||||
size_t maxsize _AND
|
||||
_CONST CHAR *format _AND
|
||||
_CONST struct tm *tim_p)
|
||||
#endif /* !_WANT_C99_TIME_FORMATS */
|
||||
{
|
||||
size_t count = 0;
|
||||
int i, len;
|
||||
@ -375,6 +662,9 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
|
||||
CHAR ctlocbuf[CTLOCBUFLEN];
|
||||
#endif
|
||||
size_t ctloclen;
|
||||
CHAR alt;
|
||||
CHAR pad;
|
||||
unsigned long width;
|
||||
|
||||
struct lc_time_T *_CurrentTimeLocale = __get_current_time_locale ();
|
||||
for (;;)
|
||||
@ -386,13 +676,42 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*format == CQ('\0'))
|
||||
break;
|
||||
|
||||
format++;
|
||||
if (*format == CQ('E') || *format == CQ('O'))
|
||||
format++;
|
||||
pad = '\0';
|
||||
width = 0;
|
||||
|
||||
/* POSIX-1.2008 feature: '0' and '+' modifiers require 0-padding with
|
||||
slightly different semantics. */
|
||||
if (*format == CQ('0') || *format == CQ('+'))
|
||||
pad = *format++;
|
||||
|
||||
/* POSIX-1.2008 feature: A minimum field width can be specified. */
|
||||
if (*format >= CQ('1') && *format <= CQ('9'))
|
||||
{
|
||||
CHAR *fp;
|
||||
width = STRTOUL (format, &fp, 10);
|
||||
format = fp;
|
||||
}
|
||||
|
||||
alt = CQ('\0');
|
||||
if (*format == CQ('E'))
|
||||
{
|
||||
alt = *format++;
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (!*era_info && *_CurrentTimeLocale->era)
|
||||
*era_info = get_era_info (tim_p, _CurrentTimeLocale->era);
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
}
|
||||
else if (*format == CQ('O'))
|
||||
{
|
||||
alt = *format++;
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (!*alt_digits && *_CurrentTimeLocale->alt_digits)
|
||||
*alt_digits = get_alt_digits (_CurrentTimeLocale->alt_digits);
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
}
|
||||
|
||||
switch (*format)
|
||||
{
|
||||
@ -438,24 +757,39 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
|
||||
}
|
||||
break;
|
||||
case CQ('c'):
|
||||
_ctloc (c_fmt);
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt == 'E' && *era_info && *_CurrentTimeLocale->era_d_t_fmt)
|
||||
_ctloc (era_d_t_fmt);
|
||||
else
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
_ctloc (c_fmt);
|
||||
goto recurse;
|
||||
case CQ('r'):
|
||||
_ctloc (ampm_fmt);
|
||||
goto recurse;
|
||||
case CQ('x'):
|
||||
_ctloc (x_fmt);
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt == 'E' && *era_info && *_CurrentTimeLocale->era_d_fmt)
|
||||
_ctloc (era_d_fmt);
|
||||
else
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
_ctloc (x_fmt);
|
||||
goto recurse;
|
||||
case CQ('X'):
|
||||
_ctloc (X_fmt);
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt == 'E' && *era_info && *_CurrentTimeLocale->era_t_fmt)
|
||||
_ctloc (era_t_fmt);
|
||||
else
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
_ctloc (X_fmt);
|
||||
recurse:
|
||||
if (*ctloc)
|
||||
{
|
||||
/* Recurse to avoid need to replicate %Y formation. */
|
||||
size_t adjust = strftime (&s[count], maxsize - count, ctloc,
|
||||
tim_p);
|
||||
if (adjust > 0)
|
||||
count += adjust;
|
||||
len = __strftime (&s[count], maxsize - count, ctloc, tim_p,
|
||||
era_info, alt_digits);
|
||||
if (len > 0)
|
||||
count += len;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
@ -482,38 +816,97 @@ recurse:
|
||||
Be careful of both overflow and sign adjustment due to the
|
||||
asymmetric range of years.
|
||||
*/
|
||||
int neg = tim_p->tm_year < -YEAR_BASE;
|
||||
int century = tim_p->tm_year >= 0
|
||||
? tim_p->tm_year / 100 + YEAR_BASE / 100
|
||||
: abs (tim_p->tm_year + YEAR_BASE) / 100;
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%s%.*d"),
|
||||
neg ? CQ("-") : CQ(""), 2 - neg, century);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt == 'E' && *era_info)
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%" SFLG "s"),
|
||||
(*era_info)->era_C);
|
||||
else
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
{
|
||||
CHAR *fmt = CQ("%s%.*d");
|
||||
char *pos = "";
|
||||
int neg = tim_p->tm_year < -YEAR_BASE;
|
||||
int century = tim_p->tm_year >= 0
|
||||
? tim_p->tm_year / 100 + YEAR_BASE / 100
|
||||
: abs (tim_p->tm_year + YEAR_BASE) / 100;
|
||||
if (pad) /* '0' or '+' */
|
||||
{
|
||||
fmt = CQ("%s%0.*d");
|
||||
if (century >= 100 && pad == CQ('+'))
|
||||
pos = "+";
|
||||
}
|
||||
if (width < 2)
|
||||
width = 2;
|
||||
len = snprintf (&s[count], maxsize - count, fmt,
|
||||
neg ? "-" : pos, width - neg, century);
|
||||
}
|
||||
CHECK_LENGTH ();
|
||||
}
|
||||
break;
|
||||
case CQ('d'):
|
||||
case CQ('e'):
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt == CQ('O') && *alt_digits)
|
||||
{
|
||||
if (tim_p->tm_mday < 10)
|
||||
{
|
||||
if (*format == CQ('d'))
|
||||
{
|
||||
if (maxsize - count < 2) return 0;
|
||||
len = conv_to_alt_digits (&s[count], maxsize - count,
|
||||
0, *alt_digits);
|
||||
CHECK_LENGTH ();
|
||||
}
|
||||
if (*format == CQ('e') || len == 0)
|
||||
s[count++] = CQ(' ');
|
||||
}
|
||||
len = conv_to_alt_digits (&s[count], maxsize - count,
|
||||
tim_p->tm_mday, *alt_digits);
|
||||
CHECK_LENGTH ();
|
||||
if (len > 0)
|
||||
break;
|
||||
}
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
len = snprintf (&s[count], maxsize - count,
|
||||
*format == CQ('d') ? CQ("%.2d") : CQ("%2d"),
|
||||
tim_p->tm_mday);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
*format == CQ('d') ? CQ("%.2d") : CQ("%2d"),
|
||||
tim_p->tm_mday);
|
||||
CHECK_LENGTH ();
|
||||
break;
|
||||
case CQ('D'):
|
||||
/* %m/%d/%y */
|
||||
len = snprintf (&s[count], maxsize - count,
|
||||
CQ("%.2d/%.2d/%.2d"),
|
||||
tim_p->tm_mon + 1, tim_p->tm_mday,
|
||||
tim_p->tm_year >= 0 ? tim_p->tm_year % 100
|
||||
: abs (tim_p->tm_year + YEAR_BASE) % 100);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
CQ("%.2d/%.2d/%.2d"),
|
||||
tim_p->tm_mon + 1, tim_p->tm_mday,
|
||||
tim_p->tm_year >= 0 ? tim_p->tm_year % 100
|
||||
: abs (tim_p->tm_year + YEAR_BASE) % 100);
|
||||
CHECK_LENGTH ();
|
||||
break;
|
||||
case CQ('F'):
|
||||
{ /* %F is equivalent to "%Y-%m-%d" */
|
||||
/* Recurse to avoid need to replicate %Y formation. */
|
||||
size_t adjust = strftime (&s[count], maxsize - count,
|
||||
CQ("%Y-%m-%d"), tim_p);
|
||||
if (adjust > 0)
|
||||
count += adjust;
|
||||
{ /* %F is equivalent to "%+4Y-%m-%d", flags and width can change
|
||||
that. Recurse to avoid need to replicate %Y formation. */
|
||||
CHAR fmtbuf[32], *fmt = fmtbuf;
|
||||
|
||||
*fmt++ = CQ('%');
|
||||
if (pad) /* '0' or '+' */
|
||||
*fmt++ = pad;
|
||||
else
|
||||
*fmt++ = '+';
|
||||
if (!pad)
|
||||
width = 10;
|
||||
if (width < 6)
|
||||
width = 6;
|
||||
width -= 6;
|
||||
if (width)
|
||||
{
|
||||
len = snprintf (fmt, fmtbuf + 32 - fmt, CQ("%lu"), width);
|
||||
if (len > 0)
|
||||
fmt += len;
|
||||
}
|
||||
STRCPY (fmt, CQ("Y-%m-%d"));
|
||||
len = __strftime (&s[count], maxsize - count, fmtbuf, tim_p,
|
||||
era_info, alt_digits);
|
||||
if (len > 0)
|
||||
count += len;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
@ -530,8 +923,8 @@ recurse:
|
||||
else if (adjust > 0 && tim_p->tm_year < -YEAR_BASE)
|
||||
adjust = -1;
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
|
||||
((year + adjust) % 100 + 100) % 100);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
((year + adjust) % 100 + 100) % 100);
|
||||
CHECK_LENGTH ();
|
||||
}
|
||||
break;
|
||||
case CQ('G'):
|
||||
@ -539,7 +932,7 @@ recurse:
|
||||
/* See the comments for 'C' and 'Y'; this is a variable length
|
||||
field. Although there is no requirement for a minimum number
|
||||
of digits, we use 4 for consistency with 'Y'. */
|
||||
int neg = tim_p->tm_year < -YEAR_BASE;
|
||||
int sign = tim_p->tm_year < -YEAR_BASE;
|
||||
int adjust = iso_year_adjust (tim_p);
|
||||
int century = tim_p->tm_year >= 0
|
||||
? tim_p->tm_year / 100 + YEAR_BASE / 100
|
||||
@ -547,8 +940,8 @@ recurse:
|
||||
int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
|
||||
: abs (tim_p->tm_year + YEAR_BASE) % 100;
|
||||
if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE)
|
||||
neg = adjust = 1;
|
||||
else if (adjust > 0 && neg)
|
||||
sign = adjust = 1;
|
||||
else if (adjust > 0 && sign)
|
||||
adjust = -1;
|
||||
year += adjust;
|
||||
if (year == -1)
|
||||
@ -561,45 +954,88 @@ recurse:
|
||||
year = 0;
|
||||
++century;
|
||||
}
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%s%.*d%.2d"),
|
||||
neg ? CQ("-") : CQ(""), 2 - neg, century, year);
|
||||
CHAR fmtbuf[10], *fmt = fmtbuf;
|
||||
/* int potentially overflows, so use unsigned instead. */
|
||||
unsigned p_year = century * 100 + year;
|
||||
if (sign)
|
||||
*fmt++ = CQ('-');
|
||||
else if (pad == CQ('+') && p_year >= 10000)
|
||||
{
|
||||
*fmt++ = CQ('+');
|
||||
sign = 1;
|
||||
}
|
||||
if (width && sign)
|
||||
--width;
|
||||
*fmt++ = CQ('%');
|
||||
if (pad)
|
||||
*fmt++ = CQ('0');
|
||||
STRCPY (fmt, CQ(".*u"));
|
||||
len = snprintf (&s[count], maxsize - count, fmtbuf, width, p_year);
|
||||
if (len < 0 || (count+=len) >= maxsize)
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case CQ('H'):
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt == CQ('O') && *alt_digits)
|
||||
{
|
||||
len = conv_to_alt_digits (&s[count], maxsize - count,
|
||||
tim_p->tm_hour, *alt_digits);
|
||||
CHECK_LENGTH ();
|
||||
if (len > 0)
|
||||
break;
|
||||
}
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
/*FALLTHRU*/
|
||||
case CQ('k'): /* newlib extension */
|
||||
len = snprintf (&s[count], maxsize - count,
|
||||
*format == CQ('k') ? CQ("%2d") : CQ("%.2d"),
|
||||
tim_p->tm_hour);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
*format == CQ('k') ? CQ("%2d") : CQ("%.2d"),
|
||||
tim_p->tm_hour);
|
||||
CHECK_LENGTH ();
|
||||
break;
|
||||
case CQ('I'):
|
||||
case CQ('l'): /* newlib extension */
|
||||
if (alt == CQ('O'))
|
||||
alt = CQ('\0');
|
||||
/*FALLTHRU*/
|
||||
case CQ('I'):
|
||||
{
|
||||
register int h12;
|
||||
h12 = (tim_p->tm_hour == 0 || tim_p->tm_hour == 12) ?
|
||||
12 : tim_p->tm_hour % 12;
|
||||
len = snprintf (&s[count], maxsize - count,
|
||||
*format == CQ('I') ? CQ("%.2d") : CQ("%2d"),
|
||||
h12);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt != CQ('O') || !*alt_digits
|
||||
|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
|
||||
h12, *alt_digits)))
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
len = snprintf (&s[count], maxsize - count,
|
||||
*format == CQ('I') ? CQ("%.2d") : CQ("%2d"), h12);
|
||||
CHECK_LENGTH ();
|
||||
}
|
||||
break;
|
||||
case CQ('j'):
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.3d"),
|
||||
tim_p->tm_yday + 1);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
tim_p->tm_yday + 1);
|
||||
CHECK_LENGTH ();
|
||||
break;
|
||||
case CQ('m'):
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
|
||||
tim_p->tm_mon + 1);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt != CQ('O') || !*alt_digits
|
||||
|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
|
||||
tim_p->tm_mon + 1, *alt_digits)))
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
|
||||
tim_p->tm_mon + 1);
|
||||
CHECK_LENGTH ();
|
||||
break;
|
||||
case CQ('M'):
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
|
||||
tim_p->tm_min);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt != CQ('O') || !*alt_digits
|
||||
|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
|
||||
tim_p->tm_min, *alt_digits)))
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
|
||||
tim_p->tm_min);
|
||||
CHECK_LENGTH ();
|
||||
break;
|
||||
case CQ('n'):
|
||||
if (count < maxsize - 1)
|
||||
@ -621,13 +1057,18 @@ recurse:
|
||||
break;
|
||||
case CQ('R'):
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d"),
|
||||
tim_p->tm_hour, tim_p->tm_min);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
tim_p->tm_hour, tim_p->tm_min);
|
||||
CHECK_LENGTH ();
|
||||
break;
|
||||
case CQ('S'):
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
|
||||
tim_p->tm_sec);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt != CQ('O') || !*alt_digits
|
||||
|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
|
||||
tim_p->tm_sec, *alt_digits)))
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
|
||||
tim_p->tm_sec);
|
||||
CHECK_LENGTH ();
|
||||
break;
|
||||
case CQ('t'):
|
||||
if (count < maxsize - 1)
|
||||
@ -637,10 +1078,22 @@ recurse:
|
||||
break;
|
||||
case CQ('T'):
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d:%.2d"),
|
||||
tim_p->tm_hour, tim_p->tm_min, tim_p->tm_sec);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
tim_p->tm_hour, tim_p->tm_min, tim_p->tm_sec);
|
||||
CHECK_LENGTH ();
|
||||
break;
|
||||
case CQ('u'):
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt == CQ('O') && *alt_digits)
|
||||
{
|
||||
len = conv_to_alt_digits (&s[count], maxsize - count,
|
||||
tim_p->tm_wday == 0 ? 7
|
||||
: tim_p->tm_wday,
|
||||
*alt_digits);
|
||||
CHECK_LENGTH ();
|
||||
if (len > 0)
|
||||
break;
|
||||
}
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
if (count < maxsize - 1)
|
||||
{
|
||||
if (tim_p->tm_wday == 0)
|
||||
@ -652,10 +1105,17 @@ recurse:
|
||||
return 0;
|
||||
break;
|
||||
case CQ('U'):
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
|
||||
(tim_p->tm_yday + 7 -
|
||||
tim_p->tm_wday) / 7);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt != CQ('O') || !*alt_digits
|
||||
|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
|
||||
(tim_p->tm_yday + 7 -
|
||||
tim_p->tm_wday) / 7,
|
||||
*alt_digits)))
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
|
||||
(tim_p->tm_yday + 7 -
|
||||
tim_p->tm_wday) / 7);
|
||||
CHECK_LENGTH ();
|
||||
break;
|
||||
case CQ('V'):
|
||||
{
|
||||
@ -673,11 +1133,26 @@ recurse:
|
||||
+ (YEAR_BASE - 1
|
||||
- (tim_p->tm_year < 0
|
||||
? 0 : 2000)))));
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d"), week);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt != CQ('O') || !*alt_digits
|
||||
|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
|
||||
week, *alt_digits)))
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d"), week);
|
||||
CHECK_LENGTH ();
|
||||
}
|
||||
break;
|
||||
case CQ('w'):
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt == CQ('O') && *alt_digits)
|
||||
{
|
||||
len = conv_to_alt_digits (&s[count], maxsize - count,
|
||||
tim_p->tm_wday, *alt_digits);
|
||||
CHECK_LENGTH ();
|
||||
if (len > 0)
|
||||
break;
|
||||
}
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
if (count < maxsize - 1)
|
||||
s[count++] = CQ('0') + tim_p->tm_wday;
|
||||
else
|
||||
@ -686,37 +1161,75 @@ recurse:
|
||||
case CQ('W'):
|
||||
{
|
||||
int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
|
||||
(tim_p->tm_yday + 7 - wday) / 7);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
wday = (tim_p->tm_yday + 7 - wday) / 7;
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt != CQ('O') || !*alt_digits
|
||||
|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
|
||||
wday, *alt_digits)))
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d"), wday);
|
||||
CHECK_LENGTH ();
|
||||
}
|
||||
break;
|
||||
case CQ('y'):
|
||||
{
|
||||
/* Be careful of both overflow and negative years, thanks to
|
||||
the asymmetric range of years. */
|
||||
int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
|
||||
: abs (tim_p->tm_year + YEAR_BASE) % 100;
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d"), year);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt == 'E' && *era_info)
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%d"),
|
||||
(*era_info)->year);
|
||||
else
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
{
|
||||
/* Be careful of both overflow and negative years, thanks to
|
||||
the asymmetric range of years. */
|
||||
int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
|
||||
: abs (tim_p->tm_year + YEAR_BASE) % 100;
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt != CQ('O') || !*alt_digits
|
||||
|| !(len = conv_to_alt_digits (&s[count], maxsize - count,
|
||||
year, *alt_digits)))
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%.2d"),
|
||||
year);
|
||||
}
|
||||
CHECK_LENGTH ();
|
||||
}
|
||||
break;
|
||||
case CQ('Y'):
|
||||
/* An implementation choice is to have %Y match %C%y, so that it
|
||||
* gives at least 4 digits, with leading zeros as needed. */
|
||||
if(tim_p->tm_year <= INT_MAX-YEAR_BASE) {
|
||||
/* For normal, non-overflow case. */
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%04d"),
|
||||
tim_p->tm_year + YEAR_BASE);
|
||||
}
|
||||
else {
|
||||
/* int would overflow, so use unsigned instead. */
|
||||
register unsigned year;
|
||||
year = (unsigned) tim_p->tm_year + (unsigned) YEAR_BASE;
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%04u"),
|
||||
tim_p->tm_year + YEAR_BASE);
|
||||
}
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
#ifdef _WANT_C99_TIME_FORMATS
|
||||
if (alt == 'E' && *era_info)
|
||||
{
|
||||
ctloc = (*era_info)->era_Y;
|
||||
goto recurse;
|
||||
}
|
||||
else
|
||||
#endif /* _WANT_C99_TIME_FORMATS */
|
||||
{
|
||||
CHAR fmtbuf[10], *fmt = fmtbuf;
|
||||
int sign = tim_p->tm_year < -YEAR_BASE;
|
||||
/* int potentially overflows, so use unsigned instead. */
|
||||
register unsigned year = (unsigned) tim_p->tm_year
|
||||
+ (unsigned) YEAR_BASE;
|
||||
if (sign)
|
||||
{
|
||||
*fmt++ = CQ('-');
|
||||
year = UINT_MAX - year + 1;
|
||||
}
|
||||
else if (pad == CQ('+') && year >= 10000)
|
||||
{
|
||||
*fmt++ = CQ('+');
|
||||
sign = 1;
|
||||
}
|
||||
if (width && sign)
|
||||
--width;
|
||||
*fmt++ = CQ('%');
|
||||
if (pad)
|
||||
*fmt++ = CQ('0');
|
||||
STRCPY (fmt, CQ(".*u"));
|
||||
len = snprintf (&s[count], maxsize - count, fmtbuf, width,
|
||||
year);
|
||||
CHECK_LENGTH ();
|
||||
}
|
||||
break;
|
||||
case CQ('z'):
|
||||
if (tim_p->tm_isdst >= 0)
|
||||
@ -730,9 +1243,9 @@ recurse:
|
||||
offset = -tz->__tzrule[tim_p->tm_isdst > 0].offset;
|
||||
TZ_UNLOCK;
|
||||
len = snprintf (&s[count], maxsize - count, CQ("%+03ld%.2ld"),
|
||||
offset / SECSPERHOUR,
|
||||
labs (offset / SECSPERMIN) % 60L);
|
||||
if (len < 0 || (count+=len) >= maxsize) return 0;
|
||||
offset / SECSPERHOUR,
|
||||
labs (offset / SECSPERMIN) % 60L);
|
||||
CHECK_LENGTH ();
|
||||
}
|
||||
break;
|
||||
case CQ('Z'):
|
||||
@ -760,6 +1273,8 @@ recurse:
|
||||
else
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
if (*format)
|
||||
format++;
|
||||
@ -771,7 +1286,7 @@ recurse:
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/* The remainder of this file can serve as a regression test. Compile
|
||||
* with -D_REGRESSION_TEST. */
|
||||
#if defined(_REGRESSION_TEST) /* [Test code: */
|
||||
|
Loading…
x
Reference in New Issue
Block a user