]> git.tdb.fi Git - ext/subsurface.git/commitdiff
Merge branch 'testdata' of git://github.com/dirkhh/subsurface
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 9 Nov 2011 18:31:06 +0000 (12:31 -0600)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 9 Nov 2011 18:31:06 +0000 (12:31 -0600)
* 'testdata' of git://github.com/dirkhh/subsurface:
  Correctly plot dives ending below the surface

Makefile
dive.c
dive.h
divelist.c
equipment.c
packaging/debian/control
parse-xml.c
statistics.c

index 20cbf8a578ba6f2d6673a27799f34c33106a7461..1b1a31a8c6c4f18dedb59ad0201dcd57c62a1412 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,7 @@ CFLAGS=-Wall -Wno-pointer-sign -g
 INSTALL=install
 PKGCONFIG=pkg-config
 XML2CONFIG=xml2-config
+XSLCONFIG=xslt-config
 
 # these locations seem to work for SuSE and Fedora
 # prefix = $(HOME)
@@ -15,12 +16,14 @@ DESKTOPDIR = $(DATADIR)/applications
 ICONPATH = $(DATADIR)/icons/hicolor
 ICONDIR = $(ICONPATH)/scalable/apps
 MANDIR = $(DATADIR)/man/man1
+XSLTDIR = $(DATADIR)/subsurface/xslt
 gtk_update_icon_cache = gtk-update-icon-cache -f -t $(ICONPATH)
 
 NAME = subsurface
 ICONFILE = $(NAME).svg
 DESKTOPFILE = $(NAME).desktop
 MANFILES = $(NAME).1
