Skip to content

Commit

Permalink
Add mgos_conf_parse_msg()
Browse files Browse the repository at this point in the history
This version of the function is identical to mgos_conf_parse() but
allows the caller to get an error message when parsing or data type
checks fail.
  • Loading branch information
kzyapkov committed Sep 29, 2020
1 parent 1efa9e9 commit eaeb470
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 9 deletions.
11 changes: 11 additions & 0 deletions include/mgos_config_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ bool mgos_conf_parse(const struct mg_str json, const char *acl,
const struct mgos_conf_entry *schema,
struct mgos_config *cfg);

/*
* Identical to `mgos_conf_parse()` but allows the caller to get an error
* message in `msg` on parse or data type errors.
*
* If `msg` is not NULL it may contain heap-allocated eror message, which
* is owned by the caller and has to be free()d.
*/
bool mgos_conf_parse_msg(const struct mg_str json, const char *acl,
const struct mgos_conf_entry *schema,
struct mgos_config *cfg, char **msg);

/*
* Parse a sub-section of the config.
*/
Expand Down
56 changes: 47 additions & 9 deletions src/mgos_config_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct parse_ctx {
void *cfg;
bool result;
int offset_adj;
char **msg;
};

const struct mgos_conf_entry *mgos_conf_find_schema_entry_s(
Expand Down Expand Up @@ -89,6 +90,7 @@ void mgos_conf_parse_cb(void *data, const char *name, size_t name_len,
const char *path, const struct json_token *tok) {
struct parse_ctx *ctx = (struct parse_ctx *) data;
char *endptr = NULL;
char msg[100];

(void) name;
(void) name_len;
Expand All @@ -98,6 +100,9 @@ void mgos_conf_parse_cb(void *data, const char *name, size_t name_len,
if (path[0] == '\0') return; /* Last entry, the entire object */
LOG(LL_ERROR, ("Not an object"));
ctx->result = false;
if (ctx->msg) {
*ctx->msg = strdup("Not an object");
}
return;
}
path++;
Expand Down Expand Up @@ -127,7 +132,11 @@ void mgos_conf_parse_cb(void *data, const char *name, size_t name_len,
/* fall through */
case CONF_TYPE_UNSIGNED_INT:
if (tok->type != JSON_TYPE_NUMBER) {
LOG(LL_ERROR, ("[%s] is not a number", path));
snprintf(msg, sizeof(msg), "[%s] is not a number", path);
if (ctx->msg) {
*ctx->msg = strdup(msg);
}
LOG(LL_ERROR, (msg));
ctx->result = false;
return;
}
Expand All @@ -149,15 +158,23 @@ void mgos_conf_parse_cb(void *data, const char *name, size_t name_len,
break;
}
if (endptr != tok->ptr + tok->len) {
LOG(LL_ERROR,
("[%s] failed to parse [%.*s]", path, (int) tok->len, tok->ptr));
snprintf(msg, sizeof(msg), "[%s] failed to parse [%.*s]", path,
(int) tok->len, tok->ptr);
if (ctx->msg) {
*ctx->msg = strdup(msg);
}
LOG(LL_ERROR, (msg));
ctx->result = false;
return;
}
break;
case CONF_TYPE_BOOL: {
if (tok->type != JSON_TYPE_TRUE && tok->type != JSON_TYPE_FALSE) {
LOG(LL_ERROR, ("[%s] is not a boolean", path));
snprintf(msg, sizeof(msg), "[%s] is not a boolean", path);
if (ctx->msg) {
*ctx->msg = strdup(msg);
}
LOG(LL_ERROR, (msg));
ctx->result = false;
return;
}
Expand All @@ -166,7 +183,11 @@ void mgos_conf_parse_cb(void *data, const char *name, size_t name_len,
}
case CONF_TYPE_STRING: {
if (tok->type != JSON_TYPE_STRING) {
LOG(LL_ERROR, ("[%s] is not a string", path));
snprintf(msg, sizeof(msg), "[%s] is not a string", path);
if (ctx->msg) {
*ctx->msg = strdup(msg);
}
LOG(LL_ERROR, (msg));
ctx->result = false;
return;
}
Expand All @@ -176,12 +197,21 @@ void mgos_conf_parse_cb(void *data, const char *name, size_t name_len,
if (tok->len > 0) {
s = (char *) malloc(tok->len + 1);
if (s == NULL) {
snprintf(msg, sizeof(msg), "insufficient memory");
if (ctx->msg) {
*ctx->msg = strdup(msg);
}
ctx->result = false;
return;
}
int n = json_unescape(tok->ptr, tok->len, s, tok->len);
if (n < 0) {
free(s);
snprintf(msg, sizeof(msg), "[%s] invalid string", path);
if (ctx->msg) {
*ctx->msg = strdup(msg);
}
LOG(LL_ERROR, (msg));
ctx->result = false;
return;
}
Expand All @@ -202,25 +232,33 @@ void mgos_conf_parse_cb(void *data, const char *name, size_t name_len,

static bool mgos_conf_parse_off(const struct mg_str json, const char *acl,
const struct mgos_conf_entry *schema,
int offset_adj, void *cfg) {
int offset_adj, void *cfg, char **msg) {
struct parse_ctx ctx = {.schema = schema,
.acl = acl,
.cfg = cfg,
.result = true,
.offset_adj = offset_adj};
.offset_adj = offset_adj,
.msg = msg};
return (json_walk(json.p, json.len, mgos_conf_parse_cb, &ctx) >= 0 &&
ctx.result == true);
}

bool mgos_conf_parse(const struct mg_str json, const char *acl,
const struct mgos_conf_entry *schema,
struct mgos_config *cfg) {
return mgos_conf_parse_off(json, acl, schema, 0, cfg);
return mgos_conf_parse_off(json, acl, schema, 0, cfg, NULL);
}

bool mgos_conf_parse_msg(const struct mg_str json, const char *acl,
const struct mgos_conf_entry *schema,
struct mgos_config *cfg, char **msg) {
return mgos_conf_parse_off(json, acl, schema, 0, cfg, msg);
}

bool mgos_conf_parse_sub(const struct mg_str json,
const struct mgos_conf_entry *sub_schema, void *cfg) {
return mgos_conf_parse_off(json, "*", sub_schema, sub_schema->offset, cfg);
return mgos_conf_parse_off(json, "*", sub_schema, sub_schema->offset, cfg,
NULL);
}

struct emit_ctx {
Expand Down

0 comments on commit eaeb470

Please sign in to comment.