From c766fbc6a7311864af74eee145ceb77258f878de Mon Sep 17 00:00:00 2001 From: Jan-Piet Mens Date: Sat, 22 Aug 2015 16:42:35 +0200 Subject: [PATCH] Add support for CSV in ocat and GeoJSON in backend --- ocat.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++-- storage.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ storage.h | 1 + 3 files changed, 187 insertions(+), 2 deletions(-) diff --git a/ocat.c b/ocat.c index 944ac1a..f782913 100644 --- a/ocat.c +++ b/ocat.c @@ -5,6 +5,48 @@ #include #include "json.h" #include "storage.h" +#include "util.h" + +void csv_output(JsonNode *json) +{ + JsonNode *arr, *one, *j; + time_t tst = 0L; + double lat = 0.0, lon = 0.0; + char *tid = "", *addr; + + arr = json_find_member(json, "locations"); + json_foreach(one, arr) { + tid = addr = ""; + lat = lon = 0.0; + + if ((j = json_find_member(one, "tid")) != NULL) { + tid = j->string_; + } + + if ((j = json_find_member(one, "addr")) != NULL) { + addr = j->string_; + } + + if ((j = json_find_member(one, "tst")) != NULL) { + tst = j->number_; + } + + if ((j = json_find_member(one, "lat")) != NULL) { + lat = j->number_; + } + + if ((j = json_find_member(one, "lon")) != NULL) { + lon = j->number_; + } + + printf("%s,%s,%lf,%lf,%s\n", + isotime(tst), + tid, + lat, + lon, + addr); + } +} void usage(char *prog) { @@ -20,6 +62,7 @@ void usage(char *prog) printf(" YYYY-MM-DDTHH\n"); printf(" YYYY-MM-DD\n"); printf(" YYYY-MM\n"); + printf(" --format json|csv -f output format (default: JSON)\n"); exit(1); } @@ -32,6 +75,14 @@ int main(int argc, char **argv) char *username = NULL, *device = NULL, *time_from = NULL, *time_to = NULL; JsonNode *json, *obj, *locs; time_t now, s_lo, s_hi; + typedef enum { + PLAIN = 0, + GEOJSON, + CSV, + JSON, + } output_type; + output_type otype = JSON; + time(&now); @@ -43,11 +94,12 @@ int main(int argc, char **argv) { "device", required_argument, 0, 'd'}, { "from", required_argument, 0, 'F'}, { "to", required_argument, 0, 'T'}, + { "format", required_argument, 0, 'f'}, {0, 0, 0, 0} }; int optindex = 0; - c = getopt_long(argc, argv, "hlu:d:F:T:", long_options, &optindex); + c = getopt_long(argc, argv, "hlu:d:F:T:f:", long_options, &optindex); if (c == -1) break; @@ -67,6 +119,18 @@ int main(int argc, char **argv) case 'T': time_to = strdup(optarg); break; + case 'f': + if (!strcmp(optarg, "json")) + otype = JSON; + else if (!strcmp(optarg, "geojson")) + otype = GEOJSON; + else if (!strcmp(optarg, "csv")) + otype = CSV; + else { + fprintf(stderr, "%s: unrecognized output format\n", progname); + exit(2); + } + break; case 'h': case '?': /* getopt_long already printed message */ @@ -151,7 +215,28 @@ int main(int argc, char **argv) } json_append_member(obj, "locations", locs); - printf("%s\n", json_stringify(obj, " ")); + + + if (otype == JSON) { + char *js = json_stringify(obj, " "); + + if (js != NULL) { + printf("%s\n", js); + free(js); + } + + } else if (otype == CSV) { + csv_output(obj); + } else if (otype == GEOJSON) { + JsonNode *geojson = geo_json(locs); + char *js; + + js = json_stringify(geojson, " "); + if (js != NULL) { + printf("%s\n", js); + free(js); + } + } return (0); } diff --git a/storage.c b/storage.c index caf1b22..31daa74 100644 --- a/storage.c +++ b/storage.c @@ -381,3 +381,102 @@ void locations(char *filename, JsonNode *obj, JsonNode *arr, time_t s_lo, time_t fclose(fp); } + +/* + * We're being passed an array of location objects created in + * locations(). Produce a Geo JSON tree. + */ +/* +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-80.83775386582222,35.24980190252168] + }, + "properties": { + "name": "DOUBLE OAKS CENTER", + "address": "1326 WOODWARD AV" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-80.83827000459532,35.25674709224663] + }, + "properties": { + "name": "DOUBLE OAKS NEIGHBORHOOD PARK", + "address": "2605 DOUBLE OAKS RD" + } + } + ] +} +*/ + +static void geo_f_array(JsonNode *features, double lat, double lon, char *tid, char *addr) +{ + // JsonNode *features = json_mkarray(); + JsonNode *f; + + JsonNode *geom, *props; + f = json_mkobject(); + + json_append_member(f, "type", json_mkstring("Feature")); + + geom = json_mkobject(); + json_append_member(geom, "type", json_mkstring("Point")); + JsonNode *coords = json_mkarray(); + json_append_element(coords, json_mknumber(lon)); /* first LON! */ + json_append_element(coords, json_mknumber(lat)); + json_append_member(geom, "coordinates", coords); + + + + props = json_mkobject(); + json_append_member(props, "name", json_mkstring(tid)); + json_append_member(props, "address", json_mkstring(addr)); + + + json_append_member(f, "geometry", geom); + json_append_member(f, "properties", props); + + json_append_element(features, f); +} +JsonNode *geo_json(JsonNode *location_array) +{ + JsonNode *one, *j; + JsonNode *feature_array, *fcollection; + + fcollection = json_mkobject(); + json_append_member(fcollection, "type", json_mkstring("FeatureCollection")); + + feature_array = json_mkarray(); + + json_foreach(one, location_array) { + double lat = 0.0, lon = 0.0; + char *addr = "", *tid = ""; + + if ((j = json_find_member(one, "lat")) != NULL) { + lat = j->number_; + } + + if ((j = json_find_member(one, "lon")) != NULL) { + lon = j->number_; + } + if ((j = json_find_member(one, "tid")) != NULL) { + tid = j->string_; + } + if ((j = json_find_member(one, "addr")) != NULL) { + addr = j->string_; + } + + geo_f_array(feature_array, lat, lon, tid, addr); + } + + json_append_member(fcollection, "features", feature_array); + + return (fcollection); +} diff --git a/storage.h b/storage.h index 343a4ea..69af01d 100644 --- a/storage.h +++ b/storage.h @@ -8,5 +8,6 @@ JsonNode *lister(char *username, char *device, time_t s_lo, time_t s_hi); void locations(char *filename, JsonNode *obj, JsonNode *arr, time_t s_lo, time_t s_hi); int make_times(char *time_from, time_t *s_lo, char *time_to, time_t *s_to); +JsonNode *geo_json(JsonNode *json); #endif