libamxp  1.4.0
Patterns C Implementation
amxp_cron.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 
55 #ifndef _GNU_SOURCE
56 #define _GNU_SOURCE
57 #endif
58 
59 #include <stdlib.h>
60 #include <stdio.h>
61 #include <errno.h>
62 #include <string.h>
63 #include <time.h>
64 #include <ctype.h>
65 
66 #include <amxc/amxc.h>
67 #include <amxp/amxp_cron.h>
68 #include <amxc/amxc_macros.h>
69 
70 #include "amxp_cron_parser_priv.h"
71 
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
78 
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
86 
87 #define CRON_CF_ARR_LEN 7
88 
89 static int32_t amxp_cron_next_bit(const uint8_t* bits,
90  int32_t from_index,
91  int32_t to_index,
92  bool forwards,
93  bool* notfound) {
94  int32_t rv = 0;
95 
96  if(forwards) {
97  for(int32_t i = from_index; i < to_index; i++) {
98  if(cron_get_bit(bits, i)) {
99  rv = i;
100  goto exit;
101  }
102  }
103  } else {
104  for(int32_t i = from_index; i >= to_index; i--) {
105  if(cron_get_bit(bits, i)) {
106  rv = i;
107  goto exit;
108  }
109  }
110  }
111 
112  *notfound = true;
113 
114 exit:
115  return rv;
116 }
117 
118 static void push_to_fields_arr(int* arr, int fi) {
119  when_true(arr == NULL || fi == -1, exit);
120 
121  for(int i = 0; i < CRON_CF_ARR_LEN; i++) {
122  when_true(arr[i] == fi, exit);
123  }
124  for(int i = 0; i < CRON_CF_ARR_LEN; i++) {
125  if(arr[i] == -1) {
126  arr[i] = fi;
127  break;
128  }
129  }
130 
131 exit:
132  return;
133 }
134 
135 static int last_day_of_month(int month, int year) {
136  struct tm cal;
137  struct tm* calctm = NULL;
138  time_t t;
139  memset(&cal, 0, sizeof(cal));
140  cal.tm_mon = month + 1;
141  cal.tm_year = year;
142  t = mktime(&cal);
143  calctm = gmtime(&t);
144  return calctm != NULL? calctm->tm_mday:31;
145 }
146 
147 static int amxp_cron_reset_min(struct tm* calendar, int field) {
148  int rv = 1;
149  when_true(field == -1, exit);
150 
151  switch(field) {
152  case CRON_CF_SECOND:
153  calendar->tm_sec = 0;
154  break;
155  case CRON_CF_MINUTE:
156  calendar->tm_min = 0;
157  break;
158  case CRON_CF_HOUR_OF_DAY:
159  calendar->tm_hour = 0;
160  break;
161  case CRON_CF_DAY_OF_WEEK:
162  calendar->tm_wday = 0;
163  break;
165  calendar->tm_mday = 1;
166  break;
167  case CRON_CF_MONTH:
168  calendar->tm_mon = 0;
169  break;
170  case CRON_CF_YEAR:
171  calendar->tm_year = 0;
172  break;
173  }
174  rv = timegm(calendar) == -1? 1:0;
175 
176 exit:
177  return rv;
178 }
179 
180 static int amxp_cron_reset_max(struct tm* calendar, int field) {
181  int rv = 1;
182  when_true(field == -1, exit);
183 
184  switch(field) {
185  case CRON_CF_SECOND:
186  calendar->tm_sec = 59;
187  break;
188  case CRON_CF_MINUTE:
189  calendar->tm_min = 59;
190  break;
191  case CRON_CF_HOUR_OF_DAY:
192  calendar->tm_hour = 23;
193  break;
194  case CRON_CF_DAY_OF_WEEK:
195  calendar->tm_wday = 6;
196  break;
198  calendar->tm_mday = last_day_of_month(calendar->tm_mon, calendar->tm_year);
199  break;
200  case CRON_CF_MONTH:
201  calendar->tm_mon = 11;
202  break;
203  }
204  rv = timegm(calendar) == -1? 1:0;
205 
206 exit:
207  return rv;
208 }
209 
210 static int amxp_cron_reset_all(struct tm* calendar, int* fields, bool minimum) {
211  int res = 0;
212 
213  for(int i = 0; i < CRON_CF_ARR_LEN; i++) {
214  if(fields[i] != -1) {
215  res = minimum? amxp_cron_reset_min(calendar, fields[i]):amxp_cron_reset_max(calendar, fields[i]);
216  when_failed(res, exit);
217  }
218  }
219 
220 exit:
221  return res;
222 }
223 
224 static int amxp_cron_set_field(struct tm* calendar, int field, int val, bool add) {
225  int rv = 1;
226  when_true(field == -1, exit);
227 
228  switch(field) {
229  case CRON_CF_SECOND:
230  calendar->tm_sec = add? calendar->tm_sec + val:val;
231  break;
232  case CRON_CF_MINUTE:
233  calendar->tm_min = add? calendar->tm_min + val:val;
234  break;
235  case CRON_CF_HOUR_OF_DAY:
236  calendar->tm_hour = add? calendar->tm_hour + val:val;
237  break;
238  case CRON_CF_DAY_OF_WEEK:
239  if(add) {
240  /* mkgmtime ignores this field */
241  calendar->tm_mday = calendar->tm_mday + val;
242  } else {
243  calendar->tm_wday = val;
244  }
245  break;
247  calendar->tm_mday = add? calendar->tm_mday + val:val;
248  break;
249  case CRON_CF_MONTH:
250  calendar->tm_mon = add? calendar->tm_mon + val:val;
251  break;
252  case CRON_CF_YEAR:
253  calendar->tm_year = add? calendar->tm_year + val:val;
254  break;
255  }
256  rv = timegm(calendar) == -1? 1:0;
257 
258 exit:
259  return rv;
260 }
261 
262 static uint32_t amxp_cron_find_next(const uint8_t* bits,
263  int32_t max,
264  int32_t value,
265  struct tm* calendar,
266  uint32_t field,
267  uint32_t next_field,
268  int* lower_orders,
269  bool forward,
270  int* res_out) {
271  bool notfound = false;
272  int err = 0;
273  int32_t next_value = amxp_cron_next_bit(bits, value, forward? max:0, forward, &notfound);
274 
275  *res_out = 1;
276 
277  /* roll over if needed */
278  if(notfound) {
279  err = amxp_cron_set_field(calendar, next_field, forward? 1:-1, true);
280  when_failed_status(err, exit, next_value = 0);
281  if(forward) {
282  err = amxp_cron_reset_min(calendar, field);
283  } else {
284  err = amxp_cron_reset_max(calendar, field);
285  }
286  when_failed_status(err, exit, next_value = 0);
287  notfound = 0;
288  next_value = amxp_cron_next_bit(bits, forward? 0:max - 1, forward? max:value, forward, &notfound);
289  }
290 
291  if(notfound || (next_value != value)) {
292  err = amxp_cron_set_field(calendar, field, next_value, false);
293  when_failed_status(err, exit, next_value = 0);
294  err = amxp_cron_reset_all(calendar, lower_orders, forward);
295  when_failed_status(err, exit, next_value = 0);
296  }
297 
298  *res_out = 0;
299 
300 exit:
301  return next_value;
302 }
303 
304 static unsigned int amxp_cron_find_next_day(struct tm* calendar,
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,
309  int* resets,
310  bool forward,
311  int* res_out) {
312  int err;
313  unsigned int count = 0;
314  unsigned int max = 366;
315 
316  *res_out = 1;
317  while((!cron_get_bit(days_of_month, day_of_month) ||
318  !cron_get_bit(days_of_week, day_of_week)) &&
319  count++ < max) {
320  err = amxp_cron_set_field(calendar, CRON_CF_DAY_OF_MONTH, forward? 1:-1, true);
321  when_failed(err, exit);
322  day_of_month = calendar->tm_mday;
323  day_of_week = calendar->tm_wday;
324  amxp_cron_reset_all(calendar, resets, forward);
325  }
326 
327  *res_out = 0;
328 
329 exit:
330  return day_of_month;
331 }
332 
333 static int amxp_cron_calc_next(const amxp_cron_expr_t* expr, struct tm* calendar, unsigned int dot, bool forwards) {
334  int i;
335  int res = 0;
336  int* resets = NULL;
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;
349 
350  resets = (int*) calloc(CRON_CF_ARR_LEN, sizeof(int));
351  when_null(resets, return_result);
352  empty_list = (int*) calloc(CRON_CF_ARR_LEN, sizeof(int));
353  when_null(empty_list, return_result);
354  for(i = 0; i < CRON_CF_ARR_LEN; i++) {
355  resets[i] = -1;
356  empty_list[i] = -1;
357  }
358 
359  second = calendar->tm_sec;
360  update_second = amxp_cron_find_next(expr->seconds, CRON_MAX_SECONDS, second, calendar,
361  CRON_CF_SECOND, CRON_CF_MINUTE, empty_list, forwards, &res);
362  when_failed(res, return_result);
363  if(second == update_second) {
365  }
366 
367  minute = calendar->tm_min;
368  update_minute = amxp_cron_find_next(expr->minutes, CRON_MAX_MINUTES, minute, calendar,
369  CRON_CF_MINUTE, CRON_CF_HOUR_OF_DAY, resets, forwards, &res);
370  when_failed(res, return_result);
371  if(minute == update_minute) {
373  } else {
374  res = amxp_cron_calc_next(expr, calendar, dot, forwards);
375  when_failed(res, return_result);
376  }
377 
378  hour = calendar->tm_hour;
379  update_hour = amxp_cron_find_next(expr->hours, CRON_MAX_HOURS, hour, calendar,
380  CRON_CF_HOUR_OF_DAY, CRON_CF_DAY_OF_WEEK, resets, forwards, &res);
381  when_failed(res, return_result);
382  if(hour == update_hour) {
384  } else {
385  res = amxp_cron_calc_next(expr, calendar, dot, forwards);
386  when_failed(res, return_result);
387  }
388 
389  day_of_week = calendar->tm_wday;
390  day_of_month = calendar->tm_mday;
391  update_day_of_month = amxp_cron_find_next_day(calendar, expr->days_of_month, day_of_month,
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) {
396  } else {
397  res = amxp_cron_calc_next(expr, calendar, dot, forwards);
398  when_failed(res, return_result);
399  }
400 
401  month = calendar->tm_mon; /*day already adds one if no day in same month is found*/
402  update_month = amxp_cron_find_next(expr->months, CRON_MAX_MONTHS, month, calendar,
403  CRON_CF_MONTH, CRON_CF_YEAR, resets, forwards, &res);
404  when_failed(res, return_result);
405  if(month != update_month) {
406  if(forwards) {
407  when_true_status(calendar->tm_year - dot > 4, return_result, res = -1);
408  } else {
409  when_true_status(dot - calendar->tm_year > 4, return_result, res = -1);
410  }
411  res = amxp_cron_calc_next(expr, calendar, dot, forwards);
412  when_failed(res, return_result);
413  }
414 
415 return_result:
416  if((resets == NULL) || (empty_list == NULL)) {
417  res = -1;
418  }
419  free(resets);
420  free(empty_list);
421  return res;
422 }
423 
424 static void amxp_cron_remove_spaces(amxc_string_t* result, const char* days_of_week) {
425  size_t pos = 0;
426  amxc_string_set(result, days_of_week);
427  amxc_string_trim(result, NULL);
428 
429  pos = amxc_string_text_length(result);
430 
431  while(pos > 0) {
432  if(isspace(result->buffer[pos - 1]) != 0) {
433  amxc_string_remove_at(result, pos - 1, 1);
434  continue;
435  }
436  pos--;
437  }
438 }
439 
440 int amxp_cron_new(amxp_cron_expr_t** cron_expr) {
441  int retval = -1;
442  when_null(cron_expr, exit);
443 
444  *cron_expr = (amxp_cron_expr_t*) calloc(1, sizeof(amxp_cron_expr_t));
445  when_null(*cron_expr, exit);
446 
447  retval = amxp_cron_init(*cron_expr);
448 
449 exit:
450  return retval;
451 }
452 
454  when_null(cron_expr, exit);
455  when_null(*cron_expr, exit);
456 
457  amxp_cron_clean(*cron_expr);
458 
459  free(*cron_expr);
460  *cron_expr = NULL;
461 
462 exit:
463  return;
464 }
465 
467  int retval = -1;
468  when_null(cron_expr, exit);
469 
470  amxp_cron_parse_expr(cron_expr, "* * * * * *", NULL);
471  retval = 0;
472 
473 exit:
474  return retval;
475 }
476 
478  when_null(cron_expr, exit);
479 
480  amxp_cron_parse_expr(cron_expr, "* * * * * *", NULL);
481 
482 exit:
483  return;
484 }
485 
487  const char* expression,
488  const char** error) {
489  const char* err_local = NULL;
490  size_t len = 0;
491  int rv = -1;
492  amxc_var_t fields;
493  static amxp_cron_hits_t hits[] = {
494  { amxp_cron_set_hits, offsetof(amxp_cron_expr_t, seconds), 0, CRON_MAX_SECONDS },
495  { amxp_cron_set_hits, offsetof(amxp_cron_expr_t, minutes), 0, CRON_MAX_MINUTES },
496  { amxp_cron_set_hits, offsetof(amxp_cron_expr_t, hours), 0, CRON_MAX_HOURS },
497  { amxp_cron_set_days_of_month, offsetof(amxp_cron_expr_t, days_of_month), 1, CRON_MAX_DAYS_OF_MONTH },
498  { amxp_cron_set_months, offsetof(amxp_cron_expr_t, months), 1, CRON_MAX_MONTHS },
499  { amxp_cron_set_days_of_week, offsetof(amxp_cron_expr_t, days_of_week), 0, CRON_MAX_DAYS_OF_WEEK },
500  };
501 
502  if(error == NULL) {
503  error = &err_local;
504  }
505  *error = NULL;
506 
507  amxc_var_init(&fields);
508 
509  when_null_status(expression, exit, *error = "Invalid NULL expression");
510  when_null_status(target, exit, *error = "Invalid NULL target");
511  amxp_cron_reset(target);
512 
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");
517 
518  len = 0;
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);
523  len++;
524  }
525 
526 exit:
527  amxc_var_clean(&fields);
528  return rv;
529 }
530 
532  const char* time,
533  const char* days_of_week) {
534  int rv = -1;
535  amxc_string_t expr;
536  amxc_string_t strtime;
537  amxc_string_t* time_part = NULL;
538  amxc_llist_t parts;
539  int len = 0;
540  amxc_llist_it_t* it = NULL;
541 
542  amxc_string_init(&strtime, 0);
543  amxc_llist_init(&parts);
544  amxc_string_init(&expr, 0);
545 
546  when_null(target, exit);
547  when_null(time, exit);
548  when_str_empty(days_of_week, exit);
549  amxp_cron_remove_spaces(&strtime, days_of_week);
550 
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 ");
555  } else {
556  amxc_string_split_to_llist(&strtime, &parts, ':');
557  len = amxc_llist_size(&parts);
558  when_true(len < 2 || len > 3, exit);
559 
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);
564 
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);
569 
570  it = amxc_llist_take_first(&parts);
571  if(it == NULL) {
572  amxc_string_prependf(&expr, "0 ");
573  } else {
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);
577  }
578  }
579  rv = amxp_cron_parse_expr(target, amxc_string_get(&expr, 0), NULL);
580 
581 exit:
582  amxc_llist_clean(&parts, amxc_string_list_it_free);
583  amxc_string_clean(&strtime);
584  amxc_string_clean(&expr);
585  return rv;
586 }
587 
588 int amxp_cron_prev(const amxp_cron_expr_t* expr, const amxc_ts_t* ref, amxc_ts_t* next) {
589  int rv = -1;
590  struct tm calval;
591  struct tm* calendar = NULL;
592  time_t date = 0;
593  time_t original = 0;
594  time_t calculated = 0;
595  int res = 0;
596 
597  memset(&calval, 0, sizeof(struct tm));
598 
599  when_null(expr, exit);
600  when_null(next, exit);
601  when_null(ref, exit);
602 
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);
608 
609  /* calculate the previous occurrence */
610  res = amxp_cron_calc_next(expr, calendar, calendar->tm_year, false);
611  when_failed(res, exit);
612  calculated = timegm(calendar);
613  when_true(calculated == -1, exit);
614 
615  if(calculated == original) {
616  /* We arrived at the original timestamp - round up to the next whole second and try again... */
617  res = amxp_cron_set_field(calendar, CRON_CF_SECOND, -1, true);
618  when_failed(res, exit);
619  res = amxp_cron_calc_next(expr, calendar, calendar->tm_year, false);
620  when_failed(res, exit)
621  }
622 
623  next->sec = timegm(calendar) - (ref->offset * 60);
624  next->offset = ref->offset;
625  rv = 0;
626 
627 exit:
628  return rv;
629 }
630 
631 int amxp_cron_next(const amxp_cron_expr_t* expr, const amxc_ts_t* ref, amxc_ts_t* next) {
632  int rv = -1;
633  struct tm calval;
634  struct tm* calendar = NULL;
635  time_t date = 0;
636  time_t original = 0;
637  time_t calculated = 0;
638  int res = 0;
639 
640  memset(&calval, 0, sizeof(struct tm));
641 
642  when_null(expr, exit);
643  when_null(next, exit);
644  when_null(ref, exit);
645 
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);
651 
652  res = amxp_cron_calc_next(expr, calendar, calendar->tm_year, true);
653  when_failed(res, exit);
654  calculated = timegm(calendar);
655  when_true(calculated == -1, exit);
656 
657  if(calculated == original) {
658  /* We arrived at the original timestamp - round up to the next whole second and try again... */
659  res = amxp_cron_set_field(calendar, CRON_CF_SECOND, 1, true);
660  when_failed(res, exit);
661  res = amxp_cron_calc_next(expr, calendar, calendar->tm_year, true);
662  when_failed(res, exit)
663  }
664 
665  next->sec = timegm(calendar) - (ref->offset * 60);
666  next->offset = ref->offset;
667  rv = 0;
668 
669 exit:
670  return rv;
671 }
672 
673 int64_t amxp_cron_time_until_next(const amxp_cron_expr_t* expr, bool local) {
674  int64_t seconds = -1;
675  amxc_ts_t now;
676  amxc_ts_t next = { 0, 0, 0 };
677 
678  when_null(expr, exit);
679  amxc_ts_now(&now);
680  if(local) {
681  amxc_ts_to_local(&now);
682  }
683 
684  when_failed(amxp_cron_next(expr, &now, &next), exit);
685  seconds = next.sec - now.sec;
686 
687 exit:
688  return seconds;
689 }
#define CRON_CF_HOUR_OF_DAY
Definition: amxp_cron.c:81
#define CRON_MAX_DAYS_OF_WEEK
Definition: amxp_cron.c:75
#define CRON_CF_SECOND
Definition: amxp_cron.c:79
#define CRON_CF_DAY_OF_MONTH
Definition: amxp_cron.c:83
#define CRON_MAX_MONTHS
Definition: amxp_cron.c:77
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)
Definition: amxp_cron.c:304
#define CRON_CF_YEAR
Definition: amxp_cron.c:85
#define CRON_MAX_DAYS_OF_MONTH
Definition: amxp_cron.c:76
static int amxp_cron_calc_next(const amxp_cron_expr_t *expr, struct tm *calendar, unsigned int dot, bool forwards)
Definition: amxp_cron.c:333
#define CRON_CF_ARR_LEN
Definition: amxp_cron.c:87
#define CRON_MAX_HOURS
Definition: amxp_cron.c:74
static void amxp_cron_remove_spaces(amxc_string_t *result, const char *days_of_week)
Definition: amxp_cron.c:424
#define CRON_CF_DAY_OF_WEEK
Definition: amxp_cron.c:82
static int32_t amxp_cron_next_bit(const uint8_t *bits, int32_t from_index, int32_t to_index, bool forwards, bool *notfound)
Definition: amxp_cron.c:89
static int amxp_cron_reset_all(struct tm *calendar, int *fields, bool minimum)
Definition: amxp_cron.c:210
#define CRON_CF_MINUTE
Definition: amxp_cron.c:80
#define CRON_MAX_MINUTES
Definition: amxp_cron.c:73
static int amxp_cron_reset_min(struct tm *calendar, int field)
Definition: amxp_cron.c:147
#define CRON_MAX_SECONDS
Definition: amxp_cron.c:72
#define CRON_CF_MONTH
Definition: amxp_cron.c:84
static void push_to_fields_arr(int *arr, int fi)
Definition: amxp_cron.c:118
static int amxp_cron_reset_max(struct tm *calendar, int field)
Definition: amxp_cron.c:180
static int amxp_cron_set_field(struct tm *calendar, int field, int val, bool add)
Definition: amxp_cron.c:224
static int last_day_of_month(int month, int year)
Definition: amxp_cron.c:135
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)
Definition: amxp_cron.c:262
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.
Definition: amxp_cron.c:531
int amxp_cron_init(amxp_cron_expr_t *cron_expr)
Initializes an amxp_cron_expr_t structures to every second.
Definition: amxp_cron.c:466
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.
Definition: amxp_cron.c:673
int amxp_cron_new(amxp_cron_expr_t **cron_expr)
Allocates an amxp_cron_expr_t structures and initializes it to every second.
Definition: amxp_cron.c:440
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.
Definition: amxp_cron.c:486
void amxp_cron_clean(amxp_cron_expr_t *cron_expr)
Resets the amxp_cron_expr_t structure to the initialized state.
Definition: amxp_cron.c:477
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.
Definition: amxp_cron.c:588
void amxp_cron_delete(amxp_cron_expr_t **cron_expr)
Frees the previously allocated amxp_cron_expr_t structure.
Definition: amxp_cron.c:453
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.
Definition: amxp_cron.c:631
amxp_cron_set_hits_fn_t fn
Structure containing parsed cron expression.
Definition: amxp_cron.h:103
uint8_t days_of_week[1]
Definition: amxp_cron.h:107
uint8_t hours[3]
Definition: amxp_cron.h:106
uint8_t days_of_month[4]
Definition: amxp_cron.h:108
uint8_t minutes[8]
Definition: amxp_cron.h:105
uint8_t months[2]
Definition: amxp_cron.h:109
uint8_t seconds[8]
Definition: amxp_cron.h:104
int count
Definition: test_syssig.c:80