aboutsummaryrefslogtreecommitdiff
path: root/dbfp.c
diff options
context:
space:
mode:
Diffstat (limited to 'dbfp.c')
-rw-r--r--dbfp.c205
1 files changed, 199 insertions, 6 deletions
diff --git a/dbfp.c b/dbfp.c
index 807ba19..b2d8074 100644
--- a/dbfp.c
+++ b/dbfp.c
@@ -27,10 +27,16 @@ struct location_data {
struct dbfp_location *locations;
};
+struct departure_data {
+ size_t n;
+ struct dbfp_departure *departures;
+};
+
struct object_data {
const char *name;
int (*read)(const char **, size_t, void *);
void *value;
+ int required;
};
static int dbfp_parse(void *contents, size_t len, size_t n, void *data);
@@ -38,10 +44,16 @@ static int dbfp_request(struct dbfp *dbfp, char *service, char *query,
XML_Parser parser, struct parse_data *pd);
static int dbfp_url(struct dbfp *dbfp, char *service, char *query, char **url);
static int dbfp_format_url(char **out, const char *format, ...);
+static int dbfp_format_time(char **out, size_t n, const char *format,
+ const struct tm *tm);
static int check_ele_error(const char *name, const char **atts);
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_datetime(const char **atts, size_t idx, void *value,
+ const char *format);
+static int read_date(const char **atts, size_t idx, void *value);
+static int read_time(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);
@@ -49,6 +61,9 @@ static int read_object(const char **atts, struct object_data *data);
static void location_start(void *data, const char *name, const char **atts);
static void location_end(void *data, const char *name);
+static void departure_start(void *data, const char *name, const char **atts);
+static void departure_end(void *data, const char *name);
+
int dbfp_init(struct dbfp *dbfp, char *key)
{
int err = 0;
@@ -168,6 +183,74 @@ void dbfp_departure_close(struct dbfp_departure *departure)
free(departure->track);
}
+int dbfp_query_departure(struct dbfp *dbfp, struct dbfp_location *location,
+ char *location_id, time_t time, size_t *n,
+ struct dbfp_departure **departures)
+{
+ int err = 0;
+ char *query = 0;
+ char *query_time = NULL;
+ char *query_date = NULL;
+ XML_Parser parser = NULL;
+ struct departure_data dd = { .n = 0, .departures = NULL };
+ struct parse_data pd = { .error = 0, .data = &dd };
+ struct tm *tm;
+
+ if (!dbfp || !n || !departures)
+ return EINVAL;
+ if ((!location && !location_id) || (location && !location->id))
+ return EINVAL;
+
+ *n = 0;
+ *departures = 0;
+
+ if (time) {
+ tm = localtime(&time);
+ if (!tm) {
+ err = DBFP_ERROR_FORMAT;
+ goto cleanup;
+ }
+
+ err = dbfp_format_time(&query_time, 5, "%H:%M", tm);
+ if (err)
+ goto cleanup;
+
+ err = dbfp_format_time(&query_date, 10, "%Y-%m-%d", tm);
+ if (err)
+ goto cleanup;
+
+ err = dbfp_format_url(&query, "id=%s&date=%s&time=%s",
+ location ? location->id : location_id,
+ query_date, query_time);
+ } else {
+ err = dbfp_format_url(&query, "id=%s",
+ location ? location->id : location_id);
+ }
+ if (err)
+ goto cleanup;
+
+ parser = XML_ParserCreateNS(NULL, '\0');
+ XML_SetElementHandler(parser, departure_start, departure_end);
+
+ err = dbfp_request(dbfp, "departureBoard", query, parser, &pd);
+ if (err)
+ goto cleanup;
+
+ *n = dd.n;
+ *departures = dd.departures;
+
+cleanup:
+ // TODO check wheterh the elements of dd.departures should be closed
+ if (err)
+ free(dd.departures);
+ XML_ParserFree(parser);
+ free(query_time);
+ free(query_date);
+ free(query);
+
+ return err;
+}
+
static int dbfp_parse(void *contents, size_t len, size_t n, void *data)
{
XML_Parser parser = (XML_Parser)data;
@@ -251,6 +334,26 @@ static int dbfp_format_url(char **out, const char *format, ...)
return 0;
}
+static int dbfp_format_time(char **out, size_t n, const char *format,
+ const struct tm *tm)
+{
+ size_t len;
+
+ *out = malloc((n + 1) * sizeof(**out));
+ if (!*out)
+ return ENOMEM;
+
+ /* TODO: check timezone */
+ len = strftime(*out, n + 1, format, tm);
+ if (len != n) {
+ free(*out);
+ *out = NULL;
+ return DBFP_ERROR_FORMAT;
+ }
+
+ return 0;
+}
+
static int check_ele_error(const char *name, const char **atts)
{
if (strcmp(name, "Error") == 0) {
@@ -284,6 +387,31 @@ static int read_float(const char **atts, size_t idx, void *value)
return 0;
}
+static int read_datetime(const char **atts, size_t idx, void *value,
+ const char *format)
+{
+ struct tm *tm = (struct tm *)value;
+
+ /*
+ * TODO: check whether it is safe to rely on the fact that strptime
+ * does not touch the unhandled values
+ */
+ if (!strptime(atts[idx], format, tm))
+ return DBFP_ERROR_STRUCTURE;
+
+ return 0;
+}
+
+static int read_date(const char **atts, size_t idx, void *value)
+{
+ return read_datetime(atts, idx, value, "%Y-%m-%d");
+}
+
+static int read_time(const char **atts, size_t idx, void *value)
+{
+ return read_datetime(atts, idx, value, "%H:%M");
+}
+
static int read_object_indizes(const char **atts, struct object_data *data,
size_t *indizes)
{
@@ -303,7 +431,11 @@ static int read_object_indizes(const char **atts, struct object_data *data,
}
for (i = 0; data[i].name; i++) {
- if (!indizes[i])
+ /*
+ * allow some items to be missing due to the type/tyoe/tyte
+ * confusion
+ */
+ if (!indizes[i] && data[i].required)
return DBFP_ERROR_STRUCTURE;
}
@@ -329,6 +461,8 @@ static int read_object(const char **atts, struct object_data *data)
goto cleanup;
for (i = 0; data[i].name; i++) {
+ if (!indizes[i])
+ continue;
err = data[i].read(atts, indizes[i], data[i].value);
if (err)
goto cleanup;
@@ -347,11 +481,11 @@ static void location_start(void *data, const char *name, const char **atts)
struct location_data *ld = (struct location_data *)pd->data;
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 }
+ { "name", &read_string, &location.name, 1 },
+ { "id", &read_string, &location.id, 1 },
+ { "lon", &read_float, &location.lon, 1 },
+ { "lat", &read_float, &location.lat, 1 },
+ { NULL, NULL, NULL, 0 }
};
err = check_ele_error(name, atts);
@@ -385,3 +519,62 @@ cleanup:
static void location_end(void *data, const char *name)
{
}
+
+static void departure_start(void *data, const char *name, const char **atts)
+{
+ int err = 0;
+ struct parse_data *pd = (struct parse_data *)data;
+ struct departure_data *dd = (struct departure_data *)pd->data;
+ struct tm tm;
+ struct dbfp_departure departure = { NULL, NULL, NULL, NULL, 0, NULL,
+ NULL };
+ struct object_data od[] = {
+ { "name", &read_string, &departure.name, 1 },
+ { "type", &read_string, &departure.type, 0 },
+ { "tyte", &read_string, &departure.type, 0 },
+ { "tyoe", &read_string, &departure.type, 0 },
+ { "stopid", &read_string, &departure.stopid, 1 },
+ { "stop", &read_string, &departure.stop, 1 },
+ { "date", &read_date, &tm, 1 },
+ { "time", &read_time, &tm, 1 },
+ { "direction", &read_string, &departure.direction, 1 },
+ { "track", &read_string, &departure.track, 1 },
+ { NULL, NULL, NULL, 0 }
+ };
+
+ err = check_ele_error(name, atts);
+ if (err)
+ goto cleanup;
+
+ if (strcmp(name, "Departure") != 0)
+ goto cleanup;
+
+ memset(&tm, 0, sizeof(tm));
+
+ err = read_object(atts, od);
+ if (err)
+ goto cleanup;
+
+ dd->departures = realloc(dd->departures,
+ (dd->n + 1) * sizeof(*dd->departures));
+ if (!dd->departures) {
+ err = ENOMEM;
+ goto cleanup;
+ }
+
+ /* TODO: check timezone */
+ departure.time = mktime(&tm);
+
+ dd->departures[dd->n] = departure;
+ dd->n++;
+
+cleanup:
+ if (err) {
+ dbfp_departure_close(&departure);
+ pd->error = err;
+ }
+}
+
+static void departure_end(void *data, const char *name)
+{
+}