X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=parse-xml.c;h=24acb1c1cc9f7f003e490de5c732b503d6b20866;hb=42f627b8b1cf7e929a30c0a07a5fb44a4cec9e1f;hp=50f85fbfa16e97f5cc76b2111124cbaa2c07fc2b;hpb=d314b053014bf74b59050d99516527dced75d483;p=ext%2Fsubsurface.git diff --git a/parse-xml.c b/parse-xml.c index 50f85fb..24acb1c 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -16,7 +16,7 @@ struct dive_table dive_table; /* * Add a dive into the dive_table array */ -static void record_dive(struct dive *dive) +void record_dive(struct dive *dive) { int nr = dive_table.nr, allocated = dive_table.allocated; struct dive **dives = dive_table.dives; @@ -62,18 +62,8 @@ static int match(const char *pattern, int plen, return 1; } -/* - * 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. - */ -static struct units { - enum { METERS, FEET } length; - enum { LITER, CUFT } volume; - enum { BAR, PSI, PASCAL } pressure; - enum { CELSIUS, FAHRENHEIT, KELVIN } temperature; - enum { KG, LBS } weight; -} units; + +struct units input_units; /* * We're going to default to SI units for input. Yes, @@ -81,7 +71,7 @@ static struct units { * we default to bar (10^5 pascal), which people * actually use. Similarly, C instead of Kelvin. */ -static const struct units SI_units = { +const struct units SI_units = { .length = METERS, .volume = LITER, .pressure = BAR, @@ -89,10 +79,17 @@ 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.. */ -static int alloc_samples; static struct dive *dive; static struct sample *sample; static struct tm tm; @@ -107,7 +104,7 @@ static enum import_source { UDDF, } import_source; -static time_t utc_mktime(struct tm *tm) +time_t utc_mktime(struct tm *tm) { static const int mdays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 @@ -243,7 +240,7 @@ 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; @@ -275,7 +272,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; @@ -301,7 +298,7 @@ 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; @@ -412,11 +409,11 @@ static void utf8_string(char *buffer, void *_res) static void water_pressure(char *buffer, void *_depth) { depth_t *depth = _depth; - union int_or_float val; + union int_or_float val; double atm, cm; - switch (integer_or_float(buffer, &val)) { - case FLOAT: + switch (integer_or_float(buffer, &val)) { + case FLOAT: if (!val.fp) break; /* cbar to atm */ @@ -464,10 +461,10 @@ static void centibar(char *buffer, void *_pressure) static void decicelsius(char *buffer, void *_temp) { temperature_t *temp = _temp; - union int_or_float val; + union int_or_float val; - switch (integer_or_float(buffer, &val)) { - case FLOAT: + switch (integer_or_float(buffer, &val)) { + case FLOAT: temp->mkelvin = (val.fp/10 + 273.15) * 1000 + 0.5; break; default: @@ -490,6 +487,16 @@ static int uemis_fill_sample(struct sample *sample, const char *name, int len, c * Divinglog is crazy. The temperatures are in celsius. EXCEPT * for the sample temperatures, that are in Fahrenheit. * WTF? + * + * Oh, and I think Diving Log *internally* probably kept them + * in celsius, because I'm seeing entries like + * + * 32.0 + * + * in there. Which is freezing, aka 0 degC. I bet the "0" is + * what Diving Log uses for "no temperature". + * + * So throw away crap like that. */ static void fahrenheit(char *buffer, void *_temperature) { @@ -498,6 +505,9 @@ static void fahrenheit(char *buffer, void *_temperature) switch (integer_or_float(buffer, &val)) { case FLOAT: + /* Floating point equality is evil, but works for small integers */ + if (val.fp == 32.0) + break; temperature->mkelvin = (val.fp + 459.67) * 5000/9; break; default: @@ -506,12 +516,37 @@ static void fahrenheit(char *buffer, void *_temperature) free(buffer); } +/* + * Did I mention how bat-shit crazy divinglog is? The sample + * pressures are in PSI. But the tank working pressure is in + * bar. WTF^2? + * + * Crazy stuff like this is why diveclog has everything in + * these inconvenient typed structures, and you have to say + * "pressure->mbar" to get the actual value. Exactly so that + * you can never have unit confusion. + */ +static void psi(char *buffer, void *_pressure) +{ + pressure_t *pressure = _pressure; + union int_or_float val; + + switch (integer_or_float(buffer, &val)) { + case FLOAT: + pressure->mbar = val.fp * 68.95 + 0.5; + break; + default: + fprintf(stderr, "Crazy Diving Log PSI reading %s\n", buffer); + } + free(buffer); +} + static int divinglog_fill_sample(struct sample *sample, const char *name, int len, char *buf) { return MATCH(".p.time", sampletime, &sample->time) || MATCH(".p.depth", depth, &sample->depth) || MATCH(".p.temp", fahrenheit, &sample->temperature) || - MATCH(".p.press1", pressure, &sample->cylinderpressure) || + MATCH(".p.press1", psi, &sample->cylinderpressure) || 0; } @@ -615,7 +650,7 @@ static int divinglog_dive_match(struct dive *dive, const char *name, int len, ch MATCH(".entrytime", divetime, &dive->when) || MATCH(".depth", depth, &dive->maxdepth) || MATCH(".tanksize", cylindersize, &dive->cylinder[0].type.size) || - MATCH(".tanktype", utf8_string, &dive->cylinder[0].type.description) || + MATCH(".presw", pressure, &dive->cylinder[0].type.workingpressure) || MATCH(".comments", utf8_string, &dive->notes) || MATCH(".country.name", utf8_string, &country) || MATCH(".city.name", utf8_string, &city) || @@ -632,29 +667,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) @@ -669,10 +704,10 @@ static void uemis_date_unit(char *buffer, void *_unused) static void uemis_date_time(char *buffer, void *_when) { time_t *when = _when; - union int_or_float val; + union int_or_float val; - switch (integer_or_float(buffer, &val)) { - case FLOAT: + switch (integer_or_float(buffer, &val)) { + case FLOAT: *when = (val.fp - 40587) * 86400; break; default: @@ -766,13 +801,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) || @@ -878,6 +913,8 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) break; } + if (MATCH(".number", get_index, &dive->number)) + return; if (MATCH(".date", divedate, &dive->when)) return; if (MATCH(".time", divetime, &dive->when)) @@ -946,21 +983,13 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf) */ static void dive_start(void) { - unsigned int size; - if (dive) return; - - alloc_samples = 5; - size = dive_size(alloc_samples); - dive = malloc(size); - if (!dive) - exit(1); - memset(dive, 0, size); + dive = alloc_dive(); memset(&tm, 0, sizeof(tm)); } -static void sanitize_gasmix(gasmix_t *mix) +static void sanitize_gasmix(struct gasmix *mix) { unsigned int o2, he; @@ -991,7 +1020,8 @@ static void sanitize_gasmix(gasmix_t *mix) */ static void match_standard_cylinder(cylinder_type_t *type) { - int psi, cuft, len; + double cuft; + int psi, len; const char *fmt; char buffer[20], *p; @@ -999,7 +1029,8 @@ static void match_standard_cylinder(cylinder_type_t *type) if (type->description) return; - cuft = type->size.mliter / 1000; + cuft = type->size.mliter / 28317.0; + cuft *= type->workingpressure.mbar / 1013.25; psi = type->workingpressure.mbar / 68.95; switch (psi) { @@ -1007,7 +1038,7 @@ static void match_standard_cylinder(cylinder_type_t *type) fmt = "LP%d"; break; case 2600 ... 2700: /* 2640 psi: LP+10% */ - fmt = "LP%d+"; + fmt = "LP%d"; break; case 2900 ... 3100: /* 3000 psi: ALx tank */ fmt = "AL%d"; @@ -1021,7 +1052,7 @@ static void match_standard_cylinder(cylinder_type_t *type) default: return; } - len = snprintf(buffer, sizeof(buffer), fmt, cuft); + len = snprintf(buffer, sizeof(buffer), fmt, (int) (cuft+0.5)); p = malloc(len+1); if (!p) return; @@ -1052,14 +1083,15 @@ static void sanitize_cylinder_type(cylinder_type_t *type) if (!type->size.mliter) return; + if (input_units.volume == CUFT || import_source == SUUNTO) { + volume_of_air = type->size.mliter * 28.317; /* milli-cu ft to milliliter */ + atm = type->workingpressure.mbar / 1013.25; /* working pressure in atm */ + volume = volume_of_air / atm; /* milliliters at 1 atm: "true size" */ + type->size.mliter = volume + 0.5; + } + /* Ok, we have both size and pressure: try to match a description */ match_standard_cylinder(type); - - /* .. and let's assume that the 'size' was cu ft of air */ - volume_of_air = type->size.mliter * 28.317; /* milli-cu ft to milliliter */ - atm = type->workingpressure.mbar / 1013.25; /* working pressure in atm */ - volume = volume_of_air / atm; /* milliliters at 1 atm: "true size" */ - type->size.mliter = volume + 0.5; } static void sanitize_cylinder_info(struct dive *dive) @@ -1102,22 +1134,7 @@ static void cylinder_end(void) static void sample_start(void) { - int nr; - - if (!dive) - return; - nr = dive->samples; - if (nr >= alloc_samples) { - unsigned int size; - - alloc_samples = (alloc_samples * 3)/2 + 10; - size = dive_size(alloc_samples); - dive = realloc(dive, size); - if (!dive) - return; - } - sample = dive->sample + nr; - memset(sample, 0, sizeof(*sample)); + sample = prepare_sample(&dive); event_index = 0; } @@ -1126,8 +1143,8 @@ static void sample_end(void) if (!dive) return; + finish_sample(dive, sample); sample = NULL; - dive->samples++; } static void entry(const char *name, int size, const char *raw) @@ -1229,13 +1246,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) @@ -1247,18 +1264,20 @@ static void DivingLog_importer(void) * * Temperatures are in C, except in samples, * when they are in Fahrenheit. Depths are in - * meters, but pressure is in PSI. + * meters, an dpressure is in PSI in the samples, + * but in bar when it comes to working pressure. + * + * Crazy f*%^ morons. */ - units = SI_units; - units.pressure = PSI; + input_units = SI_units; } static void uddf_importer(void) { import_source = UDDF; - units = SI_units; - units.pressure = PASCAL; - units.temperature = KELVIN; + input_units = SI_units; + input_units.pressure = PASCAL; + input_units.temperature = KELVIN; } /* @@ -1320,7 +1339,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; } @@ -1334,9 +1353,9 @@ void parse_xml_file(const char *filename, GError **error) if (error != NULL) { *error = g_error_new(g_quark_from_string("divelog"), - DIVE_ERROR_PARSE, - "Failed to parse '%s'", - filename); + DIVE_ERROR_PARSE, + "Failed to parse '%s'", + filename); } return; }