calendarspec.c revision 51ffa239e8920499a9b5f85b1d98068cf931cd14
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering This file is part of systemd.
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering Copyright 2012 Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering (at your option) any later version.
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering systemd is distributed in the hope that it will be useful, but
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering Lesser General Public License for more details.
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poetteringstatic void free_chain(CalendarComponent *c) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poetteringvoid calendar_spec_free(CalendarSpec *c) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poetteringstatic int component_compare(const void *_a, const void *_b) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering CalendarComponent * const *a = _a, * const *b = _b;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poetteringstatic void sort_chain(CalendarComponent **c) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering unsigned n = 0, k;
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek for (i = *c; i; i = i->next)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering j = b = alloca(sizeof(CalendarComponent*) * n);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering for (i = *c; i; i = i->next)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering qsort(b, n, sizeof(CalendarComponent*), component_compare);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* Drop non-unique entries */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering for (k = n-1; k > 0; k--) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poetteringstatic void fix_year(CalendarComponent *c) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* Turns 12 → 2012, 89 → 1989 */
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek if (c->value >= 0 && c->value < 70)
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek if (c->value >= 70 && c->value < 100)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poetteringint calendar_spec_normalize(CalendarSpec *c) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (c->weekdays_bits <= 0 || c->weekdays_bits >= BITS_WEEKDAYS)
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek_pure_ static bool chain_valid(CalendarComponent *c, int from, int to) {
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek_pure_ bool calendar_spec_valid(CalendarSpec *c) {
2a0e0692565f0435657c93498e09cbb2d3517152Shawn Landden return false;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poetteringstatic void format_weekdays(FILE *f, const CalendarSpec *c) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering static const char *const days[] = {
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek assert(c->weekdays_bits > 0 && c->weekdays_bits <= BITS_WEEKDAYS);
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek for (x = 0, l = -1; x < (int) ELEMENTSOF(days); x++) {
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek if (c->weekdays_bits & (1 << x)) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering } else if (l >= 0) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (x > l + 1) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (l >= 0 && x > l + 1) {
505b6a61c22d5565e9308045c7b9bf79f7d0517eLennart Poetteringstatic void format_chain(FILE *f, int space, const CalendarComponent *c) {
d18d46ecea80a7f07415edb9264af6a254fd70bbZbigniew Jędrzejewski-Szmek format_chain(f, space, c->next);
a174f94d529c7ae9be589867308b669ec9b4dcc0Lennart Poetteringint calendar_spec_to_string(const CalendarSpec *c, char **p) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (c->weekdays_bits > 0 && c->weekdays_bits <= BITS_WEEKDAYS) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poetteringstatic int parse_weekdays(const char **p, CalendarSpec *c) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering static const struct {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering { "Monday", 0 },
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering for (i = 0; i < ELEMENTSOF(day_nr); i++) {
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering if (!startswith_no_case(*p, day_nr[i].name))
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt /* Couldn't find this prefix, so let's assume the
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering weekday was not specified and let's continue with
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* We reached the end of the string */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* We reached the end of the weekday spec part */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (**p == ' ') {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (**p == '-') {
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poetteringstatic int prepend_component(const char **p, CalendarComponent **c) {
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering if ((unsigned long) (int) value != value)
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering if (*e == '/') {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if ((unsigned long) (int) repeat != repeat)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (*e != 0 && *e != ' ' && *e != ',' && *e != '-' && *e != ':')
f7a5bb2842037fa27dbc99d92c3fee7fe1bbbc2aZbigniew Jędrzejewski-Szmek cc = new0(CalendarComponent, 1);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt if (*e ==',') {
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidtstatic int parse_chain(const char **p, CalendarComponent **c) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering const char *t;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (t[0] == '*') {
*c = cc;
assert(c);
if (!cc)
return -ENOMEM;
*c = cc;
assert(p);
assert(*p);
assert(c);
return -EINVAL;
return -EINVAL;
return -EINVAL;
assert(p);
assert(*p);
assert(c);
goto null_hour;
goto finish;
r = parse_chain(&t, &h);
goto fail;
r = -EINVAL;
goto fail;
r = parse_chain(&t, &m);
goto fail;
if (m != NULL)
goto null_second;
goto finish;
r = -EINVAL;
goto fail;
r = parse_chain(&t, &s);
goto fail;
goto finish;
r = -EINVAL;
goto fail;
r = const_chain(0, &h);
goto fail;
r = const_chain(0, &m);
goto fail;
r = const_chain(0, &s);
goto fail;
c->hour = h;
c->minute = m;
c->second = s;
fail:
free_chain(h);
free_chain(m);
free_chain(s);
CalendarSpec *c;
assert(p);
if (isempty(p))
return -EINVAL;
return -ENOMEM;
if (c->utc)
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
r = parse_weekdays(&p, c);
goto fail;
r = parse_date(&p, c);
goto fail;
r = parse_time(&p, c);
goto fail;
r = -EINVAL;
goto fail;
r = calendar_spec_normalize(c);
goto fail;
if (!calendar_spec_valid(c)) {
r = -EINVAL;
goto fail;
*spec = c;
fail:
const CalendarComponent *n;
bool d_set = false;
n = c->next;
d = c->value;
d_set = true;
} else if (c->repeat > 0) {
if (!d_set || k < d) {
d_set = true;
if (!d_set)
return -ENOENT;
r = *val != d;
*val = d;
struct tm t;
t = *tm;
struct tm t;
t = *tm;
struct tm c;
c = *tm;
c.tm_mon = 0;
c.tm_year ++;
c.tm_mon = 0;
c.tm_mon ++;
c.tm_mday++;
c.tm_mday ++;
c.tm_sec = 0;
c.tm_hour ++;
c.tm_min ++;
c.tm_sec = 0;
*tm = c;
time_t t;
return -EINVAL;