From 93f9f2a687b5d0e998fa2c056d4fb93f982e1907 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Thu, 29 Jun 2017 19:05:49 +0200 Subject: [PATCH] rscad: finished rudimentary parsing of RSCAD .inf file by using POSIX regular expressions --- include/villas/rtds/rscad/inf.h | 23 ++-- lib/rtds/rscad/inf.c | 187 ++++++++++++++++++++++++-------- tests/unit/rtds.c | 10 +- 3 files changed, 163 insertions(+), 57 deletions(-) diff --git a/include/villas/rtds/rscad/inf.h b/include/villas/rtds/rscad/inf.h index 4f045dbf8..2aa62cd5a 100644 --- a/include/villas/rtds/rscad/inf.h +++ b/include/villas/rtds/rscad/inf.h @@ -37,24 +37,31 @@ struct rscad_inf_timing_record { }; +union rscad_inf_value { + float f; + int i; + char *s; +}; + struct rscad_inf_element { - enum { + char *name; + + enum rscad_inf_type { RSCAD_INF_ELEMENT_STRING, RSCAD_INF_ELEMENT_OUTPUT, RSCAD_INF_ELEMENT_PUSHBUTTON, RSCAD_INF_ELEMENT_SLIDER } type; - enum { + enum rscad_inf_datatype { RSCAD_INF_DATATYPE_IEEE, - RSCAD_INF_DATATYPE_INT + RSCAD_INF_DATATYPE_INT, + RSCAD_INF_DATATYPE_STRING } datatype; - union { - float f; - int i; - char *s; - } init_value, min, max; + union rscad_inf_value init_value; + union rscad_inf_value min; + union rscad_inf_value max; int rack; uint32_t address; diff --git a/lib/rtds/rscad/inf.c b/lib/rtds/rscad/inf.c index a4c3134f9..8e8ff58b6 100644 --- a/lib/rtds/rscad/inf.c +++ b/lib/rtds/rscad/inf.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "utils.h" #include "log.h" @@ -53,6 +54,53 @@ static int rscad_inf_getline(char **line, size_t *linelen, FILE *f) return 1; } +static int rscad_inf_getattr(char **line, char **key, char **value) +{ + int ret; + + size_t kl, vl; + regex_t regex; + regmatch_t matches[4]; + regmatch_t *km, *vm, *all; + + ret = regcomp(®ex, "([a-z]+)=(\"([^\"]+)\"|[^\" ]+)", REG_EXTENDED | REG_ICASE); + if (ret) { + char buf[512]; + regerror(ret, ®ex, buf, sizeof(buf)); + + warn("Failed to compile RE: %s", buf); + return ret; + } + + ret = regexec(®ex, *line, 4, matches, 0); + if (ret) + return ret; + + int quotes = matches[3].rm_so > 0; + + all = &matches[0]; + km = &matches[1]; + vm = &matches[quotes ? 3 : 2]; + + kl = km->rm_eo - km->rm_so; + vl = vm->rm_eo - vm->rm_so; + + *key = realloc(*key, kl + 1); + *value = realloc(*value, vl + 1); + + strncpy(*key, *line + km->rm_so, kl); + strncpy(*value, *line + vm->rm_so, vl); + + (*key)[kl] = '\0'; + (*value)[vl] = '\0'; + + *line += all->rm_eo; + + regfree(®ex); + + return 0; +} + static int rscad_inf_destroy_attribute(struct rscad_inf_attribute *a) { if (a->key) @@ -75,6 +123,9 @@ static int rscad_inf_destroy_element(struct rscad_inf_element *e) if (e->units) free(e->units); + if (e->name) + free(e->name); + if (e->type == RSCAD_INF_ELEMENT_STRING && e->init_value.s) free(e->init_value.s); @@ -121,52 +172,60 @@ static int rscad_inf_parse_attributes(struct list *l, FILE *f) return 0; } +static int rscad_inf_parse_value(const char *value, enum rscad_inf_datatype dt, union rscad_inf_value *v) +{ + char *endptr; + + switch (dt) { + case RSCAD_INF_DATATYPE_IEEE: + v->f = strtod(value, &endptr); + break; + + case RSCAD_INF_DATATYPE_INT: + v->i = strtoul(value, &endptr, 10); + break; + + case RSCAD_INF_DATATYPE_STRING: + v->s = strdup(value); + break; + + default: + return -1; + } + + return value == endptr; +} + static int rscad_inf_parse_elements(struct list *l, FILE *f) { - int ret = 0; - char *line = NULL; + int ret; + char *line = NULL, *key = NULL, *value = NULL; size_t linelen = 0; - + while (rscad_inf_getline(&line, &linelen, f)) { - struct rscad_inf_element e; + char *type, *attrs; - int i = 0; - char *p = line; + type = line; - /* Handwritten tokenizer */ - char *tokens[32]; - bool inquote = false; - - while (*p && i < 32) { - /* Skip leading whitespace */ - while (*p == ' ') - p++; - - /* Save token */ - tokens[i] = p; - - while (*p) { - if (inquote) { - if (*p == '"') { - inquote = false; - break; - } - } - else { - if (*p == ' ' || *p == '=') - break; - } - - p++; - } - - *p = '\0'; - - i++; - } - tokens[i] = NULL; + attrs = strchr(line, ' '); + if (!attrs) + goto fail; + *attrs++ = '\0'; + struct rscad_inf_element e = { + .name = NULL, + .description = NULL, + .group = NULL, + .units = NULL, + .address = -1, + .rack = -1, + .datatype = RSCAD_INF_DATATYPE_STRING, + .init_value.i = 0, + .min.i = 0, + .max.i = 0 + }; + if (!strcmp(type, "String")) e.type = RSCAD_INF_ELEMENT_STRING; else if (!strcmp(type, "Output")) @@ -176,21 +235,59 @@ static int rscad_inf_parse_elements(struct list *l, FILE *f) else if (!strcmp(type, "Slider")) e.type = RSCAD_INF_ELEMENT_SLIDER; else - goto warn; + goto fail; - while (1) { - scanf(line, "%") - + while (rscad_inf_getattr(&attrs, &key, &value) == 0) { + if (!strcmp(key, "Desc")) + e.description = strdup(value); + else if (!strcmp(key, "Group")) + e.group = strdup(value); + else if (!strcmp(key, "Units")) + e.units = strdup(value); + else if (!strcmp(key, "Adr")) + e.address = strtoul(value, NULL, 16); + else if (!strcmp(key, "Rack")) + e.rack = strtoul(value, NULL, 10); + else if (!strcmp(key, "Type")) { + if (!strcmp(value, "INT")) + e.datatype = RSCAD_INF_DATATYPE_INT; + else if (!strcmp(value, "IEEE")) + e.datatype = RSCAD_INF_DATATYPE_IEEE; + else + goto fail; + } + else if (!strcmp(key, "InitValue")) { + ret = rscad_inf_parse_value(value, e.datatype, &e.init_value); + if (ret) + goto fail; + } + else if (!strcmp(key, "Min")) { + ret = rscad_inf_parse_value(value, e.datatype, &e.min); + if (ret) + goto fail; + } + else if (!strcmp(key, "Max")) { + ret = rscad_inf_parse_value(value, e.datatype, &e.max); + if (ret) + goto fail; + } + else + goto fail; } + if (e.group && e.description) + strcatf(&e.name, "%s|%s", e.group, e.description); + list_push(l, memdup(&e, sizeof(e))); - + continue; -warn: +fail: warn("Failed to parse element: %s", line); } free(line); + free(key); + free(value); return 0; } @@ -230,7 +327,7 @@ void rscad_inf_dump(struct rscad_inf *i) for (size_t j = 0; j < list_length(&i->elements); j++) { struct rscad_inf_element *e = list_at(&i->elements, j); - info("Element: type=%d", e->type); + info("Element: %s", e->name); } } diff --git a/tests/unit/rtds.c b/tests/unit/rtds.c index 4fe225872..5ffa9b7c0 100644 --- a/tests/unit/rtds.c +++ b/tests/unit/rtds.c @@ -54,15 +54,17 @@ Test(rtds, rscad_inf) rscad_inf_dump(&i); - e = rscad_inf_lookup_element(&i, "Subsystem #1|Sources|src|ABCmag"); + e = list_lookup(&i.elements, "Subsystem #1|Node Voltages|S1) N1"); cr_assert_not_null(e); - cr_assert_eq(e->address, 0x783014); + cr_assert_eq(e->address, 0x20000C); cr_assert_eq(e->rack, 4); cr_assert_eq(e->datatype, RSCAD_INF_DATATYPE_IEEE); - cr_assert_eq(e->init_value.f, 230.0); cr_assert_eq(e->min.f, 0.0); - cr_assert_eq(e->max.f, 460.0); + cr_assert_eq(e->max.f, 1.0); + cr_assert_str_eq(e->units, "kV"); + cr_assert_str_eq(e->group, "Subsystem #1|Node Voltages"); + cr_assert_str_eq(e->description, "S1) N1"); ret = rscad_inf_destroy(&i); cr_assert_eq(ret, 0);