X-Git-Url: http://git.tdb.fi/?p=ext%2Fsubsurface.git;a=blobdiff_plain;f=parse-xml.c;h=5159a334f9153f65b010f0e1cf5c4845cebcf530;hp=6840610728e0e0f6da0f89d1218e11d7c9a101c5;hb=HEAD;hpb=1d51c7772996705fb69b2b3433cd94af3543583d diff --git a/parse-xml.c b/parse-xml.c index 6840610..5159a33 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -4,8 +4,6 @@ #include #include #include -#include -#include #define __USE_XOPEN #include #include @@ -41,6 +39,70 @@ void record_dive(struct dive *dive) dive_table.nr = nr+1; } +void record_trip(struct dive *trip) +{ + dive_trip_list = insert_trip(trip, dive_trip_list); +} + +static void delete_dive_renumber(struct dive **dives, int i, int nr) +{ + struct dive *dive = dives[i]; + int number = dive->number, j; + + if (!number) + return; + + /* + * Check that all numbered dives after the deleted + * ones are consecutive, return without renumbering + * if that is not the case. + */ + for (j = i+1; j < nr; j++) { + struct dive *next = dives[j]; + if (!next->number) + break; + number++; + if (next->number != number) + return; + } + + /* + * Ok, we hit the end of the dives or a unnumbered + * dive - renumber. + */ + for (j = i+1 ; j < nr; j++) { + struct dive *next = dives[j]; + if (!next->number) + break; + next->number--; + } +} + +/* + * Remove a dive from the dive_table array + */ +void delete_dive(struct dive *dive) +{ + int nr = dive_table.nr, i; + struct dive **dives = dive_table.dives; + + /* + * Stupid. We know the dive table is sorted by date, + * we could do a binary lookup. Sue me. + */ + for (i = 0; i < nr; i++) { + struct dive *d = dives[i]; + if (d != dive) + continue; + /* should we re-number? */ + delete_dive_renumber(dives, i, nr); + memmove(dives+i, dives+i+1, sizeof(struct dive *)*(nr-i-1)); + dives[nr] = NULL; + dive_table.nr = nr-1; + break; + } +} + static void start_match(const char *type, const char *name, char *buffer) { if (verbose > 2) @@ -78,6 +140,7 @@ struct units input_units; * 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. + * And kg instead of g. */ const struct units SI_units = { .length = METERS, @@ -98,16 +161,16 @@ const struct units IMPERIAL_units = { /* * Dive info as it is being built up.. */ -static struct dive *dive; -static struct sample *sample; +static struct dive *cur_dive, *cur_trip = NULL; +static struct sample *cur_sample; static struct { int active; duration_t time; int type, flags, value; const char *name; -} event; -static struct tm tm; -static int cylinder_index; +} cur_event; +static struct tm cur_tm; +static int cur_cylinder_index, cur_ws_index; static enum import_source { UNKNOWN, @@ -153,22 +216,22 @@ static void divedate(char *buffer, void *_when) time_t *when = _when; int success = 0; - success = tm.tm_sec | tm.tm_min | tm.tm_hour; + success = cur_tm.tm_sec | cur_tm.tm_min | cur_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; + cur_tm.tm_year = y; + cur_tm.tm_mon = m-1; + cur_tm.tm_mday = d; } else if (sscanf(buffer, "%d-%d-%d", &y, &m, &d) == 3) { - tm.tm_year = y; - tm.tm_mon = m-1; - tm.tm_mday = d; + cur_tm.tm_year = y; + cur_tm.tm_mon = m-1; + cur_tm.tm_mday = d; } else { fprintf(stderr, "Unable to parse date '%s'\n", buffer); success = 0; } if (success) - *when = utc_mktime(&tm); + *when = utc_mktime(&cur_tm); free(buffer); } @@ -179,11 +242,11 @@ static void divetime(char *buffer, void *_when) time_t *when = _when; if (sscanf(buffer, "%d:%d:%d", &h, &m, &s) >= 2) { - tm.tm_hour = h; - tm.tm_min = m; - tm.tm_sec = s; - if (tm.tm_year) - *when = utc_mktime(&tm); + cur_tm.tm_hour = h; + cur_tm.tm_min = m; + cur_tm.tm_sec = s; + if (cur_tm.tm_year) + *when = utc_mktime(&cur_tm); } free(buffer); } @@ -197,13 +260,13 @@ static void divedatetime(char *buffer, void *_when) if (sscanf(buffer, "%d-%d-%d %d:%d:%d", &y, &m, &d, &hr, &min, &sec) == 6) { - tm.tm_year = y; - tm.tm_mon = m-1; - tm.tm_mday = d; - tm.tm_hour = hr; - tm.tm_min = min; - tm.tm_sec = sec; - *when = utc_mktime(&tm); + cur_tm.tm_year = y; + cur_tm.tm_mon = m-1; + cur_tm.tm_mday = d; + cur_tm.tm_hour = hr; + cur_tm.tm_min = min; + cur_tm.tm_sec = sec; + *when = utc_mktime(&cur_tm); } free(buffer); } @@ -300,6 +363,27 @@ static void depth(char *buffer, void *_depth) free(buffer); } +static void weight(char *buffer, void *_weight) +{ + weight_t *weight = _weight; + union int_or_float val; + + switch (integer_or_float(buffer, &val)) { + case FLOAT: + switch (input_units.weight) { + case KG: + weight->grams = val.fp * 1000 + 0.5; + break; + case LBS: + weight->grams = val.fp * 453.6 + 0.5; + break; + } + break; + default: + printf("Strange depth reading %s\n", buffer); + } +} + static void temperature(char *buffer, void *_temperature) { temperature_t *temperature = _temperature; @@ -378,7 +462,7 @@ static void gasmix(char *buffer, void *_fraction) /* libdivecomputer does negative percentages. */ if (*buffer == '-') return; - if (cylinder_index < MAX_CYLINDERS) + if (cur_cylinder_index < MAX_CYLINDERS) percent(buffer, _fraction); } @@ -456,6 +540,17 @@ static void get_index(char *buffer, void *_i) free(buffer); } +static void get_tripflag(char *buffer, void *_tf) +{ + tripflag_t *tf = _tf; + tripflag_t i; + + *tf = TF_NONE; + for (i = NO_TRIP; i < NUM_TRIPFLAGS; i++) + if(! strcmp(buffer, tripflag_names[i])) + *tf = i; +} + static void centibar(char *buffer, void *_pressure) { pressure_t *pressure = _pressure; @@ -568,6 +663,7 @@ static int uddf_fill_sample(struct sample *sample, const char *name, int len, ch return MATCH(".divetime", sampletime, &sample->time) || MATCH(".depth", depth, &sample->depth) || MATCH(".temperature", temperature, &sample->temperature) || + MATCH(".tankpressure", pressure, &sample->cylinderpressure) || 0; } @@ -575,8 +671,8 @@ static void eventtime(char *buffer, void *_duration) { duration_t *duration = _duration; sampletime(buffer, duration); - if (sample) - duration->seconds += sample->time.seconds; + if (cur_sample) + duration->seconds += cur_sample->time.seconds; } static void try_to_fill_event(const char *name, char *buf) @@ -584,17 +680,17 @@ static void try_to_fill_event(const char *name, char *buf) int len = strlen(name); start_match("event", name, buf); - if (MATCH(".event", utf8_string, &event.name)) + if (MATCH(".event", utf8_string, &cur_event.name)) return; - if (MATCH(".name", utf8_string, &event.name)) + if (MATCH(".name", utf8_string, &cur_event.name)) return; - if (MATCH(".time", eventtime, &event.time)) + if (MATCH(".time", eventtime, &cur_event.time)) return; - if (MATCH(".type", get_index, &event.type)) + if (MATCH(".type", get_index, &cur_event.type)) return; - if (MATCH(".flags", get_index, &event.flags)) + if (MATCH(".flags", get_index, &cur_event.flags)) return; - if (MATCH(".value", get_index, &event.value)) + if (MATCH(".value", get_index, &cur_event.value)) return; nonmatch("event", name, buf); } @@ -806,7 +902,7 @@ static int uemis_gas_template; static int uemis_cylinder_index(void *_cylinder) { cylinder_t *cylinder = _cylinder; - unsigned int index = cylinder - dive->cylinder; + unsigned int index = cylinder - cur_dive->cylinder; if (index > 6) { fprintf(stderr, "Uemis cylinder pointer calculations broken\n"); @@ -838,14 +934,14 @@ static void uemis_cylindersize(char *buffer, void *_cylinder) { int index = uemis_cylinder_index(_cylinder); if (index >= 0) - cylindersize(buffer, &dive->cylinder[index].type.size); + cylindersize(buffer, &cur_dive->cylinder[index].type.size); } static void uemis_percent(char *buffer, void *_cylinder) { int index = uemis_cylinder_index(_cylinder); if (index >= 0) - percent(buffer, &dive->cylinder[index].gasmix.o2); + percent(buffer, &cur_dive->cylinder[index].gasmix.o2); } static int uemis_dive_match(struct dive **divep, const char *name, int len, char *buf) @@ -982,6 +1078,8 @@ static void try_to_fill_dive(struct dive **divep, const char *name, char *buf) if (MATCH(".number", get_index, &dive->number)) return; + if (MATCH(".tripflag", get_tripflag, &dive->tripflag)) + return; if (MATCH(".date", divedate, &dive->when)) return; if (MATCH(".time", divetime, &dive->when)) @@ -1020,6 +1118,10 @@ static void try_to_fill_dive(struct dive **divep, const char *name, char *buf) return; if (MATCH(".location", utf8_string, &dive->location)) return; + if (MATCH(".suit", utf8_string, &dive->suit)) + return; + if (MATCH(".divesuit", utf8_string, &dive->suit)) + return; if (MATCH(".notes", utf8_string, &dive->notes)) return; if (MATCH(".divemaster", utf8_string, &dive->divemaster)) @@ -1028,27 +1130,53 @@ static void try_to_fill_dive(struct dive **divep, const char *name, char *buf) return; if (MATCH(".rating", get_index, &dive->rating)) return; - if (MATCH(".cylinder.size", cylindersize, &dive->cylinder[cylinder_index].type.size)) + if (MATCH(".cylinder.size", cylindersize, &dive->cylinder[cur_cylinder_index].type.size)) return; - if (MATCH(".cylinder.workpressure", pressure, &dive->cylinder[cylinder_index].type.workingpressure)) + if (MATCH(".cylinder.workpressure", pressure, &dive->cylinder[cur_cylinder_index].type.workingpressure)) return; - if (MATCH(".cylinder.description", utf8_string, &dive->cylinder[cylinder_index].type.description)) + if (MATCH(".cylinder.description", utf8_string, &dive->cylinder[cur_cylinder_index].type.description)) return; - if (MATCH(".cylinder.start", pressure, &dive->cylinder[cylinder_index].start)) + if (MATCH(".cylinder.start", pressure, &dive->cylinder[cur_cylinder_index].start)) return; - if (MATCH(".cylinder.end", pressure, &dive->cylinder[cylinder_index].end)) + if (MATCH(".cylinder.end", pressure, &dive->cylinder[cur_cylinder_index].end)) return; - - if (MATCH(".o2", gasmix, &dive->cylinder[cylinder_index].gasmix.o2)) + if (MATCH(".weightsystem.description", utf8_string, &dive->weightsystem[cur_ws_index].description)) + return; + if (MATCH(".weightsystem.weight", weight, &dive->weightsystem[cur_ws_index].weight)) + return; + if (MATCH("weight", weight, &dive->weightsystem[cur_ws_index].weight)) return; - if (MATCH(".n2", gasmix_nitrogen, &dive->cylinder[cylinder_index].gasmix)) + if (MATCH(".o2", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.o2)) return; - if (MATCH(".he", gasmix, &dive->cylinder[cylinder_index].gasmix.he)) + if (MATCH(".n2", gasmix_nitrogen, &dive->cylinder[cur_cylinder_index].gasmix)) + return; + if (MATCH(".he", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.he)) return; nonmatch("dive", name, buf); } +/* We're in the top-level trip xml. Try to convert whatever value to a trip value */ +static void try_to_fill_trip(struct dive **divep, const char *name, char *buf) +{ + int len = strlen(name); + + start_match("trip", name, buf); + + struct dive *dive = *divep; + + if (MATCH(".date", divedate, &dive->when)) { + dive->when = utc_mktime(&cur_tm); + return; + } + if (MATCH(".location", utf8_string, &dive->location)) + return; + if (MATCH(".notes", utf8_string, &dive->notes)) + return; + + nonmatch("trip", name, buf); +} + /* * File boundaries are dive boundaries. But sometimes there are * multiple dives per file, so there can be other events too that @@ -1057,32 +1185,51 @@ static void try_to_fill_dive(struct dive **divep, const char *name, char *buf) */ static void dive_start(void) { - if (dive) + if (cur_dive) return; - dive = alloc_dive(); - memset(&tm, 0, sizeof(tm)); + cur_dive = alloc_dive(); + memset(&cur_tm, 0, sizeof(cur_tm)); } static void dive_end(void) { - if (!dive) + if (!cur_dive) + return; + record_dive(cur_dive); + cur_dive = NULL; + cur_cylinder_index = 0; + cur_ws_index = 0; +} + +static void trip_start(void) +{ + if (cur_trip) return; - record_dive(dive); - dive = NULL; - cylinder_index = 0; + cur_trip = alloc_dive(); + memset(&cur_tm, 0, sizeof(cur_tm)); +} + +static void trip_end(void) +{ + if (!cur_trip) + return; + record_trip(cur_trip); + cur_trip = NULL; } static void event_start(void) { - memset(&event, 0, sizeof(event)); - event.active = 1; + memset(&cur_event, 0, sizeof(cur_event)); + cur_event.active = 1; } static void event_end(void) { - if (event.name && strcmp(event.name, "surface") != 0) - add_event(dive, event.time.seconds, event.type, event.flags, event.value, event.name); - event.active = 0; + if (cur_event.name && strcmp(cur_event.name, "surface") != 0) + add_event(cur_dive, cur_event.time.seconds, + cur_event.type, cur_event.flags, + cur_event.value, cur_event.name); + cur_event.active = 0; } static void cylinder_start(void) @@ -1091,21 +1238,30 @@ static void cylinder_start(void) static void cylinder_end(void) { - cylinder_index++; + cur_cylinder_index++; +} + +static void ws_start(void) +{ +} + +static void ws_end(void) +{ + cur_ws_index++; } static void sample_start(void) { - sample = prepare_sample(&dive); + cur_sample = prepare_sample(&cur_dive); } static void sample_end(void) { - if (!dive) + if (!cur_dive) return; - finish_sample(dive, sample); - sample = NULL; + finish_sample(cur_dive); + cur_sample = NULL; } static void entry(const char *name, int size, const char *raw) @@ -1116,16 +1272,20 @@ static void entry(const char *name, int size, const char *raw) return; memcpy(buf, raw, size); buf[size] = 0; - if (event.active) { + if (cur_event.active) { try_to_fill_event(name, buf); return; } - if (sample) { - try_to_fill_sample(sample, name, buf); + if (cur_sample) { + try_to_fill_sample(cur_sample, name, buf); + return; + } + if (cur_trip) { + try_to_fill_trip(&cur_trip, name, buf); return; } - if (dive) { - try_to_fill_dive(&dive, name, buf); + if (cur_dive) { + try_to_fill_dive(&cur_dive, name, buf); return; } } @@ -1249,6 +1409,7 @@ static struct nesting { } nesting[] = { { "dive", dive_start, dive_end }, { "Dive", dive_start, dive_end }, + { "trip", trip_start, trip_end }, { "sample", sample_start, sample_end }, { "waypoint", sample_start, sample_end }, { "SAMPLE", sample_start, sample_end }, @@ -1256,6 +1417,7 @@ static struct nesting { { "event", event_start, event_end }, { "gasmix", cylinder_start, cylinder_end }, { "cylinder", cylinder_start, cylinder_end }, + { "weightsystem", ws_start, ws_end }, { "P", sample_start, sample_end }, /* Import type recognition */ @@ -1302,84 +1464,25 @@ static void reset_all(void) import_source = UNKNOWN; } -struct memblock { - void *buffer; - size_t size; -}; - -static int readfile(const char *filename, struct memblock *mem) -{ - int ret, fd = open(filename, O_RDONLY); - struct stat st; - - mem->buffer = NULL; - mem->size = 0; - - fd = open(filename, O_RDONLY); - if (fd < 0) - return fd; - ret = fstat(fd, &st); - if (ret < 0) - goto out; - ret = -EINVAL; - if (!S_ISREG(st.st_mode)) - goto out; - ret = 0; - if (!st.st_size) - goto out; - mem->buffer = malloc(st.st_size); - ret = -1; - errno = ENOMEM; - if (!mem->buffer) - goto out; - mem->size = st.st_size; - ret = read(fd, mem->buffer, mem->size); - if (ret < 0) - goto free; - if (ret == mem->size) - goto out; - errno = EIO; - ret = -1; -free: - free(mem->buffer); - mem->buffer = NULL; - mem->size = 0; -out: - close(fd); - return ret; -} - -void parse_xml_file(const char *filename, GError **error) +void parse_xml_buffer(const char *url, const char *buffer, int size, GError **error) { xmlDoc *doc; - struct memblock mem; - - if (readfile(filename, &mem) < 0) { - fprintf(stderr, "Failed to read '%s'.\n", filename); - if (error) { - *error = g_error_new(g_quark_from_string("subsurface"), - DIVE_ERROR_PARSE, - "Failed to read '%s'", - filename); - } - return; - } - doc = xmlReadMemory(mem.buffer, mem.size, filename, NULL, 0); + doc = xmlReadMemory(buffer, size, url, NULL, 0); if (!doc) { - fprintf(stderr, "Failed to parse '%s'.\n", filename); + fprintf(stderr, "Failed to parse '%s'.\n", url); if (error != NULL) { *error = g_error_new(g_quark_from_string("subsurface"), DIVE_ERROR_PARSE, "Failed to parse '%s'", - filename); + url); } return; } - /* we assume that the last (or only) filename passed as argument is a - * great filename to use as default when saving the dives */ - set_filename(filename); + /* we assume that the last (or only) filename passed as argument is a + * great filename to use as default when saving the dives */ + set_filename(url); reset_all(); dive_start(); #ifdef XSLT @@ -1424,7 +1527,11 @@ static xsltStylesheetPtr try_get_stylesheet(const char *path, int len, const cha static xsltStylesheetPtr get_stylesheet(const char *name) { - const char *path = xslt_path, *next; + const char *path, *next; + + path = getenv("SUBSURFACE_XSLT_PATH"); + if (!path) + path = xslt_path; do { int len;