+XSLTFILES = xslt/*.xslt
 
 MACOSXINSTALL = /Applications/Subsurface.app
 MACOSXFILES = packaging/macosx
@@ -77,7 +80,7 @@ LIBGTK = $(shell $(PKGCONFIG) --libs gtk+-2.0 glib-2.0 gconf-2.0)
 LIBDIVECOMPUTERCFLAGS = $(LIBDIVECOMPUTERINCLUDES)
 LIBDIVECOMPUTER = $(LIBDIVECOMPUTERARCHIVE) $(LIBUSB)
 
-LIBS = $(LIBXML2) $(LIBGTK) $(LIBDIVECOMPUTER) -lpthread
+LIBS = $(LIBXML2) $(LIBXSLT) $(LIBGTK) $(LIBDIVECOMPUTER) -lpthread
 
 OBJS = main.o dive.o profile.o info.o equipment.o divelist.o \
        parse-xml.o save-xml.o libdivecomputer.o print.o uemis.o \
@@ -98,12 +101,26 @@ install: $(NAME)
        fi
        $(INSTALL) -d -m 755 $(MANDIR)
        $(INSTALL) -m 644 $(MANFILES) $(MANDIR)
+       @-if test ! -z "$(XSLT)"; then \
+               $(INSTALL) -d -m 755 $(DATADIR)/subsurface; \
+               $(INSTALL) -d -m 755 $(XSLTDIR); \
+               $(INSTALL) -m 644 $(XSLTFILES) $(XSLTDIR); \
+       fi
 
 LIBXML2 = $(shell $(XML2CONFIG) --libs)
+LIBXSLT = $(shell $(XSLCONFIG) --libs)
 XML2CFLAGS = $(shell $(XML2CONFIG) --cflags)
 GLIB2CFLAGS = $(shell $(PKGCONFIG) --cflags glib-2.0)
 GCONF2CFLAGS =  $(shell $(PKGCONFIG) --cflags gconf-2.0)
 GTK2CFLAGS = $(shell $(PKGCONFIG) --cflags gtk+-2.0)
+CFLAGS += $(shell $(XSLCONFIG) --cflags)
+
+ifneq ($(strip $(LIBXSLT)),)
+       # We still need proper paths and install options for OSX and Windows
+       ifeq ($(shell sh -c 'uname -s 2>/dev/null || echo not'),Linux)
+               XSLT=-DXSLT='"$(XSLTDIR)"'
+       endif
+endif
 
 install-macosx: $(NAME)
        $(INSTALL) -d -m 755 $(MACOSXINSTALL)/Contents/Resources
@@ -116,7 +133,7 @@ install-macosx: $(NAME)
        $(INSTALL) $(MACOSXFILES)/Subsurface.icns $(MACOSXINSTALL)/Contents/Resources/
 
 parse-xml.o: parse-xml.c dive.h
-       $(CC) $(CFLAGS) $(GLIB2CFLAGS) -c $(XML2CFLAGS)  parse-xml.c
+       $(CC) $(CFLAGS) $(GLIB2CFLAGS) -c $(XML2CFLAGS) $(XSLT) parse-xml.c
 
 save-xml.o: save-xml.c dive.h
        $(CC) $(CFLAGS) $(GLIB2CFLAGS) -c save-xml.c
diff --git a/dive.c b/dive.c
index cb94e7925ce01695659ac1c5de33da192e77ef30..bd1b92619198851b6bdc3f70b162c75f3af7cc48 100644 (file)
--- a/dive.c
+++ b/dive.c
@@ -207,46 +207,21 @@ static void update_temperature(temperature_t *temperature, int new)
        }
 }
 
-/*
- * If you have more than 32 cylinders, you'd better have a 64-bit build.
- * And if you have more than 64 cylinders, you need to use another tool,
- * or fix this up to do something odd.
- */
-static unsigned long fixup_pressure(struct dive *dive, struct sample *sample, unsigned long flags)
+static void fixup_pressure(struct dive *dive, struct sample *sample)
 {
-       unsigned long mask;
        unsigned int pressure, index;
        cylinder_t *cyl;
 
        pressure = sample->cylinderpressure.mbar;
        if (!pressure)
-               return flags;
+               return;
        index = sample->cylinderindex;
        if (index >= MAX_CYLINDERS)
-               return flags;
+               return;
        cyl = dive->cylinder + index;
-       if (!cyl->start.mbar)
-               cyl->start.mbar = pressure;
-       /*
-        * If we already have an end pressure, without
-        * ever having seen a sample for this cylinder,
-        * that means that somebody set the end pressure
-        * by hand
-        */
-       mask = 1ul << index;
-       if (cyl->end.mbar) {
-               if (!(flags & mask))
-                       return flags;
-       }
-       flags |= mask;
-
-       /* we need to handle the user entering beginning and end tank pressures
-        * - maybe even IF we have samples. But for now if we have air pressure
-        * data in the samples, we use that instead of the minimum
-        * if (!cyl->end.mbar || pressure < cyl->end.mbar)
-        */
-       cyl->end.mbar = pressure;
-       return flags;
+       if (!cyl->sample_start.mbar)
+               cyl->sample_start.mbar = pressure;
+       cyl->sample_end.mbar = pressure;
 }
 
 struct dive *fixup_dive(struct dive *dive)
@@ -258,7 +233,6 @@ struct dive *fixup_dive(struct dive *dive)
        int maxdepth = 0, mintemp = 0;
        int lastdepth = 0;
        int lasttemp = 0;
-       unsigned long flags = 0;
 
        for (i = 0; i < dive->samples; i++) {
                struct sample *sample = dive->sample + i;
@@ -276,7 +250,7 @@ struct dive *fixup_dive(struct dive *dive)
                                maxdepth = depth;
                }
 
