diff options
author | Lars Henriksen <LarsHenriksen@get2net.dk> | 2020-05-07 21:39:23 +0200 |
---|---|---|
committer | Lukas Fleischer <lfleischer@calcurse.org> | 2020-05-12 09:24:11 -0400 |
commit | bd238bfd7c443fd974f5b7edd6c1abc0349bfa78 (patch) | |
tree | 46ee867794426eee0eae031d65ffd86b98026693 /src | |
parent | fabacecd16eb62ff94dfa8955862852a410e3524 (diff) | |
download | calcurse-bd238bfd7c443fd974f5b7edd6c1abc0349bfa78.tar.gz calcurse-bd238bfd7c443fd974f5b7edd6c1abc0349bfa78.zip |
Fix recurrence rule expansion with ordered weekday
When the order of a weekday in BYDAY rule expansion (like -5SA or 5SU
for monthly or 55WE for yearly) exceeds the number of available weekdays
in the period (month or year), rule expansion with negative order could
result in a floating point exception. The reason: the modified frequency
might become zero.
Solution. Check order against number of available weekdays and terminate
expansion early whenever possible (also for positive orders).
Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk>
Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/recur.c | 63 |
1 files changed, 43 insertions, 20 deletions
diff --git a/src/recur.c b/src/recur.c index 997fb15..647ba11 100644 --- a/src/recur.c +++ b/src/recur.c @@ -1173,7 +1173,7 @@ static int expand_monthly(time_t start, long dur, struct rpt *rpt, llist_t *exc, LLIST_FOREACH(&rpt->bywday, i) { w = LLIST_GET_DATA(i); - int order, wday; + int order, wday, nbwd; localtime_r(&start, &tm_start); /* @@ -1188,6 +1188,11 @@ static int expand_monthly(time_t start, long dur, struct rpt *rpt, llist_t *exc, */ order = *w / WEEKINDAYS; wday = *w % WEEKINDAYS; + nbwd = wday_per_month(tm_day.tm_mon + 1, + tm_day.tm_year + 1900, + wday); + if (nbwd < order) + return 0; r.freq = order; tm_start.tm_mday = 1; tm_start.tm_mon = tm_day.tm_mon; @@ -1218,11 +1223,12 @@ static int expand_monthly(time_t start, long dur, struct rpt *rpt, llist_t *exc, */ order = -(*w) / WEEKINDAYS; wday = -(*w) % WEEKINDAYS; - r.freq = wday_per_month( - tm_day.tm_mon + 1, - tm_day.tm_year + 1900, - wday - ) - order + 1; + nbwd = wday_per_month(tm_day.tm_mon + 1, + tm_day.tm_year + 1900, + wday); + if (nbwd < order) + return 0; + r.freq = nbwd - order + 1; tm_start.tm_mday = 1; tm_start.tm_mon = tm_day.tm_mon; tm_start.tm_year = tm_day.tm_year; @@ -1259,7 +1265,7 @@ static int expand_yearly(time_t start, long dur, struct rpt *rpt, llist_t *exc, { struct tm tm_start, tm_day; llist_item_t *i, *j; - int *m, *w, mday, wday, order; + int *m, *w, mday, wday, order, nbwd; time_t nstart; struct rpt r; @@ -1312,6 +1318,19 @@ static int expand_yearly(time_t start, long dur, struct rpt *rpt, llist_t *exc, */ order = *w / WEEKINDAYS; wday = *w % WEEKINDAYS; + if (rpt->bymonth.head) + nbwd = wday_per_month( + tm_day.tm_mon + 1, + tm_day.tm_year + 1900, + wday + ); + else + nbwd = wday_per_year( + tm_day.tm_year + 1900, + wday + ); + if (nbwd < order) + return 0; r.freq = order; tm_start.tm_mday = 1; if (rpt->bymonth.head) @@ -1344,21 +1363,25 @@ static int expand_yearly(time_t start, long dur, struct rpt *rpt, llist_t *exc, */ order = -(*w) / WEEKINDAYS; wday = -(*w) % WEEKINDAYS; - if (rpt->bymonth.head) { - r.freq = wday_per_month( - tm_day.tm_mon + 1, - tm_day.tm_year + 1900, - wday - ) - order + 1; + if (rpt->bymonth.head) + nbwd = wday_per_month( + tm_day.tm_mon + 1, + tm_day.tm_year + 1900, + wday + ); + else + nbwd = wday_per_year( + tm_day.tm_year + 1900, + wday + ); + if (nbwd < order) + return 0; + r.freq = nbwd - order + 1; + tm_start.tm_mday = 1; + if (rpt->bymonth.head) tm_start.tm_mon = tm_day.tm_mon; - } else { - r.freq = wday_per_year( - tm_day.tm_year + 1900, - wday - ) - order + 1; + else tm_start.tm_mon = 0; - } - tm_start.tm_mday = 1; tm_start.tm_year = tm_day.tm_year; tm_start.tm_isdst = -1; nstart = date_sec_change( |