Add timespec -- add tests for it too.

This commit is contained in:
Pim van Pelt
2018-10-28 12:47:42 +01:00
parent 9ee393bc8a
commit 3e3d9dcbe0
8 changed files with 492 additions and 33 deletions

193
src/timespec.c Normal file
View File

@ -0,0 +1,193 @@
#include "timespec.h"
/* Private prototypes and declarations */
struct mgos_timespec_spec {
uint8_t start_h, start_m, start_s;
uint8_t stop_h, stop_m, stop_s;
SLIST_ENTRY(mgos_timespec_spec) entries;
};
struct mgos_timespec {
SLIST_HEAD(mgos_timespec_specs, mgos_timespec_spec) specs;
};
static bool timespec_spec_parse(const char *spec, struct mgos_timespec_spec *out) {
uint8_t start_h = 0, start_m = 0, start_s = 0;
uint8_t stop_h = 0, stop_m = 0, stop_s = 0;
char * p;
int i;
if (!spec || strlen(spec) == 0) {
LOG(LL_ERROR, ("spec cannot be NULL or empty"));
return false;
}
for (i = 1; i < (int) strlen(spec); i++) {
if (spec[i] != ':' && spec[i] != '-' && !(spec[i] >= '0' && spec[i] <= '9')) {
LOG(LL_ERROR, ("spec='%s': illegal chars, only want [:\\-0-9]", spec));
return false;
}
}
p = (char *)spec;
if (!isdigit((int)*p)) {
LOG(LL_ERROR, ("spec='%s': start time must begin with a digit", spec));
return false;
}
// start_h
i = strtol(p, &p, 10);
if (i < 0 || i > 23) {
LOG(LL_ERROR, ("spec='%s': start hour must be [0..23]", spec));
return false;
}
start_h = i;
if (*p == ':') {
// start_m
i = strtol(p + 1, &p, 10);
if (i < 0 || i > 59) {
LOG(LL_ERROR, ("spec='%s': start minute must be [0..59]", spec));
return false;
}
start_m = i;
}
if (*p == ':') {
// start_s
i = strtol(p + 1, &p, 10);
if (i < 0 || i > 59) {
LOG(LL_ERROR, ("spec='%s': start second must be [0..59]", spec));
return false;
}
start_s = i;
}
if (*p != '-') {
LOG(LL_ERROR, ("spec='%s': No separator '-' found after start", spec));
return false;
}
// stop_h
if (!isdigit((int)*(p + 1))) {
LOG(LL_ERROR, ("spec='%s': stop time must begin with a digit", spec));
return false;
}
i = strtol(p + 1, &p, 10);
if (i < 0 || i > 23) {
LOG(LL_ERROR, ("spec='%s': stop hour must be [0..23]", spec));
return false;
}
stop_h = i;
if (*p == ':') {
// start_m
i = strtol(p + 1, &p, 10);
if (i < 0 || i > 59) {
LOG(LL_ERROR, ("spec='%s': stop minute must be [0..59]", spec));
return false;
}
stop_m = i;
}
if (*p == ':') {
// stop_s
i = strtol(p + 1, &p, 10);
if (i < 0 || i > 59) {
LOG(LL_ERROR, ("spec='%s': stop second must be [0..59]", spec));
return false;
}
stop_s = i;
}
if (*p) {
LOG(LL_ERROR, ("spec='%s': dangling characters after stop time", spec));
return false;
}
// LOG(LL_DEBUG, ("start=%d stop=%d", start, stop));
if (out) {
out->start_h = start_h;
out->start_m = start_m;
out->start_s = start_s;
out->stop_h = stop_h;
out->stop_m = stop_m;
out->stop_s = stop_s;
}
return true;
}
struct mgos_timespec *timespec_create() {
struct mgos_timespec *ts = calloc(1, sizeof(struct mgos_timespec));
if (!ts) {
return NULL;
}
return ts;
}
bool timespec_destroy(struct mgos_timespec **ts) {
if (!ts) {
return false;
}
while (!SLIST_EMPTY(&(*ts)->specs)) {
struct mgos_timespec_spec *t_spec;
t_spec = SLIST_FIRST(&(*ts)->specs);
SLIST_REMOVE_HEAD(&(*ts)->specs, entries);
if (t_spec) {
// LOG(LL_DEBUG, ("Removed mgos_timespec_spec"));
free(t_spec);
}
}
free(*ts);
*ts = NULL;
return true;
}
bool timespec_add_spec(struct mgos_timespec *ts, const char *spec) {
struct mgos_timespec_spec *t_spec = calloc(1, sizeof(struct mgos_timespec_spec));
if (!ts) {
return false;
}
if (!t_spec) {
LOG(LL_ERROR, ("Could not alloc memory for struct mgos_timespec_spec"));
return false;
}
if (!timespec_spec_parse(spec, t_spec)) {
LOG(LL_ERROR, ("spec='%s' is malformed, refusing to add", spec));
return false;
}
SLIST_INSERT_HEAD(&ts->specs, t_spec, entries);
return true;
}
bool timespec_match(const struct mgos_timespec *ts, const struct tm *tm) {
struct mgos_timespec_spec *t_spec;
if (!ts) {
return false;
}
SLIST_FOREACH(t_spec, &ts->specs, entries) {
uint32_t start, stop, target;
start = t_spec->start_h * 3600 + t_spec->start_m * 60 + t_spec->start_s;
stop = t_spec->stop_h * 3600 + t_spec->stop_m * 60 + t_spec->stop_s;
target = tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
if (start == stop) {
continue;
}
if (stop >= start) {
if (target >= start && target < stop) {
// LOG(LL_DEBUG, ("start=%d stop=%d target=%d matched", start, stop, target));
return true;
}
} else {
if (target >= start || target < stop) {
// LOG(LL_DEBUG, ("start=%d stop=%d target=%d matched", start, stop, target));
return true;
}
}
// LOG(LL_DEBUG, ("start=%d stop=%d target=%d did not match", start, stop, target));
}
(void)tm;
return false;
}