#define _XOPEN_SOURCE #include #include #include #include #include #include "keyword.h" #include "macros.h" #include "misc.h" void *get_keyword_offset_ptr(const keyword *key, void *ptr) { char *ret = (char *)(ptr+key->offsets[0]); for (int i = 1; (int64_t)key->offsets[i] >= 0; ++i) { ret = *(char **)(ret+key->offsets[i]); } return (void *)ret; } keyword_val get_keyword_value(const keyword *key, char *value, int *error) { keyword_val val = {0}; int dummy = 0; error = (error != NULL) ? error : &dummy; *error = 0; switch (key->type) { case TYPE_INT : case TYPE_BOOL : val.i = strtol(value, NULL, 0); break; case TYPE_TIME : if (key->time_fmt != NULL) { struct tm tm = {0}; if (strptime(value, key->time_fmt, &tm) != NULL) { tm.tm_isdst = -1; val.t = mktime(&tm); } else { *error = 3; } } else { *error = 4; } break; case TYPE_STRING: val.str = make_str(value); break; case TYPE_FLOAT : val.f = strtof(value, NULL); break; default : *error = 2; break; } return val; } int set_keyword(const keyword *key, keyword_val val, void *ret, void *ctx) { const int callback_ret = (key->callback != NULL) ? key->callback(ctx, ret, key, val) : 0; if (callback_ret < 0 || callback_ret > 0) { return (callback_ret > 0) ? 0 : 5; } else { char *tmp_ret = (char *)get_keyword_offset_ptr(key, ret); switch (key->type) { case TYPE_INT : case TYPE_BOOL : *(int *)tmp_ret = val.i; break; case TYPE_TIME : *(time_t *)tmp_ret = val.t; break; case TYPE_STRING: *(char **)tmp_ret = val.str; break; case TYPE_FLOAT : *(float *)tmp_ret = val.f; break; default : return 6; break; } return 0; } } keyword_val parse_keyword(const keyword *key, char *key_str, char *value, int *error) { int dummy = 0; error = (error != NULL) ? error : &dummy; if (!strcmp(key->key, key_str)) { return get_keyword_value(key, value, error); } else { *error = 1; return (keyword_val){0}; } } int parse_keywords(const keyword **keys, char *key, char *value, void *ret, void *ctx) { keyword_val val = {0}; int error = 0; for (int i = 0; keys[i] != NULL; ++i) { val = parse_keyword(keys[i], key, value, &error); if (!error) { return set_keyword(keys[i], val, ret, ctx); } } return error; } int parse_key_value_file(void *ret, void *ctx, const keyword **keywords, char *buf, const char *delm, parse_callback *parse_cb) { if (buf != NULL) { int ret_val = 0; for (;;) { char *lhs, *rhs; /* Find the keyword before the delimiter(s). */ lhs = strtok_r(skip_whitespace(buf), delm, &buf); /* Remove any whitespace ahead of us. */ lhs = strtok_r(lhs, " \t\v\r\n", &rhs); /* Did we hit EOF? */ if (is_empty(lhs) || is_empty(buf)) { break; } else { int error; char *tmp = skip_whitespace(buf); /* Does the right hand side start with a double, or single quote? */ if (*tmp == '\"' || *tmp == '\'') { const char *delm = (*delm == '\"') ? "\"" : "\'"; /* Get the string in between the start, and end qoute. */ rhs = get_str_delm_range(tmp, delm, delm, &buf); } else { /* Get the rest of the line. */ rhs = strtok_r(tmp, "\n", &buf); } /* Did we fail to parse the keyword? */ if (error = parse_keywords(keywords, lhs, rhs, ret, ctx)) { log(LOG_WARNING, "Failed to parse keyword \"%s\". Error code: %i", lhs, error); ret_val = error; } } /* Do we have a parse callback? */ if (parse_cb != NULL) { /* Did the callback return an error. */ if (parse_cb(&ret, ctx, buf) < 0) { ret_val = 7; break; } } } return ret_val; } else { return 8; } }