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)
{
{
int d,m,y;
time_t *when = _when;
+ int success = 0;
+ success = tm.tm_sec | tm.tm_min | tm.tm_hour;
if (sscanf(buffer, "%d.%d.%d", &d, &m, &y) == 3) {
tm.tm_year = y;
tm.tm_mon = m-1;
tm.tm_mday = d;
- if (tm.tm_sec | tm.tm_min | tm.tm_hour)
- *when = utc_mktime(&tm);
+ } else if (sscanf(buffer, "%d-%d-%d", &y, &m, &d) == 3) {
+ tm.tm_year = y;
+ tm.tm_mon = m-1;
+ tm.tm_mday = d;
+ } else {
+ fprintf(stderr, "Unable to parse date '%s'\n", buffer);
+ success = 0;
}
+
+ if (success)
+ *when = utc_mktime(&tm);
+
free(buffer);
}
case FLOAT:
/* Maybe it's in Bar? */
if (val.fp < 500.0) {
- pressure->mbar = val.fp * 1000;
+ pressure->mbar = val.fp * 1000 + 0.5;
break;
}
printf("Unknown fractional pressure reading %s\n", buffer);
val.fp = val.i;
/* fallthrough */
case FLOAT:
- depth->mm = val.fp * 1000;
+ depth->mm = val.fp * 1000 + 0.5;
break;
default:
printf("Strange depth reading %s\n", buffer);
break;
/* Celsius */
if (val.fp < 50.0) {
- temperature->mkelvin = (val.fp + 273.16) * 1000;
+ temperature->mkelvin = (val.fp + 273.15) * 1000 + 0.5;
break;
}
/* Fahrenheit */
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)
+{
+ /* libdivecomputer does negative percentages. */
+ if (*buffer == '-')
+ return;
+ if (gasmix_index < MAX_MIXES)
+ percent(buffer, _fraction);
+}
+
+static void gasmix_nitrogen(char *buffer, void *_gasmix)
+{
+ /* Ignore n2 percentages. There's no value in them. */
+}
+
#define MATCH(pattern, fn, dest) \
match(pattern, strlen(pattern), name, len, fn, buf, dest)
return;
if (MATCH(".sample.depth", depth, &sample->depth))
return;
+ if (MATCH(".sample.temp", temperature, &sample->temperature))
+ return;
if (MATCH(".sample.temperature", temperature, &sample->temperature))
return;
if (MATCH(".sample.sampletime", sampletime, &sample->time))
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)
{
return;
if (MATCH(".meandepth", depth, &dive->meandepth))
return;
+ if (MATCH(".duration", duration, &dive->duration))
+ return;
if (MATCH(".divetime", duration, &dive->duration))
return;
if (MATCH(".divetimesec", duration, &dive->duration))
return;
if (MATCH(".cylinderendpressure", pressure, &dive->end_pressure))
return;
+
+ if (MATCH(".o2", gasmix, &dive->gasmix[gasmix_index].o2))
+ return;
+ if (MATCH(".n2", gasmix_nitrogen, &dive->gasmix[gasmix_index]))
+ 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);
}
return p;
}
+static void sanitize_gasmix(struct dive *dive)
+{
+ int i;
+
+ for (i = 0; i < MAX_MIXES; i++) {
+ gasmix_t *mix = dive->gasmix+i;
+ unsigned int o2, he;
+
+ o2 = mix->o2.permille;
+ he = mix->he.permille;
+
+ /* Regular air: leave empty */
+ if (!he) {
+ if (!o2)
+ continue;
+ /* 20.9% or 21% O2 is just air */
+ if (o2 >= 209 && o2 <= 210) {
+ mix->o2.permille = 0;
+ continue;
+ }
+ }
+
+ /* Sane mix? */
+ if (o2 <= 1000 && he <= 1000 && o2+he <= 1000)
+ continue;
+ fprintf(stderr, "Odd gasmix: %d O2 %d He\n", o2, he);
+ memset(mix, 0, sizeof(*mix));
+ }
+}
+
static void dive_end(void)
{
if (!dive)
return;
if (!dive->name)
dive->name = generate_name(dive);
+ sanitize_gasmix(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)
}
sample = dive->sample + nr;
memset(sample, 0, sizeof(*sample));
+ event_index = 0;
}
static void sample_end(void)
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();
}
}