static int parse_chain(const char **p, bool usec, CalendarComponent **c) { const char *t; CalendarComponent *cc = NULL; int r; assert(p); assert(c); t = *p; if (t[0] == '*') { if (usec) { r = const_chain(0, c); if (r < 0) return r; (*c)->repeat = USEC_PER_SEC; } else *c = NULL; *p = t + 1; return 0; } r = prepend_component(&t, usec, 0, &cc); if (r < 0) { free_chain(cc); return r; } *p = t; *c = cc; return 0; }
static int calendarspec_from_time_t(CalendarSpec *c, time_t time) { struct tm tm; CalendarComponent *year = NULL, *month = NULL, *day = NULL, *hour = NULL, *minute = NULL, *us = NULL; int r; if (!gmtime_r(&time, &tm)) return -ERANGE; r = const_chain(tm.tm_year + 1900, &year); if (r < 0) return r; r = const_chain(tm.tm_mon + 1, &month); if (r < 0) return r; r = const_chain(tm.tm_mday, &day); if (r < 0) return r; r = const_chain(tm.tm_hour, &hour); if (r < 0) return r; r = const_chain(tm.tm_min, &minute); if (r < 0) return r; r = const_chain(tm.tm_sec * USEC_PER_SEC, &us); if (r < 0) return r; c->utc = true; c->year = year; c->month = month; c->day = day; c->hour = hour; c->minute = minute; c->microsecond = us; return 0; }
int calendar_spec_from_string(const char *p, CalendarSpec **spec) { CalendarSpec *c; int r; assert(p); assert(spec); if (isempty(p)) return -EINVAL; c = new0(CalendarSpec, 1); if (!c) return -ENOMEM; if (strcaseeq(p, "hourly")) { r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->second); if (r < 0) goto fail; } else if (strcaseeq(p, "daily")) { r = const_chain(0, &c->hour); if (r < 0) goto fail; r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->second); if (r < 0) goto fail; } else if (strcaseeq(p, "monthly")) { r = const_chain(1, &c->day); if (r < 0) goto fail; r = const_chain(0, &c->hour); if (r < 0) goto fail; r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->second); 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; r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->second); if (r < 0) goto fail; } else { r = parse_weekdays(&p, c); if (r < 0) goto fail; r = parse_date(&p, c); if (r < 0) goto fail; r = parse_time(&p, c); if (r < 0) goto fail; if (*p != 0) { r = -EINVAL; goto fail; } } r = calendar_spec_normalize(c); if (r < 0) goto fail; if (!calendar_spec_valid(c)) { r = -EINVAL; goto fail; } *spec = c; return 0; fail: calendar_spec_free(c); return r; }
static int parse_time(const char **p, CalendarSpec *c) { CalendarComponent *h = NULL, *m = NULL, *s = NULL; const char *t; int r; assert(p); assert(*p); assert(c); t = *p; if (*t == 0) { /* If no time is specified at all, but a date of some * kind, then this means 00:00:00 */ if (c->day || c->weekdays_bits > 0) goto null_hour; goto finish; } r = parse_chain(&t, &h); if (r < 0) goto fail; if (*t != ':') { r = -EINVAL; goto fail; } t++; r = parse_chain(&t, &m); if (r < 0) goto fail; /* Already at the end? Then it's hours and minutes, and seconds are 0 */ if (*t == 0) { if (m != NULL) goto null_second; goto finish; } if (*t != ':') { r = -EINVAL; goto fail; } t++; r = parse_chain(&t, &s); if (r < 0) goto fail; /* At the end? Then it's hours, minutes and seconds */ if (*t == 0) goto finish; r = -EINVAL; goto fail; null_hour: r = const_chain(0, &h); if (r < 0) goto fail; r = const_chain(0, &m); if (r < 0) goto fail; null_second: r = const_chain(0, &s); if (r < 0) goto fail; finish: *p = t; c->hour = h; c->minute = m; c->second = s; return 0; fail: free_chain(h); free_chain(m); free_chain(s); return r; }
int calendar_spec_from_string(const char *p, CalendarSpec **spec) { const char *utc; CalendarSpec *c; int r; assert(p); assert(spec); c = new0(CalendarSpec, 1); if (!c) return -ENOMEM; c->dst = -1; c->timezone = NULL; utc = endswith_no_case(p, " UTC"); if (utc) { c->utc = true; p = strndupa(p, utc - p); } else { const char *e = NULL; int j; tzset(); /* Check if the local timezone was specified? */ for (j = 0; j <= 1; j++) { if (isempty(tzname[j])) continue; e = endswith_no_case(p, tzname[j]); if (!e) continue; if (e == p) continue; if (e[-1] != ' ') continue; break; } /* Found one of the two timezones specified? */ if (IN_SET(j, 0, 1)) { p = strndupa(p, e - p - 1); c->dst = j; } else { const char *last_space; last_space = strrchr(p, ' '); if (last_space != NULL && timezone_is_valid(last_space + 1)) { c->timezone = strdup(last_space + 1); if (!c->timezone) { r = -ENOMEM; goto fail; } p = strndupa(p, last_space - p); } } } if (isempty(p)) { r = -EINVAL; goto fail; } if (strcaseeq(p, "minutely")) { r = const_chain(0, &c->microsecond); if (r < 0) goto fail; } else if (strcaseeq(p, "hourly")) { r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->microsecond); if (r < 0) goto fail; } else if (strcaseeq(p, "daily")) { r = const_chain(0, &c->hour); if (r < 0) goto fail; r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->microsecond); if (r < 0) goto fail; } else if (strcaseeq(p, "monthly")) { r = const_chain(1, &c->day); if (r < 0) goto fail; r = const_chain(0, &c->hour); if (r < 0) goto fail; r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->microsecond); 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; r = const_chain(1, &c->day); if (r < 0) goto fail; r = const_chain(0, &c->hour); if (r < 0) goto fail; r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->microsecond); 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; r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->microsecond); if (r < 0) goto fail; } else if (strcaseeq(p, "quarterly")) { r = const_chain(1, &c->month); if (r < 0) goto fail; r = const_chain(4, &c->month); if (r < 0) goto fail; r = const_chain(7, &c->month); if (r < 0) goto fail; r = const_chain(10, &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; r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->microsecond); if (r < 0) goto fail; } else if (strcaseeq(p, "biannually") || strcaseeq(p, "bi-annually") || strcaseeq(p, "semiannually") || strcaseeq(p, "semi-annually")) { r = const_chain(1, &c->month); if (r < 0) goto fail; r = const_chain(7, &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; r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->microsecond); if (r < 0) goto fail; } else { r = parse_weekdays(&p, c); if (r < 0) goto fail; r = parse_date(&p, c); if (r < 0) goto fail; if (r == 0) { r = parse_calendar_time(&p, c); if (r < 0) goto fail; } if (*p != 0) { r = -EINVAL; goto fail; } } r = calendar_spec_normalize(c); if (r < 0) goto fail; if (!calendar_spec_valid(c)) { r = -EINVAL; goto fail; } *spec = c; return 0; fail: calendar_spec_free(c); return r; }
static int parse_calendar_time(const char **p, CalendarSpec *c) { CalendarComponent *h = NULL, *m = NULL, *s = NULL; const char *t; int r; assert(p); assert(*p); assert(c); t = *p; /* If no time is specified at all, then this means 00:00:00 */ if (*t == 0) goto null_hour; r = parse_chain(&t, false, &h); if (r < 0) goto fail; if (*t != ':') { r = -EINVAL; goto fail; } t++; r = parse_chain(&t, false, &m); if (r < 0) goto fail; /* Already at the end? Then it's hours and minutes, and seconds are 0 */ if (*t == 0) goto null_second; if (*t != ':') { r = -EINVAL; goto fail; } t++; r = parse_chain(&t, true, &s); if (r < 0) goto fail; /* At the end? Then it's hours, minutes and seconds */ if (*t == 0) goto finish; r = -EINVAL; goto fail; null_hour: r = const_chain(0, &h); if (r < 0) goto fail; r = const_chain(0, &m); if (r < 0) goto fail; null_second: r = const_chain(0, &s); if (r < 0) goto fail; finish: *p = t; c->hour = h; c->minute = m; c->microsecond = s; return 0; fail: free_chain(h); free_chain(m); free_chain(s); return r; }
int calendar_spec_from_string(const char *p, CalendarSpec **spec) { CalendarSpec *c; int r; const char *utc; assert(p); assert(spec); if (isempty(p)) return -EINVAL; c = new0(CalendarSpec, 1); if (!c) return -ENOMEM; utc = endswith_no_case(p, " UTC"); if (utc) { c->utc = true; p = strndupa(p, utc - p); } 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; r = const_chain(0, &c->second); if (r < 0) goto fail; } else if (strcaseeq(p, "daily")) { r = const_chain(0, &c->hour); if (r < 0) goto fail; r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->second); if (r < 0) goto fail; } else if (strcaseeq(p, "monthly")) { r = const_chain(1, &c->day); if (r < 0) goto fail; r = const_chain(0, &c->hour); if (r < 0) goto fail; r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->second); 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; r = const_chain(1, &c->day); if (r < 0) goto fail; r = const_chain(0, &c->hour); if (r < 0) goto fail; r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->second); 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; r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->second); if (r < 0) goto fail; } else if (strcaseeq(p, "quarterly")) { r = const_chain(1, &c->month); if (r < 0) goto fail; r = const_chain(4, &c->month); if (r < 0) goto fail; r = const_chain(7, &c->month); if (r < 0) goto fail; r = const_chain(10, &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; r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->second); if (r < 0) goto fail; } else if (strcaseeq(p, "biannually") || strcaseeq(p, "bi-annually") || strcaseeq(p, "semiannually") || strcaseeq(p, "semi-annually")) { r = const_chain(1, &c->month); if (r < 0) goto fail; r = const_chain(7, &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; r = const_chain(0, &c->minute); if (r < 0) goto fail; r = const_chain(0, &c->second); if (r < 0) goto fail; } else { r = parse_weekdays(&p, c); if (r < 0) goto fail; r = parse_date(&p, c); if (r < 0) goto fail; r = parse_time(&p, c); if (r < 0) goto fail; if (*p != 0) { r = -EINVAL; goto fail; } } r = calendar_spec_normalize(c); if (r < 0) goto fail; if (!calendar_spec_valid(c)) { r = -EINVAL; goto fail; } *spec = c; return 0; fail: calendar_spec_free(c); return r; }