[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