From 9512da3f7af8193bf381080cf52e1b0d29e71e6c Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Tue, 31 May 2016 11:45:58 +0200 Subject: dbfp: refactoring: introduce generic object parser This commit replaces the manual parsing of the XML location element with a generic read_object method. The structure of the element to parse and the destination of the parsed data is defined in an object_data array. --- dbfp.c | 139 +++++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 80 insertions(+), 59 deletions(-) diff --git a/dbfp.c b/dbfp.c index 0b41810..05343a1 100644 --- a/dbfp.c +++ b/dbfp.c @@ -26,18 +26,24 @@ struct location_data { struct dbfp_location *locations; }; +struct object_data { + const char *name; + int (*read)(const char **, size_t, void *); + void *value; +}; + static int dbfp_parse(void *contents, size_t len, size_t n, void *data); static int dbfp_request(struct dbfp *dbfp, char *service, char *query, XML_Parser parser); static int dbfp_url(struct dbfp *dbfp, char *service, char *query, char **url); static int check_ele_error(const char *name, const char **atts); -static int read_string(const char **atts, size_t idx, char **str); -static int read_float(const char **atts, size_t idx, float *f); +static int read_string(const char **atts, size_t idx, void *value); +static int read_float(const char **atts, size_t idx, void *value); +static int read_object_indizes(const char **atts, struct object_data *data, + size_t *indizes); +static int read_object(const char **atts, struct object_data *data); -static int add_location(struct location_data *ld, const char **atts, - size_t idx_name, size_t idx_id, size_t idx_lon, - size_t idx_lat); static void location_start(void *data, const char *name, const char **atts); static void location_end(void *data, const char *name); @@ -147,6 +153,7 @@ int dbfp_query_location_name(struct dbfp *dbfp, char *input, *locations = ld.locations; cleanup: + // TODO check whether the elements of ld.locations should be closed if (err) free(ld.locations); if (input_enc) @@ -235,8 +242,10 @@ static int check_ele_error(const char *name, const char **atts) return 0; } -static int read_string(const char **atts, size_t idx, char **str) +static int read_string(const char **atts, size_t idx, void *value) { + char **str = (char **)value; + *str = strdup(atts[idx]); if (!*str) return ENOMEM; @@ -244,8 +253,9 @@ static int read_string(const char **atts, size_t idx, char **str) return 0; } -static int read_float(const char **atts, size_t idx, float *f) +static int read_float(const char **atts, size_t idx, void *value) { + float *f = (float *)value; char *endptr = NULL; errno = 0; @@ -256,48 +266,58 @@ static int read_float(const char **atts, size_t idx, float *f) return 0; } -static int add_location(struct location_data *ld, const char **atts, - size_t idx_name, size_t idx_id, size_t idx_lon, - size_t idx_lat) +static int read_object_indizes(const char **atts, struct object_data *data, + size_t *indizes) +{ + size_t i; + size_t j; + + for (i = 0; data[i].name; i++) + indizes[i] = 0; + + for (i = 0; atts[i]; i += 2) { + for (j = 0; data[j].name; j++) { + if (strcmp(atts[i], data[j].name) == 0) { + indizes[j] = i + 1; + break; + } + } + } + + for (i = 0; data[i].name; i++) { + if (!indizes[i]) + return DBFP_ERROR_STRUCTURE; + } + + return 0; +} + +static int read_object(const char **atts, struct object_data *data) { int err = 0; - char *name = NULL; - char *id = NULL; - float lon; - float lat; + size_t i = 0; + size_t n = 0; + size_t *indizes; - err = read_string(atts, idx_name, &name); - if (err) - goto cleanup; - err = read_string(atts, idx_id, &id); - if (err) - goto cleanup; - err = read_float(atts, idx_lon, &lon); - if (err) - goto cleanup; - err = read_float(atts, idx_lat, &lat); + for (i = 0; data[i].name; i++) + n++; + + indizes = malloc(n * sizeof(*indizes)); + if (!indizes) + return ENOMEM; + + err = read_object_indizes(atts, data, indizes); if (err) goto cleanup; - /* TODO(robin.krahl): don't give up the old memory if realloc fails */ - ld->locations = realloc(ld->locations, - (ld->n + 1) * sizeof(*ld->locations)); - if (!ld->locations) { - err = ENOMEM; - goto cleanup; + for (i = 0; data[i].name; i++) { + err = data[i].read(atts, indizes[i], data[i].value); + if (err) + goto cleanup; } - ld->locations[ld->n].name = name; - ld->locations[ld->n].id = id; - ld->locations[ld->n].lon = lon; - ld->locations[ld->n].lat = lat; - ld->n++; - cleanup: - if (err) { - free(name); - free(id); - } + free(indizes); return err; } @@ -307,11 +327,14 @@ static void location_start(void *data, const char *name, const char **atts) int err = 0; struct parse_data *pd = (struct parse_data *)data; struct location_data *ld = (struct location_data *)pd->data; - size_t idx_name = 0; - size_t idx_id = 0; - size_t idx_lon = 0; - size_t idx_lat = 0; - size_t i; + struct dbfp_location location = { NULL, NULL, 0, 0 }; + struct object_data od[] = { + { "name", &read_string, &location.name }, + { "id", &read_string, &location.id }, + { "lon", &read_float, &location.lon }, + { "lat", &read_float, &location.lat }, + { NULL, NULL, NULL } + }; err = check_ele_error(name, atts); if (err) @@ -320,27 +343,25 @@ static void location_start(void *data, const char *name, const char **atts) if (strcmp(name, "StopLocation") != 0) goto cleanup; - for (i = 0; atts[i]; i += 2) { - if (strcmp(atts[i], "name") == 0) - idx_name = i + 1; - else if (strcmp(atts[i], "id") == 0) - idx_id = i + 1; - else if (strcmp(atts[i], "lon") == 0) - idx_lon = i + 1; - else if (strcmp(atts[i], "lat") == 0) - idx_lat = i + 1; - } + err = read_object(atts, od); + if (err) + goto cleanup; - if (!idx_name || !idx_id || !idx_lon || !idx_lat) { - err = DBFP_ERROR_STRUCTURE; + ld->locations = realloc(ld->locations, + (ld->n + 1) * sizeof(*ld->locations)); + if (!ld->locations) { + err = ENOMEM; goto cleanup; } - err = add_location(ld, atts, idx_name, idx_id, idx_lon, idx_lat); + ld->locations[ld->n] = location; + ld->n++; cleanup: - if (err) + if (err) { + dbfp_location_close(&location); pd->error = err; + } } static void location_end(void *data, const char *name) -- cgit v1.2.1