X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=parse-xml.c;h=92da468f44a2f946bdada7e310a924f6141e931b;hb=28cadad14460ba5702cae1dac7c700f34a9add6d;hp=90fdb1ad1ea751fe29cf0045e1acc8f4f4e41b7f;hpb=c24fd4b82cf4476c6d9c863ee03f2d729b64e5f0;p=ext%2Fsubsurface.git diff --git a/parse-xml.c b/parse-xml.c index 90fdb1a..92da468 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -62,21 +62,16 @@ static int match(const char *pattern, int plen, return 1; } + +struct units input_units; + /* - * We keep our internal data in well-specified units, but - * the input may come in some random format. This keeps track - * of the incoming units. + * We're going to default to SI units for input. Yes, + * technically the SI unit for pressure is Pascal, but + * we default to bar (10^5 pascal), which people + * actually use. Similarly, C instead of Kelvin. */ -static struct units { - enum { METERS, FEET } length; - enum { LITER, CUFT } volume; - enum { BAR, PSI } pressure; - enum { CELSIUS, FAHRENHEIT } temperature; - enum { KG, LBS } weight; -} units; - -/* We're going to default to SI units for input */ -static const struct units SI_units = { +const struct units SI_units = { .length = METERS, .volume = LITER, .pressure = BAR, @@ -84,6 +79,14 @@ static const struct units SI_units = { .weight = KG }; +const struct units IMPERIAL_units = { + .length = FEET, + .volume = CUFT, + .pressure = PSI, + .temperature = FAHRENHEIT, + .weight = LBS +}; + /* * Dive info as it is being built up.. */ @@ -99,6 +102,7 @@ static enum import_source { SUUNTO, UEMIS, DIVINGLOG, + UDDF, } import_source; static time_t utc_mktime(struct tm *tm) @@ -237,7 +241,10 @@ static void pressure(char *buffer, void *_press) /* Just ignore zero values */ if (!val.fp) break; - switch (units.pressure) { + switch (input_units.pressure) { + case PASCAL: + mbar = val.fp / 100; + break; case BAR: /* Assume mbar, but if it's really small, it's bar */ mbar = val.fp; @@ -266,7 +273,7 @@ static void depth(char *buffer, void *_depth) switch (integer_or_float(buffer, &val)) { case FLOAT: - switch (units.length) { + switch (input_units.length) { case METERS: depth->mm = val.fp * 1000 + 0.5; break; @@ -292,7 +299,10 @@ static void temperature(char *buffer, void *_temperature) if (!val.fp) break; /* Celsius */ - switch (units.temperature) { + switch (input_units.temperature) { + case KELVIN: + temperature->mkelvin = val.fp * 1000; + break; case CELSIUS: temperature->mkelvin = (val.fp + 273.15) * 1000 + 0.5; break; @@ -503,6 +513,14 @@ static int divinglog_fill_sample(struct sample *sample, const char *name, int le 0; } +static int uddf_fill_sample(struct sample *sample, const char *name, int len, char *buf) +{ + return MATCH(".divetime", sampletime, &sample->time) || + MATCH(".depth", depth, &sample->depth) || + MATCH(".temperature", temperature, &sample->temperature) || + 0; +} + /* We're in samples - try to convert the random xml value to something useful */ static void try_to_fill_sample(struct sample *sample, const char *name, char *buf) { @@ -535,6 +553,11 @@ static void try_to_fill_sample(struct sample *sample, const char *name, char *bu return; break; + case UDDF: + if (uddf_fill_sample(sample, name, len, buf)) + return; + break; + default: break; } @@ -607,29 +630,29 @@ static int buffer_value(char *buffer) static void uemis_length_unit(char *buffer, void *_unused) { - units.length = buffer_value(buffer) ? FEET : METERS; + input_units.length = buffer_value(buffer) ? FEET : METERS; } static void uemis_volume_unit(char *buffer, void *_unused) { - units.volume = buffer_value(buffer) ? CUFT : LITER; + input_units.volume = buffer_value(buffer) ? CUFT : LITER; } static void uemis_pressure_unit(char *buffer, void *_unused) { #if 0 - units.pressure = buffer_value(buffer) ? PSI : BAR; + input_units.pressure = buffer_value(buffer) ? PSI : BAR; #endif } static void uemis_temperature_unit(char *buffer, void *_unused) { - units.temperature = buffer_value(buffer) ? FAHRENHEIT : CELSIUS; + input_units.temperature = buffer_value(buffer) ? FAHRENHEIT : CELSIUS; } static void uemis_weight_unit(char *buffer, void *_unused) { - units.weight = buffer_value(buffer) ? LBS : KG; + input_units.weight = buffer_value(buffer) ? LBS : KG; } static void uemis_time_unit(char *buffer, void *_unused) @@ -648,7 +671,7 @@ static void uemis_date_time(char *buffer, void *_when) switch (integer_or_float(buffer, &val)) { case FLOAT: - *when = (val.fp - 40587.5) * 86400; + *when = (val.fp - 40587) * 86400; break; default: fprintf(stderr, "Strange julian date: %s", buffer); @@ -665,10 +688,14 @@ static void uemis_date_time(char *buffer, void *_when) */ static void uemis_time_zone(char *buffer, void *_when) { +#if 0 /* seems like this is only used to display it correctly + * the stored time appears to be UTC */ + time_t *when = _when; signed char tz = atoi(buffer); *when += tz * 3600; +#endif } /* 0 - air ; 1 - nitrox1 ; 2 - nitrox2 ; 3 = nitrox3 */ @@ -737,13 +764,13 @@ static void uemis_percent(char *buffer, void *_cylinder) static int uemis_dive_match(struct dive *dive, const char *name, int len, char *buf) { - return MATCH(".units.length", uemis_length_unit, &units) || - MATCH(".units.volume", uemis_volume_unit, &units) || - MATCH(".units.pressure", uemis_pressure_unit, &units) || - MATCH(".units.temperature", uemis_temperature_unit, &units) || - MATCH(".units.weight", uemis_weight_unit, &units) || - MATCH(".units.time", uemis_time_unit, &units) || - MATCH(".units.date", uemis_date_unit, &units) || + return MATCH(".units.length", uemis_length_unit, &input_units) || + MATCH(".units.volume", uemis_volume_unit, &input_units) || + MATCH(".units.pressure", uemis_pressure_unit, &input_units) || + MATCH(".units.temperature", uemis_temperature_unit, &input_units) || + MATCH(".units.weight", uemis_weight_unit, &input_units) || + MATCH(".units.time", uemis_time_unit, &input_units) || + MATCH(".units.date", uemis_date_unit, &input_units) || MATCH(".date_time", uemis_date_time, &dive->when) || MATCH(".time_zone", uemis_time_zone, &dive->when) || MATCH(".ambient.temperature", decicelsius, &dive->airtemp) || @@ -765,6 +792,58 @@ static int uemis_dive_match(struct dive *dive, const char *name, int len, char * 0; } +/* + * Uddf specifies ISO 8601 time format. + * + * There are many variations on that. This handles the useful cases. + */ +static void uddf_datetime(char *buffer, void *_when) +{ + char c; + int y,m,d,hh,mm,ss; + time_t *when = _when; + struct tm tm = { 0 }; + int i; + + i = sscanf(buffer, "%d-%d-%d%c%d:%d:%d", &y, &m, &d, &c, &hh, &mm, &ss); + if (i == 7) + goto success; + ss = 0; + if (i == 6) + goto success; + + i = sscanf(buffer, "%04d%02d%02d%c%02d%02d%02d", &y, &m, &d, &c, &hh, &mm, &ss); + if (i == 7) + goto success; + ss = 0; + if (i == 6) + goto success; +bad_date: + printf("Bad date time %s\n", buffer); + free(buffer); + return; + +success: + if (c != 'T' && c != ' ') + goto bad_date; + tm.tm_year = y; + tm.tm_mon = m - 1; + tm.tm_mday = d; + tm.tm_hour = hh; + tm.tm_min = mm; + tm.tm_sec = ss; + *when = utc_mktime(&tm); + free(buffer); +} + +static int uddf_dive_match(struct dive *dive, const char *name, int len, char *buf) +{ + return MATCH(".datetime", uddf_datetime, &dive->when) || + MATCH(".diveduration", duration, &dive->duration) || + MATCH(".greatestdepth", depth, &dive->maxdepth) || + 0; +} + /* 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) { @@ -788,6 +867,11 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) return; break; + case UDDF: + if (uddf_dive_match(dive, name, len, buf)) + return; + break; + default: break; } @@ -1143,13 +1227,13 @@ static void visit(xmlNode *n) static void suunto_importer(void) { import_source = SUUNTO; - units = SI_units; + input_units = SI_units; } static void uemis_importer(void) { import_source = UEMIS; - units = SI_units; + input_units = SI_units; } static void DivingLog_importer(void) @@ -1163,8 +1247,16 @@ static void DivingLog_importer(void) * when they are in Fahrenheit. Depths are in * meters, but pressure is in PSI. */ - units = SI_units; - units.pressure = PSI; + input_units = SI_units; + input_units.pressure = PSI; +} + +static void uddf_importer(void) +{ + import_source = UDDF; + input_units = SI_units; + input_units.pressure = PASCAL; + input_units.temperature = KELVIN; } /* @@ -1178,6 +1270,7 @@ static struct nesting { { "dive", dive_start, dive_end }, { "Dive", dive_start, dive_end }, { "sample", sample_start, sample_end }, + { "waypoint", sample_start, sample_end }, { "SAMPLE", sample_start, sample_end }, { "reading", sample_start, sample_end }, { "event", event_start, event_end }, @@ -1189,6 +1282,7 @@ static struct nesting { { "SUUNTO", suunto_importer }, { "Divinglog", DivingLog_importer }, { "pre_dive", uemis_importer }, + { "uddf", uddf_importer }, { NULL, } }; @@ -1224,7 +1318,7 @@ static void reset_all(void) * data within one file, we might have to reset it per * dive for that format. */ - units = SI_units; + input_units = SI_units; import_source = UNKNOWN; }