- new constants - functions for month's labels - OnCalendar=minutely case - minor fixes
HTH
From 750176cf1cc325f7668b12856b84bf084622f754 Mon Sep 17 00:00:00 2001 From: Daniele Medri <dme...@gmail.com> Date: Sun, 26 Oct 2014 07:16:04 +0100 Subject: [PATCH 1/7] calendar: add constant values --- src/shared/calendarspec.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c index 64d0dec..73f87c6 100644 --- a/src/shared/calendarspec.c +++ b/src/shared/calendarspec.c @@ -24,6 +24,12 @@ #include "calendarspec.h" +#define CENTURY_ONE 1900 +#define CENTURY_TWO 2000 +#define CENTURY_GAP 70 +#define BITS_WEEKDAYS 127 +#define BITS_MONTHS 127 + static void free_chain(CalendarComponent *c) { CalendarComponent *n; @@ -107,11 +113,11 @@ static void fix_year(CalendarComponent *c) { while(c) { CalendarComponent *n = c->next; - if (c->value >= 0 && c->value < 70) - c->value += 2000; + if (c->value >= 0 && c->value < CENTURY_GAP) + c->value += CENTURY_TWO; - if (c->value >= 70 && c->value < 100) - c->value += 1900; + if (c->value >= CENTURY_GAP && c->value < 100) + c->value += CENTURY_ONE; c = n; } @@ -157,7 +163,9 @@ _pure_ bool calendar_spec_valid(CalendarSpec *c) { if (c->weekdays_bits > 127) return false; - if (!chain_valid(c->year, 1970, 2199)) + if (!chain_valid(c->year, + (CENTURY_ONE + CENTURY_GAP), + (CENTURY_TWO + CENTURY_GAP))) return false; if (!chain_valid(c->month, 1, 12)) @@ -847,9 +855,9 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { mktime(&c); c.tm_isdst = -1; - c.tm_year += 1900; + c.tm_year += CENTURY_ONE; r = find_matching_component(spec->year, &c.tm_year); - c.tm_year -= 1900; + c.tm_year -= CENTURY_ONE; if (r > 0) { c.tm_mon = 0; -- 1.9.3
From a7b1f3434576c50a9c4b2748941c63b400874443 Mon Sep 17 00:00:00 2001 From: Daniele Medri <dme...@gmail.com> Date: Sun, 26 Oct 2014 07:19:59 +0100 Subject: [PATCH 2/7] calendar: constant value for weekdays --- src/shared/calendarspec.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c index 73f87c6..67fd76a 100644 --- a/src/shared/calendarspec.c +++ b/src/shared/calendarspec.c @@ -126,7 +126,7 @@ static void fix_year(CalendarComponent *c) { int calendar_spec_normalize(CalendarSpec *c) { assert(c); - if (c->weekdays_bits <= 0 || c->weekdays_bits >= 127) + if (c->weekdays_bits <= 0 || c->weekdays_bits >= BITS_WEEKDAYS) c->weekdays_bits = -1; fix_year(c->year); @@ -160,7 +160,7 @@ _pure_ static bool chain_valid(CalendarComponent *c, int from, int to) { _pure_ bool calendar_spec_valid(CalendarSpec *c) { assert(c); - if (c->weekdays_bits > 127) + if (c->weekdays_bits > BITS_WEEKDAYS) return false; if (!chain_valid(c->year, @@ -202,7 +202,7 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) { assert(f); assert(c); - assert(c->weekdays_bits > 0 && c->weekdays_bits <= 127); + assert(c->weekdays_bits > 0 && c->weekdays_bits <= BITS_WEEKDAYS); for (x = 0, l = -1; x < (int) ELEMENTSOF(days); x++) { @@ -267,7 +267,7 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) { if (!f) return -ENOMEM; - if (c->weekdays_bits > 0 && c->weekdays_bits <= 127) { + if (c->weekdays_bits > 0 && c->weekdays_bits <= BITS_WEEKDAYS) { format_weekdays(f, c); fputc(' ', f); } @@ -830,7 +830,7 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm) { struct tm t; int k; - if (weekdays_bits < 0 || weekdays_bits >= 127) + if (weekdays_bits < 0 || weekdays_bits >= BITS_WEEKDAYS) return true; t = *tm; -- 1.9.3
From 68778e1c730d25de33d449cc045f25e3bb2fc6c1 Mon Sep 17 00:00:00 2001 From: Daniele Medri <dme...@gmail.com> Date: Sun, 26 Oct 2014 07:39:53 +0100 Subject: [PATCH 3/7] calendar: functions and callings to handle the months's labels --- src/shared/calendarspec.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++ src/shared/calendarspec.h | 1 + 2 files changed, 199 insertions(+) diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c index 67fd76a..196a330 100644 --- a/src/shared/calendarspec.c +++ b/src/shared/calendarspec.c @@ -129,6 +129,9 @@ int calendar_spec_normalize(CalendarSpec *c) { if (c->weekdays_bits <= 0 || c->weekdays_bits >= BITS_WEEKDAYS) c->weekdays_bits = -1; + if (c->months_bits <= 0 || c->months_bits >= BITS_MONTHS) + c->months_bits = -1; + fix_year(c->year); sort_chain(&c->year); @@ -163,6 +166,9 @@ _pure_ bool calendar_spec_valid(CalendarSpec *c) { if (c->weekdays_bits > BITS_WEEKDAYS) return false; + if (c->months_bits > BITS_MONTHS) + return false; + if (!chain_valid(c->year, (CENTURY_ONE + CENTURY_GAP), (CENTURY_TWO + CENTURY_GAP))) @@ -235,6 +241,60 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) { } } +static void format_months(FILE *f, const CalendarSpec *c) { + static const char *const months[] = { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + }; + + int l, x; + bool need_colon = false; + + assert(f); + assert(c); + assert(c->months_bits > 0 && c->months_bits <= BITS_MONTHS); + + for (x = 0, l = -1; x < (int) ELEMENTSOF(months); x++) { + + if (c->months_bits & (1 << x)) { + + if (l < 0) { + if (need_colon) + fputc(',', f); + else + need_colon = true; + + fputs(months[x], f); + l = x; + } + + } else if (l >= 0) { + + if (x > l + 1) { + fputc(x > l + 2 ? '-' : ',', f); + fputs(months[x-1], f); + } + + l = -1; + } + } + + if (l >= 0 && x > l + 1) { + fputc(x > l + 2 ? '-' : ',', f); + fputs(months[x-1], f); + } +} + static void format_chain(FILE *f, int space, const CalendarComponent *c) { assert(f); @@ -272,6 +332,11 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) { fputc(' ', f); } + if (c->months_bits > 0 && c->months_bits <= BITS_MONTHS) { + format_months(f, c); + fputc(' ', f); + } + format_chain(f, 4, c->year); fputc('-', f); format_chain(f, 2, c->month); @@ -391,6 +456,108 @@ static int parse_weekdays(const char **p, CalendarSpec *c) { } } +static int parse_months(const char **p, CalendarSpec *c) { + static const struct { + const char *name; + const int nr; + } month_nr[] = { + { "January", 0 }, + { "Jan", 0 }, + { "February", 1 }, + { "Feb", 1 }, + { "March", 2 }, + { "Mar", 2 }, + { "April", 3 }, + { "Apr", 3 }, + { "May", 4 }, + { "June", 5 }, + { "Jun", 5 }, + { "July", 6 }, + { "Jul", 6 }, + { "August", 7 }, + { "Aug", 7 }, + { "September", 8 }, + { "Sep", 8 }, + { "October", 9 }, + { "Oct", 9 }, + { "November", 10 }, + { "Nov", 10 }, + { "December", 11 }, + { "Dec", 11 } + }; + + int l = -1; + bool first = true; + + assert(p); + assert(*p); + assert(c); + + for (;;) { + unsigned i; + + if (!first && **p == ' ') + return 0; + + for (i = 0; i < ELEMENTSOF(month_nr); i++) { + size_t skip; + + if (!startswith_no_case(*p, month_nr[i].name)) + continue; + + skip = strlen(month_nr[i].name); + + if ((*p)[skip] != '-' && + (*p)[skip] != ',' && + (*p)[skip] != ' ' && + (*p)[skip] != 0) + return -EINVAL; + + c->months_bits |= 1 << month_nr[i].nr; + + if (l >= 0) { + int j; + + if (l > month_nr[i].nr) + return -EINVAL; + + for (j = l + 1; j < month_nr[i].nr; j++) + c->months_bits |= 1 << j; + } + + *p += skip; + break; + } + + /* Couldn't find this prefix, so let's assume the + weekday was not specified and let's continue with + the date */ + if (i >= ELEMENTSOF(month_nr)) + return first ? 0 : -EINVAL; + + /* We reached the end of the string */ + if (**p == 0) + return 0; + + /* We reached the end of the month spec part */ + if (**p == ' ') { + *p += strspn(*p, " "); + return 0; + } + + if (**p == '-') { + if (l >= 0) + return -EINVAL; + + l = month_nr[i].nr; + } else + l = -1; + + *p += 1; + first = false; + } +} + static int prepend_component(const char **p, CalendarComponent **c) { unsigned long value, repeat = 0; char *e = NULL, *ee = NULL; @@ -579,6 +746,9 @@ static int parse_time(const char **p, CalendarSpec *c) { if (c->day || c->weekdays_bits > 0) goto null_hour; + if (c->month || c->months_bits > 0) + goto null_hour; + goto finish; } @@ -841,6 +1011,21 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm) { return (weekdays_bits & (1 << k)); } +static bool matches_month(int months_bits, const struct tm *tm) { + struct tm t; + int k; + + if (months_bits < 0 || months_bits >= BITS_MONTHS) + return true; + + t = *tm; + if (mktime(&t) == (time_t) -1) + return false; + + k = t.tm_mon == 0 ? 11 : t.tm_mon - 1; + return (months_bits & (1 << k)); +} + static int find_next(const CalendarSpec *spec, struct tm *tm) { struct tm c; int r; @@ -855,6 +1040,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { mktime(&c); c.tm_isdst = -1; + /* years */ c.tm_year += CENTURY_ONE; r = find_matching_component(spec->year, &c.tm_year); c.tm_year -= CENTURY_ONE; @@ -867,6 +1053,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { if (r < 0 || tm_out_of_bounds(&c)) return r; + /* months */ c.tm_mon += 1; r = find_matching_component(spec->month, &c.tm_mon); c.tm_mon -= 1; @@ -883,6 +1070,14 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { continue; } + if (!matches_month(spec->months_bits, &c)) { + c.tm_mon ++; + c.tm_mday = 1; + c.tm_hour = c.tm_min = c.tm_sec = 0; + continue; + } + + /* weekdays */ r = find_matching_component(spec->day, &c.tm_mday); if (r > 0) c.tm_hour = c.tm_min = c.tm_sec = 0; @@ -899,6 +1094,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { continue; } + /* hours */ r = find_matching_component(spec->hour, &c.tm_hour); if (r > 0) c.tm_min = c.tm_sec = 0; @@ -908,6 +1104,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { continue; } + /* minutes */ r = find_matching_component(spec->minute, &c.tm_min); if (r > 0) c.tm_sec = 0; @@ -917,6 +1114,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { continue; } + /* seconds */ r = find_matching_component(spec->second, &c.tm_sec); if (r < 0 || tm_out_of_bounds(&c)) { c.tm_min ++; diff --git a/src/shared/calendarspec.h b/src/shared/calendarspec.h index 7baf318..462bacc 100644 --- a/src/shared/calendarspec.h +++ b/src/shared/calendarspec.h @@ -36,6 +36,7 @@ typedef struct CalendarComponent { typedef struct CalendarSpec { int weekdays_bits; + int months_bits; CalendarComponent *year; CalendarComponent *month; -- 1.9.3
From d89ef0cfe5103c0b94f700e883835b16a816ce3c Mon Sep 17 00:00:00 2001 From: Daniele Medri <dme...@gmail.com> Date: Sun, 26 Oct 2014 07:55:34 +0100 Subject: [PATCH 4/7] calendar: new case 'minutely' --- src/shared/calendarspec.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c index 196a330..6186301 100644 --- a/src/shared/calendarspec.c +++ b/src/shared/calendarspec.c @@ -833,7 +833,12 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { if (!c) return -ENOMEM; - if (strcaseeq(p, "hourly")) { + if (strcaseeq(p, "minutely")) { + r = const_chain(0, &c->second); + if (r < 0) + goto fail; + + } else if (strcaseeq(p, "hourly")) { r = const_chain(0, &c->minute); if (r < 0) goto fail; -- 1.9.3
From 0180fdc1271d6674438fa8427a74b24650639751 Mon Sep 17 00:00:00 2001 From: Daniele Medri <dme...@gmail.com> Date: Sun, 26 Oct 2014 07:57:03 +0100 Subject: [PATCH 5/7] calendar: re-ordering 'weekly' --- src/shared/calendarspec.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c index 6186301..fae7dfd 100644 --- a/src/shared/calendarspec.c +++ b/src/shared/calendarspec.c @@ -857,10 +857,10 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { if (r < 0) goto fail; - } else if (strcaseeq(p, "monthly")) { - r = const_chain(1, &c->day); - if (r < 0) - goto fail; + } else if (strcaseeq(p, "weekly")) { + + c->weekdays_bits = 1; + r = const_chain(0, &c->hour); if (r < 0) goto fail; @@ -871,11 +871,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { if (r < 0) goto fail; - } else if (strcaseeq(p, "annually") || strcaseeq(p, "yearly") - || strcaseeq(p, "anually") /* backwards compatibility */ ) { - r = const_chain(1, &c->month); - if (r < 0) - goto fail; + } else if (strcaseeq(p, "monthly")) { r = const_chain(1, &c->day); if (r < 0) goto fail; @@ -889,10 +885,14 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { if (r < 0) goto fail; - } else if (strcaseeq(p, "weekly")) { - - c->weekdays_bits = 1; - + } else if (strcaseeq(p, "annually") || strcaseeq(p, "yearly") + || strcaseeq(p, "anually") /* backwards compatibility */ ) { + r = const_chain(1, &c->month); + if (r < 0) + goto fail; + r = const_chain(1, &c->day); + if (r < 0) + goto fail; r = const_chain(0, &c->hour); if (r < 0) goto fail; -- 1.9.3
From b16c7840eeedfe656a38781fe8eba1a866601d1d Mon Sep 17 00:00:00 2001 From: Daniele Medri <dme...@gmail.com> Date: Sun, 26 Oct 2014 07:58:48 +0100 Subject: [PATCH 6/7] calendar: no backward compatibility for erroneous label --- src/shared/calendarspec.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c index fae7dfd..8e6c871 100644 --- a/src/shared/calendarspec.c +++ b/src/shared/calendarspec.c @@ -885,8 +885,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { if (r < 0) goto fail; - } else if (strcaseeq(p, "annually") || strcaseeq(p, "yearly") - || strcaseeq(p, "anually") /* backwards compatibility */ ) { + } else if (strcaseeq(p, "annually") || strcaseeq(p, "yearly")) { r = const_chain(1, &c->month); if (r < 0) goto fail; -- 1.9.3
From ec9f8add7663d22bfcc7be67b874dff69e486e93 Mon Sep 17 00:00:00 2001 From: Daniele Medri <dme...@gmail.com> Date: Sun, 26 Oct 2014 08:00:21 +0100 Subject: [PATCH 7/7] calendar: parse months --- src/shared/calendarspec.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c index 8e6c871..ec84d65 100644 --- a/src/shared/calendarspec.c +++ b/src/shared/calendarspec.c @@ -907,6 +907,10 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { if (r < 0) goto fail; + r = parse_months(&p, c); + if (r < 0) + goto fail; + r = parse_date(&p, c); if (r < 0) goto fail; -- 1.9.3
_______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel