66 #include <amxc/amxc.h>
68 #include <amxc/amxc_macros.h>
72 #define CRON_MAX_SECONDS 60
73 #define CRON_MAX_MINUTES 60
74 #define CRON_MAX_HOURS 24
75 #define CRON_MAX_DAYS_OF_WEEK 8
76 #define CRON_MAX_DAYS_OF_MONTH 32
77 #define CRON_MAX_MONTHS 13
79 #define CRON_CF_SECOND 0
80 #define CRON_CF_MINUTE 1
81 #define CRON_CF_HOUR_OF_DAY 2
82 #define CRON_CF_DAY_OF_WEEK 3
83 #define CRON_CF_DAY_OF_MONTH 4
84 #define CRON_CF_MONTH 5
85 #define CRON_CF_YEAR 6
87 #define CRON_CF_ARR_LEN 7
97 for(int32_t i = from_index; i < to_index; i++) {
104 for(int32_t i = from_index; i >= to_index; i--) {
119 when_true(arr == NULL || fi == -1, exit);
122 when_true(arr[i] == fi, exit);
137 struct tm* calctm = NULL;
139 memset(&cal, 0,
sizeof(cal));
140 cal.tm_mon = month + 1;
144 return calctm != NULL? calctm->tm_mday:31;
149 when_true(field == -1, exit);
153 calendar->tm_sec = 0;
156 calendar->tm_min = 0;
159 calendar->tm_hour = 0;
162 calendar->tm_wday = 0;
165 calendar->tm_mday = 1;
168 calendar->tm_mon = 0;
171 calendar->tm_year = 0;
174 rv = timegm(calendar) == -1? 1:0;
182 when_true(field == -1, exit);
186 calendar->tm_sec = 59;
189 calendar->tm_min = 59;
192 calendar->tm_hour = 23;
195 calendar->tm_wday = 6;
201 calendar->tm_mon = 11;
204 rv = timegm(calendar) == -1? 1:0;
214 if(fields[i] != -1) {
216 when_failed(res, exit);
226 when_true(field == -1, exit);
230 calendar->tm_sec = add? calendar->tm_sec + val:val;
233 calendar->tm_min = add? calendar->tm_min + val:val;
236 calendar->tm_hour = add? calendar->tm_hour + val:val;
241 calendar->tm_mday = calendar->tm_mday + val;
243 calendar->tm_wday = val;
247 calendar->tm_mday = add? calendar->tm_mday + val:val;
250 calendar->tm_mon = add? calendar->tm_mon + val:val;
253 calendar->tm_year = add? calendar->tm_year + val:val;
256 rv = timegm(calendar) == -1? 1:0;
271 bool notfound =
false;
273 int32_t next_value =
amxp_cron_next_bit(bits, value, forward? max:0, forward, ¬found);
280 when_failed_status(err, exit, next_value = 0);
286 when_failed_status(err, exit, next_value = 0);
288 next_value =
amxp_cron_next_bit(bits, forward? 0:max - 1, forward? max:value, forward, ¬found);
291 if(notfound || (next_value != value)) {
293 when_failed_status(err, exit, next_value = 0);
295 when_failed_status(err, exit, next_value = 0);
305 const uint8_t* days_of_month,
306 unsigned int day_of_month,
307 const uint8_t* days_of_week,
308 unsigned int day_of_week,
313 unsigned int count = 0;
314 unsigned int max = 366;
321 when_failed(err, exit);
322 day_of_month = calendar->tm_mday;
323 day_of_week = calendar->tm_wday;
337 int* empty_list = NULL;
338 unsigned int second = 0;
339 unsigned int update_second = 0;
340 unsigned int minute = 0;
341 unsigned int update_minute = 0;
342 unsigned int hour = 0;
343 unsigned int update_hour = 0;
344 unsigned int day_of_week = 0;
345 unsigned int day_of_month = 0;
346 unsigned int update_day_of_month = 0;
347 unsigned int month = 0;
348 unsigned int update_month = 0;
351 when_null(resets, return_result);
353 when_null(empty_list, return_result);
359 second = calendar->tm_sec;
362 when_failed(res, return_result);
363 if(second == update_second) {
367 minute = calendar->tm_min;
370 when_failed(res, return_result);
371 if(minute == update_minute) {
375 when_failed(res, return_result);
378 hour = calendar->tm_hour;
381 when_failed(res, return_result);
382 if(hour == update_hour) {
386 when_failed(res, return_result);
389 day_of_week = calendar->tm_wday;
390 day_of_month = calendar->tm_mday;
392 expr->
days_of_week, day_of_week, resets, forwards, &res);
393 when_failed(res, return_result);
394 if(day_of_month == update_day_of_month) {
398 when_failed(res, return_result);
401 month = calendar->tm_mon;
404 when_failed(res, return_result);
405 if(month != update_month) {
407 when_true_status(calendar->tm_year - dot > 4, return_result, res = -1);
409 when_true_status(dot - calendar->tm_year > 4, return_result, res = -1);
412 when_failed(res, return_result);
416 if((resets == NULL) || (empty_list == NULL)) {
426 amxc_string_set(result, days_of_week);
427 amxc_string_trim(result, NULL);
429 pos = amxc_string_text_length(result);
432 if(isspace(result->buffer[pos - 1]) != 0) {
433 amxc_string_remove_at(result, pos - 1, 1);
442 when_null(cron_expr, exit);
445 when_null(*cron_expr, exit);
454 when_null(cron_expr, exit);
455 when_null(*cron_expr, exit);
468 when_null(cron_expr, exit);
478 when_null(cron_expr, exit);
487 const char* expression,
488 const char** error) {
489 const char* err_local = NULL;
507 amxc_var_init(&fields);
509 when_null_status(expression, exit, *error =
"Invalid NULL expression");
510 when_null_status(target, exit, *error =
"Invalid NULL target");
513 amxc_var_set(ssv_string_t, &fields, expression);
514 amxc_var_cast(&fields, AMXC_VAR_ID_LIST);
515 len = amxc_llist_size(amxc_var_constcast(amxc_llist_t, &fields));
516 when_false_status(len == 6, exit, *error =
"Invalid number of fields, expression must consist of 6 fields");
519 amxc_var_for_each(field, &fields) {
520 uint8_t* target_field = (uint8_t*) (((
char*) (target)) + hits[len].
offset);
521 rv = hits[len].
fn(field, target_field, hits[len].min, hits[len].max, error);
522 when_failed(rv, exit);
527 amxc_var_clean(&fields);
533 const char* days_of_week) {
536 amxc_string_t strtime;
537 amxc_string_t* time_part = NULL;
540 amxc_llist_it_t* it = NULL;
542 amxc_string_init(&strtime, 0);
543 amxc_llist_init(&parts);
544 amxc_string_init(&expr, 0);
546 when_null(target, exit);
547 when_null(time, exit);
548 when_str_empty(days_of_week, exit);
551 amxc_string_setf(&expr,
"* * %s", amxc_string_get(&strtime, 0));
552 amxc_string_set(&strtime, time);
553 if(amxc_string_is_empty(&strtime)) {
554 amxc_string_prependf(&expr,
"0 0 0 ");
556 amxc_string_split_to_llist(&strtime, &parts,
':');
557 len = amxc_llist_size(&parts);
558 when_true(len < 2 || len > 3, exit);
560 it = amxc_llist_take_first(&parts);
561 time_part = amxc_string_from_llist_it(it);
562 amxc_string_prependf(&expr,
"%s ", amxc_string_get(time_part, 0));
563 amxc_string_delete(&time_part);
565 it = amxc_llist_take_first(&parts);
566 time_part = amxc_string_from_llist_it(it);
567 amxc_string_prependf(&expr,
"%s ", amxc_string_get(time_part, 0));
568 amxc_string_delete(&time_part);
570 it = amxc_llist_take_first(&parts);
572 amxc_string_prependf(&expr,
"0 ");
574 time_part = amxc_string_from_llist_it(it);
575 amxc_string_prependf(&expr,
"%s ", amxc_string_get(time_part, 0));
576 amxc_string_delete(&time_part);
582 amxc_llist_clean(&parts, amxc_string_list_it_free);
583 amxc_string_clean(&strtime);
584 amxc_string_clean(&expr);
591 struct tm* calendar = NULL;
594 time_t calculated = 0;
597 memset(&calval, 0,
sizeof(
struct tm));
599 when_null(expr, exit);
600 when_null(next, exit);
601 when_null(ref, exit);
603 date = ref->sec + (ref->offset * 60);
604 calendar = gmtime_r(&date, &calval);
605 when_null(calendar, exit);
606 original = timegm(calendar);
607 when_true(original == -1, exit);
611 when_failed(res, exit);
612 calculated = timegm(calendar);
613 when_true(calculated == -1, exit);
615 if(calculated == original) {
618 when_failed(res, exit);
620 when_failed(res, exit)
623 next->sec = timegm(calendar) - (ref->offset * 60);
624 next->offset = ref->offset;
634 struct tm* calendar = NULL;
637 time_t calculated = 0;
640 memset(&calval, 0,
sizeof(
struct tm));
642 when_null(expr, exit);
643 when_null(next, exit);
644 when_null(ref, exit);
646 date = ref->sec + (ref->offset * 60);
647 calendar = gmtime_r(&date, &calval);
648 when_null(calendar, exit);
649 original = timegm(calendar);
650 when_true(original == -1, exit);
653 when_failed(res, exit);
654 calculated = timegm(calendar);
655 when_true(calculated == -1, exit);
657 if(calculated == original) {
660 when_failed(res, exit);
662 when_failed(res, exit)
665 next->sec = timegm(calendar) - (ref->offset * 60);
666 next->offset = ref->offset;
674 int64_t seconds = -1;
676 amxc_ts_t next = { 0, 0, 0 };
678 when_null(expr, exit);
681 amxc_ts_to_local(&now);
685 seconds = next.sec - now.sec;
#define CRON_CF_HOUR_OF_DAY
#define CRON_MAX_DAYS_OF_WEEK
#define CRON_CF_DAY_OF_MONTH
static unsigned int amxp_cron_find_next_day(struct tm *calendar, const uint8_t *days_of_month, unsigned int day_of_month, const uint8_t *days_of_week, unsigned int day_of_week, int *resets, bool forward, int *res_out)
#define CRON_MAX_DAYS_OF_MONTH
static int amxp_cron_calc_next(const amxp_cron_expr_t *expr, struct tm *calendar, unsigned int dot, bool forwards)
static void amxp_cron_remove_spaces(amxc_string_t *result, const char *days_of_week)
#define CRON_CF_DAY_OF_WEEK
static int32_t amxp_cron_next_bit(const uint8_t *bits, int32_t from_index, int32_t to_index, bool forwards, bool *notfound)
static int amxp_cron_reset_all(struct tm *calendar, int *fields, bool minimum)
static int amxp_cron_reset_min(struct tm *calendar, int field)
static void push_to_fields_arr(int *arr, int fi)
static int amxp_cron_reset_max(struct tm *calendar, int field)
static int amxp_cron_set_field(struct tm *calendar, int field, int val, bool add)
static int last_day_of_month(int month, int year)
static uint32_t amxp_cron_find_next(const uint8_t *bits, int32_t max, int32_t value, struct tm *calendar, uint32_t field, uint32_t next_field, int *lower_orders, bool forward, int *res_out)
Ambiorix cron expression parser.
PRIVATE uint8_t cron_get_bit(const uint8_t *rbyte, int idx)
PRIVATE int amxp_cron_set_months(amxc_var_t *value, uint8_t *target, uint32_t min, uint32_t max, const char **error)
PRIVATE int amxp_cron_set_hits(amxc_var_t *value, uint8_t *target, uint32_t min, uint32_t max, const char **error)
PRIVATE int amxp_cron_set_days_of_month(amxc_var_t *value, uint8_t *target, uint32_t min, uint32_t max, const char **error)
PRIVATE int amxp_cron_set_days_of_week(amxc_var_t *value, uint8_t *target, uint32_t min, uint32_t max, const char **error)
PRIVATE int amxp_cron_reset(amxp_cron_expr_t *cron_expr)
int amxp_cron_build_weekly(amxp_cron_expr_t *target, const char *time, const char *days_of_week)
Builds a weekly cron expression that is triggered at a certain time on certain days of the week.
int amxp_cron_init(amxp_cron_expr_t *cron_expr)
Initializes an amxp_cron_expr_t structures to every second.
int64_t amxp_cron_time_until_next(const amxp_cron_expr_t *expr, bool local)
Calculates the time in seconds until next trigger of a parsed cron expression occurs.
int amxp_cron_new(amxp_cron_expr_t **cron_expr)
Allocates an amxp_cron_expr_t structures and initializes it to every second.
int amxp_cron_parse_expr(amxp_cron_expr_t *target, const char *expression, const char **error)
Allocates and initializes an amxp_cron_expr_t structures and parses the given cron expression.
void amxp_cron_clean(amxp_cron_expr_t *cron_expr)
Resets the amxp_cron_expr_t structure to the initialized state.
int amxp_cron_prev(const amxp_cron_expr_t *expr, const amxc_ts_t *ref, amxc_ts_t *next)
Calculates the previous trigger time for a parsed cron expression.
void amxp_cron_delete(amxp_cron_expr_t **cron_expr)
Frees the previously allocated amxp_cron_expr_t structure.
int amxp_cron_next(const amxp_cron_expr_t *expr, const amxc_ts_t *ref, amxc_ts_t *next)
Calculates the next trigger time for a parsed cron expression.
amxp_cron_set_hits_fn_t fn
Structure containing parsed cron expression.