-               flags = fixup_pressure(dive, sample, flags);
+               fixup_pressure(dive, sample);
 
                if (temp) {
                        /*
@@ -311,8 +285,12 @@ struct dive *fixup_dive(struct dive *dive)
        add_people(dive->divemaster);
        add_location(dive->location);
        for (i = 0; i < MAX_CYLINDERS; i++) {
-               cylinder_type_t *type = &dive->cylinder[i].type;
-               add_cylinder_description(type);
+               cylinder_t *cyl = dive->cylinder + i;
+               add_cylinder_description(&cyl->type);
+               if (cyl->sample_start.mbar == cyl->start.mbar)
+                       cyl->start.mbar = 0;
+               if (cyl->sample_end.mbar == cyl->end.mbar)
+                       cyl->end.mbar = 0;
        }
 
        return dive;
diff --git a/dive.h b/dive.h
index cf11e1f89384bb34176e9eb5c14879cb89f73be1..0116a1cf78a3d07ac4da2ccbe725de15f7e35d9e 100644 (file)
--- a/dive.h
+++ b/dive.h
@@ -5,6 +5,7 @@
 #include <time.h>
 
 #include <glib.h>
+#include <libxml/tree.h>
 
 /*
  * Some silly typedefs to make our units very explicit.
@@ -83,7 +84,7 @@ typedef struct {
 typedef struct {
        cylinder_type_t type;
        struct gasmix gasmix;
-       pressure_t start, end;
+       pressure_t start, end, sample_start, sample_end;
 } cylinder_t;
 
 extern int get_pressure_units(unsigned int mb, const char **units);
@@ -253,6 +254,10 @@ extern void parse_xml_init(void);
 extern void parse_xml_file(const char *filename, GError **error);
 extern void set_filename(const char *filename);
 
+#ifdef XSLT
+extern xmlDoc *test_xslt_transforms(xmlDoc *doc);
+#endif
+
 extern void show_dive_info(struct dive *);
 extern void flush_dive_info_changes(struct dive *);
 
index 2d04eb5b09e4469f13ad5029b6838294497a6d2a..eb8f231432a99f33f40a8ca0341aee8a66b14148 100644 (file)
@@ -299,6 +299,7 @@ static double calculate_airuse(struct dive *dive)
        int i;
 
        for (i = 0; i < MAX_CYLINDERS; i++) {
+               pressure_t start, end;
                cylinder_t *cyl = dive->cylinder + i;
                int size = cyl->type.size.mliter;
                double kilo_atm;
@@ -306,7 +307,9 @@ static double calculate_airuse(struct dive *dive)
                if (!size)
                        continue;
 
-               kilo_atm = (to_ATM(cyl->start) - to_ATM(cyl->end)) / 1000.0;
+               start = cyl->start.mbar ? cyl->start : cyl->sample_start;
+               end = cyl->end.mbar ? cyl->end : cyl->sample_end;
+               kilo_atm = (to_ATM(start) - to_ATM(end)) / 1000.0;
 
                /* Liters of air at 1 atm == milliliters at 1k atm*/
                airuse += kilo_atm * size;
index c7a683b898a9a391547219bda9c1bba717f4e921..19abbe67294c7c6fea26f9b708c7bf3a95a761fe 100644 (file)
@@ -45,7 +45,8 @@ struct cylinder_widget {
        const char *name;
        GtkWidget *hbox;
        GtkComboBox *description;
-       GtkSpinButton *size, *pressure, *start, *end;
+       GtkSpinButton *size, *pressure;
+       GtkWidget *start, *end, *pressure_button;
        GtkWidget *o2, *gasmix_button;
 };
 
@@ -71,12 +72,12 @@ static int convert_volume_pressure(int ml, int mbar, double *v, double *p)
        int decimals = 1;
        double volume, pressure;
 
+       volume = ml / 1000.0;
        if (mbar) {
                if (output_units.volume == CUFT) {
                        volume = ml_to_cuft(ml);
                        volume *= bar_to_atm(mbar / 1000.0);
-               } else
-                       volume = ml / 1000.0;
+               }
 
                if (output_units.pressure == PSI) {
                        pressure = mbar_to_PSI(mbar);
@@ -98,14 +99,27 @@ static void set_cylinder_type_spinbuttons(struct cylinder_widget *cylinder, int
        gtk_spin_button_set_value(cylinder->pressure, pressure);
 }
 
-static void set_cylinder_pressure_spinbuttons(struct cylinder_widget *cylinder, int start, int end)
+static void set_cylinder_pressure_spinbuttons(struct cylinder_widget *cylinder, cylinder_t *cyl)
 {
+       int set;
+       unsigned int start, end;
        double pressure;
 
+       start = cyl->start.mbar;
+       end = cyl->end.mbar;
+       set = start || end;
+       if (!set) {
+               start = cyl->sample_start.mbar;
+               end = cyl->sample_end.mbar;
+       }
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cylinder->pressure_button), set);
+       gtk_widget_set_sensitive(cylinder->start, set);
+       gtk_widget_set_sensitive(cylinder->end, set);
+
        convert_pressure(start, &pressure);
-       gtk_spin_button_set_value(cylinder->start, pressure);
+       gtk_spin_button_set_value(GTK_SPIN_BUTTON(cylinder->start), pressure);
        convert_pressure(end, &pressure);
-       gtk_spin_button_set_value(cylinder->end, pressure);
+       gtk_spin_button_set_value(GTK_SPIN_BUTTON(cylinder->end), pressure);
 }
 
 /*
@@ -266,8 +280,7 @@ static void show_cylinder(cylinder_t *cyl, struct cylinder_widget *cylinder)
 
        set_cylinder_type_spinbuttons(cylinder,
                cyl->type.size.mliter, cyl->type.workingpressure.mbar);
-       set_cylinder_pressure_spinbuttons(cylinder,
-               cyl->start.mbar, cyl->end.mbar);
+       set_cylinder_pressure_spinbuttons(cylinder, cyl);
        o2 = cyl->gasmix.o2.permille / 10.0;
        gtk_widget_set_sensitive(cylinder->o2, !!o2);
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cylinder->gasmix_button), !!o2);
@@ -283,18 +296,24 @@ static int cyl_nothing(cylinder_t *cyl)
                !cyl->type.description &&
                !cyl->gasmix.o2.permille &&
                !cyl->gasmix.he.permille &&
+               !cyl->sample_start.mbar &&
+               !cyl->sample_end.mbar &&
                !cyl->start.mbar &&
                !cyl->end.mbar;
 }
 
 static void set_one_cylinder(int index, cylinder_t *cyl, GtkListStore *model, GtkTreeIter *iter)
 {
+       unsigned int start, end;
+
+       start = cyl->start.mbar ? : cyl->sample_start.mbar;
+       end = cyl->end.mbar ? : cyl->sample_end.mbar;
        gtk_list_store_set(model, iter,
                CYL_DESC, cyl->type.description ? : "",
                CYL_SIZE, cyl->type.size.mliter,
                CYL_WORKP, cyl->type.workingpressure.mbar,
-               CYL_STARTP, cyl->start.mbar,
-               CYL_ENDP, cyl->end.mbar,
+               CYL_STARTP, start,
+               CYL_ENDP, end,
                CYL_O2, cyl->gasmix.o2.permille,
                CYL_HE, cyl->gasmix.he.permille,
                -1);
@@ -397,8 +416,10 @@ static void record_cylinder_changes(cylinder_t *cyl, struct cylinder_widget *cyl
        desc = gtk_combo_box_get_active_text(box);
        volume = gtk_spin_button_get_value(cylinder->size);
        pressure = gtk_spin_button_get_value(cylinder->pressure);
-       start = gtk_spin_button_get_value(cylinder->start);
-       end = gtk_spin_button_get_value(cylinder->end);
+       start = gtk_spin_button_get_value(GTK_SPIN_BUTTON(cylinder->start));
+       end = gtk_spin_button_get_value(GTK_SPIN_BUTTON(cylinder->end));
+       if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cylinder->pressure_button)))
+               start = end = 0;
        o2 = gtk_spin_button_get_value(GTK_SPIN_BUTTON(cylinder->o2))*10 + 0.5;
        if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cylinder->gasmix_button)))
                o2 = 0;
@@ -490,6 +511,16 @@ static void nitrox_cb(GtkToggleButton *button, gpointer data)
        gtk_widget_set_sensitive(cylinder->o2, state);
 }
 
+static void pressure_cb(GtkToggleButton *button, gpointer data)
+{
+       struct cylinder_widget *cylinder = data;
+       int state;
+
+       state = gtk_toggle_button_get_active(button);
+       gtk_widget_set_sensitive(cylinder->start, state);
+       gtk_widget_set_sensitive(cylinder->end, state);
+}
+
 static gboolean completion_cb(GtkEntryCompletion *widget, GtkTreeModel *model, GtkTreeIter *iter, struct cylinder_widget *cylinder)
 {
        const char *desc;
@@ -553,11 +584,15 @@ static void cylinder_widget(GtkWidget *vbox, struct cylinder_widget *cylinder, G
        hbox = gtk_hbox_new(FALSE, 3);
        gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
 
+       cylinder->pressure_button = gtk_check_button_new();
+       gtk_box_pack_start(GTK_BOX(hbox), cylinder->pressure_button, FALSE, FALSE, 3);
+       g_signal_connect(cylinder->pressure_button, "toggled", G_CALLBACK(pressure_cb), cylinder);
+
        widget = create_spinbutton(hbox, "Start Pressure", 0, 5000, 1);
-       cylinder->start = GTK_SPIN_BUTTON(widget);
+       cylinder->start = widget;
 
        widget = create_spinbutton(hbox, "End Pressure", 0, 5000, 1);
-       cylinder->end = GTK_SPIN_BUTTON(widget);
+       cylinder->end = widget;
 
        /*
         * Cylinder gas mix: Air, Nitrox or Trimix
index 7c2aa36e25cb3f137446f31d7c62ed9cb1317b92..b90fe1cbe3a232e7d0246277b59ea6105b41ca2c 100644 (file)
@@ -2,7 +2,8 @@ Source: subsurface
 Priority: optional
 Maintainer: Roland Dreier <roland@digitalvampire.org>
 Build-Depends: autoconf, automake, libtool, debhelper (>= 8), dh-autoreconf,
- pkg-config, libgtk2.0-dev, libgconf2-dev, libxml2-dev, libdivecomputer-dev
+ pkg-config, libgtk2.0-dev, libgconf2-dev, libxml2-dev, libdivecomputer-dev,
+ libxslt-dev
 Standards-Version: 3.9.2
 Section: utils
 Homepage: http://subsurface.hohndel.org
index 5eabc353c17c47e4e68db5e0db2ded912f2b1437..bc4d4c54661aeb1db4d2462e49625ce8b5997174 100644 (file)
@@ -3,10 +3,14 @@
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <unistd.h>
 #define __USE_XOPEN
 #include <time.h>
 #include <libxml/parser.h>
 #include <libxml/tree.h>
+#ifdef XSLT
+#include <libxslt/transform.h>
+#endif
 
 #include "dive.h"
 #include "uemis.h"
@@ -1466,6 +1470,9 @@ void parse_xml_file(const char *filename, GError **error)
        set_filename(filename);
        reset_all();
        dive_start();
+#ifdef XSLT
+       doc = test_xslt_transforms(doc);
+#endif
        traverse(xmlDocGetRootElement(doc));
        dive_end();
        xmlFreeDoc(doc);
@@ -1476,3 +1483,70 @@ void parse_xml_init(void)
 {
        LIBXML_TEST_VERSION
 }
+
+#ifdef XSLT
+
+/* Maybe we'll want a environment variable that can override this.. */
+static const char *xslt_path = XSLT ":xslt:.";
+
+static xsltStylesheetPtr try_get_stylesheet(const char *path, int len, const char *name)
+{
+       xsltStylesheetPtr ret;
+       int namelen = strlen(name);
+       char *filename = malloc(len+1+namelen+1);
+
+       if (!filename)
+               return NULL;
+
+       memcpy(filename, path, len);
+       filename[len] = G_DIR_SEPARATOR;
+       memcpy(filename + len + 1, name, namelen+1);
+
+       ret = NULL;
+       if (!access(filename, R_OK))
+               ret = xsltParseStylesheetFile(filename);
+       free(filename);
+
+       return ret;
+}
+
+static xsltStylesheetPtr get_stylesheet(const char *name)
+{
+       const char *path = xslt_path, *next;
+
+       do {
+               int len;
+               xsltStylesheetPtr ret;
+
+               next = strchr(path, ':');
+               len = strlen(path);
+               if (next) {
+                       len = next - path;
+                       next++;
+               }
+               ret = try_get_stylesheet(path, len, name);
+               if (ret)
+                       return ret;
+       } while ((path = next) != NULL);
+
+       return NULL;
+}
+
+xmlDoc *test_xslt_transforms(xmlDoc *doc)
+{
+       xmlDoc *transformed;
+       xsltStylesheetPtr xslt = NULL;
+       xmlNode *root_element = xmlDocGetRootElement(doc);
+       if (strcasecmp(root_element->name, "JDiveLog") == 0) {
+               xmlSubstituteEntitiesDefault(1);
+               xslt = get_stylesheet("jdivelog2subsurface.xslt");
+               if (xslt == NULL)
+                       return doc;
+               transformed = xsltApplyStylesheet(xslt, doc, NULL);
+               xmlFreeDoc(doc);
+               xsltFreeStylesheet(xslt);
+               return transformed;
+       }
+       return doc;
+}
+#endif
index d714220430aa0febabc074cfa2b76d62ef414b26..4c637944329f8e3bea52257909c6f7f666acca16 100644 (file)
@@ -125,10 +125,18 @@ void show_dive_stats(struct dive *dive)
        const char *unit;
        int idx, offset, gas_used;
        struct dive *prev_dive;
