calendarspec: allow ranges in date and time specifications

Resolves #3042
This commit is contained in:
Douglas Christman 2016-06-30 20:16:05 -04:00
parent 563a69f480
commit 32b5236916
4 changed files with 54 additions and 21 deletions

1
TODO
View File

@ -565,7 +565,6 @@ Features:
o CLOCK_REALTIME makes jumps (TFD_TIMER_CANCEL_ON_SET)
o DST changes
- Support 2012-02~4 as syntax for specifying the fourth to last day of the month.
- calendarspec: support value ranges with ".." notation. Example: 2013-4..8-1
- Modulate timer frequency based on battery state
* add libsystemd-password or so to query passwords during boot using the password agent logic

View File

@ -227,7 +227,8 @@
values separated by commas. Values may also be suffixed with
<literal>/</literal> and a repetition value, which indicates that
the value and all values plus multiples of the repetition value
are matched.</para>
are matched. Each component may also contain a range of values
separated by <literal>..</literal>.</para>
<para>The seconds component may contain decimal fractions both in
the value and the repetition. All fractions are rounded to 6
@ -273,6 +274,7 @@ Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03
monday *-12-* 17:00 → Mon *-12-* 17:00:00
Mon,Fri *-*-3,1,2 *:30:45 → Mon,Fri *-*-01,02,03 *:30:45
12,14,13,12:20,10,30 → *-*-* 12,13,14:10,20,30:00
12..14:10,20,30 → *-*-* 12,13,14:10,20,30:00
mon,fri *-1/2-1,3 *:30:45 → Mon,Fri *-01/2-01,03 *:30:45
03-05 08:05:40 → *-03-05 08:05:40
08:05:40 → *-*-* 08:05:40
@ -281,6 +283,7 @@ Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03
Sat,Sun 08:05:40 → Sat,Sun *-*-* 08:05:40
2003-03-05 05:40 → 2003-03-05 05:40:00
05:40:23.4200004/3.1700005 → 05:40:23.420000/3.170001
2003-02..04-05 → 2003-02,03,04-05 00:00:00
2003-03-05 05:40 UTC → 2003-03-05 05:40:00 UTC
2003-03-05 → 2003-03-05 00:00:00
03-05 → *-03-05 00:00:00

View File

@ -32,6 +32,8 @@
#include "parse-util.h"
#include "string-util.h"
/* Longest valid date/time range is 1970..2199 */
#define MAX_RANGE_LEN 230
#define BITS_WEEKDAYS 127
static void free_chain(CalendarComponent *c) {
@ -448,8 +450,26 @@ static int parse_component_decimal(const char **p, bool usec, unsigned long *res
return 0;
}
static int const_chain(int value, CalendarComponent **c) {
CalendarComponent *cc = NULL;
assert(c);
cc = new0(CalendarComponent, 1);
if (!cc)
return -ENOMEM;
cc->value = value;
cc->repeat = 0;
cc->next = *c;
*c = cc;
return 0;
}
static int prepend_component(const char **p, bool usec, CalendarComponent **c) {
unsigned long value, repeat = 0;
unsigned long i, value, range_end, range_inc, repeat = 0;
CalendarComponent *cc;
int r;
const char *e;
@ -471,6 +491,30 @@ static int prepend_component(const char **p, bool usec, CalendarComponent **c) {
if (repeat == 0)
return -ERANGE;
} else if (e[0] == '.' && e[1] == '.') {
e += 2;
r = parse_component_decimal(&e, usec, &range_end);
if (r < 0)
return r;
if (value >= range_end)
return -EINVAL;
range_inc = usec ? USEC_PER_SEC : 1;
/* Don't allow impossibly large ranges... */
if (range_end - value >= MAX_RANGE_LEN * range_inc)
return -EINVAL;
/* ...or ranges with only a single element */
if (range_end - value < range_inc)
return -EINVAL;
for (i = value; i <= range_end; i += range_inc) {
r = const_chain(i, c);
if (r < 0)
return r;
}
}
if (*e != 0 && *e != ' ' && *e != ',' && *e != '-' && *e != ':')
@ -495,24 +539,6 @@ static int prepend_component(const char **p, bool usec, CalendarComponent **c) {
return 0;
}
static int const_chain(int value, CalendarComponent **c) {
CalendarComponent *cc = NULL;
assert(c);
cc = new0(CalendarComponent, 1);
if (!cc)
return -ENOMEM;
cc->value = value;
cc->repeat = 0;
cc->next = *c;
*c = cc;
return 0;
}
static int parse_chain(const char **p, bool usec, CalendarComponent **c) {
const char *t;
CalendarComponent *cc = NULL;

View File

@ -124,6 +124,10 @@ int main(int argc, char* argv[]) {
test_one("2016-03-27 03:17:00.4200005", "2016-03-27 03:17:00.420001");
test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000");
test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000");
test_one("9..11,13:00,30", "*-*-* 09,10,11,13:00,30:00");
test_one("1..3-1..3 1..3:1..3", "*-01,02,03-01,02,03 01,02,03:01,02,03:00");
test_one("00:00:1.125..2.125", "*-*-* 00:00:01.125000,02.125000");
test_one("00:00:1.0..3.8", "*-*-* 00:00:01,02,03");
test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000);
test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000);
@ -146,6 +150,7 @@ int main(int argc, char* argv[]) {
assert_se(calendar_spec_from_string("2000-03-05.23 00:00:00", &c) < 0);
assert_se(calendar_spec_from_string("2000-03-05 00:00.1:00", &c) < 0);
assert_se(calendar_spec_from_string("00:00:00/0.00000001", &c) < 0);
assert_se(calendar_spec_from_string("00:00:00.0..00.9", &c) < 0);
return 0;
}