#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifndef _REENTRANT
# define _REENTRANT 1
#endif
#ifdef _LIBC
# define HAVE_LIMITS_H 1
# define HAVE_MBLEN 1
# define HAVE_MBRLEN 1
# define HAVE_STRUCT_ERA_ENTRY 1
# define HAVE_TM_GMTOFF 1
# define HAVE_TM_ZONE 1
# define HAVE_TZNAME 1
# define HAVE_TZSET 1
# define MULTIBYTE_IS_FORMAT_SAFE 1
# define STDC_HEADERS 1
# include "../locale/localeinfo.h"
#endif
#if defined emacs && !defined HAVE_BCOPY
# define HAVE_MEMCPY 1
#endif
#include <ctype.h>
#include <sys/types.h>
#ifdef TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#if HAVE_TZNAME
extern char *tzname[];
#endif
#define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
#if DO_MULTIBYTE
# if HAVE_MBRLEN
# include <wchar.h>
# else
# define mbstate_t int
# define mbrlen(s, n, ps) mblen (s, n)
# define mbsinit(ps) (*(ps) == 0)
# endif
static const mbstate_t mbstate_zero;
#endif
#if HAVE_LIMITS_H
# include <limits.h>
#endif
#if STDC_HEADERS
# include <stddef.h>
# include <stdlib.h>
# include <string.h>
#else
# ifndef HAVE_MEMCPY
# define memcpy(d, s, n) bcopy ((s), (d), (n))
# endif
#endif
#ifdef _LIBC
# define MEMPCPY(d, s, n) __mempcpy (d, s, n)
#else
# ifndef HAVE_MEMPCPY
# define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
# endif
#endif
#ifndef __P
# if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif
#ifndef PTR
# ifdef __STDC__
# define PTR void *
# else
# define PTR char *
# endif
#endif
#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif
#ifndef NULL
# define NULL 0
#endif
#define TYPE_SIGNED(t) ((t) -1 < 0)
#define INT_STRLEN_BOUND(t) \
((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
#define TM_YEAR_BASE 1900
#ifndef __isleap
# define __isleap(year) \
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
#endif
#ifdef _LIBC
# define gmtime_r __gmtime_r
# define localtime_r __localtime_r
# define tzname __tzname
# define tzset __tzset
#else
# if ! HAVE_LOCALTIME_R
# if ! HAVE_TM_GMTOFF
# undef gmtime_r
# define gmtime_r my_gmtime_r
static struct tm *gmtime_r __P ((const time_t *, struct tm *));
static struct tm *
gmtime_r (t, tp)
const time_t *t;
struct tm *tp;
{
struct tm *l = gmtime (t);
if (! l)
return 0;
*tp = *l;
return tp;
}
# endif
# undef localtime_r
# define localtime_r my_ftime_localtime_r
static struct tm *localtime_r __P ((const time_t *, struct tm *));
static struct tm *
localtime_r (t, tp)
const time_t *t;
struct tm *tp;
{
struct tm *l = localtime (t);
if (! l)
return 0;
*tp = *l;
return tp;
}
# endif
#endif
#if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
static const char spaces[16] =
{ ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' };
static const char zeroes[16] =
{ '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0' };
# define memset_space(P, Len) \
do { \
int _len = (Len); \
\
do \
{ \
int _this = _len > 16 ? 16 : _len; \
(P) = MEMPCPY ((P), spaces, _this); \
_len -= _this; \
} \
while (_len > 0); \
} while (0)
# define memset_zero(P, Len) \
do { \
int _len = (Len); \
\
do \
{ \
int _this = _len > 16 ? 16 : _len; \
(P) = MEMPCPY ((P), zeroes, _this); \
_len -= _this; \
} \
while (_len > 0); \
} while (0)
#else
# define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
# define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
#endif
#define add(n, f) \
do \
{ \
int _n = (n); \
int _delta = width - _n; \
int _incr = _n + (_delta > 0 ? _delta : 0); \
if (i + _incr >= maxsize) \
return 0; \
if (p) \
{ \
if (_delta > 0) \
{ \
if (pad == '0') \
memset_zero (p, _delta); \
else \
memset_space (p, _delta); \
} \
f; \
p += _n; \
} \
i += _incr; \
} while (0)
#define cpy(n, s) \
add ((n), \
if (to_lowcase) \
memcpy_lowcase (p, (s), _n); \
else if (to_uppcase) \
memcpy_uppcase (p, (s), _n); \
else \
memcpy ((PTR) p, (PTR) (s), _n))
#ifdef _LIBC
# define TOUPPER(Ch) toupper (Ch)
# define TOLOWER(Ch) tolower (Ch)
#else
# define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
# define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
#endif
#define ISDIGIT(Ch) ((unsigned int) (Ch) - '0' <= 9)
static char *memcpy_lowcase __P ((char *dest, const char *src, size_t len));
static char *
memcpy_lowcase (dest, src, len)
char *dest;
const char *src;
size_t len;
{
while (len-- > 0)
dest[len] = TOLOWER ((unsigned char) src[len]);
return dest;
}
static char *memcpy_uppcase __P ((char *dest, const char *src, size_t len));
static char *
memcpy_uppcase (dest, src, len)
char *dest;
const char *src;
size_t len;
{
while (len-- > 0)
dest[len] = TOUPPER ((unsigned char) src[len]);
return dest;
}
#if ! HAVE_TM_GMTOFF
# define tm_diff ftime_tm_diff
static int tm_diff __P ((const struct tm *, const struct tm *));
static int
tm_diff (a, b)
const struct tm *a;
const struct tm *b;
{
int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
int a100 = a4 / 25 - (a4 % 25 < 0);
int b100 = b4 / 25 - (b4 % 25 < 0);
int a400 = a100 >> 2;
int b400 = b100 >> 2;
int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
int years = a->tm_year - b->tm_year;
int days = (365 * years + intervening_leap_days
+ (a->tm_yday - b->tm_yday));
return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+ (a->tm_min - b->tm_min))
+ (a->tm_sec - b->tm_sec));
}
#endif
#define ISO_WEEK_START_WDAY 1
#define ISO_WEEK1_WDAY 4
#define YDAY_MINIMUM (-366)
static int iso_week_days __P ((int, int));
#ifdef __GNUC__
__inline__
#endif
static int
iso_week_days (yday, wday)
int yday;
int wday;
{
int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
return (yday
- (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
+ ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
}
#if !(defined _NL_CURRENT || HAVE_STRFTIME)
static 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
#ifdef emacs
# define my_strftime emacs_strftime
#else
# define my_strftime strftime
#endif
#if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
size_t _strftime_copytm __P ((char *, size_t, const char *,
const struct tm *));
size_t
my_strftime (s, maxsize, format, tp)
char *s;
size_t maxsize;
const char *format;
const struct tm *tp;
{
struct tm tmcopy;
tmcopy = *tp;
return _strftime_copytm (s, maxsize, format, &tmcopy);
}
# undef my_strftime
# define my_strftime(S, Maxsize, Format, Tp) \
_strftime_copytm (S, Maxsize, Format, Tp)
#endif
size_t
my_strftime (s, maxsize, format, tp)
char *s;
size_t maxsize;
const char *format;
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
# if !HAVE_STRFTIME
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
#endif
#if defined _NL_CURRENT || !HAVE_STRFTIME
size_t wkday_len = strlen (f_wkday);
size_t month_len = strlen (f_month);
#endif
const char *zone;
size_t zonelen;
size_t i = 0;
char *p = s;
const char *f;
zone = NULL;
#if HAVE_TM_ZONE
zone = (const char *) tp->tm_zone;
#endif
#if HAVE_TZNAME
# if HAVE_TZSET
tzset ();
# endif
if (!(zone && *zone) && tp->tm_isdst >= 0)
zone = tzname[tp->tm_isdst];
#endif
if (! zone)
zone = "";
zonelen = strlen (zone);
if (hour12 > 12)
hour12 -= 12;
else
if (hour12 == 0) hour12 = 12;
for (f = format; *f != '\0'; ++f)
{
int pad = 0;
int modifier;
int digits;
int number_value;
int negative_number;
const char *subfmt;
char *bufp;
char buf[1 + (sizeof (int) < sizeof (time_t)
? INT_STRLEN_BOUND (time_t)
: INT_STRLEN_BOUND (int))];
int width = -1;
int to_lowcase = 0;
int to_uppcase = 0;
int change_case = 0;
int format_char;
#if DO_MULTIBYTE
switch (*f)
{
case '%':
break;
case '\a': case '\b': case '\t': case '\n':
case '\v': case '\f': case '\r':
case ' ': case '!': case '"': case '#': case '&': case'\'':
case '(': case ')': case '*': case '+': case ',': case '-':
case '.': case '/': case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7': case '8': case '9':
case ':': case ';': case '<': case '=': case '>': case '?':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
case 'r': case 's': case 't': case 'u': case 'v': case 'w':
case 'x': case 'y': case 'z': case '{': case '|': case '}':
case '~':
add (1, *p = *f);
continue;
default:
{
mbstate_t mbstate = mbstate_zero;
size_t len = 0;
do
{
size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
if (bytes == 0)
break;
if (bytes == (size_t) -2 || bytes == (size_t) -1)
{
len++;
break;
}
len += bytes;
}
while (! mbsinit (&mbstate));
cpy (len, f);
continue;
}
}
#else
if (*f != '%')
{
add (1, *p = *f);
continue;
}
#endif
while (1)
{
switch (*++f)
{
case '_':
case '-':
case '0':
pad = *f;
continue;
case '^':
to_uppcase = 1;
continue;
case '#':
change_case = 1;
continue;
default:
break;
}
break;
}
if (ISDIGIT (*f))
{
width = 0;
do
{
width *= 10;
width += *f - '0';
++f;
}
while (ISDIGIT (*f));
}
switch (*f)
{
case 'E':
case 'O':
modifier = *f++;
break;
default:
modifier = 0;
break;
}
format_char = *f;
switch (format_char)
{
#define DO_NUMBER(d, v) \
digits = width == -1 ? d : width; \
number_value = v; goto do_number
#define DO_NUMBER_SPACEPAD(d, v) \
digits = width == -1 ? d : width; \
number_value = v; goto do_number_spacepad
case '%':
if (modifier != 0)
goto bad_format;
add (1, *p = *f);
break;
case 'a':
if (modifier != 0)
goto bad_format;
if (change_case)
{
to_uppcase = 1;
to_lowcase = 0;
}
#if defined _NL_CURRENT || !HAVE_STRFTIME
cpy (aw_len, a_wkday);
break;
#else
goto underlying_strftime;
#endif
case 'A':
if (modifier != 0)
goto bad_format;
if (change_case)
{
to_uppcase = 1;
to_lowcase = 0;
}
#if defined _NL_CURRENT || !HAVE_STRFTIME
cpy (wkday_len, f_wkday);
break;
#else
goto underlying_strftime;
#endif
case 'b':
case 'h':
if (modifier != 0)
goto bad_format;
#if defined _NL_CURRENT || !HAVE_STRFTIME
cpy (am_len, a_month);
break;
#else
goto underlying_strftime;
#endif
case 'B':
if (modifier != 0)
goto bad_format;
if (change_case)
{
to_uppcase = 1;
to_lowcase = 0;
}
#if defined _NL_CURRENT || !HAVE_STRFTIME
cpy (month_len, f_month);
break;
#else
goto underlying_strftime;
#endif
case 'c':
if (modifier == 'O')
goto bad_format;
#ifdef _NL_CURRENT
if (! (modifier == 'E'
&& *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
#else
# if HAVE_STRFTIME
goto underlying_strftime;
# else
subfmt = "%a %b %e %H:%M:%S %Y";
# endif
#endif
subformat:
{
char *old_start = p;
size_t len = my_strftime (NULL, maxsize - i, subfmt, tp);
if (len == 0 && *subfmt)
return 0;
add (len, my_strftime (p, maxsize - i, subfmt, tp));
if (to_uppcase)
while (old_start < p)
{
*old_start = TOUPPER ((unsigned char) *old_start);
++old_start;
}
}
break;
#if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
underlying_strftime:
{
char ufmt[4];
char *u = ufmt;
char ubuf[1024];
size_t len;
*u++ = '%';
if (modifier != 0)
*u++ = modifier;
*u++ = format_char;
*u = '\0';
ubuf[0] = '\1';
len = strftime (ubuf, sizeof ubuf, ufmt, tp);
if (len == 0 && ubuf[0] != '\0')
return 0;
cpy (len, ubuf);
}
break;
#endif
case 'C':
if (modifier == 'O')
goto bad_format;
if (modifier == 'E')
{
#if HAVE_STRUCT_ERA_ENTRY
struct era_entry *era = _nl_get_era_entry (tp);
if (era)
{
size_t len = strlen (era->name_fmt);
cpy (len, era->name_fmt);
break;
}
#else
# if HAVE_STRFTIME
goto underlying_strftime;
# endif
#endif
}
{
int year = tp->tm_year + TM_YEAR_BASE;
DO_NUMBER (1, year / 100 - (year % 100 < 0));
}
case 'x':
if (modifier == 'O')
goto bad_format;
#ifdef _NL_CURRENT
if (! (modifier == 'E'
&& *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
subfmt = _NL_CURRENT (LC_TIME, D_FMT);
goto subformat;
#else
# if HAVE_STRFTIME
goto underlying_strftime;
# else
# endif
#endif
case 'D':
if (modifier != 0)
goto bad_format;
subfmt = "%m/%d/%y";
goto subformat;
case 'd':
if (modifier == 'E')
goto bad_format;
DO_NUMBER (2, tp->tm_mday);
case 'e':
if (modifier == 'E')
goto bad_format;
DO_NUMBER_SPACEPAD (2, tp->tm_mday);
do_number_spacepad:
if (pad != '0')
pad = '_';
do_number:
if (modifier == 'O' && 0 <= number_value)
{
#ifdef _NL_CURRENT
const char *cp = _nl_get_alt_digit (number_value);
if (cp != NULL)
{
size_t digitlen = strlen (cp);
if (digitlen != 0)
{
cpy (digitlen, cp);
break;
}
}
#else
# if HAVE_STRFTIME
goto underlying_strftime;
# endif
#endif
}
{
unsigned int u = number_value;
bufp = buf + sizeof (buf);
negative_number = number_value < 0;
if (negative_number)
u = -u;
do
*--bufp = u % 10 + '0';
while ((u /= 10) != 0);
}
do_number_sign_and_padding:
if (negative_number)
*--bufp = '-';
if (pad != '-')
{
int padding = digits - (buf + sizeof (buf) - bufp);
if (pad == '_')
{
while (0 < padding--)
*--bufp = ' ';
}
else
{
bufp += negative_number;
while (0 < padding--)
*--bufp = '0';
if (negative_number)
*--bufp = '-';
}
}
cpy (buf + sizeof (buf) - bufp, bufp);
break;
case 'F':
if (modifier != 0)
goto bad_format;
subfmt = "%Y-%m-%d";
goto subformat;
case 'H':
if (modifier == 'E')
goto bad_format;
DO_NUMBER (2, tp->tm_hour);
case 'I':
if (modifier == 'E')
goto bad_format;
DO_NUMBER (2, hour12);
case 'k':
if (modifier == 'E')
goto bad_format;
DO_NUMBER_SPACEPAD (2, tp->tm_hour);
case 'l':
if (modifier == 'E')
goto bad_format;
DO_NUMBER_SPACEPAD (2, hour12);
case 'j':
if (modifier == 'E')
goto bad_format;
DO_NUMBER (3, 1 + tp->tm_yday);
case 'M':
if (modifier == 'E')
goto bad_format;
DO_NUMBER (2, tp->tm_min);
case 'm':
if (modifier == 'E')
goto bad_format;
DO_NUMBER (2, tp->tm_mon + 1);
case 'n':
add (1, *p = '\n');
break;
case 'P':
to_lowcase = 1;
#if !defined _NL_CURRENT && HAVE_STRFTIME
format_char = 'p';
#endif
case 'p':
if (change_case)
{
to_uppcase = 0;
to_lowcase = 1;
}
#if defined _NL_CURRENT || !HAVE_STRFTIME
cpy (ap_len, ampm);
break;
#else
goto underlying_strftime;
#endif
case 'R':
subfmt = "%H:%M";
goto subformat;
case 'r':
#ifdef _NL_CURRENT
if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
#endif
subfmt = "%I:%M:%S %p";
goto subformat;
case 'S':
if (modifier == 'E')
goto bad_format;
DO_NUMBER (2, tp->tm_sec);
case 's':
{
struct tm ltm;
time_t t;
ltm = *tp;
t = mktime (<m);
bufp = buf + sizeof (buf);
negative_number = t < 0;
do
{
int d = t % 10;
t /= 10;
if (negative_number)
{
d = -d;
if (0 < -1 % 10 && d < 0)
{
t++;
d += 10;
}
}
*--bufp = d + '0';
}
while (t != 0);
digits = 1;
goto do_number_sign_and_padding;
}
case 'X':
if (modifier == 'O')
goto bad_format;
#ifdef _NL_CURRENT
if (! (modifier == 'E'
&& *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
subfmt = _NL_CURRENT (LC_TIME, T_FMT);
goto subformat;
#else
# if HAVE_STRFTIME
goto underlying_strftime;
# else
# endif
#endif
case 'T':
subfmt = "%H:%M:%S";
goto subformat;
case 't':
add (1, *p = '\t');
break;
case 'f':
case 'u':
DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
case 'U':
if (modifier == 'E')
goto bad_format;
DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
case 'V':
case 'g':
case 'G':
if (modifier == 'E')
goto bad_format;
{
int year = tp->tm_year + TM_YEAR_BASE;
int days = iso_week_days (tp->tm_yday, tp->tm_wday);
if (days < 0)
{
year--;
days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
tp->tm_wday);
}
else
{
int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
tp->tm_wday);
if (0 <= d)
{
year++;
days = d;
}
}
switch (*f)
{
case 'g':
DO_NUMBER (2, (year % 100 + 100) % 100);
case 'G':
DO_NUMBER (1, year);
default:
DO_NUMBER (2, days / 7 + 1);
}
}
case 'W':
if (modifier == 'E')
goto bad_format;
DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
case 'w':
if (modifier == 'E')
goto bad_format;
DO_NUMBER (1, tp->tm_wday);
case 'Y':
if (modifier == 'E')
{
#if HAVE_STRUCT_ERA_ENTRY
struct era_entry *era = _nl_get_era_entry (tp);
if (era)
{
subfmt = strchr (era->name_fmt, '\0') + 1;
goto subformat;
}
#else
# if HAVE_STRFTIME
goto underlying_strftime;
# endif
#endif
}
if (modifier == 'O')
goto bad_format;
else
DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
case 'y':
if (modifier == 'E')
{
#if HAVE_STRUCT_ERA_ENTRY
struct era_entry *era = _nl_get_era_entry (tp);
if (era)
{
int delta = tp->tm_year - era->start_date[0];
DO_NUMBER (1, (era->offset
+ (era->direction == '-' ? -delta : delta)));
}
#else
# if HAVE_STRFTIME
goto underlying_strftime;
# endif
#endif
}
DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
case 'Z':
if (change_case)
{
to_uppcase = 0;
to_lowcase = 1;
}
cpy (zonelen, zone);
break;
case 'z':
if (tp->tm_isdst < 0)
break;
{
int diff;
#if HAVE_TM_GMTOFF
diff = tp->tm_gmtoff;
#else
struct tm gtm;
struct tm ltm;
time_t lt;
ltm = *tp;
lt = mktime (<m);
if (lt == (time_t) -1)
{
struct tm tm;
if (! localtime_r (<, &tm)
|| ((ltm.tm_sec ^ tm.tm_sec)
| (ltm.tm_min ^ tm.tm_min)
| (ltm.tm_hour ^ tm.tm_hour)
| (ltm.tm_mday ^ tm.tm_mday)
| (ltm.tm_mon ^ tm.tm_mon)
| (ltm.tm_year ^ tm.tm_year)))
break;
}
if (! gmtime_r (<, >m))
break;
diff = tm_diff (<m, >m);
#endif
if (diff < 0)
{
add (1, *p = '-');
diff = -diff;
}
else
add (1, *p = '+');
diff /= 60;
DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
}
case '\0':
--f;
default:
bad_format:
{
int flen;
for (flen = 1; f[1 - flen] != '%'; flen++)
continue;
cpy (flen, &f[1 - flen]);
}
break;
}
}
if (p)
*p = '\0';
return i;
}