]> git.tdb.fi Git - ext/subsurface.git/blobdiff - parse-xml.c
Fix profile and average depth for freedives
[ext/subsurface.git] / parse-xml.c
index cc2d0076d42f36491d6ce6809a12056a68067d8a..5159a334f9153f65b010f0e1cf5c4845cebcf530 100644 (file)
@@ -4,8 +4,6 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
 #define __USE_XOPEN
 #include <time.h>
 #include <libxml/parser.h>
@@ -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,7 +161,7 @@ const struct units IMPERIAL_units = {
 /*
  * Dive info as it is being built up..
  */
-static struct dive *cur_dive;
+static struct dive *cur_dive, *cur_trip = NULL;
 static struct sample *cur_sample;
 static struct {
        int active;
@@ -107,7 +170,7 @@ static struct {
        const char *name;
 } cur_event;
 static struct tm cur_tm;
-static int cur_cylinder_index;
+static int cur_cylinder_index, cur_ws_index;
 
 static enum import_source {
        UNKNOWN,
@@ -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;
@@ -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;
 }
 
@@ -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))
@@ -1038,7 +1140,12 @@ static void try_to_fill_dive(struct dive **divep, const char *name, char *buf)
                return;
        if (MATCH(".cylinder.end", pressure, &dive->cylinder[cur_cylinder_index].end))
                return;
-
+       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(".o2", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.o2))
                return;
        if (MATCH(".n2", gasmix_nitrogen, &dive->cylinder[cur_cylinder_index].gasmix))
@@ -1049,6 +1156,27 @@ static void try_to_fill_dive(struct dive **divep, const char *name, char *buf)
        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
@@ -1070,6 +1198,23 @@ static void dive_end(void)
        record_dive(cur_dive);
        cur_dive = NULL;
        cur_cylinder_index = 0;
+       cur_ws_index = 0;
+}
+
+static void trip_start(void)
+{
+       if (cur_trip)
+               return;
+       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)
@@ -1096,6 +1241,15 @@ static void cylinder_end(void)
        cur_cylinder_index++;
 }
 
+static void ws_start(void)
+{
+}
+
+static void ws_end(void)
+{
+       cur_ws_index++;
+}
+
 static void sample_start(void)
 {
        cur_sample = prepare_sample(&cur_dive);
@@ -1126,6 +1280,10 @@ static void entry(const char *name, int size, const char *raw)
                try_to_fill_sample(cur_sample, name, buf);
                return;
        }
+       if (cur_trip) {
+               try_to_fill_trip(&cur_trip, name, buf);
+               return;
+       }
        if (cur_dive) {
                try_to_fill_dive(&cur_dive, name, buf);
                return;
@@ -1251,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 },
@@ -1258,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 */
@@ -1304,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
@@ -1426,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;