Proposed strftime.c and localtime.c changes for long years
Olson, Arthur David (NIH/NCI)
olsona at dc37a.nci.nih.gov
Tue Sep 7 12:21:29 UTC 2004
Attached are changes (based on those circulated on the list earlier by Paul
Eggert) to strftime.c and localtime.c; these changes allow for the
possibility that adding an int year to TM_YEAR_BASE might overflow an int,
so the relevant math is done with longs. There are also a couple of cosmetic
changes. Note that no changes to the way strftime handles two-digit year
output requests are being (deliberately) made at this point.
I hope to update the ftp bundle to incorporate these changes in about a
week; I'd welcome any feedback before then.
--ado
------- localtime.c -------
*** /tmp/geta17327 Tue Sep 7 08:12:24 2004
--- /tmp/getb17327 Tue Sep 7 08:12:24 2004
***************
*** 5,11 ****
#ifndef lint
#ifndef NOID
! static char elsieid[] = "@(#)localtime.c 7.78";
#endif /* !defined NOID */
#endif /* !defined lint */
--- 5,11 ----
#ifndef lint
#ifndef NOID
! static char elsieid[] = "@(#)localtime.c 7.79";
#endif /* !defined NOID */
#endif /* !defined lint */
***************
*** 134,139 ****
--- 134,142 ----
static void localsub P((const time_t * timep, long offset,
struct tm * tmp));
static int increment_overflow P((int * number, int delta));
+ static int long_increment_overflow P((long * number, int
delta));
+ static int long_normalize_overflow P((long * tensptr,
+ int * unitsptr, int base));
static int normalize_overflow P((int * tensptr, int * unitsptr,
int base));
static void settzname P((void));
***************
*** 1149,1155 ****
register const struct lsinfo * lp;
register long days;
register long rem;
! register int y;
register int yleap;
register const int * ip;
register long corr;
--- 1152,1158 ----
register const struct lsinfo * lp;
register long days;
register long rem;
! register long y;
register int yleap;
register const int * ip;
register long corr;
***************
*** 1218,1224 ****
y = EPOCH_YEAR;
#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
! register int newy;
newy = y + days / DAYSPERNYEAR;
if (days < 0)
--- 1221,1227 ----
y = EPOCH_YEAR;
#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
! register long newy;
newy = y + days / DAYSPERNYEAR;
if (days < 0)
***************
*** 1259,1264 ****
--- 1262,1268 ----
char * buf;
{
struct tm tm;
+ extern char * asctime_r();
return asctime_r(localtime_r(timep, &tm), buf);
}
***************
*** 1294,1299 ****
--- 1298,1315 ----
}
static int
+ long_increment_overflow(number, delta)
+ long * number;
+ int delta;
+ {
+ long number0;
+
+ number0 = *number;
+ *number += delta;
+ return (*number < number0) != (delta < 0);
+ }
+
+ static int
normalize_overflow(tensptr, unitsptr, base)
int * const tensptr;
int * const unitsptr;
***************
*** 1309,1314 ****
--- 1325,1345 ----
}
static int
+ long_normalize_overflow(tensptr, unitsptr, base)
+ long * const tensptr;
+ int * const unitsptr;
+ const int base;
+ {
+ register int tensdelta;
+
+ tensdelta = (*unitsptr >= 0) ?
+ (*unitsptr / base) :
+ (-1 - (-1 - *unitsptr) / base);
+ *unitsptr -= tensdelta * base;
+ return long_increment_overflow(tensptr, tensdelta);
+ }
+
+ static int
tmcomp(atmp, btmp)
register const struct tm * const atmp;
register const struct tm * const btmp;
***************
*** 1335,1342 ****
register const struct state * sp;
register int dir;
register int bits;
! register int i, j ;
register int saved_seconds;
time_t newt;
time_t t;
struct tm yourtm, mytm;
--- 1366,1375 ----
register const struct state * sp;
register int dir;
register int bits;
! register int i, j;
register int saved_seconds;
+ register long li;
+ long y;
time_t newt;
time_t t;
struct tm yourtm, mytm;
***************
*** 1352,1393 ****
return WRONG;
if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour,
HOURSPERDAY))
return WRONG;
! if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon,
MONSPERYEAR))
return WRONG;
/*
! ** Turn yourtm.tm_year into an actual year number for now.
** It is converted back to an offset from TM_YEAR_BASE later.
*/
! if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
return WRONG;
while (yourtm.tm_mday <= 0) {
! if (increment_overflow(&yourtm.tm_year, -1))
return WRONG;
! i = yourtm.tm_year + (1 < yourtm.tm_mon);
! yourtm.tm_mday += year_lengths[isleap(i)];
}
while (yourtm.tm_mday > DAYSPERLYEAR) {
! i = yourtm.tm_year + (1 < yourtm.tm_mon);
! yourtm.tm_mday -= year_lengths[isleap(i)];
! if (increment_overflow(&yourtm.tm_year, 1))
return WRONG;
}
for ( ; ; ) {
! i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
if (yourtm.tm_mday <= i)
break;
yourtm.tm_mday -= i;
if (++yourtm.tm_mon >= MONSPERYEAR) {
yourtm.tm_mon = 0;
! if (increment_overflow(&yourtm.tm_year, 1))
return WRONG;
}
}
! if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
return WRONG;
if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
saved_seconds = 0;
! else if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
/*
** We can't set tm_sec to 0, because that might push the
** time below the minimum representable time.
--- 1385,1438 ----
return WRONG;
if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour,
HOURSPERDAY))
return WRONG;
! y = yourtm.tm_year;
! /*
! ** Hands off tm_year for a while.
! */
! #define tm_year USE_Y_NOT_YOURTM_TM_YEAR
! if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
return WRONG;
/*
! ** Turn y into an actual year number for now.
** It is converted back to an offset from TM_YEAR_BASE later.
*/
! if (long_increment_overflow(&y, TM_YEAR_BASE))
return WRONG;
while (yourtm.tm_mday <= 0) {
! if (long_increment_overflow(&y, -1))
return WRONG;
! li = y + (1 < yourtm.tm_mon);
! yourtm.tm_mday += year_lengths[isleap(li)];
}
while (yourtm.tm_mday > DAYSPERLYEAR) {
! li = y + (1 < yourtm.tm_mon);
! yourtm.tm_mday -= year_lengths[isleap(li)];
! if (long_increment_overflow(&y, 1))
return WRONG;
}
for ( ; ; ) {
! i = mon_lengths[isleap(y)][yourtm.tm_mon];
if (yourtm.tm_mday <= i)
break;
yourtm.tm_mday -= i;
if (++yourtm.tm_mon >= MONSPERYEAR) {
yourtm.tm_mon = 0;
! if (long_increment_overflow(&y, 1))
return WRONG;
}
}
! if (long_increment_overflow(&y, -TM_YEAR_BASE))
return WRONG;
+ /*
+ ** Hands back on tm_year.
+ */
+ #undef tm_year
+ yourtm.tm_year = y;
+ if (yourtm.tm_year != y)
+ return WRONG;
if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
saved_seconds = 0;
! else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
/*
** We can't set tm_sec to 0, because that might push the
** time below the minimum representable time.
------- strftime.c -------
*** /tmp/geta17306 Tue Sep 7 08:12:07 2004
--- /tmp/getb17306 Tue Sep 7 08:12:07 2004
***************
*** 1,6 ****
#ifndef lint
#ifndef NOID
! static char elsieid[] = "@(#)strftime.c 7.64";
/*
** Based on the UCB version with the ID appearing below.
** This is ANSIish only when "multibyte character == plain character".
--- 1,6 ----
#ifndef lint
#ifndef NOID
! static char elsieid[] = "@(#)strftime.c 7.66";
/*
** Based on the UCB version with the ID appearing below.
** This is ANSIish only when "multibyte character == plain character".
***************
*** 108,113 ****
--- 108,114 ----
static char * _add P((const char *, char *, const char *));
static char * _conv P((int, const char *, char *, const char *));
+ static char * _lconv P((long, const char *, char *, const char *));
static char * _fmt P((const char *, const struct tm *, char *, const char
*, int *));
size_t strftime P((char *, size_t, const char *, const struct tm *));
***************
*** 210,217 ****
** something completely different.
** (ado, 1993-05-24)
*/
! pt = _conv((t->tm_year + TM_YEAR_BASE) /
100,
! "%02d", pt, ptlim);
continue;
case 'c':
{
--- 211,219 ----
** something completely different.
** (ado, 1993-05-24)
*/
! pt = _lconv((t->tm_year +
! (long) TM_YEAR_BASE) / 100,
! "%02ld", pt, ptlim);
continue;
case 'c':
{
***************
*** 379,390 ****
** (ado, 1996-01-02)
*/
{
! int year;
int yday;
int wday;
int w;
! year = t->tm_year + TM_YEAR_BASE;
yday = t->tm_yday;
wday = t->tm_wday;
for ( ; ; ) {
--- 381,393 ----
** (ado, 1996-01-02)
*/
{
! long year;
int yday;
int wday;
int w;
! year = t->tm_year;
! year += TM_YEAR_BASE;
yday = t->tm_yday;
wday = t->tm_wday;
for ( ; ; ) {
***************
*** 426,436 ****
DAYSPERNYEAR;
}
#ifdef XPG4_1994_04_09
! if ((w == 52
! && t->tm_mon == TM_JANUARY)
! || (w == 1
! && t->tm_mon ==
TM_DECEMBER))
! w = 53;
#endif /* defined XPG4_1994_04_09 */
if (*format == 'V')
pt = _conv(w, "%02d",
--- 429,439 ----
DAYSPERNYEAR;
}
#ifdef XPG4_1994_04_09
! if ((w == 52 &&
! t->tm_mon == TM_JANUARY) ||
! (w == 1 &&
! t->tm_mon == TM_DECEMBER))
! w = 53;
#endif /* defined XPG4_1994_04_09 */
if (*format == 'V')
pt = _conv(w, "%02d",
***************
*** 437,446 ****
pt, ptlim);
else if (*format == 'g') {
*warnp = IN_ALL;
! pt = _conv(year % 100,
"%02d",
pt, ptlim);
- } else pt = _conv(year, "%04d",
- pt, ptlim);
}
continue;
case 'v':
--- 440,449 ----
pt, ptlim);
else if (*format == 'g') {
*warnp = IN_ALL;
! pt = _conv(int(year % 100),
! "%02d", pt, ptlim);
! } else pt = _lconv(year, "%04ld",
pt, ptlim);
}
continue;
case 'v':
***************
*** 477,488 ****
continue;
case 'y':
*warnp = IN_ALL;
! pt = _conv((t->tm_year + TM_YEAR_BASE) %
100,
"%02d", pt, ptlim);
continue;
case 'Y':
! pt = _conv(t->tm_year + TM_YEAR_BASE,
"%04d",
! pt, ptlim);
continue;
case 'Z':
#ifdef TM_ZONE
--- 480,493 ----
continue;
case 'y':
*warnp = IN_ALL;
! pt = _conv(
! (int) ((t->tm_year +
! (long) TM_YEAR_BASE) % 100),
"%02d", pt, ptlim);
continue;
case 'Y':
! pt = _lconv(t->tm_year + (long)
TM_YEAR_BASE,
! "%04ld", pt, ptlim);
continue;
case 'Z':
#ifdef TM_ZONE
***************
*** 582,587 ****
--- 587,605 ----
char buf[INT_STRLEN_MAXIMUM(int) + 1];
(void) sprintf(buf, format, n);
+ return _add(buf, pt, ptlim);
+ }
+
+ static char *
+ _lconv(n, format, pt, ptlim)
+ const long n;
+ const char * const format;
+ char * const pt;
+ const char * const ptlim;
+ {
+ char buf[INT_STRLEN_MAXIMUM(long) + 1];
+
+ (void) sprintf(buf, format, n);
return _add(buf, pt, ptlim);
}
More information about the tz
mailing list