+       struct tm *tm;
 
        process_all_dives(dive, &prev_dive);
 
-       strftime(buf, 80, "%a, %b %d, %Y, %k:%M", gmtime(&dive->when));
+       tm = gmtime(&dive->when);
+       snprintf(buf, sizeof(buf),
+               "%s, %s %d, %d %2d:%02d",
+               weekday(tm->tm_wday),
+               monthname(tm->tm_mon),
+               tm->tm_mday, tm->tm_year + 1900,
+               tm->tm_hour, tm->tm_min);
+
        set_label(info_stat_w.date, buf);
        set_label(info_stat_w.dive_time, "%d min", (dive->duration.seconds + 30) / 60);
        if (prev_dive)
@@ -157,11 +165,14 @@ void show_dive_stats(struct dive *dive)
        /* for the O2/He readings just create a list of them */
        for (idx = 0; idx < MAX_CYLINDERS; idx++) {
                cylinder_t *cyl = &dive->cylinder[idx];
+               unsigned int start, end;
+
+               start = cyl->start.mbar ? : cyl->sample_start.mbar;
+               end = cyl->end.mbar ? : cyl->sample_end.mbar;
                /* we assume that every valid cylinder has either a working pressure
                 * or a size; but for good measure let's also accept cylinders with
                 * a starting or ending pressure*/
-               if (cyl->type.workingpressure.mbar || cyl->type.size.mliter ||
-                       cyl->start.mbar || cyl->end.mbar) {
+               if (cyl->type.workingpressure.mbar || cyl->type.size.mliter || start || end) {
                        /* 0% O2 strangely means air, so 21% - I don't like that at all */
                        int o2 = cyl->gasmix.o2.permille ? : 209;
                        if (offset > 0) {
@@ -174,9 +185,8 @@ void show_dive_stats(struct dive *dive)
                }
                /* and if we have size, start and end pressure, we can
                 * calculate the total gas used */
-               if (cyl->type.size.mliter && cyl->start.mbar && cyl->end.mbar)
-                       gas_used += cyl->type.size.mliter / 1000.0 *
-                               (cyl->start.mbar - cyl->end.mbar);
+               if (cyl->type.size.mliter && start && end)
+                       gas_used += cyl->type.size.mliter / 1000.0 * (start - end);
        }
        set_label(info_stat_w.o2he, buf);
        if (gas_used) {