diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-03-09 12:19:41 -0700 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2014-03-09 19:36:35 -0700 |
commit | 5fcb36f5a83a0eb1a45553f8d1c6d1e0e2fb41af (patch) | |
tree | dc9c171d29cb8092fd6926adde0d6d69a1c1b5ba /load-git.c | |
parent | 719656b438c0574b4a98c5cda1ad742849312733 (diff) | |
download | subsurface-5fcb36f5a83a0eb1a45553f8d1c6d1e0e2fb41af.tar.gz |
Parse basic trip and dive data from the git blobs
Some things are still missing: samples and events, and cylinder and
weightsystem information. But most of the basics are there (although
the lack of sample data makes a big visual impact)
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'load-git.c')
-rw-r--r-- | load-git.c | 328 |
1 files changed, 318 insertions, 10 deletions
diff --git a/load-git.c b/load-git.c index ac1acd3a2..6024cdf3c 100644 --- a/load-git.c +++ b/load-git.c @@ -14,19 +14,302 @@ #include "device.h" #include "membuffer.h" -static void divecomputer_parser(const char *line, struct membuffer *str, void *_dc) +struct keyword_action { + const char *keyword; + void (*fn)(char *, struct membuffer *, void *); +}; +#define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0])) + +extern degrees_t parse_degrees(char *buf, char **end); +static void parse_dive_gps(char *line, struct membuffer *str, void *_dive) { -// struct divecomputer *dc = _dc; + struct dive *dive = _dive; + + dive->latitude = parse_degrees(line, &line); + dive->longitude = parse_degrees(line, &line); +} + +static char *get_utf8(struct membuffer *b) +{ + int len = b->len; + char *res; + + if (!len) + return NULL; + res = malloc(len+1); + if (res) { + memcpy(res, b->buffer, len); + res[len] = 0; + } + return res; +} + +static temperature_t get_temperature(char *line) +{ + temperature_t t; + t.mkelvin = C_to_mkelvin(ascii_strtod(line, NULL)); + return t; +} + +static depth_t get_depth(char *line) +{ + depth_t d; + d.mm = rint(1000*ascii_strtod(line, NULL)); + return d; +} + +static pressure_t get_pressure(char *line) +{ + pressure_t p; + p.mbar = rint(1000*ascii_strtod(line, NULL)); + return p; +} + +static void update_date(timestamp_t *when, char *line) +{ + unsigned yyyy, mm, dd; + struct tm tm; + + if (sscanf(line, "%04u-%02u-%02u", &yyyy, &mm, &dd) != 3) + return; + utc_mkdate(*when, &tm); + tm.tm_year = yyyy - 1900; + tm.tm_mon = mm - 1; + tm.tm_mday = dd; + *when = utc_mktime(&tm); +} + +static void update_time(timestamp_t *when, char *line) +{ + unsigned h, m, s = 0; + struct tm tm; + + if (sscanf(line, "%02u:%02u:%02u", &h, &m, &s) < 2) + return; + utc_mkdate(*when, &tm); + tm.tm_hour = h; + tm.tm_min = m; + tm.tm_sec = s; + *when = utc_mktime(&tm); +} + +static duration_t get_duration(char *line) +{ + int m = 0, s = 0; + duration_t d; + sscanf(line, "%d:%d", &m, &s); + d.seconds = m*60+s; + return d; +} + +static int get_index(char *line) +{ return atoi(line); } +static int get_hex(char *line) +{ return strtoul(line, NULL, 16); } + +static void parse_dive_location(char *line, struct membuffer *str, void *_dive) +{ struct dive *dive = _dive; dive->location = get_utf8(str); } + +static void parse_dive_divemaster(char *line, struct membuffer *str, void *_dive) +{ struct dive *dive = _dive; dive->divemaster = get_utf8(str); } + +static void parse_dive_buddy(char *line, struct membuffer *str, void *_dive) +{ struct dive *dive = _dive; dive->buddy = get_utf8(str); } + +static void parse_dive_suit(char *line, struct membuffer *str, void *_dive) +{ struct dive *dive = _dive; dive->suit = get_utf8(str); } + +static void parse_dive_notes(char *line, struct membuffer *str, void *_dive) +{ struct dive *dive = _dive; dive->notes = get_utf8(str); } + +/* + * We can have multiple tags in the membuffer. They are separated by + * NUL bytes. + */ +static void parse_dive_tags(char *line, struct membuffer *str, void *_dive) +{ + struct dive *dive = _dive; + const char *tag; + int len = str->len; + + if (!len) + return; + + /* Make sure there is a NUL at the end too */ + tag = mb_cstring(str); + for (;;) { + int taglen = strlen(tag); + if (taglen) + taglist_add_tag(dive->tag_list, tag); + len -= taglen; + if (!len) + return; + tag += taglen+1; + len--; + } } -static void dive_parser(const char *line, struct membuffer *str, void *_dive) +static void parse_dive_airtemp(char *line, struct membuffer *str, void *_dive) +{ struct dive *dive = _dive; dive->airtemp = get_temperature(line); } + +static void parse_dive_watertemp(char *line, struct membuffer *str, void *_dive) +{ struct dive *dive = _dive; dive->watertemp = get_temperature(line); } + +static void parse_dive_duration(char *line, struct membuffer *str, void *_dive) +{ struct dive *dive = _dive; dive->duration = get_duration(line); } + +static void parse_dive_rating(char *line, struct membuffer *str, void *_dive) +{ struct dive *dive = _dive; dive->rating = get_index(line); } + +static void parse_dive_visibility(char *line, struct membuffer *str, void *_dive) +{ struct dive *dive = _dive; dive->visibility = get_index(line); } + +static void parse_dive_notrip(char *line, struct membuffer *str, void *_dive) +{ struct dive *dive = _dive; dive->tripflag = NO_TRIP; } + +/* FIXME! Cylinders and weigthsystems not parsed */ +static void parse_dive_cylinder(char *line, struct membuffer *str, void *_dive) { } +static void parse_dive_weightsystem(char *line, struct membuffer *str, void *_dive) { } + +static int match_action(char *line, struct membuffer *str, void *data, + struct keyword_action *action, unsigned nr_action) { -// struct dive *dive = _dive; + char *p = line, c; + unsigned low, high; + + while ((c = *p) >= 'a' && c <= 'z') + p++; + if (p == line) + return -1; + switch (c) { + case 0: + break; + case ' ': + *p++ = 0; + break; + default: + return -1; + } + + /* Standard binary search in a table */ + low = 0; + high = nr_action; + while (low < high) { + unsigned mid = (low+high)/2; + struct keyword_action *a = action + mid; + int cmp = strcmp(line, a->keyword); + if (!cmp) { + a->fn(p, str, data); + return 0; + } + if (cmp < 0) + high = mid; + else + low = mid+1; + } +report_error("Unmatched action '%s'", line); + return -1; } -static void trip_parser(const char *line, struct membuffer *str, void *_trip) +/* FIXME! Samples not parsed */ +static void sample_parser(char *line, struct divecomputer *dc) { -// dive_trip_t *trip = _trip; +} + +static void parse_dc_airtemp(char *line, struct membuffer *str, void *_dc) +{ struct divecomputer *dc = _dc; dc->airtemp = get_temperature(line); } + +static void parse_dc_date(char *line, struct membuffer *str, void *_dc) +{ struct divecomputer *dc = _dc; update_date(&dc->when, line); } + +static void parse_dc_deviceid(char *line, struct membuffer *str, void *_dc) +{ struct divecomputer *dc = _dc; dc->deviceid = get_hex(line); } + +static void parse_dc_diveid(char *line, struct membuffer *str, void *_dc) +{ struct divecomputer *dc = _dc; dc->diveid = get_hex(line); } + +static void parse_dc_duration(char *line, struct membuffer *str, void *_dc) +{ struct divecomputer *dc = _dc; dc->duration = get_duration(line); } + +static void parse_dc_maxdepth(char *line, struct membuffer *str, void *_dc) +{ struct divecomputer *dc = _dc; dc->maxdepth = get_depth(line); } + +static void parse_dc_meandepth(char *line, struct membuffer *str, void *_dc) +{ struct divecomputer *dc = _dc; dc->meandepth = get_depth(line); } + +static void parse_dc_model(char *line, struct membuffer *str, void *_dc) +{ struct divecomputer *dc = _dc; dc->model = get_utf8(str); } + +static void parse_dc_surfacepressure(char *line, struct membuffer *str, void *_dc) +{ struct divecomputer *dc = _dc; dc->surface_pressure = get_pressure(line); } + +static void parse_dc_surfacetime(char *line, struct membuffer *str, void *_dc) +{ struct divecomputer *dc = _dc; dc->surfacetime = get_duration(line); } + +static void parse_dc_time(char *line, struct membuffer *str, void *_dc) +{ struct divecomputer *dc = _dc; update_time(&dc->when, line); } + +static void parse_dc_watertemp(char *line, struct membuffer *str, void *_dc) +{ struct divecomputer *dc = _dc; dc->watertemp = get_temperature(line); } + +/* FIXME! Events not parsed */ +static void parse_dc_event(char *line, struct membuffer *str, void *_dc) +{ } + +static void parse_trip_date(char *line, struct membuffer *str, void *_trip) +{ dive_trip_t *trip = _trip; update_date(&trip->when, line); } + +static void parse_trip_time(char *line, struct membuffer *str, void *_trip) +{ dive_trip_t *trip = _trip; update_time(&trip->when, line); } + +static void parse_trip_location(char *line, struct membuffer *str, void *_trip) +{ dive_trip_t *trip = _trip; trip->location = get_utf8(str); } + +static void parse_trip_notes(char *line, struct membuffer *str, void *_trip) +{ dive_trip_t *trip = _trip; trip->notes = get_utf8(str); } + +/* These need to be sorted! */ +struct keyword_action dc_action[] = { +#undef D +#define D(x) { #x, parse_dc_ ## x } + D(airtemp), D(date), D(deviceid), D(diveid), D(duration), + D(event), D(maxdepth), D(meandepth), D(model), + D(surfacepressure), D(surfacetime), D(time), D(watertemp), +}; + +/* Sample lines start with a space or a number */ +static void divecomputer_parser(char *line, struct membuffer *str, void *_dc) +{ + char c = *line; + if (c < 'a' || c > 'z') + sample_parser(line, _dc); + match_action(line, str, _dc, dc_action, ARRAY_SIZE(dc_action)); +} + +/* These need to be sorted! */ +struct keyword_action dive_action[] = { +#undef D +#define D(x) { #x, parse_dive_ ## x } + D(airtemp), D(buddy), D(cylinder), D(divemaster), D(duration), + D(gps), D(location), D(notes), D(notrip), D(rating), D(suit), + D(tags), D(visibility), D(watertemp), D(weightsystem) +}; + +static void dive_parser(char *line, struct membuffer *str, void *_dive) +{ + match_action(line, str, _dive, dive_action, ARRAY_SIZE(dive_action)); +} + +/* These need to be sorted! */ +struct keyword_action trip_action[] = { +#undef D +#define D(x) { #x, parse_trip_ ## x } + D(date), D(location), D(notes), D(time), +}; + +static void trip_parser(char *line, struct membuffer *str, void *_trip) +{ + match_action(line, str, _trip, trip_action, ARRAY_SIZE(trip_action)); } /* @@ -105,7 +388,7 @@ static const char *parse_one_string(const char *buf, const char *end, struct mem return p; } -typedef void (line_fn_t)(const char *, struct membuffer *, void *); +typedef void (line_fn_t)(char *, struct membuffer *, void *); #define MAXLINE 100 static unsigned parse_one_line(const char *buf, unsigned size, line_fn_t *fn, void *fndata, struct membuffer *b) { @@ -155,6 +438,7 @@ static void for_each_line(git_blob *blob, line_fn_t *fn, void *fndata) #define GIT_WALK_OK 0 #define GIT_WALK_SKIP 1 +static struct divecomputer *active_dc; static struct dive *active_dive; static dive_trip_t *active_trip; @@ -167,8 +451,6 @@ static struct dive *create_new_dive(timestamp_t when) if (active_trip) add_dive_to_trip(dive, active_trip); - record_dive(dive); - return dive; } @@ -293,6 +575,8 @@ static int dive_directory(const char *root, const char *name, int timeoff) tm.tm_mon = mm-1; tm.tm_mday = dd; + if (active_dive) + record_dive(active_dive); active_dive = create_new_dive(utc_mktime(&tm)); return GIT_WALK_OK; } @@ -392,6 +676,23 @@ git_blob *git_tree_entry_blob(git_repository *repo, const git_tree_entry *entry) return blob; } +static struct divecomputer *create_new_dc(struct dive *dive) +{ + struct divecomputer *dc = &dive->dc; + + while (dc->next) + dc = dc->next; + /* Did we already fill that in? */ + if (dc->samples || dc->model || dc->when) { + struct divecomputer *newdc = calloc(1, sizeof(*newdc)); + if (newdc) { + dc->next = newdc; + dc = newdc; + } + } + return dc; +} + /* * We should *really* try to delay the dive computer data parsing * until necessary, in order to reduce load-time. The parsing is @@ -401,10 +702,14 @@ git_blob *git_tree_entry_blob(git_repository *repo, const git_tree_entry *entry) static int parse_divecomputer_entry(git_repository *repo, const git_tree_entry *entry, const char *suffix) { git_blob *blob = git_tree_entry_blob(repo, entry); + if (!blob) return report_error("Unable to read divecomputer file"); - for_each_line(blob, divecomputer_parser, active_dive); + + active_dc = create_new_dc(active_dive); + for_each_line(blob, divecomputer_parser, active_dc); git_blob_free(blob); + active_dc = NULL; return 0; } @@ -508,5 +813,8 @@ int git_load_dives(char *where) ret = do_git_load(repo, branch); git_repository_free(repo); + if (active_dive) + record_dive(active_dive); + active_dive = NULL; return ret; } |