[systemd-devel] [PATCH 3/7] calendar: functions and callings to handle the months's labels
Daniele Medri
dmedri at gmail.com
Mon Oct 27 00:42:41 PDT 2014
---
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
More information about the systemd-devel
mailing list