From f5d8b5e021a62bf3e36e18aa9aebee331fece8dd Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 25 Feb 2016 21:31:16 +0100 Subject: Support durations in recurrence ending dates When spending the end date of recurring items, allow date duration specifiers such as "+5d" or "+3w2d". Signed-off-by: Lukas Fleischer --- src/utils.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) (limited to 'src/utils.c') diff --git a/src/utils.c b/src/utils.c index 4ce9364..4300b59 100644 --- a/src/utils.c +++ b/src/utils.c @@ -453,6 +453,26 @@ void date_sec2date_fmt(long sec, const char *fmt, char *datef) #endif } +/* + * Used to change date by adding a certain amount of days or weeks. + * Returns 0 on success, 1 otherwise. + */ +int date_change(struct tm *date, int delta_month, int delta_day) +{ + struct tm t; + + t = *date; + t.tm_mon += delta_month; + t.tm_mday += delta_day; + + if (mktime(&t) == -1) { + return 1; + } else { + *date = t; + return 0; + } +} + /* * Used to change date by adding a certain amount of days or weeks. */ @@ -839,6 +859,77 @@ parse_date(const char *date_string, enum datefmt datefmt, int *year, return 1; } +/* + * Convert a date duration string into a number of days. + * + * Returns 1 on success and 0 on failure. + */ +int parse_date_duration(const char *string, unsigned *days) +{ + enum { + STATE_INITIAL, + STATE_WWDD_DD, + STATE_DONE + } state = STATE_INITIAL; + + const char *p; + unsigned in = 0, frac = 0, denom = 1; + unsigned dur = 0; + + if (!string || *string == '\0') + return 0; + + /* parse string using a simple state machine */ + for (p = string; *p; p++) { + if (state == STATE_DONE) { + return 0; + } else if ((*p >= '0') && (*p <= '9')) { + in = in * 10 + (int)(*p - '0'); + if (frac) + denom *= 10; + } else if (*p == '.') { + if (frac) + return 0; + frac++; + } else { + switch (state) { + case STATE_INITIAL: + if (*p == 'w') { + dur += in * WEEKINDAYS / denom; + state = STATE_WWDD_DD; + } else if (*p == 'd') { + dur += in / denom; + state = STATE_DONE; + } else { + return 0; + } + break; + case STATE_WWDD_DD: + if (*p == 'd') { + dur += in / denom; + state = STATE_DONE; + } else { + return 0; + } + break; + default: + break; + } + + in = frac = 0; + denom = 1; + } + } + + if (state == STATE_DONE && in > 0) + return 0; + + dur += in; + *days = dur; + + return 1; +} + /* * Check if time is valid. */ -- cgit v1.2.3-54-g00ecf