[PATCH] Added import for Liquivision LVD log files

Henrik Brautaset Aronsen subsurface at henrik.synth.no
Fri Nov 7 09:24:50 PST 2014


One more thing.  If I first import "stig dykker logg.lvd" that I sent you,
then click on a dive or three,  and then import "griffon.lvd", Subsurface
crashes:

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   org.hohndel.subsurface         0x00000001000157a7
try_to_open_liquivision + 3895
1   org.hohndel.subsurface         0x0000000100010fde parse_file + 1358
2   org.hohndel.subsurface         0x000000010007be3c
MainWindow::importFiles(QStringList) + 300
3   org.hohndel.subsurface         0x000000010007c4e3
MainWindow::on_actionImportDiveLog_triggered() + 931
4   org.hohndel.subsurface         0x0000000100131310
MainWindow::qt_metacall(QMetaObject::Call, int, void**) + 80
5   QtCore                         0x00000001034faf86
QMetaObject::activate(QObject*, int, int, void**) + 2374
6   QtWidgets                     0x0000000103e6faef
QAction::activate(QAction::ActionEvent) + 271
7   QtWidgets                     0x0000000103e6ff54
QAction::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) + 404
8   QtCore                         0x00000001034fb015
QMetaObject::activate(QObject*, int, int, void**) + 2517
9   libqcocoa.dylib               0x00000001069ec310 -[QCocoaMenuDelegate
itemFired:] + 112
10  libsystem_trace.dylib         0x00007fff8b09ccd7 _os_activity_initiate
+ 75
11  com.apple.AppKit               0x00007fff91c6b5e7 -[NSApplication
sendAction:to:from:] + 410
12  com.apple.AppKit               0x00007fff91c8572a -[NSMenuItem
_corePerformAction] + 382
13  com.apple.AppKit               0x00007fff91c85447 -[NSCarbonMenuImpl
performActionWithHighlightingForItemAtIndex:] + 114
14  libsystem_trace.dylib         0x00007fff8b09ccd7 _os_activity_initiate
+ 75
15  com.apple.AppKit               0x00007fff91cd2ce6 -[NSMenu
performActionForItemAtIndex:] + 131
16  com.apple.AppKit               0x00007fff91cd2c56 -[NSMenu
_internalPerformActionForItemAtIndex:] + 35
17  com.apple.AppKit               0x00007fff91cd2aa2 -[NSCarbonMenuImpl
_carbonCommandProcessEvent:handlerCallRef:] + 107
18  com.apple.AppKit               0x00007fff91c7b03b NSSLMMenuEventHandler
+ 724
19  com.apple.HIToolbox           0x00007fff925c232c
DispatchEventToHandlers(EventTargetRec*, OpaqueEventRef*, HandlerCallRec*)
+ 1260
20  com.apple.HIToolbox           0x00007fff925c176e
SendEventToEventTargetInternal(OpaqueEventRef*, OpaqueEventTargetRef*,
HandlerCallRec*) + 386
21  com.apple.HIToolbox           0x00007fff925d6286 SendEventToEventTarget
+ 40
22  com.apple.HIToolbox           0x00007fff9260b795
SendHICommandEvent(unsigned int, HICommand const*, unsigned int, unsigned
int, unsigned char, void const*, OpaqueEventTargetRef*,
OpaqueEventTargetRef*, OpaqueEventRef**) + 428
23  com.apple.HIToolbox           0x00007fff9263ee8d
SendMenuCommandWithContextAndModifiers + 59
24  com.apple.HIToolbox           0x00007fff9263ee34
SendMenuItemSelectedEvent + 188
25  com.apple.HIToolbox           0x00007fff9263ed06
FinishMenuSelection(SelectionData*, MenuResult*, MenuResult*) + 96
26  com.apple.HIToolbox           0x00007fff926468b1
MenuSelectCore(MenuData*, Point, double, unsigned int, OpaqueMenuRef**,
unsigned short*) + 702
27  com.apple.HIToolbox           0x00007fff9264649e _HandleMenuSelection2
+ 446
28  com.apple.AppKit               0x00007fff91c00e6e
_NSHandleCarbonMenuEvent + 277
29  com.apple.AppKit               0x00007fff91a9cb90 _DPSNextEvent + 1843
30  com.apple.AppKit               0x00007fff91a9bfd0 -[NSApplication
nextEventMatchingMask:untilDate:inMode:dequeue:] + 194
31  com.apple.AppKit               0x00007fff91a8ff73 -[NSApplication run]
+ 594
32  libqcocoa.dylib               0x00000001069e891d
QCocoaEventDispatcher::processEvents(QFlags<QEventLoop::ProcessEventsFlag>)
+ 2189
33  QtCore                         0x00000001034c565d
QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 381
34  QtCore                         0x00000001034c863c
QCoreApplication::exec() + 364
35  org.hohndel.subsurface         0x0000000100018d42 main + 1698
36  org.hohndel.subsurface         0x0000000100006894 start + 52


