aboutsummaryrefslogtreecommitdiff
path: root/dbfp.c
diff options
context:
space:
mode:
authorRobin Krahl <me@robin-krahl.de>2016-03-10 04:21:10 +0100
committerRobin Krahl <me@robin-krahl.de>2016-03-10 04:21:10 +0100
commit913fc9d2c2935e0faf34657747286ce83af21853 (patch)
treebb4c060bd6de36642a0b54bf7dc0cbe8c7c57938 /dbfp.c
parent2ae18059f986154efe06fe7fda92a1bb53cca50a (diff)
downloaddbfp-913fc9d2c2935e0faf34657747286ce83af21853.tar.gz
dbfp-913fc9d2c2935e0faf34657747286ce83af21853.tar.bz2
dbfp: improve error handling
Get rid of the complicated dbfp_status structure and use plain old return codes. This leads to a cleaner interface and fixes the problem with unsufficient error handling introduced with 1648e81. The drawback is that the details of curl and expat errors are hidden from the user, but this can be adressed later.
Diffstat (limited to 'dbfp.c')
-rw-r--r--dbfp.c214
1 files changed, 116 insertions, 98 deletions
diff --git a/dbfp.c b/dbfp.c
index d822f20..8aed661 100644
--- a/dbfp.c
+++ b/dbfp.c
@@ -18,23 +18,26 @@
#define DBFP_URL_LEN 8000
struct parse_data {
- struct dbfp_status *status;
+ int error;
void *data;
};
-struct loc_data {
+struct location_data {
size_t n;
- struct dbfp_location *locs;
+ struct dbfp_location *locations;
};
static int dbfp_parse(void *contents, size_t len, size_t n, void *data);
-static void dbfp_request(struct dbfp *dbfp, char *service, char *query,
- XML_Parser parser, struct dbfp_status *status);
+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 void handle_loc(struct loc_data *ld, const char **atts);
-static void loc_ele_start(void *data, const char *name, const char **atts);
-static void loc_ele_end(void *data, const char *name);
+static int check_ele_error(const char *name, const char **atts);
+
+static int add_location(struct location_data *ld, const char **atts,
+ size_t idx_name, size_t idx_id);
+static void location_start(void *data, const char *name, const char **atts);
+static void location_end(void *data, const char *name);
int dbfp_init(struct dbfp *dbfp, char *key)
{
@@ -60,66 +63,55 @@ void dbfp_close(struct dbfp *dbfp)
free(dbfp->key);
}
-struct dbfp_status dbfp_query_location_name(struct dbfp *dbfp, char *input,
- size_t *n, struct dbfp_location **out)
+int dbfp_query_location_name(struct dbfp *dbfp, char *input,
+ size_t *n, struct dbfp_location **locations)
{
- struct dbfp_status status = { 0, 0, 0, 0, 0 };
+ int err;
char *query = NULL;
- int len;
- struct parse_data pd;
- struct loc_data ld;
XML_Parser parser = NULL;
+ int len;
+ struct location_data ld = { .n = 0, .locations = NULL };
+ struct parse_data pd = { .error = 0, .data = &ld };
- if (!dbfp || !input) {
- status.error = 1;
- status.run_error = EINVAL;
- goto cleanup;
- }
+ if (!dbfp || !input || !n || !locations)
+ return EINVAL;
+
+ *n = 0;
+ *locations = NULL;
/*
* TODO(robin.krahl): improve query building and implement HTML
* encoding.
*/
query = malloc(DBFP_URL_LEN);
- if (!query) {
- status.error = 1;
- status.run_error = ENOMEM;
- goto cleanup;
- }
+ if (!query)
+ return ENOMEM;
len = snprintf(query, DBFP_URL_LEN, "input=%s", input);
if (len < 0 || len >= DBFP_URL_LEN) {
- status.error = 1;
- status.run_error = -1;
+ err = DBFP_ERROR_FORMAT;
goto cleanup;
}
- pd.status = &status;
- pd.data = &ld;
- ld.n = 0;
- ld.locs = NULL;
-
parser = XML_ParserCreateNS(NULL, '\0');
XML_SetUserData(parser, &pd);
- XML_SetElementHandler(parser, loc_ele_start, loc_ele_end);
-
- dbfp_request(dbfp, "location.name", query, parser, &status);
-
- if (!status.error) {
- if (n)
- *n = ld.n;
- if (out)
- *out = ld.locs;
- else
- free(ld.locs);
- } else {
- free(ld.locs);
- }
+ XML_SetElementHandler(parser, location_start, location_end);
+
+ err = dbfp_request(dbfp, "location.name", query, parser);
+ if (pd.error)
+ err = pd.error;
+ if (err)
+ goto cleanup;
+
+ *n = ld.n;
+ *locations = ld.locations;
cleanup:
+ if (err)
+ free(ld.locations);
XML_ParserFree(parser);
free(query);
- return status;
+ return err;
}
static int dbfp_parse(void *contents, size_t len, size_t n, void *data)
@@ -130,28 +122,26 @@ static int dbfp_parse(void *contents, size_t len, size_t n, void *data)
pd = (struct parse_data *)XML_GetUserData(parser);
- if (!pd->status->parse_error && !XML_Parse(parser, contents, size, 0)) {
- pd->status->error = 1;
- pd->status->parse_error = XML_GetErrorCode(parser);
- }
+ if (!pd->error && !XML_Parse(parser, contents, size, 0))
+ pd->error = DBFP_ERROR_PARSE;
return size;
}
-static void dbfp_request(struct dbfp *dbfp, char *service, char *query,
- XML_Parser parser, struct dbfp_status *status)
+static int dbfp_request(struct dbfp *dbfp, char *service, char *query,
+ XML_Parser parser)
{
- char *url;
+ int err = 0;
+ char *url = NULL;
CURL *curl = NULL;
- status->run_error = dbfp_url(dbfp, service, query, &url);
- if (status->run_error)
+ err = dbfp_url(dbfp, service, query, &url);
+ if (err)
goto cleanup;
curl = curl_easy_init();
if (!curl) {
- status->error = 1;
- status->run_error = -1;
+ err = DBFP_ERROR_CURL;
goto cleanup;
}
@@ -159,16 +149,15 @@ static void dbfp_request(struct dbfp *dbfp, char *service, char *query,
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, dbfp_parse);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)parser);
- status->curl_error = curl_easy_perform(curl);
-
- if (status->parse_error)
- fprintf(stderr, "Parse error %d: %s\n", status->parse_error,
- XML_ErrorString(status->parse_error));
+ if (curl_easy_perform(curl) != CURLE_OK)
+ err = DBFP_ERROR_CURL;
cleanup:
if (curl)
curl_easy_cleanup(curl);
free(url);
+
+ return err;
}
static int dbfp_url(struct dbfp *dbfp, char *service, char *query, char **url)
@@ -184,61 +173,90 @@ static int dbfp_url(struct dbfp *dbfp, char *service, char *query, char **url)
if (len < 0 || len >= DBFP_URL_LEN) {
free(*url);
*url = NULL;
- return -1;
+ return DBFP_ERROR_FORMAT;
}
return 0;
}
-static void handle_loc(struct loc_data *ld, const char **atts)
+static int check_ele_error(const char *name, const char **atts)
{
- char *name = NULL;
- char *id = NULL;
- size_t i;
+ if (strcmp(name, "Error") == 0) {
+ return DBFP_ERROR_API;
+ }
- /*
- * TODO(robin.krahl): fix error handling for the cases that a)
- * name or id is not set and b) realloc fails.
- */
+ return 0;
+}
- for (i = 0; atts[i]; i += 2) {
- if (strcmp(atts[i], "name") == 0)
- name = strdup(atts[i + 1]);
- else if (strcmp(atts[i], "id") == 0)
- id = strdup(atts[i + 1]);
+static int add_location(struct location_data *ld, const char **atts,
+ size_t idx_name, size_t idx_id)
+{
+ int err = 0;
+ char *val_name = NULL;
+ char *val_id = NULL;
+
+ val_name = strdup(atts[idx_name]);
+ val_id = strdup(atts[idx_id]);
+ if (!val_name || !val_id) {
+ err = ENOMEM;
+ goto cleanup;
}
- if (name && id) {
- ld->locs = realloc(ld->locs, (ld->n + 1) * sizeof(*ld->locs));
- if (ld->locs) {
- ld->n++;
- ld->locs[ld->n - 1].name = name;
- ld->locs[ld->n - 1].id = id;
- }
- } else {
- free(name);
- free(id);
+ ld->locations = realloc(ld->locations,
+ (ld->n + 1) * sizeof(*ld->locations));
+ if (!ld->locations) {
+ err = ENOMEM;
+ goto cleanup;
}
+
+ ld->n++;
+ ld->locations[ld->n - 1].name = val_name;
+ ld->locations[ld->n - 1].id = val_id;
+
+cleanup:
+ if (err) {
+ free(val_name);
+ free(val_id);
+ }
+
+ return err;
}
-static void loc_ele_start(void *data, const char *name, const char **atts)
+static void location_start(void *data, const char *name, const char **atts)
{
+ int err = 0;
struct parse_data *pd = (struct parse_data *)data;
- struct loc_data *ld = (struct loc_data *)pd->data;
+ struct location_data *ld = (struct location_data *)pd->data;
+ size_t idx_name = 0;
+ size_t idx_id = 0;
size_t i;
- if (strcmp(name, "Error") == 0) {
- for (i = 0; atts[i]; i += 2) {
- if (strcmp(atts[i], "code")) {
- fprintf(stderr, "err code %s\n", atts[i + 1]);
- break;
- }
- }
- } else if (strcmp(name, "StopLocation") == 0) {
- handle_loc(ld, atts);
+ err = check_ele_error(name, atts);
+ if (err)
+ goto cleanup;
+
+ 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;
}
+
+ if (!idx_name || !idx_id) {
+ err = DBFP_ERROR_STRUCTURE;
+ goto cleanup;
+ }
+
+ err = add_location(ld, atts, idx_name, idx_id);
+
+cleanup:
+ if (err)
+ pd->error = err;
}
-static void loc_ele_end(void *data, const char *name)
+static void location_end(void *data, const char *name)
{
}