Correct the calculation of "a leap year" in parseDWM. The calculation

would only match a leap year every 400 years.  The parseDWM code first
showed up in April 2000, so the first time this bug would cause any
confusion is in Feb 2004.

MFC after:	18 days
This commit is contained in:
Garance A Drosehn 2003-09-14 00:56:50 +00:00
parent 5cd10ac5d9
commit 526d55a405
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=120046

View File

@ -48,6 +48,42 @@ __FBSDID("$FreeBSD$");
#include "extern.h"
static int days_pmonth(int month, int year);
/*
* Simple routine to calculate the number of days in a given month.
*/
static int
days_pmonth(int month, int year)
{
static const int mtab[] = {31, 28, 31, 30, 31, 30, 31, 31,
30, 31, 30, 31};
int ndays;
ndays = mtab[month];
if (month == 1) {
/*
* We are usually called with a 'tm-year' value
* (ie, the value = the number of years past 1900).
*/
if (year < 1900)
year += 1900;
if (year % 4 == 0) {
/*
* This is a leap year, as long as it is not a
* multiple of 100, or if it is a multiple of
* both 100 and 400.
*/
if (year % 100 != 0)
ndays++; /* not multiple of 100 */
else if (year % 400 == 0)
ndays++; /* is multiple of 100 and 400 */
}
}
return (ndays);
}
/*-
* Parse a limited subset of ISO 8601. The specific format is as follows:
*
@ -158,12 +194,11 @@ parse8601(const char *s, time_t *next_time)
time_t
parseDWM(char *s, time_t *next_time)
{
int daysmon;
char *t;
time_t tsecs;
struct tm tm, *tmp;
long l;
int nd;
static int mtab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int WMseen = 0;
int Dseen = 0;
@ -172,17 +207,8 @@ parseDWM(char *s, time_t *next_time)
if (next_time != NULL)
*next_time = (time_t)-1;
/* set no. of days per month */
nd = mtab[tm.tm_mon];
if (tm.tm_mon == 1) {
if (((tm.tm_year + 1900) % 4 == 0) &&
((tm.tm_year + 1900) % 100 != 0) &&
((tm.tm_year + 1900) % 400 == 0)) {
nd++; /* leap year, 29 days in february */
}
}
/* Save away the number of days in this month */
daysmon = days_pmonth(tm.tm_mon, tm.tm_year);
tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
for (;;) {
@ -218,9 +244,9 @@ parseDWM(char *s, time_t *next_time)
tm.tm_mday += save;
if (tm.tm_mday > nd) {
if (tm.tm_mday > daysmon) {
tm.tm_mon++;
tm.tm_mday = tm.tm_mday - nd;
tm.tm_mday = tm.tm_mday - daysmon;
}
}
break;
@ -231,7 +257,7 @@ parseDWM(char *s, time_t *next_time)
WMseen++;
s++;
if (tolower(*s) == 'l') {
tm.tm_mday = nd;
tm.tm_mday = daysmon;
s++;
t = s;
} else {
@ -239,7 +265,7 @@ parseDWM(char *s, time_t *next_time)
if (l < 1 || l > 31)
return (-1);
if (l > nd)
if (l > daysmon)
return (-1);
tm.tm_mday = l;
}