Henrik

On Fri, Nov 7, 2014 at 6:18 PM, Henrik Brautaset Aronsen <
subsurface at henrik.synth.no> wrote:

> It works fine with the files I tried.  Just a couple of things:
>
> I think you need to add ...
>
>   extern int try_to_open_liquivision(const char *filename, struct memblock
> *mem);
>
> ... in file.h, my compiler complains:
>
>   file.c:361:10: warning: implicit declaration of function
> 'try_to_open_liquivision' is invalid in C99.
>
> Also, there seems to be a = vs == problem in:
>
>   liquivision.c:225:23: note: use '=' to turn this equality comparison
> into an assignment
>     sample->depth.mm == array_uint16_le(ds + (d - 1) * 2) * 10; // cm->mm
>
>
> Henrik
>
>
>
> On Fri, Nov 7, 2014 at 6:10 PM, Henrik Brautaset Aronsen <
> subsurface at henrik.synth.no> wrote:
> >
> > Great work!
> >
> > H
> >
> > On Fri, Nov 7, 2014 at 5:30 PM, John Van Ostrand <john at vanostrand.com>
> wrote:
> >>
> >> Support includes cylinder pressures and works for v3.0 log files.
> >> ---
> >>  CMakeLists.txt       |   1 +
> >>  file.c               |   2 +
> >>  liquivision.c        | 352
> +++++++++++++++++++++++++++++++++++++++++++++++++++
> >>  qt-ui/mainwindow.cpp |   8 +-
> >>  subsurface.pro       |   1 +
> >>  5 files changed, 361 insertions(+), 3 deletions(-)
> >>  create mode 100644 liquivision.c
> >>
> >> diff --git a/CMakeLists.txt b/CMakeLists.txt
> >> index c04e968..868ad4f 100644
> >> --- a/CMakeLists.txt
> >> +++ b/CMakeLists.txt
> >> @@ -85,6 +85,7 @@ SET(SUBSURFACE_CORE_LIB_SRCS
> >>         equipment.c
> >>         file.c
> >>         libdivecomputer.c
> >> +       liquivision.c
> >>         load-git.c
> >>         membuffer.c
> >>         parse-xml.c
> >> diff --git a/file.c b/file.c
> >> index bab7909..dadc11f 100644
> >> --- a/file.c
> >> +++ b/file.c
> >> @@ -357,6 +357,8 @@ static int open_by_filename(const char *filename,
> const char *fmt, struct memblo
> >>         /* Cochran export comma-separated-value files */
> >>         if (!strcasecmp(fmt, "DPT"))
> >>                 return try_to_open_csv(filename, mem, CSV_DEPTH);
> >> +       if (!strcasecmp(fmt, "LVD"))
> >> +               return try_to_open_liquivision(filename, mem);
> >>         if (!strcasecmp(fmt, "TMP"))
> >>                 return try_to_open_csv(filename, mem, CSV_TEMP);
> >>         if (!strcasecmp(fmt, "HP1"))
> >> diff --git a/liquivision.c b/liquivision.c
> >> new file mode 100644
> >> index 0000000..bb71bfd
> >> --- /dev/null
> >> +++ b/liquivision.c
> >> @@ -0,0 +1,352 @@
> >> +#include <string.h>
> >> +
> >> +#include "dive.h"
> >> +#include "divelist.h"
> >> +#include "file.h"
> >> +
> >> +
> >> +// Convert bytes into an INT
> >> +#define array_uint16_le(p) ((unsigned int) (p)[0] \
> >> +                                                       + ((p)[1]<<8) )
> >> +#define array_uint32_le(p) ((unsigned int) (p)[0] \
> >> +                                                       + ((p)[1]<<8) +
> ((p)[2]<<16) \
> >> +                                                       + ((p)[3]<<24))
> >> +
> >> +
> >> +static void
> >> +parse_dives (int log_version, const unsigned char *buf, unsigned int
> buf_size) {
> >> +       unsigned int ptr = 0;
> >> +       unsigned char model;
> >> +
> >> +       struct dive *dive;
> >> +       struct divecomputer *dc;
> >> +       struct sample *sample;
> >> +
> >> +       while (ptr < buf_size) {
> >> +               dive = alloc_dive();
> >> +               dc = &dive->dc;
> >> +
> >> +               // Model 0=Xen, 1,2=Xeo, 4=Lynx, other=Liquivision
> >> +               model = *(buf + ptr);
> >> +               switch (model) {
> >> +               case 0:
> >> +                       dc->model = "Xen";
> >> +                       break;
> >> +               case 1:
> >> +               case 2:
> >> +                       dc->model = "Xeo";
> >> +                       break;
> >> +               case 4:
> >> +                       dc->model = "Lynx";
> >> +                       break;
> >> +               default:
> >> +                       dc->model = "LiquiVision";
> >> +                       break;
> >> +               }
> >> +               ptr++;
> >> +
> >> +               // Dive location, assemble Location and Place
> >> +               unsigned int len, place_len;
> >> +               len = array_uint32_le(buf + ptr);
> >> +               ptr += 4;
> >> +               place_len = array_uint32_le(buf + ptr + len);
> >> +
> >> +               if (len && place_len) {
> >> +                       dive->location = malloc(len + place_len + 4);
> >> +                       memset(dive->location, 0, len + place_len + 4);
> >> +                       memcpy(dive->location, buf + ptr, len);
> >> +                       memcpy(dive->location + len, ", ", 2);
> >> +                       memcpy(dive->location + len + 2, buf + ptr +
> len + 4, place_len);
> >> +               } else if (len) {
> >> +                       dive->location = strndup(buf + ptr, len);
> >> +               } else if (place_len) {
> >> +                       dive->location = strndup(buf + ptr + len + 4,
> place_len);
> >> +               }
> >> +
> >> +               ptr += len + 4 + place_len;
> >> +
> >> +               // Dive comment
> >> +               len = array_uint32_le(buf + ptr);
> >> +               ptr += 4;
> >> +
> >> +               // Blank notes are better than the default text
> >> +               if (len && strncmp(buf + ptr, "Comment ...", 11)) {
> >> +                       dive->notes = strndup(buf + ptr, len);
> >> +               }
> >> +               ptr += len;
> >> +
> >> +               dive->id = array_uint32_le(buf + ptr);
> >> +               ptr += 4;
> >> +
> >> +               dive->number = array_uint16_le(buf + ptr) + 1;
> >> +               ptr += 2;
> >> +
> >> +               dive->duration.seconds = array_uint32_le(buf + ptr);
>  // seconds
> >> +               ptr += 4;
> >> +
> >> +               dive->maxdepth.mm = array_uint16_le(buf + ptr) * 10;
>  // cm->mm
> >> +               ptr += 2;
> >> +
> >> +               dive->meandepth.mm = array_uint16_le(buf + ptr) * 10;
>   // cm->mm
> >> +               ptr += 2;
> >> +
> >> +               dive->when = array_uint32_le(buf + ptr);
> >> +               ptr += 4;
> >> +
> >> +               //unsigned int end_time = array_uint32_le(buf + ptr);
> >> +               ptr += 4;
> >> +
> >> +               //unsigned int sit = array_uint32_le(buf + ptr);
> >> +               ptr += 4;
> >> +               //if (sit == 0xffffffff) {
> >> +               //}
> >> +
> >> +               dive->surface_pressure.mbar = array_uint16_le(buf +
> ptr);               // ???
> >> +               ptr += 2;
> >> +
> >> +               //unsigned int rep_dive = array_uint16_le(buf + ptr);
> >> +               ptr += 2;
> >> +
> >> +               dive->mintemp.mkelvin =
>  C_to_mkelvin((float)array_uint16_le(buf + ptr)/10);// C->mK
> >> +               ptr += 2;
> >> +
> >> +               dive->maxtemp.mkelvin =
>  C_to_mkelvin((float)array_uint16_le(buf + ptr)/10);// C->mK
> >> +               ptr += 2;
> >> +
> >> +               dive->salinity = *(buf + ptr);  // ???
> >> +               ptr += 1;
> >> +
> >> +               unsigned int sample_count = array_uint32_le(buf + ptr);
> >> +               ptr += 4;
> >> +
> >> +               // Sample interval
> >> +               unsigned char sample_interval;
> >> +               sample_interval = 1;
> >> +
> >> +               unsigned char intervals[6] = {1,2,5,10,30,60};
> >> +               if (*(buf + ptr) < 6)
> >> +                       sample_interval = intervals[*(buf + ptr)];
> >> +               ptr += 1;
> >> +
> >> +               float start_cns = 0;
> >> +               unsigned char dive_mode = 0, algorithm = 0;
> >> +               if (array_uint32_le(buf + ptr) != sample_count) {
> >> +                       // Xeo, with CNS and OTU
> >> +                       start_cns = *(float *) (buf + ptr);
> >> +                       ptr += 4;
> >> +                       dive->cns = *(float *) (buf + ptr);     // end
> cns
> >> +                       ptr += 4;
> >> +                       dive->otu = *(float *) (buf + ptr);
> >> +                       ptr += 4;
> >> +                       dive_mode = *(buf + ptr++);     // 0=Deco,
> 1=Gauge, 2=None
> >> +                       algorithm = *(buf + ptr++);     // 0=ZH-L16C+GF
> >> +                       sample_count = array_uint32_le(buf + ptr);
> >> +               }
> >> +               ptr += 4;
> >> +
> >> +               // Parse dive samples
> >> +               const unsigned char *ds = buf + ptr;
> >> +               const unsigned char *ts = buf + ptr + sample_count * 2
> + 4;
> >> +               const unsigned char *ps = buf + ptr + sample_count * 4
> + 4;
> >> +               unsigned int ps_count = array_uint32_le(ps);
> >> +               ps += 4;
> >> +
> >> +               // Bump ptr
> >> +               ptr += sample_count * 4 + 4;
> >> +
> >> +               // Handle events
> >> +               unsigned int event;
> >> +               unsigned int ps_ptr;
> >> +               ps_ptr = 0;
> >> +
> >> +               unsigned int d = 0, e;
> >> +               int event_time, mbar, sensor;
> >> +
> >> +               // Loop through events
> >> +               for (e = 0; e < ps_count; e++) {
> >> +                       // Get event
> >> +                       event = array_uint16_le(ps + ps_ptr);
> >> +                       ps_ptr += 2;
> >> +
> >> +                       switch (event) {
> >> +                       case 0x0002:    //      Unknown
> >> +                       case 0x0004:    //      Unknown
> >> +                               ps_ptr +=  4;
> >> +                               continue;
> >> +                       case 0x0005:    // Unknown
> >> +                               ps_ptr += 6;
> >> +                               continue;
> >> +                       case 0x0007:    // Gas
> >> +                               // 4 byte time
> >> +                               // 1 byte O2, 1 bye He
> >> +                               ps_ptr += 6;
> >> +                               continue;
> >> +                       case 0x0008:
> >> +                               // 4 byte time
> >> +                               // 2 byte gas set point 2
> >> +                               ps_ptr += 6;
> >> +                               continue;
> >> +                       case 0x000f:
> >> +                               // Tank pressure
> >> +                               event_time = array_uint32_le(ps +
> ps_ptr);
> >> +                               sensor = 0; //array_uint16_le(ps +
> ps_ptr + 4);
> >> +                               mbar = array_uint16_le(ps + ps_ptr + 6)
> * 10; // cb->mb
> >> +                               // 1 byte PSR
> >> +                               // 1 byte ST
> >> +                               ps_ptr += 10;
> >> +                               break;
> >> +                       case 0x0010:
> >> +                               ps_ptr += 26;
> >> +                               continue;
> >> +                       case 0x0015:    // Unknown
> >> +                               ps_ptr += 2;
> >> +                               continue;
> >> +                       default:
> >> +                               ps_ptr += 4;
> >> +                               continue;
> >> +                       }
> >> +
> >> +                       int sample_time, next_time, last_time;
> >> +                       int depth_mm, last_depth, temp_mk, last_temp;
> >> +
> >> +                       while (true) {
> >> +                               sample = prepare_sample(dc);
> >> +
> >> +                               // Get sample times
> >> +                               sample_time = d * sample_interval;
> >> +                               depth_mm = array_uint16_le(ds + d * 2)
> * 10; // cm->mm
> >> +                               temp_mk =
> C_to_mkelvin(array_uint16_le(ts + d * 2) / 10); // dC->mK
> >> +                               next_time = (d < sample_count - 1 ? (d
> + 1) * sample_interval : sample_time);
> >> +                               last_time = (d ? (d - 1) *
> sample_interval : 0);
> >> +
> >> +                               if (d == sample_count) {
> >> +                                       // We still have events to
> record
> >> +                                       sample->time.seconds =
> event_time;
> >> +                                       sample->depth.mm ==
> array_uint16_le(ds + (d - 1) * 2) * 10; // cm->mm
> >> +                                       sample->temperature.mkelvin =
> C_to_mkelvin(array_uint16_le(ts + (d - 1) * 2) / 10); // dC->mK
> >> +                                       sample->sensor = sensor;
> >> +                                       sample->cylinderpressure.mbar =
> mbar;
> >> +                                       finish_sample(dc);
> >> +
> >> +                                       break;
> >> +                               } else if (event_time > sample_time) {
> >> +                                       // Record sample and loop
> >> +                                       sample->time.seconds =
> sample_time;
> >> +                                       sample->depth.mm = depth_mm;
> >> +                                       sample->temperature.mkelvin =
> temp_mk;
> >> +                                       finish_sample(dc);
> >> +                                       d++;
> >> +
> >> +                                       continue;
> >> +                               } else if (event_time == sample_time) {
> >> +                                       sample->time.seconds =
> sample_time;
> >> +                                       sample->depth.mm = depth_mm;
> >> +                                       sample->temperature.mkelvin =
> temp_mk;
> >> +                                       sample->sensor = sensor;
> >> +                                       sample->cylinderpressure.mbar =
> mbar;
> >> +                                       finish_sample(dc);
> >> +
> >> +                                       break;
> >> +                               } else {        // Event is prior to
> sample
> >> +                                       sample->time.seconds =
> event_time;
> >> +                                       sample->sensor = sensor;
> >> +                                       sample->cylinderpressure.mbar =
> mbar;
> >> +                                       if (last_time == sample_time) {
> >> +                                               sample->depth.mm =
> depth_mm;
> >> +
> sample->temperature.mkelvin = temp_mk;
> >> +                                       } else {
> >> +                                               // Extrapolate
> >> +                                               last_depth =
> array_uint16_le(ds + (d - 1) * 2) * 10; // cm->mm
> >> +                                               last_temp =
> C_to_mkelvin(array_uint16_le(ts + (d - 1) * 2) / 10); // dC->mK
> >> +                                               sample->depth.mm =
> last_depth + (depth_mm - last_depth)
> >> +                                                       * (event_time -
> last_time) / sample_interval;
> >> +
> sample->temperature.mkelvin = last_temp + (temp_mk - last_temp)
> >> +                                                       * (event_time -
> last_time) / sample_interval;
> >> +                                       }
> >> +                                       finish_sample(dc);
> >> +
> >> +                                       break;
> >> +                               }
> >> +                       } // while (true);
> >> +               } // for each event sample
> >> +
> >> +               // record trailing depth samples
> >> +               for ( ;d < sample_count; d++) {
> >> +                       sample = prepare_sample(dc);
> >> +                       sample->time.seconds = d * sample_interval;
> >> +
> >> +                       sample->depth.mm = array_uint16_le(ds + d * 2)
> * 10; // cm->mm
> >> +                       sample->temperature.mkelvin =
> >> +                               C_to_mkelvin((float)array_uint16_le(ts
> + d * 2) / 10);
> >> +                       finish_sample(dc);
> >> +               }
> >> +
> >> +               if (log_version == 3 && model == 4) {
> >> +                       // Advance to begin of next dive
> >> +                       switch (array_uint16_le(ps + ps_ptr)) {
> >> +                       case 0x0000:
> >> +                               ps_ptr += 5;
> >> +                               break;
> >> +                       case 0x0100:
> >> +                               ps_ptr += 7;
> >> +                               break;
> >> +                       case 0x0200:
> >> +                               ps_ptr += 9;
> >> +                               break;
> >> +                       case 0x0300:
> >> +                               ps_ptr += 11;
> >> +                               break;
> >> +                       case 0x0b0b:
> >> +                               ps_ptr += 27;
> >> +                               break;
> >> +                       }
> >> +
> >> +                       while (*(ps + ps_ptr) != 0x04)
> >> +                               ps_ptr++;
> >> +               }
> >> +
> >> +               // End dive
> >> +               dive->downloaded = true;
> >> +               record_dive(dive);
> >> +               mark_divelist_changed(true);
> >> +
> >> +               // Advance ptr for next dive
> >> +               ptr += ps_ptr + 4;
> >> +       } // while
> >> +
> >> +       save_dives("/tmp/test.xml");
> >> +}
> >> +
> >> +
> >> +int
> >> +try_to_open_liquivision(const char *filename, struct memblock *mem)
> >> +{
> >> +       void *name;
> >> +       const unsigned char *buf = mem->buffer;
> >> +       unsigned int buf_size = mem->size;
> >> +       unsigned int ptr;
> >> +       int log_version;
> >> +
> >> +       // Get name
> >> +       unsigned int len = array_uint32_le(buf);
> >> +       if (len) {
> >> +               name = malloc(len);
> >> +               strncpy(name, buf + 4, len);
> >> +       }
> >> +       ptr = 4 + len;
> >> +
> >> +       unsigned int dive_count = array_uint32_le(buf + ptr);
> >> +       if (dive_count == 0xffffffff) {
> >> +               // File version 3.0
> >> +               log_version = 3;
> >> +               ptr += 6;
> >> +               dive_count = array_uint32_le(buf + ptr);
> >> +       } else {
> >> +               log_version = 2;
> >> +       }
> >> +       ptr += 4;
> >> +
> >> +       parse_dives(log_version, buf + ptr, buf_size - ptr);
> >> +
> >> +       return 1;
> >> +}
> >> diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
> >> index cc2d970..5811d4e 100644
> >> --- a/qt-ui/mainwindow.cpp
> >> +++ b/qt-ui/mainwindow.cpp
> >> @@ -725,7 +725,8 @@ QString MainWindow::filter()
> >>         QString f;
> >>         f += "ALL ( *.ssrf *.xml *.XML *.uddf *.udcf *.UDFC *.jlb *.JLB
> ";
> >>         f += "*.sde *.SDE *.dld *.DLD ";
> >> -       f += "*.db *.can";
> >> +       f += "*.db *.can ";
> >> +       f += "*.lvd ";
> >>         f += ");;";
> >>
> >>         f += "Subsurface (*.ssrf);;";
> >> @@ -737,7 +738,8 @@ QString MainWindow::filter()
> >>         f += "SDE (*.sde *.SDE);;";
> >>         f += "DLD (*.dld *.DLD);;";
> >>         f += "DB (*.db);;";
> >> -       f += "CAN (*.can)";
> >> +       f += "CAN (*.can);;";
> >> +       f += "LVD (*.lvd)";
> >>
> >>         return f;
> >>  }
> >> @@ -1247,7 +1249,7 @@ void MainWindow::loadFiles(const QStringList
> fileNames)
> >>  void MainWindow::on_actionImportDiveLog_triggered()
> >>  {
> >>         QStringList fileNames = QFileDialog::getOpenFileNames(this,
> tr("Open dive log file"), lastUsedDir(),
> >> -               tr("Dive log files (*.xml *.uddf *.udcf *.csv *.jlb
> *.dld *.sde *.db *.can);;"
> >> +               tr("Dive log files (*.xml *.uddf *.udcf *.csv *.jlb
> *.dld *.sde *.db *.can *.lvd);;"
> >>                         "XML files (*.xml);;UDDF/UDCF files(*.uddf
> *.udcf);;JDiveLog files(*.jlb);;"
> >>                         "Suunto files(*.sde *.db);;CSV
> files(*.csv);;MkVI files(*.txt);;All files(*)"));
> >>
> >> diff --git a/subsurface.pro b/subsurface.pro
> >> index 7b38fd6..07e7b29 100644
> >> --- a/subsurface.pro
> >> +++ b/subsurface.pro
> >> @@ -120,6 +120,7 @@ SOURCES =  \
> >>         file.c \
> >>         gettextfromc.cpp \
> >>         libdivecomputer.c \
> >> +       liquivision.c \
> >>         load-git.c \
> >>         main.cpp \
> >>         membuffer.c \
> >> --
> >> 1.8.3.1
> >>
> >> _______________________________________________
> >> subsurface mailing list
> >> subsurface at subsurface-divelog.org
> >> http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface
> >
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.subsurface-divelog.org/pipermail/subsurface/attachments/20141107/d09f6320/attachment-0001.html>


More information about the subsurface mailing list