fix(cron): caught some more bugs
ci/woodpecker/pr/build Pipeline is pending
Details
ci/woodpecker/pr/docker Pipeline is pending
Details
ci/woodpecker/pr/docs Pipeline is pending
Details
ci/woodpecker/pr/lint Pipeline is pending
Details
ci/woodpecker/pr/man Pipeline is pending
Details
ci/woodpecker/pr/test Pipeline is pending
Details
ci/woodpecker/pr/build Pipeline is pending
Details
ci/woodpecker/pr/docker Pipeline is pending
Details
ci/woodpecker/pr/docs Pipeline is pending
Details
ci/woodpecker/pr/lint Pipeline is pending
Details
ci/woodpecker/pr/man Pipeline is pending
Details
ci/woodpecker/pr/test Pipeline is pending
Details
parent
6d1b4aadb6
commit
4f093c08a7
|
@ -11,7 +11,8 @@ typedef enum cron_parse_error {
|
||||||
cron_parse_invalid_expression = 1,
|
cron_parse_invalid_expression = 1,
|
||||||
cron_parse_invalid_number = 2,
|
cron_parse_invalid_number = 2,
|
||||||
cron_parse_out_of_range = 3,
|
cron_parse_out_of_range = 3,
|
||||||
cron_parse_too_many_parts = 4
|
cron_parse_too_many_parts = 4,
|
||||||
|
cron_parse_not_enough_parts = 5
|
||||||
} cron_parse_error;
|
} cron_parse_error;
|
||||||
|
|
||||||
typedef struct cron_expression {
|
typedef struct cron_expression {
|
||||||
|
|
|
@ -112,7 +112,7 @@ cron_parse_error ce_parse_part(uint64_t *out, char *s, uint8_t min,
|
||||||
*out = 0;
|
*out = 0;
|
||||||
|
|
||||||
char *next;
|
char *next;
|
||||||
enum cron_parse_error res;
|
cron_parse_error res;
|
||||||
|
|
||||||
while ((next = strchr(s, ',')) != NULL) {
|
while ((next = strchr(s, ',')) != NULL) {
|
||||||
next[0] = '\0';
|
next[0] = '\0';
|
||||||
|
@ -180,13 +180,12 @@ uint8_t bf_to_nums(uint8_t **out, uint64_t bf, uint8_t min, uint8_t max) {
|
||||||
/*
|
/*
|
||||||
* Parse a cron expression string into a cron_expression struct.
|
* Parse a cron expression string into a cron_expression struct.
|
||||||
*/
|
*/
|
||||||
enum cron_parse_error ce_parse_expression(cron_expression *out, char *s) {
|
cron_parse_error ce_parse_expression(cron_expression *out, char *s) {
|
||||||
// The parsing functions modify the input string in-place
|
// The parsing functions modify the input string in-place
|
||||||
s = strdup(s);
|
s = strdup(s);
|
||||||
char *orig_s = s;
|
char *orig_s = s;
|
||||||
|
|
||||||
enum cron_parse_error res = cron_parse_ok;
|
cron_parse_error res = cron_parse_ok;
|
||||||
uint64_t bfs[max_parts];
|
|
||||||
|
|
||||||
// First we divide the input string into its parts, divided by spaces.
|
// First we divide the input string into its parts, divided by spaces.
|
||||||
// Each part is delimited by a NULL byte.
|
// Each part is delimited by a NULL byte.
|
||||||
|
@ -207,23 +206,19 @@ enum cron_parse_error ce_parse_expression(cron_expression *out, char *s) {
|
||||||
next[0] = '\0';
|
next[0] = '\0';
|
||||||
parts[part_count] = s;
|
parts[part_count] = s;
|
||||||
|
|
||||||
|
part_count++;
|
||||||
|
|
||||||
// Skip multiple spaces
|
// Skip multiple spaces
|
||||||
offset = 1;
|
offset = 1;
|
||||||
while (next[offset] == ' ') {
|
while (next[offset] == ' ') {
|
||||||
offset++;
|
offset++;
|
||||||
}
|
}
|
||||||
s = next + offset;
|
s = next + offset;
|
||||||
|
|
||||||
part_count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The loop exited because we already have 4 parts, yet there's still at
|
// Each iteration of the loop skips all trailing spaces. This means that, if
|
||||||
// least one more part that follows.
|
// s[0] isn't '\0', there's still another part before the end of the string.
|
||||||
if (next != NULL) {
|
if (s[0] != '\0') {
|
||||||
res = cron_parse_too_many_parts;
|
|
||||||
goto end;
|
|
||||||
} else if (s[0] != '\0') {
|
|
||||||
// There's one more excessive trailing part
|
|
||||||
if (part_count == max_parts) {
|
if (part_count == max_parts) {
|
||||||
res = cron_parse_too_many_parts;
|
res = cron_parse_too_many_parts;
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -233,6 +228,11 @@ enum cron_parse_error ce_parse_expression(cron_expression *out, char *s) {
|
||||||
part_count++;
|
part_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (part_count < min_parts) {
|
||||||
|
res = cron_parse_not_enough_parts;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
// We now parse the parts in reverse. This is because the month part
|
// We now parse the parts in reverse. This is because the month part
|
||||||
// determines the maximum value of the day part.
|
// determines the maximum value of the day part.
|
||||||
|
|
||||||
|
@ -268,6 +268,8 @@ enum cron_parse_error ce_parse_expression(cron_expression *out, char *s) {
|
||||||
res = ce_parse_part(&bit_field, parts[2], min[2], max_day_value);
|
res = ce_parse_part(&bit_field, parts[2], min[2], max_day_value);
|
||||||
|
|
||||||
if (res != cron_parse_ok) {
|
if (res != cron_parse_ok) {
|
||||||
|
free(out->months);
|
||||||
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,6 +287,9 @@ enum cron_parse_error ce_parse_expression(cron_expression *out, char *s) {
|
||||||
res = ce_parse_part(&bit_field, parts[1], min[1], max[1]);
|
res = ce_parse_part(&bit_field, parts[1], min[1], max[1]);
|
||||||
|
|
||||||
if (res != cron_parse_ok) {
|
if (res != cron_parse_ok) {
|
||||||
|
free(out->months);
|
||||||
|
free(out->days);
|
||||||
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,6 +301,10 @@ enum cron_parse_error ce_parse_expression(cron_expression *out, char *s) {
|
||||||
res = ce_parse_part(&bit_field, parts[0], min[0], max[0]);
|
res = ce_parse_part(&bit_field, parts[0], min[0], max[0]);
|
||||||
|
|
||||||
if (res != cron_parse_ok) {
|
if (res != cron_parse_ok) {
|
||||||
|
free(out->months);
|
||||||
|
free(out->days);
|
||||||
|
free(out->hours);
|
||||||
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@ enum ParseError as u8 {
|
||||||
invalid_number = 2
|
invalid_number = 2
|
||||||
out_of_range = 3
|
out_of_range = 3
|
||||||
too_many_parts = 4
|
too_many_parts = 4
|
||||||
|
not_enough_parts = 5
|
||||||
}
|
}
|
||||||
|
|
||||||
// str returns the string representation of a ParseError.
|
// str returns the string representation of a ParseError.
|
||||||
|
@ -83,6 +84,7 @@ fn (e ParseError) str() string {
|
||||||
.invalid_number { 'Invalid number' }
|
.invalid_number { 'Invalid number' }
|
||||||
.out_of_range { 'Out of range' }
|
.out_of_range { 'Out of range' }
|
||||||
.too_many_parts { 'Too many parts' }
|
.too_many_parts { 'Too many parts' }
|
||||||
|
.not_enough_parts { 'Not enough parts' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,14 @@ fn test_not_allowed() {
|
||||||
res = false
|
res = false
|
||||||
parse_expression('0 /5') or { res = true }
|
parse_expression('0 /5') or { res = true }
|
||||||
assert res
|
assert res
|
||||||
|
|
||||||
|
res = false
|
||||||
|
parse_expression('0 ') or { res = true }
|
||||||
|
assert res
|
||||||
|
|
||||||
|
res = false
|
||||||
|
parse_expression('0') or { res = true }
|
||||||
|
assert res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_leading_star() {
|
fn test_leading_star() {
|
||||||
|
@ -43,3 +51,7 @@ fn test_auto_extend() ! {
|
||||||
|
|
||||||
assert ce1 == ce2 && ce2 == ce3
|
assert ce1 == ce2 && ce2 == ce3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_four() {
|
||||||
|
parse_expression('0 1 2 3 ') or { assert false }
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue