summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Henriksen <LarsHenriksen@get2net.dk>2020-05-07 21:39:23 +0200
committerLukas Fleischer <lfleischer@calcurse.org>2020-05-12 09:24:11 -0400
commitbd238bfd7c443fd974f5b7edd6c1abc0349bfa78 (patch)
tree46ee867794426eee0eae031d65ffd86b98026693
parentfabacecd16eb62ff94dfa8955862852a410e3524 (diff)
downloadcalcurse-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>
-rw-r--r--src/recur.c63
-rw-r--r--test/data/rfc55451
-rwxr-xr-xtest/recur-009.sh13
3 files changed, 57 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(
diff --git a/test/data/rfc5545 b/test/data/rfc5545
index 421dd53..d9863ce 100644
--- a/test/data/rfc5545
+++ b/test/data/rfc5545
@@ -25,3 +25,4 @@
12/25/1997 [1] {3Y w-11} Last Thursday of the year every third year, forever (FREQ=YEARLY;INTERVAL=3;BYDAY=-1TH)
06/22/1997 [1] {2Y w0 w1} Every Sunday and Monday, every other year (FREQ=YEARLY;INTERVAL=2;BYDAY=SU,MO)
02/01/1997 [1] {1Y -> 01/31/2005 d1 d29 m2} Every year on February 1 and 29 for eight years (RRULE:FREQ=YEARLY;UNTIL=20050131T000000Z;BYMONTH=2;BYMONTHDAY=1,29)
+08/01/2020 @ 08:41 -> 08/01/2020 @ 10:11 {1M w-41} |negative ordered weekday may not exist
diff --git a/test/recur-009.sh b/test/recur-009.sh
index 6ee302d..2558b4c 100755
--- a/test/recur-009.sh
+++ b/test/recur-009.sh
@@ -6,6 +6,13 @@
if [ "$1" = 'actual' ]; then
"$CALCURSE" --read-only -D "$DATA_DIR"/ -c "$DATA_DIR/rfc5545" \
-Q --from 1/1/1996 --to 12/31/2007 --filter-type recur
+ echo ""
+ echo "Floating point exception?"
+ "$CALCURSE" --read-only -D "$DATA_DIR"/ -c "$DATA_DIR/rfc5545" \
+ -Q --day 8/1/2020 --filter-type recur &&
+ "$CALCURSE" --read-only -D "$DATA_DIR"/ -c "$DATA_DIR/rfc5545" \
+ -Q --day 11/1/2020 --filter-type recur &&
+ echo "No Floating point exception on November 1, 2020"
elif [ "$1" = 'expected' ]; then
cat <<EOD
11/05/96:
@@ -5323,6 +5330,12 @@ elif [ "$1" = 'expected' ]; then
12/31/07:
* Every Sunday and Monday, every other year (FREQ=YEARLY;INTERVAL=2;BYDAY=SU,MO)
+
+Floating point exception?
+08/01/20:
+ - 08:41 -> 10:11
+ negative ordered weekday may not exist
+No Floating point exception on November 1, 2020
EOD
else
./run-test "$0"