diff options
-rw-r--r-- | dive.h | 5 | ||||
-rw-r--r-- | parse-xml.c | 135 |
2 files changed, 119 insertions, 21 deletions
@@ -67,7 +67,7 @@ typedef struct { typedef struct { fraction_t o2; fraction_t n2; - fraction_t he2; + fraction_t he; } gasmix_t; typedef struct { @@ -100,6 +100,8 @@ struct sample { int tankindex; }; +#define MAX_MIXES (4) + struct dive { const char *name; time_t when; @@ -108,6 +110,7 @@ struct dive { depth_t visibility; temperature_t airtemp, watertemp; pressure_t beginning_pressure, end_pressure; + gasmix_t gasmix[MAX_MIXES]; int samples; struct sample sample[]; }; diff --git a/parse-xml.c b/parse-xml.c index 95625d12f..892e0fb20 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -69,6 +69,8 @@ static int alloc_samples; static struct dive *dive; static struct sample *sample; static struct tm tm; +static int suunto; +static int event_index, gasmix_index; static time_t utc_mktime(struct tm *tm) { @@ -300,6 +302,35 @@ static void duration(char *buffer, void *_time) sampletime(buffer, _time); } +static void percent(char *buffer, void *_fraction) +{ + fraction_t *fraction = _fraction; + union int_or_float val; + + switch (integer_or_float(buffer, &val)) { + /* C or F? Who knows? Let's default to Celsius */ + case INTEGER: + val.fp = val.i; + /* Fallthrough */ + case FLOAT: + if (val.fp <= 100.0) + fraction->permille = val.fp * 10 + 0.5; + break; + + default: + printf("Strange percentage reading %s\n", buffer); + break; + } + free(buffer); +} + +static void gasmix(char *buffer, void *_fraction) +{ + if (gasmix_index < MAX_MIXES) + percent(buffer, _fraction); +} + + #define MATCH(pattern, fn, dest) \ match(pattern, strlen(pattern), name, len, fn, buf, dest) @@ -325,6 +356,21 @@ static void try_to_fill_sample(struct sample *sample, const char *name, char *bu nonmatch("sample", name, buf); } +/* + * Crazy suunto xml. Look at how those o2/he things match up. + */ +static int suunto_dive_match(struct dive *dive, const char *name, int len, char *buf) +{ + return MATCH(".o2pct", percent, &dive->gasmix[0].o2) || + MATCH(".hepct_0", percent, &dive->gasmix[0].he) || + MATCH(".o2pct_2", percent, &dive->gasmix[1].o2) || + MATCH(".hepct_1", percent, &dive->gasmix[1].he) || + MATCH(".o2pct_3", percent, &dive->gasmix[2].o2) || + MATCH(".hepct_2", percent, &dive->gasmix[2].he) || + MATCH(".o2pct_4", percent, &dive->gasmix[3].o2) || + MATCH(".hepct_3", percent, &dive->gasmix[3].he); +} + /* We're in the top-level dive xml. Try to convert whatever value to a dive value */ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) { @@ -355,6 +401,18 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) return; if (MATCH(".cylinderendpressure", pressure, &dive->end_pressure)) return; + + if (MATCH(".o2", gasmix, &dive->gasmix[gasmix_index].o2)) + return; + if (MATCH(".n2", gasmix, &dive->gasmix[gasmix_index].n2)) + return; + if (MATCH(".he", gasmix, &dive->gasmix[gasmix_index].he)) + return; + + /* Suunto XML files are some crazy sh*t. */ + if (suunto && suunto_dive_match(dive, name, len, buf)) + return; + nonmatch("dive", name, buf); } @@ -415,6 +473,35 @@ static void dive_end(void) dive->name = generate_name(dive); record_dive(dive); dive = NULL; + gasmix_index = 0; +} + +static void suunto_start(void) +{ + suunto++; +} + +static void suunto_end(void) +{ + suunto--; +} + +static void event_start(void) +{ +} + +static void event_end(void) +{ + event_index++; +} + +static void gasmix_start(void) +{ +} + +static void gasmix_end(void) +{ + gasmix_index++; } static void sample_start(void) @@ -435,6 +522,7 @@ static void sample_start(void) } sample = dive->sample + nr; memset(sample, 0, sizeof(*sample)); + event_index = 0; } static void sample_end(void) @@ -550,34 +638,41 @@ static void visit(xmlNode *n) traverse(n->children); } +/* + * I'm sure this could be done as some fancy DTD rules. + * It's just not worth the headache. + */ +static struct nesting { + const char *name; + void (*start)(void), (*end)(void); +} nesting[] = { + { "dive", dive_start, dive_end }, + { "SUUNTO", suunto_start, suunto_end }, + { "sample", sample_start, sample_end }, + { "SAMPLE", sample_start, sample_end }, + { "event", event_start, event_end }, + { "gasmix", gasmix_start, gasmix_end }, + { NULL, } +}; + static void traverse(xmlNode *root) { xmlNode *n; for (n = root; n; n = n->next) { - /* XML from libdivecomputer: 'dive' per new dive */ - if (!strcmp(n->name, "dive")) { - dive_start(); - visit(n); - dive_end(); - continue; - } + struct nesting *rule = nesting; - /* - * At least both libdivecomputer and Suunto - * agree on "sample". - * - * Well - almost. Ignore case. - */ - if (!strcasecmp(n->name, "sample")) { - sample_start(); - visit(n); - sample_end(); - continue; - } + do { + if (!strcmp(rule->name, n->name)) + break; + rule++; + } while (rule->name); - /* Anything else - just visit it and recurse */ + if (rule->start) + rule->start(); visit(n); + if (rule->end) + rule->end(); } } |