libamxp  1.4.0
Patterns C Implementation
amxp_cron.c File Reference
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <amxc/amxc.h>
#include <amxp/amxp_cron.h>
#include <amxc/amxc_macros.h>
#include "amxp_cron_parser_priv.h"

Go to the source code of this file.

Macros

#define _GNU_SOURCE
 
#define CRON_MAX_SECONDS   60
 
#define CRON_MAX_MINUTES   60
 
#define CRON_MAX_HOURS   24
 
#define CRON_MAX_DAYS_OF_WEEK   8
 
#define CRON_MAX_DAYS_OF_MONTH   32
 
#define CRON_MAX_MONTHS   13
 
#define CRON_CF_SECOND   0
 
#define CRON_CF_MINUTE   1
 
#define CRON_CF_HOUR_OF_DAY   2
 
#define CRON_CF_DAY_OF_WEEK   3
 
#define CRON_CF_DAY_OF_MONTH   4
 
#define CRON_CF_MONTH   5
 
#define CRON_CF_YEAR   6
 
#define CRON_CF_ARR_LEN   7
 

Functions

static int32_t amxp_cron_next_bit (const uint8_t *bits, int32_t from_index, int32_t to_index, bool forwards, bool *notfound)
 
static void push_to_fields_arr (int *arr, int fi)
 
static int last_day_of_month (int month, int year)
 
static int amxp_cron_reset_min (struct tm *calendar, int field)
 
static int amxp_cron_reset_max (struct tm *calendar, int field)
 
static int amxp_cron_reset_all (struct tm *calendar, int *fields, bool minimum)
 
static int amxp_cron_set_field (struct tm *calendar, int field, int val, bool add)
 
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)
 
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)
 
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)
 
int amxp_cron_new (amxp_cron_expr_t **cron_expr)
 Allocates an amxp_cron_expr_t structures and initializes it to every second. More...
 
void amxp_cron_delete (amxp_cron_expr_t **cron_expr)
 Frees the previously allocated amxp_cron_expr_t structure. More...
 
int amxp_cron_init (amxp_cron_expr_t *cron_expr)
 Initializes an amxp_cron_expr_t structures to every second. More...
 
void amxp_cron_clean (amxp_cron_expr_t *cron_expr)
 Resets the amxp_cron_expr_t structure to the initialized state. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 

Macro Definition Documentation

◆ _GNU_SOURCE

#define _GNU_SOURCE

Definition at line 56 of file amxp_cron.c.

◆ CRON_CF_ARR_LEN

#define CRON_CF_ARR_LEN   7

Definition at line 87 of file amxp_cron.c.

◆ CRON_CF_DAY_OF_MONTH

#define CRON_CF_DAY_OF_MONTH   4

Definition at line 83 of file amxp_cron.c.

◆ CRON_CF_DAY_OF_WEEK

#define CRON_CF_DAY_OF_WEEK   3

Definition at line 82 of file amxp_cron.c.

◆ CRON_CF_HOUR_OF_DAY

#define CRON_CF_HOUR_OF_DAY   2

Definition at line 81 of file amxp_cron.c.

◆ CRON_CF_MINUTE

#define CRON_CF_MINUTE   1

Definition at line 80 of file amxp_cron.c.

◆ CRON_CF_MONTH

#define CRON_CF_MONTH   5

Definition at line 84 of file amxp_cron.c.

◆ CRON_CF_SECOND

#define CRON_CF_SECOND   0

Definition at line 79 of file amxp_cron.c.

◆ CRON_CF_YEAR

#define CRON_CF_YEAR   6

Definition at line 85 of file amxp_cron.c.

◆ CRON_MAX_DAYS_OF_MONTH

#define CRON_MAX_DAYS_OF_MONTH   32

Definition at line 76 of file amxp_cron.c.

◆ CRON_MAX_DAYS_OF_WEEK

#define CRON_MAX_DAYS_OF_WEEK   8

Definition at line 75 of file amxp_cron.c.

◆ CRON_MAX_HOURS

#define CRON_MAX_HOURS   24

Definition at line 74 of file amxp_cron.c.

◆ CRON_MAX_MINUTES

#define CRON_MAX_MINUTES   60

Definition at line 73 of file amxp_cron.c.

◆ CRON_MAX_MONTHS

#define CRON_MAX_MONTHS   13

Definition at line 77 of file amxp_cron.c.

◆ CRON_MAX_SECONDS

#define CRON_MAX_SECONDS   60

Definition at line 72 of file amxp_cron.c.

Function Documentation

◆ amxp_cron_calc_next()

static int amxp_cron_calc_next ( const amxp_cron_expr_t expr,
struct tm *  calendar,
unsigned int  dot,
bool  forwards 
)
static

Definition at line 333 of file amxp_cron.c.

333  {
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 }
#define CRON_CF_HOUR_OF_DAY
Definition: amxp_cron.c:81
#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
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
#define CRON_CF_DAY_OF_WEEK
Definition: amxp_cron.c:82
#define CRON_CF_MINUTE
Definition: amxp_cron.c:80
#define CRON_MAX_MINUTES
Definition: amxp_cron.c:73
#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 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
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

◆ amxp_cron_find_next()

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 
)
static

Definition at line 262 of file amxp_cron.c.

270  {
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 }
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
static int amxp_cron_reset_min(struct tm *calendar, int field)
Definition: amxp_cron.c:147
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

◆ amxp_cron_find_next_day()

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 
)
static

Definition at line 304 of file amxp_cron.c.

311  {
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 }
PRIVATE uint8_t cron_get_bit(const uint8_t *rbyte, int idx)
int count
Definition: test_syssig.c:80

◆ amxp_cron_next_bit()

static int32_t amxp_cron_next_bit ( const uint8_t *  bits,
int32_t  from_index,
int32_t  to_index,
bool  forwards,
bool *  notfound 
)
static

Definition at line 89 of file amxp_cron.c.

93  {
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 }

◆ amxp_cron_remove_spaces()

static void amxp_cron_remove_spaces ( amxc_string_t *  result,
const char *  days_of_week 
)
static

Definition at line 424 of file amxp_cron.c.

424  {
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 }

◆ amxp_cron_reset_all()

static int amxp_cron_reset_all ( struct tm *  calendar,
int *  fields,
bool  minimum 
)
static

Definition at line 210 of file amxp_cron.c.

210  {
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 }

◆ amxp_cron_reset_max()

static int amxp_cron_reset_max ( struct tm *  calendar,
int  field 
)
static

Definition at line 180 of file amxp_cron.c.

180  {
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 }
static int last_day_of_month(int month, int year)
Definition: amxp_cron.c:135

◆ amxp_cron_reset_min()

static int amxp_cron_reset_min ( struct tm *  calendar,
int  field 
)
static

Definition at line 147 of file amxp_cron.c.

147  {
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 }

◆ amxp_cron_set_field()

static int amxp_cron_set_field ( struct tm *  calendar,
int  field,
int  val,
bool  add 
)
static

Definition at line 224 of file amxp_cron.c.

224  {
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 }

◆ last_day_of_month()

static int last_day_of_month ( int  month,
int  year 
)
static

Definition at line 135 of file amxp_cron.c.

135  {
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 }

◆ push_to_fields_arr()

static void push_to_fields_arr ( int *  arr,
int  fi 
)
static

Definition at line 118 of file amxp_cron.c.

118  {
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 }