Add timespec -- add tests for it too.
This commit is contained in:
193
src/timespec.c
Normal file
193
src/timespec.c
Normal 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;
|
||||
}
|
Reference in New Issue
Block a user