2011-09-01 23:27:52 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <time.h>
|
2013-10-19 17:35:36 +00:00
|
|
|
#include <unistd.h>
|
Initial implementation of git save format
This saves the dive data into a git object repository instead of a
single XML file.
We create a git object tree with each dive as a separate file,
hierarchically by trip and date.
NOTE 1: This largely duplicates the XML saving code, because trying to
share it seemed just too painful: the logic is very similar, but the
details of the actual strings end up differing sufficiently that there
are tons of trivial differences.
The git save format is line-based with minimal quoting, while XML quotes
everything with either "<..\>" or using single quotes around attributes.
NOTE 2: You currently need a dummy "file" to save to, which points to
the real save location: the git repository and branch to be used. We
should make this a config thing, but for testing, do something like
this:
echo git /home/torvalds/scuba:linus > git-test
to create that git information file, and when you use "Save To" and
specify "git-test" as the file to save to, subsurface will use the new
git save logic to save to the branch "linus" in the repository found at
"/home/torvalds/scuba".
NOTE 3: The git save format uses just the git object directory, it does
*not* check out the result in any git working tree or index. So after
you do a save, you can do
git log -p linus
to see what actually happened in that branch, but it will not affect any
actual checked-out state in the repository.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-03-06 21:28:39 +00:00
|
|
|
#include <fcntl.h>
|
2011-09-01 23:27:52 +00:00
|
|
|
|
|
|
|
#include "dive.h"
|
2015-06-20 13:45:12 +00:00
|
|
|
#include "divelist.h"
|
2013-01-09 20:07:09 +00:00
|
|
|
#include "device.h"
|
2014-01-16 02:03:11 +00:00
|
|
|
#include "membuffer.h"
|
2015-06-01 06:12:30 +00:00
|
|
|
#include "strndup.h"
|
2015-06-13 15:01:06 +00:00
|
|
|
#include "git-access.h"
|
2015-06-21 13:37:24 +00:00
|
|
|
#include "qthelperfromc.h"
|
2011-09-01 23:27:52 +00:00
|
|
|
|
2011-09-02 02:56:04 +00:00
|
|
|
/*
|
|
|
|
* We're outputting utf8 in xml.
|
|
|
|
* We need to quote the characters <, >, &.
|
|
|
|
*
|
2011-09-02 03:28:17 +00:00
|
|
|
* Technically I don't think we'd necessarily need to quote the control
|
|
|
|
* characters, but at least libxml2 doesn't like them. It doesn't even
|
|
|
|
* allow them quoted. So we just skip them and replace them with '?'.
|
|
|
|
*
|
2012-08-27 20:19:06 +00:00
|
|
|
* If we do this for attributes, we need to quote the quotes we use too.
|
2011-09-02 02:56:04 +00:00
|
|
|
*/
|
2014-01-16 02:03:11 +00:00
|
|
|
static void quote(struct membuffer *b, const char *text, int is_attribute)
|
2011-09-02 02:56:04 +00:00
|
|
|
{
|
2014-06-02 17:10:54 +00:00
|
|
|
int is_html = 0;
|
|
|
|
put_quoted(b, text, is_attribute, is_html);
|
2011-09-02 02:56:04 +00:00
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void show_utf8(struct membuffer *b, const char *text, const char *pre, const char *post, int is_attribute)
|
2011-09-02 02:56:04 +00:00
|
|
|
{
|
|
|
|
int len;
|
2014-05-07 06:47:41 +00:00
|
|
|
char *cleaned;
|
2014-05-06 22:27:49 +00:00
|
|
|
|
|
|
|
if (!text)
|
|
|
|
return;
|
2014-05-07 16:28:26 +00:00
|
|
|
/* remove leading and trailing space */
|
2014-07-10 19:37:29 +00:00
|
|
|
/* We need to combine isascii() with isspace(),
|
|
|
|
* because we can only trust isspace() with 7-bit ascii,
|
|
|
|
* on windows for example */
|
|
|
|
while (isascii(*text) && isspace(*text))
|
2014-05-06 22:27:49 +00:00
|
|
|
text++;
|
|
|
|
len = strlen(text);
|
|
|
|
if (!len)
|
|
|
|
return;
|
2014-07-10 19:37:29 +00:00
|
|
|
while (len && isascii(text[len - 1]) && isspace(text[len - 1]))
|
2014-05-06 22:27:49 +00:00
|
|
|
len--;
|
2015-06-01 06:12:30 +00:00
|
|
|
cleaned = strndup(text, len);
|
2014-01-16 02:03:11 +00:00
|
|
|
put_string(b, pre);
|
2014-05-07 06:47:41 +00:00
|
|
|
quote(b, cleaned, is_attribute);
|
2014-01-16 02:03:11 +00:00
|
|
|
put_string(b, post);
|
2014-05-07 06:47:41 +00:00
|
|
|
free(cleaned);
|
2011-09-02 02:56:04 +00:00
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void save_depths(struct membuffer *b, struct divecomputer *dc)
|
2011-09-05 16:39:55 +00:00
|
|
|
{
|
|
|
|
/* What's the point of this dive entry again? */
|
2013-01-23 18:25:31 +00:00
|
|
|
if (!dc->maxdepth.mm && !dc->meandepth.mm)
|
2011-09-05 16:39:55 +00:00
|
|
|
return;
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
put_string(b, " <depth");
|
|
|
|
put_depth(b, dc->maxdepth, " max='", " m'");
|
|
|
|
put_depth(b, dc->meandepth, " mean='", " m'");
|
|
|
|
put_string(b, " />\n");
|
2011-09-05 16:39:55 +00:00
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void save_dive_temperature(struct membuffer *b, struct dive *dive)
|
2013-02-14 17:44:18 +00:00
|
|
|
{
|
2013-11-29 20:05:21 +00:00
|
|
|
if (!dive->airtemp.mkelvin && !dive->watertemp.mkelvin)
|
2013-02-14 23:18:48 +00:00
|
|
|
return;
|
2013-12-07 04:13:12 +00:00
|
|
|
if (dive->airtemp.mkelvin == dc_airtemp(&dive->dc) && dive->watertemp.mkelvin == dc_watertemp(&dive->dc))
|
2013-02-14 23:18:48 +00:00
|
|
|
return;
|
2013-02-14 17:44:18 +00:00
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
put_string(b, " <divetemperature");
|
|
|
|
if (dive->airtemp.mkelvin != dc_airtemp(&dive->dc))
|
|
|
|
put_temperature(b, dive->airtemp, " air='", " C'");
|
|
|
|
if (dive->watertemp.mkelvin != dc_watertemp(&dive->dc))
|
|
|
|
put_temperature(b, dive->watertemp, " water='", " C'");
|
|
|
|
put_string(b, "/>\n");
|
2013-02-14 17:44:18 +00:00
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void save_temperatures(struct membuffer *b, struct divecomputer *dc)
|
2011-09-05 16:39:55 +00:00
|
|
|
{
|
2013-01-23 18:25:31 +00:00
|
|
|
if (!dc->airtemp.mkelvin && !dc->watertemp.mkelvin)
|
2011-09-05 16:39:55 +00:00
|
|
|
return;
|
2014-01-16 02:03:11 +00:00
|
|
|
put_string(b, " <temperature");
|
|
|
|
put_temperature(b, dc->airtemp, " air='", " C'");
|
|
|
|
put_temperature(b, dc->watertemp, " water='", " C'");
|
|
|
|
put_string(b, " />\n");
|
2011-09-05 16:39:55 +00:00
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void save_airpressure(struct membuffer *b, struct divecomputer *dc)
|
2012-11-12 19:57:49 +00:00
|
|
|
{
|
2013-01-23 18:25:31 +00:00
|
|
|
if (!dc->surface_pressure.mbar)
|
2012-11-12 19:57:49 +00:00
|
|
|
return;
|
2014-01-16 02:03:11 +00:00
|
|
|
put_string(b, " <surface");
|
|
|
|
put_pressure(b, dc->surface_pressure, " pressure='", " bar'");
|
|
|
|
put_string(b, " />\n");
|
2012-11-12 19:57:49 +00:00
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void save_salinity(struct membuffer *b, struct divecomputer *dc)
|
2012-11-12 19:57:49 +00:00
|
|
|
{
|
2012-12-05 19:57:40 +00:00
|
|
|
/* only save if we have a value that isn't the default of sea water */
|
2013-02-09 00:15:18 +00:00
|
|
|
if (!dc->salinity || dc->salinity == SEAWATER_SALINITY)
|
2012-11-12 19:57:49 +00:00
|
|
|
return;
|
2014-01-16 02:03:11 +00:00
|
|
|
put_string(b, " <water");
|
|
|
|
put_salinity(b, dc->salinity, " salinity='", " g/l'");
|
|
|
|
put_string(b, " />\n");
|
2012-11-12 19:57:49 +00:00
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void save_overview(struct membuffer *b, struct dive *dive)
|
2011-09-01 23:27:52 +00:00
|
|
|
{
|
2014-02-16 23:42:56 +00:00
|
|
|
show_utf8(b, dive->divemaster, " <divemaster>", "</divemaster>\n", 0);
|
|
|
|
show_utf8(b, dive->buddy, " <buddy>", "</buddy>\n", 0);
|
|
|
|
show_utf8(b, dive->notes, " <notes>", "</notes>\n", 0);
|
|
|
|
show_utf8(b, dive->suit, " <suit>", "</suit>\n", 0);
|
2011-09-01 23:27:52 +00:00
|
|
|
}
|
|
|
|
|
2014-08-17 18:26:21 +00:00
|
|
|
static void put_gasmix(struct membuffer *b, struct gasmix *mix)
|
|
|
|
{
|
|
|
|
int o2 = mix->o2.permille;
|
|
|
|
int he = mix->he.permille;
|
|
|
|
|
|
|
|
if (o2) {
|
|
|
|
put_format(b, " o2='%u.%u%%'", FRACTION(o2, 10));
|
|
|
|
if (he)
|
|
|
|
put_format(b, " he='%u.%u%%'", FRACTION(he, 10));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void save_cylinder_info(struct membuffer *b, struct dive *dive)
|
2011-09-01 23:27:52 +00:00
|
|
|
{
|
Fix missing save of (almost empty) cylinder information
If we have no explicit cylinder info at all (it's normal air, no size or
working pressure information, and no beginning/end pressure information),
we don't save the cylinders in question because that would be redundant.
Such non-saved cylinders may still show up in the equipment list because
there may be implicit mention of them elsewhere, notably due to sample
data, so not saving them is the right thing to do - there is nothing to
save.
However, we missed one case: if there were other cylinders that *did* have
explicit information in it following such an uninteresting cylinder, we do
need to save the cylinder information for the useless case - if only in
order to be able to save the non-useless information for subsequent
cylinders.
This patch does that. Now, if you had an air-filled cylinder with no
information as your first cylinder, and a 51% nitrox as your second one,
it will save that information as
<cylinder />
<cylinder o2='51.0%' />
rather than dropping the cylinder information entirely.
This bug has been there for a long time, and was hidden by the fact that
normally you'd fill in cylinder descriptions etc after importing new
dives. It also used to be that we saved the cylinder beginning/end
pressure even if that was generated from the sample data, so if you
imported from a air-integrated computer and had samples for that cylinder,
we used to save it even though it was technically redundant.
We stopped saving redundant air sample information in commit 0089dd8819b7
("Don't save cylinder start/end pressures unless set by hand").
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Removed start and end in save_cylinder_info(). These two variables are no
longer used.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-09-21 21:06:57 +00:00
|
|
|
int i, nr;
|
2011-09-01 23:27:52 +00:00
|
|
|
|
Fix missing save of (almost empty) cylinder information
If we have no explicit cylinder info at all (it's normal air, no size or
working pressure information, and no beginning/end pressure information),
we don't save the cylinders in question because that would be redundant.
Such non-saved cylinders may still show up in the equipment list because
there may be implicit mention of them elsewhere, notably due to sample
data, so not saving them is the right thing to do - there is nothing to
save.
However, we missed one case: if there were other cylinders that *did* have
explicit information in it following such an uninteresting cylinder, we do
need to save the cylinder information for the useless case - if only in
order to be able to save the non-useless information for subsequent
cylinders.
This patch does that. Now, if you had an air-filled cylinder with no
information as your first cylinder, and a 51% nitrox as your second one,
it will save that information as
<cylinder />
<cylinder o2='51.0%' />
rather than dropping the cylinder information entirely.
This bug has been there for a long time, and was hidden by the fact that
normally you'd fill in cylinder descriptions etc after importing new
dives. It also used to be that we saved the cylinder beginning/end
pressure even if that was generated from the sample data, so if you
imported from a air-integrated computer and had samples for that cylinder,
we used to save it even though it was technically redundant.
We stopped saving redundant air sample information in commit 0089dd8819b7
("Don't save cylinder start/end pressures unless set by hand").
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Removed start and end in save_cylinder_info(). These two variables are no
longer used.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-09-21 21:06:57 +00:00
|
|
|
nr = nr_cylinders(dive);
|
|
|
|
|
|
|
|
for (i = 0; i < nr; i++) {
|
2014-02-16 23:42:56 +00:00
|
|
|
cylinder_t *cylinder = dive->cylinder + i;
|
2011-09-04 03:31:18 +00:00
|
|
|
int volume = cylinder->type.size.mliter;
|
2011-09-04 20:34:22 +00:00
|
|
|
const char *description = cylinder->type.description;
|
2011-09-01 23:27:52 +00:00
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " <cylinder");
|
Don't save cylinder working pressure
It was a mistake to save it - and I did it just because other dive
managers did. It's a totally nonsensical measure, and nobody cares.
The only thing that matters is the size of the cylinder, and the
*actual* pressures. Those give actual air consumption numbers, and are
meaningful and unambiguous.
So the "working pressure" for a cylinder is pointless except for two
things:
- if you don't know the actual physical size, you need the "working
pressure" along with the air size (eg "85 cuft") in order to compute
the physical size. So we do use the working pressure on *input* from
systems that report cylinder sizes that way.
- People may well want to know what kind of cylinder they were diving,
and again, you can make a good guess about this from the working
pressure. So saving information like "HP100+" for the cylinder would
be a good thing.
But notice how in neither case do we actually want to save the working
pressure itself. And in fact saving it actually makes the output format
ambiguous: if we give both size and working pressure, what does 'size'
mean? Is it physical size in liters, or air size in cu ft?
So saving working pressure is just wrong. Get rid of it.
I'm going to add some kind of "cylinder description" thing, which we can
save instead (and perhaps guess standard cylinders from input like the
working pressure from dive logs that don't do this sanely - which is all
of them, as far as I can tell).
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-09-04 18:23:41 +00:00
|
|
|
if (volume)
|
2014-01-16 02:03:11 +00:00
|
|
|
put_milli(b, " size='", volume, " l'");
|
|
|
|
put_pressure(b, cylinder->type.workingpressure, " workpressure='", " bar'");
|
|
|
|
show_utf8(b, description, " description='", "'", 1);
|
2014-08-17 18:26:21 +00:00
|
|
|
put_gasmix(b, &cylinder->gasmix);
|
2014-11-15 17:40:53 +00:00
|
|
|
put_pressure(b, cylinder->start, " start='", " bar'");
|
|
|
|
put_pressure(b, cylinder->end, " end='", " bar'");
|
2014-11-16 22:11:34 +00:00
|
|
|
if (cylinder->cylinder_use != OC_GAS)
|
|
|
|
show_utf8(b, cylinderuse_text[cylinder->cylinder_use], " use='", "'", 1);
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " />\n");
|
2011-09-01 23:27:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void save_weightsystem_info(struct membuffer *b, struct dive *dive)
|
2011-12-24 03:41:16 +00:00
|
|
|
{
|
2013-11-27 21:59:17 +00:00
|
|
|
int i, nr;
|
2011-12-24 03:41:16 +00:00
|
|
|
|
2013-11-27 21:59:17 +00:00
|
|
|
nr = nr_weightsystems(dive);
|
|
|
|
|
|
|
|
for (i = 0; i < nr; i++) {
|
2014-02-16 23:42:56 +00:00
|
|
|
weightsystem_t *ws = dive->weightsystem + i;
|
2011-12-24 03:41:16 +00:00
|
|
|
int grams = ws->weight.grams;
|
|
|
|
const char *description = ws->description;
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " <weightsystem");
|
|
|
|
put_milli(b, " weight='", grams, " kg'");
|
|
|
|
show_utf8(b, description, " description='", "'", 1);
|
|
|
|
put_format(b, " />\n");
|
2011-12-24 03:41:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void show_index(struct membuffer *b, int value, const char *pre, const char *post)
|
2011-09-23 01:02:54 +00:00
|
|
|
{
|
|
|
|
if (value)
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " %s%d%s", pre, value, post);
|
2011-09-23 01:02:54 +00:00
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void save_sample(struct membuffer *b, struct sample *sample, struct sample *old)
|
2011-09-01 23:27:52 +00:00
|
|
|
{
|
2014-02-16 23:42:56 +00:00
|
|
|
put_format(b, " <sample time='%u:%02u min'", FRACTION(sample->time.seconds, 60));
|
2014-01-16 02:03:11 +00:00
|
|
|
put_milli(b, " depth='", sample->depth.mm, " m'");
|
2015-01-03 05:29:40 +00:00
|
|
|
if (sample->temperature.mkelvin && sample->temperature.mkelvin != old->temperature.mkelvin) {
|
|
|
|
put_temperature(b, sample->temperature, " temp='", " C'");
|
|
|
|
old->temperature = sample->temperature;
|
|
|
|
}
|
2014-11-21 13:02:53 +00:00
|
|
|
put_pressure(b, sample->cylinderpressure, " pressure='", " bar'");
|
|
|
|
put_pressure(b, sample->o2cylinderpressure, " o2pressure='", " bar'");
|
First step in cleaning up cylinder pressure sensor logic
This clarifies/changes the meaning of our "cylinderindex" entry in our
samples. It has been rather confused, because different dive computers
have done things differently, and the naming really hasn't helped.
There are two totally different - and independent - cylinder "indexes":
- the pressure sensor index, which indicates which cylinder the sensor
data is from.
- the "active cylinder" index, which indicates which cylinder we actually
breathe from.
These two values really are totally independent, and have nothing
what-so-ever to do with each other. The sensor index may well be fixed:
many dive computers only support a single pressure sensor (whether
wireless or wired), and the sensor index is thus always zero.
Other dive computers may support multiple pressure sensors, and the gas
switch event may - or may not - indicate that the sensor changed too. A
dive computer might give the sensor data for *all* cylinders it can read,
regardless of which one is the one we're actively breathing. In fact, some
dive computers might give sensor data for not just *your* cylinder, but
your buddies.
This patch renames "cylinderindex" in the samples as "sensor", making it
quite clear that it's about which sensor index the pressure data in the
sample is about.
The way we figure out which is the currently active gas is with an
explicit has change event. If a computer (like the Uemis Zurich) joins the
two concepts together, then a sensor change should also create a gas
switch event. This patch also changes the Uemis importer to do that.
Finally, it should be noted that the plot info works totally separately
from the sample data, and is about what we actually *display*, not about
the sample pressures etc. In the plot info, the "cylinderindex" does in
fact mean the currently active cylinder, and while it is initially set to
match the sensor information from the samples, we then walk the gas change
events and fix it up - and if the active cylinder differs from the sensor
cylinder, we clear the sensor data.
[Dirk Hohndel: this conflicted with some of my recent changes - I think
I merged things correctly...]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-31 04:00:51 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We only show sensor information for samples with pressure, and only if it
|
|
|
|
* changed from the previous sensor we showed.
|
|
|
|
*/
|
|
|
|
if (sample->cylinderpressure.mbar && sample->sensor != old->sensor) {
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " sensor='%d'", sample->sensor);
|
First step in cleaning up cylinder pressure sensor logic
This clarifies/changes the meaning of our "cylinderindex" entry in our
samples. It has been rather confused, because different dive computers
have done things differently, and the naming really hasn't helped.
There are two totally different - and independent - cylinder "indexes":
- the pressure sensor index, which indicates which cylinder the sensor
data is from.
- the "active cylinder" index, which indicates which cylinder we actually
breathe from.
These two values really are totally independent, and have nothing
what-so-ever to do with each other. The sensor index may well be fixed:
many dive computers only support a single pressure sensor (whether
wireless or wired), and the sensor index is thus always zero.
Other dive computers may support multiple pressure sensors, and the gas
switch event may - or may not - indicate that the sensor changed too. A
dive computer might give the sensor data for *all* cylinders it can read,
regardless of which one is the one we're actively breathing. In fact, some
dive computers might give sensor data for not just *your* cylinder, but
your buddies.
This patch renames "cylinderindex" in the samples as "sensor", making it
quite clear that it's about which sensor index the pressure data in the
sample is about.
The way we figure out which is the currently active gas is with an
explicit has change event. If a computer (like the Uemis Zurich) joins the
two concepts together, then a sensor change should also create a gas
switch event. This patch also changes the Uemis importer to do that.
Finally, it should be noted that the plot info works totally separately
from the sample data, and is about what we actually *display*, not about
the sample pressures etc. In the plot info, the "cylinderindex" does in
fact mean the currently active cylinder, and while it is initially set to
match the sensor information from the samples, we then walk the gas change
events and fix it up - and if the active cylinder differs from the sensor
cylinder, we clear the sensor data.
[Dirk Hohndel: this conflicted with some of my recent changes - I think
I merged things correctly...]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-31 04:00:51 +00:00
|
|
|
old->sensor = sample->sensor;
|
|
|
|
}
|
|
|
|
|
2012-12-01 21:02:30 +00:00
|
|
|
/* the deco/ndl values are stored whenever they change */
|
First step in cleaning up cylinder pressure sensor logic
This clarifies/changes the meaning of our "cylinderindex" entry in our
samples. It has been rather confused, because different dive computers
have done things differently, and the naming really hasn't helped.
There are two totally different - and independent - cylinder "indexes":
- the pressure sensor index, which indicates which cylinder the sensor
data is from.
- the "active cylinder" index, which indicates which cylinder we actually
breathe from.
These two values really are totally independent, and have nothing
what-so-ever to do with each other. The sensor index may well be fixed:
many dive computers only support a single pressure sensor (whether
wireless or wired), and the sensor index is thus always zero.
Other dive computers may support multiple pressure sensors, and the gas
switch event may - or may not - indicate that the sensor changed too. A
dive computer might give the sensor data for *all* cylinders it can read,
regardless of which one is the one we're actively breathing. In fact, some
dive computers might give sensor data for not just *your* cylinder, but
your buddies.
This patch renames "cylinderindex" in the samples as "sensor", making it
quite clear that it's about which sensor index the pressure data in the
sample is about.
The way we figure out which is the currently active gas is with an
explicit has change event. If a computer (like the Uemis Zurich) joins the
two concepts together, then a sensor change should also create a gas
switch event. This patch also changes the Uemis importer to do that.
Finally, it should be noted that the plot info works totally separately
from the sample data, and is about what we actually *display*, not about
the sample pressures etc. In the plot info, the "cylinderindex" does in
fact mean the currently active cylinder, and while it is initially set to
match the sensor information from the samples, we then walk the gas change
events and fix it up - and if the active cylinder differs from the sensor
cylinder, we clear the sensor data.
[Dirk Hohndel: this conflicted with some of my recent changes - I think
I merged things correctly...]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-31 04:00:51 +00:00
|
|
|
if (sample->ndl.seconds != old->ndl.seconds) {
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " ndl='%u:%02u min'", FRACTION(sample->ndl.seconds, 60));
|
First step in cleaning up cylinder pressure sensor logic
This clarifies/changes the meaning of our "cylinderindex" entry in our
samples. It has been rather confused, because different dive computers
have done things differently, and the naming really hasn't helped.
There are two totally different - and independent - cylinder "indexes":
- the pressure sensor index, which indicates which cylinder the sensor
data is from.
- the "active cylinder" index, which indicates which cylinder we actually
breathe from.
These two values really are totally independent, and have nothing
what-so-ever to do with each other. The sensor index may well be fixed:
many dive computers only support a single pressure sensor (whether
wireless or wired), and the sensor index is thus always zero.
Other dive computers may support multiple pressure sensors, and the gas
switch event may - or may not - indicate that the sensor changed too. A
dive computer might give the sensor data for *all* cylinders it can read,
regardless of which one is the one we're actively breathing. In fact, some
dive computers might give sensor data for not just *your* cylinder, but
your buddies.
This patch renames "cylinderindex" in the samples as "sensor", making it
quite clear that it's about which sensor index the pressure data in the
sample is about.
The way we figure out which is the currently active gas is with an
explicit has change event. If a computer (like the Uemis Zurich) joins the
two concepts together, then a sensor change should also create a gas
switch event. This patch also changes the Uemis importer to do that.
Finally, it should be noted that the plot info works totally separately
from the sample data, and is about what we actually *display*, not about
the sample pressures etc. In the plot info, the "cylinderindex" does in
fact mean the currently active cylinder, and while it is initially set to
match the sensor information from the samples, we then walk the gas change
events and fix it up - and if the active cylinder differs from the sensor
cylinder, we clear the sensor data.
[Dirk Hohndel: this conflicted with some of my recent changes - I think
I merged things correctly...]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-31 04:00:51 +00:00
|
|
|
old->ndl = sample->ndl;
|
|
|
|
}
|
2014-07-09 20:13:36 +00:00
|
|
|
if (sample->tts.seconds != old->tts.seconds) {
|
|
|
|
put_format(b, " tts='%u:%02u min'", FRACTION(sample->tts.seconds, 60));
|
|
|
|
old->tts = sample->tts;
|
|
|
|
}
|
2015-07-22 15:20:39 +00:00
|
|
|
if (sample->rbt.seconds)
|
|
|
|
put_format(b, " rbt='%u:%02u min'", FRACTION(sample->rbt.seconds, 60));
|
First step in cleaning up cylinder pressure sensor logic
This clarifies/changes the meaning of our "cylinderindex" entry in our
samples. It has been rather confused, because different dive computers
have done things differently, and the naming really hasn't helped.
There are two totally different - and independent - cylinder "indexes":
- the pressure sensor index, which indicates which cylinder the sensor
data is from.
- the "active cylinder" index, which indicates which cylinder we actually
breathe from.
These two values really are totally independent, and have nothing
what-so-ever to do with each other. The sensor index may well be fixed:
many dive computers only support a single pressure sensor (whether
wireless or wired), and the sensor index is thus always zero.
Other dive computers may support multiple pressure sensors, and the gas
switch event may - or may not - indicate that the sensor changed too. A
dive computer might give the sensor data for *all* cylinders it can read,
regardless of which one is the one we're actively breathing. In fact, some
dive computers might give sensor data for not just *your* cylinder, but
your buddies.
This patch renames "cylinderindex" in the samples as "sensor", making it
quite clear that it's about which sensor index the pressure data in the
sample is about.
The way we figure out which is the currently active gas is with an
explicit has change event. If a computer (like the Uemis Zurich) joins the
two concepts together, then a sensor change should also create a gas
switch event. This patch also changes the Uemis importer to do that.
Finally, it should be noted that the plot info works totally separately
from the sample data, and is about what we actually *display*, not about
the sample pressures etc. In the plot info, the "cylinderindex" does in
fact mean the currently active cylinder, and while it is initially set to
match the sensor information from the samples, we then walk the gas change
events and fix it up - and if the active cylinder differs from the sensor
cylinder, we clear the sensor data.
[Dirk Hohndel: this conflicted with some of my recent changes - I think
I merged things correctly...]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-31 04:00:51 +00:00
|
|
|
if (sample->in_deco != old->in_deco) {
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " in_deco='%d'", sample->in_deco ? 1 : 0);
|
First step in cleaning up cylinder pressure sensor logic
This clarifies/changes the meaning of our "cylinderindex" entry in our
samples. It has been rather confused, because different dive computers
have done things differently, and the naming really hasn't helped.
There are two totally different - and independent - cylinder "indexes":
- the pressure sensor index, which indicates which cylinder the sensor
data is from.
- the "active cylinder" index, which indicates which cylinder we actually
breathe from.
These two values really are totally independent, and have nothing
what-so-ever to do with each other. The sensor index may well be fixed:
many dive computers only support a single pressure sensor (whether
wireless or wired), and the sensor index is thus always zero.
Other dive computers may support multiple pressure sensors, and the gas
switch event may - or may not - indicate that the sensor changed too. A
dive computer might give the sensor data for *all* cylinders it can read,
regardless of which one is the one we're actively breathing. In fact, some
dive computers might give sensor data for not just *your* cylinder, but
your buddies.
This patch renames "cylinderindex" in the samples as "sensor", making it
quite clear that it's about which sensor index the pressure data in the
sample is about.
The way we figure out which is the currently active gas is with an
explicit has change event. If a computer (like the Uemis Zurich) joins the
two concepts together, then a sensor change should also create a gas
switch event. This patch also changes the Uemis importer to do that.
Finally, it should be noted that the plot info works totally separately
from the sample data, and is about what we actually *display*, not about
the sample pressures etc. In the plot info, the "cylinderindex" does in
fact mean the currently active cylinder, and while it is initially set to
match the sensor information from the samples, we then walk the gas change
events and fix it up - and if the active cylinder differs from the sensor
cylinder, we clear the sensor data.
[Dirk Hohndel: this conflicted with some of my recent changes - I think
I merged things correctly...]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-31 04:00:51 +00:00
|
|
|
old->in_deco = sample->in_deco;
|
|
|
|
}
|
|
|
|
if (sample->stoptime.seconds != old->stoptime.seconds) {
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " stoptime='%u:%02u min'", FRACTION(sample->stoptime.seconds, 60));
|
First step in cleaning up cylinder pressure sensor logic
This clarifies/changes the meaning of our "cylinderindex" entry in our
samples. It has been rather confused, because different dive computers
have done things differently, and the naming really hasn't helped.
There are two totally different - and independent - cylinder "indexes":
- the pressure sensor index, which indicates which cylinder the sensor
data is from.
- the "active cylinder" index, which indicates which cylinder we actually
breathe from.
These two values really are totally independent, and have nothing
what-so-ever to do with each other. The sensor index may well be fixed:
many dive computers only support a single pressure sensor (whether
wireless or wired), and the sensor index is thus always zero.
Other dive computers may support multiple pressure sensors, and the gas
switch event may - or may not - indicate that the sensor changed too. A
dive computer might give the sensor data for *all* cylinders it can read,
regardless of which one is the one we're actively breathing. In fact, some
dive computers might give sensor data for not just *your* cylinder, but
your buddies.
This patch renames "cylinderindex" in the samples as "sensor", making it
quite clear that it's about which sensor index the pressure data in the
sample is about.
The way we figure out which is the currently active gas is with an
explicit has change event. If a computer (like the Uemis Zurich) joins the
two concepts together, then a sensor change should also create a gas
switch event. This patch also changes the Uemis importer to do that.
Finally, it should be noted that the plot info works totally separately
from the sample data, and is about what we actually *display*, not about
the sample pressures etc. In the plot info, the "cylinderindex" does in
fact mean the currently active cylinder, and while it is initially set to
match the sensor information from the samples, we then walk the gas change
events and fix it up - and if the active cylinder differs from the sensor
cylinder, we clear the sensor data.
[Dirk Hohndel: this conflicted with some of my recent changes - I think
I merged things correctly...]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-31 04:00:51 +00:00
|
|
|
old->stoptime = sample->stoptime;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sample->stopdepth.mm != old->stopdepth.mm) {
|
2014-01-16 02:03:11 +00:00
|
|
|
put_milli(b, " stopdepth='", sample->stopdepth.mm, " m'");
|
First step in cleaning up cylinder pressure sensor logic
This clarifies/changes the meaning of our "cylinderindex" entry in our
samples. It has been rather confused, because different dive computers
have done things differently, and the naming really hasn't helped.
There are two totally different - and independent - cylinder "indexes":
- the pressure sensor index, which indicates which cylinder the sensor
data is from.
- the "active cylinder" index, which indicates which cylinder we actually
breathe from.
These two values really are totally independent, and have nothing
what-so-ever to do with each other. The sensor index may well be fixed:
many dive computers only support a single pressure sensor (whether
wireless or wired), and the sensor index is thus always zero.
Other dive computers may support multiple pressure sensors, and the gas
switch event may - or may not - indicate that the sensor changed too. A
dive computer might give the sensor data for *all* cylinders it can read,
regardless of which one is the one we're actively breathing. In fact, some
dive computers might give sensor data for not just *your* cylinder, but
your buddies.
This patch renames "cylinderindex" in the samples as "sensor", making it
quite clear that it's about which sensor index the pressure data in the
sample is about.
The way we figure out which is the currently active gas is with an
explicit has change event. If a computer (like the Uemis Zurich) joins the
two concepts together, then a sensor change should also create a gas
switch event. This patch also changes the Uemis importer to do that.
Finally, it should be noted that the plot info works totally separately
from the sample data, and is about what we actually *display*, not about
the sample pressures etc. In the plot info, the "cylinderindex" does in
fact mean the currently active cylinder, and while it is initially set to
match the sensor information from the samples, we then walk the gas change
events and fix it up - and if the active cylinder differs from the sensor
cylinder, we clear the sensor data.
[Dirk Hohndel: this conflicted with some of my recent changes - I think
I merged things correctly...]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-31 04:00:51 +00:00
|
|
|
old->stopdepth = sample->stopdepth;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sample->cns != old->cns) {
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " cns='%u%%'", sample->cns);
|
First step in cleaning up cylinder pressure sensor logic
This clarifies/changes the meaning of our "cylinderindex" entry in our
samples. It has been rather confused, because different dive computers
have done things differently, and the naming really hasn't helped.
There are two totally different - and independent - cylinder "indexes":
- the pressure sensor index, which indicates which cylinder the sensor
data is from.
- the "active cylinder" index, which indicates which cylinder we actually
breathe from.
These two values really are totally independent, and have nothing
what-so-ever to do with each other. The sensor index may well be fixed:
many dive computers only support a single pressure sensor (whether
wireless or wired), and the sensor index is thus always zero.
Other dive computers may support multiple pressure sensors, and the gas
switch event may - or may not - indicate that the sensor changed too. A
dive computer might give the sensor data for *all* cylinders it can read,
regardless of which one is the one we're actively breathing. In fact, some
dive computers might give sensor data for not just *your* cylinder, but
your buddies.
This patch renames "cylinderindex" in the samples as "sensor", making it
quite clear that it's about which sensor index the pressure data in the
sample is about.
The way we figure out which is the currently active gas is with an
explicit has change event. If a computer (like the Uemis Zurich) joins the
two concepts together, then a sensor change should also create a gas
switch event. This patch also changes the Uemis importer to do that.
Finally, it should be noted that the plot info works totally separately
from the sample data, and is about what we actually *display*, not about
the sample pressures etc. In the plot info, the "cylinderindex" does in
fact mean the currently active cylinder, and while it is initially set to
match the sensor information from the samples, we then walk the gas change
events and fix it up - and if the active cylinder differs from the sensor
cylinder, we clear the sensor data.
[Dirk Hohndel: this conflicted with some of my recent changes - I think
I merged things correctly...]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-31 04:00:51 +00:00
|
|
|
old->cns = sample->cns;
|
|
|
|
}
|
|
|
|
|
2014-11-17 19:04:36 +00:00
|
|
|
if ((sample->o2sensor[0].mbar) && (sample->o2sensor[0].mbar != old->o2sensor[0].mbar)) {
|
|
|
|
put_milli(b, " sensor1='", sample->o2sensor[0].mbar, " bar'");
|
|
|
|
old->o2sensor[0] = sample->o2sensor[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((sample->o2sensor[1].mbar) && (sample->o2sensor[1].mbar != old->o2sensor[1].mbar)) {
|
|
|
|
put_milli(b, " sensor2='", sample->o2sensor[1].mbar, " bar'");
|
|
|
|
old->o2sensor[1] = sample->o2sensor[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((sample->o2sensor[2].mbar) && (sample->o2sensor[2].mbar != old->o2sensor[2].mbar)) {
|
|
|
|
put_milli(b, " sensor3='", sample->o2sensor[2].mbar, " bar'");
|
|
|
|
old->o2sensor[2] = sample->o2sensor[2];
|
|
|
|
}
|
|
|
|
|
2014-10-19 14:07:07 +00:00
|
|
|
if (sample->setpoint.mbar != old->setpoint.mbar) {
|
|
|
|
put_milli(b, " po2='", sample->setpoint.mbar, " bar'");
|
|
|
|
old->setpoint = sample->setpoint;
|
First step in cleaning up cylinder pressure sensor logic
This clarifies/changes the meaning of our "cylinderindex" entry in our
samples. It has been rather confused, because different dive computers
have done things differently, and the naming really hasn't helped.
There are two totally different - and independent - cylinder "indexes":
- the pressure sensor index, which indicates which cylinder the sensor
data is from.
- the "active cylinder" index, which indicates which cylinder we actually
breathe from.
These two values really are totally independent, and have nothing
what-so-ever to do with each other. The sensor index may well be fixed:
many dive computers only support a single pressure sensor (whether
wireless or wired), and the sensor index is thus always zero.
Other dive computers may support multiple pressure sensors, and the gas
switch event may - or may not - indicate that the sensor changed too. A
dive computer might give the sensor data for *all* cylinders it can read,
regardless of which one is the one we're actively breathing. In fact, some
dive computers might give sensor data for not just *your* cylinder, but
your buddies.
This patch renames "cylinderindex" in the samples as "sensor", making it
quite clear that it's about which sensor index the pressure data in the
sample is about.
The way we figure out which is the currently active gas is with an
explicit has change event. If a computer (like the Uemis Zurich) joins the
two concepts together, then a sensor change should also create a gas
switch event. This patch also changes the Uemis importer to do that.
Finally, it should be noted that the plot info works totally separately
from the sample data, and is about what we actually *display*, not about
the sample pressures etc. In the plot info, the "cylinderindex" does in
fact mean the currently active cylinder, and while it is initially set to
match the sensor information from the samples, we then walk the gas change
events and fix it up - and if the active cylinder differs from the sensor
cylinder, we clear the sensor data.
[Dirk Hohndel: this conflicted with some of my recent changes - I think
I merged things correctly...]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-31 04:00:51 +00:00
|
|
|
}
|
2014-01-17 22:00:28 +00:00
|
|
|
show_index(b, sample->heartbeat, "heartbeat='", "'");
|
2014-06-03 17:21:41 +00:00
|
|
|
show_index(b, sample->bearing.degrees, "bearing='", "'");
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " />\n");
|
2011-09-01 23:27:52 +00:00
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void save_one_event(struct membuffer *b, struct event *ev)
|
2011-09-23 01:02:54 +00:00
|
|
|
{
|
2014-02-16 23:42:56 +00:00
|
|
|
put_format(b, " <event time='%d:%02d min'", FRACTION(ev->time.seconds, 60));
|
2014-01-16 02:03:11 +00:00
|
|
|
show_index(b, ev->type, "type='", "'");
|
|
|
|
show_index(b, ev->flags, "flags='", "'");
|
|
|
|
show_index(b, ev->value, "value='", "'");
|
|
|
|
show_utf8(b, ev->name, " name='", "'", 1);
|
2014-08-17 18:26:21 +00:00
|
|
|
if (event_is_gaschange(ev)) {
|
|
|
|
if (ev->gas.index >= 0) {
|
|
|
|
show_index(b, ev->gas.index, "cylinder='", "'");
|
|
|
|
put_gasmix(b, &ev->gas.mix);
|
|
|
|
} else if (!event_gasmix_redundant(ev))
|
|
|
|
put_gasmix(b, &ev->gas.mix);
|
|
|
|
}
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " />\n");
|
2011-09-23 01:02:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void save_events(struct membuffer *b, struct event *ev)
|
2011-09-23 01:02:54 +00:00
|
|
|
{
|
|
|
|
while (ev) {
|
2014-01-16 02:03:11 +00:00
|
|
|
save_one_event(b, ev);
|
2011-09-23 01:02:54 +00:00
|
|
|
ev = ev->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Get rid of crazy empty tag_list element at the start
So this is totally unrelated to the git repository format, except for
the fact that I noticed it while writing the git saving code.
The subsurface divetag list handling is being stupid, and has a
initial dummy entry at the head of the list for no good reason.
I say "no good reason", because there *is* a reason for it: it allows
code to avoid the special case of empty list and adding entries to
before the first entry etc etc. But that reason is a really *bad*
reason, because it's valid only because people don't understand basic
list manipulation and pointers to pointers.
So get rid of the dummy element, and do things right instead - by
passing a *pointer* to the list, instead of the list. And then when
traversing the list and looking for a place to insert things, don't go
to the next entry - just update the "pointer to pointer" to point to
the address of the next entry. Each entry in a C linked list is no
different than the list itself, so you can use the pointer to the
pointer to the next entry as a pointer to the list.
This is a pet peeve of mine. The real beauty of pointers can never be
understood unless you understand the indirection they allow. People
who grew up with Pascal and were corrupted by that mindset are
mentally stunted. Niklaus Wirth has a lot to answer for!
But never fear. You too can overcome that mental limitation, it just
needs some brain exercise. Reading this patch may help. In particular,
contemplate the new "taglist_add_divetag()".
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-03-10 17:18:13 +00:00
|
|
|
static void save_tags(struct membuffer *b, struct tag_entry *entry)
|
2013-04-09 20:06:30 +00:00
|
|
|
{
|
Get rid of crazy empty tag_list element at the start
So this is totally unrelated to the git repository format, except for
the fact that I noticed it while writing the git saving code.
The subsurface divetag list handling is being stupid, and has a
initial dummy entry at the head of the list for no good reason.
I say "no good reason", because there *is* a reason for it: it allows
code to avoid the special case of empty list and adding entries to
before the first entry etc etc. But that reason is a really *bad*
reason, because it's valid only because people don't understand basic
list manipulation and pointers to pointers.
So get rid of the dummy element, and do things right instead - by
passing a *pointer* to the list, instead of the list. And then when
traversing the list and looking for a place to insert things, don't go
to the next entry - just update the "pointer to pointer" to point to
the address of the next entry. Each entry in a C linked list is no
different than the list itself, so you can use the pointer to the
pointer to the next entry as a pointer to the list.
This is a pet peeve of mine. The real beauty of pointers can never be
understood unless you understand the indirection they allow. People
who grew up with Pascal and were corrupted by that mindset are
mentally stunted. Niklaus Wirth has a lot to answer for!
But never fear. You too can overcome that mental limitation, it just
needs some brain exercise. Reading this patch may help. In particular,
contemplate the new "taglist_add_divetag()".
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-03-10 17:18:13 +00:00
|
|
|
if (entry) {
|
|
|
|
const char *sep = " tags='";
|
|
|
|
do {
|
|
|
|
struct divetag *tag = entry->tag;
|
|
|
|
put_string(b, sep);
|
2013-11-02 01:12:42 +00:00
|
|
|
/* If the tag has been translated, write the source to the xml file */
|
2015-02-17 17:28:00 +00:00
|
|
|
quote(b, tag->source ?: tag->name, 1);
|
Get rid of crazy empty tag_list element at the start
So this is totally unrelated to the git repository format, except for
the fact that I noticed it while writing the git saving code.
The subsurface divetag list handling is being stupid, and has a
initial dummy entry at the head of the list for no good reason.
I say "no good reason", because there *is* a reason for it: it allows
code to avoid the special case of empty list and adding entries to
before the first entry etc etc. But that reason is a really *bad*
reason, because it's valid only because people don't understand basic
list manipulation and pointers to pointers.
So get rid of the dummy element, and do things right instead - by
passing a *pointer* to the list, instead of the list. And then when
traversing the list and looking for a place to insert things, don't go
to the next entry - just update the "pointer to pointer" to point to
the address of the next entry. Each entry in a C linked list is no
different than the list itself, so you can use the pointer to the
pointer to the next entry as a pointer to the list.
This is a pet peeve of mine. The real beauty of pointers can never be
understood unless you understand the indirection they allow. People
who grew up with Pascal and were corrupted by that mindset are
mentally stunted. Niklaus Wirth has a lot to answer for!
But never fear. You too can overcome that mental limitation, it just
needs some brain exercise. Reading this patch may help. In particular,
contemplate the new "taglist_add_divetag()".
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-03-10 17:18:13 +00:00
|
|
|
sep = ", ";
|
|
|
|
} while ((entry = entry->next) != NULL);
|
|
|
|
put_string(b, "'");
|
2013-04-09 20:06:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-06 18:34:19 +00:00
|
|
|
static void save_extra_data(struct membuffer *b, struct extra_data *ed)
|
|
|
|
{
|
|
|
|
while (ed) {
|
|
|
|
if (ed->key && ed->value) {
|
|
|
|
put_string(b, " <extradata");
|
|
|
|
show_utf8(b, ed->key, " key='", "'", 1);
|
|
|
|
show_utf8(b, ed->value, " value='", "'", 1);
|
|
|
|
put_string(b, " />\n");
|
|
|
|
}
|
|
|
|
ed = ed->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void show_date(struct membuffer *b, timestamp_t when)
|
2012-08-22 05:04:24 +00:00
|
|
|
{
|
2012-09-20 00:35:52 +00:00
|
|
|
struct tm tm;
|
|
|
|
|
2012-11-25 02:50:21 +00:00
|
|
|
utc_mkdate(when, &tm);
|
2012-08-22 05:04:24 +00:00
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " date='%04u-%02u-%02u'",
|
2014-02-16 23:42:56 +00:00
|
|
|
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " time='%02u:%02u:%02u'",
|
2014-02-16 23:42:56 +00:00
|
|
|
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
2012-11-25 02:50:21 +00:00
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void save_samples(struct membuffer *b, int nr, struct sample *s)
|
2011-09-01 23:27:52 +00:00
|
|
|
{
|
2014-02-16 23:42:56 +00:00
|
|
|
struct sample dummy = {};
|
2012-12-01 21:02:30 +00:00
|
|
|
|
|
|
|
while (--nr >= 0) {
|
2014-01-16 02:03:11 +00:00
|
|
|
save_sample(b, s, &dummy);
|
2012-12-01 21:02:30 +00:00
|
|
|
s++;
|
|
|
|
}
|
|
|
|
}
|
2012-11-25 04:29:14 +00:00
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void save_dc(struct membuffer *b, struct dive *dive, struct divecomputer *dc)
|
2012-12-01 21:02:30 +00:00
|
|
|
{
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " <divecomputer");
|
|
|
|
show_utf8(b, dc->model, " model='", "'", 1);
|
2012-11-25 19:44:27 +00:00
|
|
|
if (dc->deviceid)
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " deviceid='%08x'", dc->deviceid);
|
2012-11-25 19:44:27 +00:00
|
|
|
if (dc->diveid)
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " diveid='%08x'", dc->diveid);
|
2012-11-25 04:29:14 +00:00
|
|
|
if (dc->when && dc->when != dive->when)
|
2014-01-16 02:03:11 +00:00
|
|
|
show_date(b, dc->when);
|
2013-01-23 18:25:31 +00:00
|
|
|
if (dc->duration.seconds && dc->duration.seconds != dive->dc.duration.seconds)
|
2014-01-16 02:03:11 +00:00
|
|
|
put_duration(b, dc->duration, " duration='", " min'");
|
2015-01-10 23:01:15 +00:00
|
|
|
if (dc->divemode != OC) {
|
2014-11-16 23:11:18 +00:00
|
|
|
for (enum dive_comp_type i = 0; i < NUM_DC_TYPE; i++)
|
2015-01-10 23:01:15 +00:00
|
|
|
if (dc->divemode == i)
|
|
|
|
show_utf8(b, divemode_text[i], " dctype='", "'", 1);
|
2014-11-17 19:04:36 +00:00
|
|
|
if (dc->no_o2sensors)
|
|
|
|
put_format(b," no_o2sensors='%d'", dc->no_o2sensors);
|
2014-11-16 23:11:18 +00:00
|
|
|
}
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, ">\n");
|
|
|
|
save_depths(b, dc);
|
|
|
|
save_temperatures(b, dc);
|
|
|
|
save_airpressure(b, dc);
|
|
|
|
save_salinity(b, dc);
|
|
|
|
put_duration(b, dc->surfacetime, " <surfacetime>", " min</surfacetime>\n");
|
2014-11-06 18:34:19 +00:00
|
|
|
save_extra_data(b, dc->extra_data);
|
2014-01-16 02:03:11 +00:00
|
|
|
save_events(b, dc->events);
|
|
|
|
save_samples(b, dc->samples, dc->sample);
|
|
|
|
|
|
|
|
put_format(b, " </divecomputer>\n");
|
2012-11-25 02:50:21 +00:00
|
|
|
}
|
2012-09-20 00:35:52 +00:00
|
|
|
|
2014-06-03 17:26:27 +00:00
|
|
|
static void save_picture(struct membuffer *b, struct picture *pic)
|
|
|
|
{
|
|
|
|
put_string(b, " <picture filename='");
|
2014-12-09 17:37:49 +00:00
|
|
|
put_quoted(b, pic->filename, true, false);
|
2014-06-03 17:26:27 +00:00
|
|
|
put_string(b, "'");
|
2014-07-08 19:29:06 +00:00
|
|
|
if (pic->offset.seconds) {
|
|
|
|
int offset = pic->offset.seconds;
|
|
|
|
char sign = '+';
|
|
|
|
if (offset < 0) {
|
|
|
|
sign = '-';
|
|
|
|
offset = -offset;
|
|
|
|
}
|
|
|
|
put_format(b, " offset='%c%u:%02u min'", sign, FRACTION(offset, 60));
|
|
|
|
}
|
2014-06-03 17:26:27 +00:00
|
|
|
if (pic->latitude.udeg || pic->longitude.udeg) {
|
|
|
|
put_degrees(b, pic->latitude, " gps='", " ");
|
|
|
|
put_degrees(b, pic->longitude, "", "'");
|
|
|
|
}
|
2015-02-26 13:39:42 +00:00
|
|
|
if (hashstring(pic->filename))
|
|
|
|
put_format(b, " hash='%s'", hashstring(pic->filename));
|
|
|
|
|
2014-06-03 17:26:27 +00:00
|
|
|
put_string(b, "/>\n");
|
|
|
|
}
|
|
|
|
|
2015-04-28 18:27:36 +00:00
|
|
|
void save_one_dive_to_mb(struct membuffer *b, struct dive *dive)
|
2012-11-25 02:50:21 +00:00
|
|
|
{
|
|
|
|
struct divecomputer *dc;
|
2011-09-01 23:27:52 +00:00
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
put_string(b, "<dive");
|
2011-09-11 18:36:33 +00:00
|
|
|
if (dive->number)
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " number='%d'", dive->number);
|
2012-11-26 22:52:07 +00:00
|
|
|
if (dive->tripflag == NO_TRIP)
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " tripflag='NOTRIP'");
|
2011-12-08 04:49:22 +00:00
|
|
|
if (dive->rating)
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " rating='%d'", dive->rating);
|
2012-10-28 22:49:02 +00:00
|
|
|
if (dive->visibility)
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, " visibility='%d'", dive->visibility);
|
Get rid of crazy empty tag_list element at the start
So this is totally unrelated to the git repository format, except for
the fact that I noticed it while writing the git saving code.
The subsurface divetag list handling is being stupid, and has a
initial dummy entry at the head of the list for no good reason.
I say "no good reason", because there *is* a reason for it: it allows
code to avoid the special case of empty list and adding entries to
before the first entry etc etc. But that reason is a really *bad*
reason, because it's valid only because people don't understand basic
list manipulation and pointers to pointers.
So get rid of the dummy element, and do things right instead - by
passing a *pointer* to the list, instead of the list. And then when
traversing the list and looking for a place to insert things, don't go
to the next entry - just update the "pointer to pointer" to point to
the address of the next entry. Each entry in a C linked list is no
different than the list itself, so you can use the pointer to the
pointer to the next entry as a pointer to the list.
This is a pet peeve of mine. The real beauty of pointers can never be
understood unless you understand the indirection they allow. People
who grew up with Pascal and were corrupted by that mindset are
mentally stunted. Niklaus Wirth has a lot to answer for!
But never fear. You too can overcome that mental limitation, it just
needs some brain exercise. Reading this patch may help. In particular,
contemplate the new "taglist_add_divetag()".
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-03-10 17:18:13 +00:00
|
|
|
save_tags(b, dive->tag_list);
|
2015-09-08 16:45:09 +00:00
|
|
|
if (dive->dive_site_uuid) {
|
|
|
|
if (get_dive_site_by_uuid(dive->dive_site_uuid) != NULL)
|
|
|
|
put_format(b, " divesiteid='%8x'", dive->dive_site_uuid);
|
|
|
|
else if (verbose)
|
|
|
|
fprintf(stderr, "removed reference to non-existant dive site with uuid %08x\n", dive->dive_site_uuid);
|
|
|
|
}
|
2014-01-16 02:03:11 +00:00
|
|
|
show_date(b, dive->when);
|
|
|
|
put_format(b, " duration='%u:%02u min'>\n",
|
2014-02-16 23:42:56 +00:00
|
|
|
FRACTION(dive->dc.duration.seconds, 60));
|
2014-01-16 02:03:11 +00:00
|
|
|
save_overview(b, dive);
|
|
|
|
save_cylinder_info(b, dive);
|
|
|
|
save_weightsystem_info(b, dive);
|
|
|
|
save_dive_temperature(b, dive);
|
2012-11-25 02:50:21 +00:00
|
|
|
/* Save the dive computer data */
|
2014-05-13 22:32:45 +00:00
|
|
|
for_each_dc(dive, dc)
|
2014-01-16 02:03:11 +00:00
|
|
|
save_dc(b, dive, dc);
|
2014-06-03 17:26:27 +00:00
|
|
|
FOR_EACH_PICTURE(dive)
|
|
|
|
save_picture(b, picture);
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, "</dive>\n");
|
|
|
|
}
|
|
|
|
|
2014-03-14 17:11:26 +00:00
|
|
|
int save_dive(FILE *f, struct dive *dive)
|
2014-01-16 02:03:11 +00:00
|
|
|
{
|
2014-02-16 23:42:56 +00:00
|
|
|
struct membuffer buf = { 0 };
|
2014-01-16 02:03:11 +00:00
|
|
|
|
2015-04-28 18:27:36 +00:00
|
|
|
save_one_dive_to_mb(&buf, dive);
|
2014-01-16 02:03:11 +00:00
|
|
|
flush_buffer(&buf, f);
|
2014-03-14 17:11:26 +00:00
|
|
|
/* Error handling? */
|
|
|
|
return 0;
|
2011-09-01 23:27:52 +00:00
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
static void save_trip(struct membuffer *b, dive_trip_t *trip)
|
Allow overlapping (and disjoint) dive trips
We used to have the rule that a dive trip has to have all dives in it in
sequential order, even though our XML file really is much more flexible,
and allows arbitrary nesting of dives within a dive trip.
Put another way, the old model had fairly inflexible rules:
- the dive array is sorted by time
- a dive trip is always a contiguous slice of this sorted array
which makes perfect sense when you think of the dive and trip list as a
physical activity by one person, but leads to various very subtle issues
in the general case when there are no guarantees that the user then uses
subsurface that way.
In particular, if you load the XML files of two divers that have
overlapping dive trips, the end result is incredibly messy, and does not
conform to the above model at all.
There's two ways to enforce such conformance:
- disallow that kind of behavior entirely.
This is actually hard. Our XML files aren't date-based, they are
based on XML nesting rules, and even a single XML file can have
nesting that violates the date ordering. With multiple XML files,
it's trivial to do in practice, and while we could just fail at
loading, the failure would have to be a hard failure that leaves the
user no way to use the data at all.
- try to "fix it up" by sorting, splitting, and combining dive trips
automatically.
Dirk had a patch to do this, but it really does destroy the actual
dive data: if you load both mine and Dirk's dive trips, you ended up
with a result that followed the above two technical rules, but that
didn't actually make any *sense*.
So this patch doesn't try to enforce the rules, and instead just changes
them to be more generic:
- the dive array is still sorted by dive time
- a dive trip is just an arbitrary collection of dives.
The relaxed rules means that mixing dives and dive trips for two people
is trivial, and we can easily handle any XML file. The dive trip is
defined by the XML nesting level, and is totally independent of any
date-based sorting.
It does require a few things:
- when we save our dive data, we have to do it hierarchically by dive
trip, not just by walking the dive array linearly.
- similarly, when we create the dive tree model, we can't just blindly
walk the array of dives one by one, we have to look up the correct
trip (parent)
- when we try to merge two dives that are adjacent (by date sorting),
we can't do it if they are in different trips.
but apart from that, nothing else really changes.
NOTE! Despite the new relaxed model, creating totally disjoing dive
trips is not all that easy (nor is there any *reason* for it to be
easty). Our GUI interfaces still are "add dive to trip above" etc, and
the automatic adding of dives to dive trips is obviously still based on
date.
So this does not really change the expected normal usage, the relaxed
data structure rules just mean that we don't need to worry about the odd
cases as much, because we can just let them be.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-30 19:00:37 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct dive *dive;
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, "<trip");
|
|
|
|
show_date(b, trip->when);
|
2014-02-16 23:42:56 +00:00
|
|
|
show_utf8(b, trip->location, " location=\'", "\'", 1);
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, ">\n");
|
2014-02-16 23:42:56 +00:00
|
|
|
show_utf8(b, trip->notes, "<notes>", "</notes>\n", 0);
|
Allow overlapping (and disjoint) dive trips
We used to have the rule that a dive trip has to have all dives in it in
sequential order, even though our XML file really is much more flexible,
and allows arbitrary nesting of dives within a dive trip.
Put another way, the old model had fairly inflexible rules:
- the dive array is sorted by time
- a dive trip is always a contiguous slice of this sorted array
which makes perfect sense when you think of the dive and trip list as a
physical activity by one person, but leads to various very subtle issues
in the general case when there are no guarantees that the user then uses
subsurface that way.
In particular, if you load the XML files of two divers that have
overlapping dive trips, the end result is incredibly messy, and does not
conform to the above model at all.
There's two ways to enforce such conformance:
- disallow that kind of behavior entirely.
This is actually hard. Our XML files aren't date-based, they are
based on XML nesting rules, and even a single XML file can have
nesting that violates the date ordering. With multiple XML files,
it's trivial to do in practice, and while we could just fail at
loading, the failure would have to be a hard failure that leaves the
user no way to use the data at all.
- try to "fix it up" by sorting, splitting, and combining dive trips
automatically.
Dirk had a patch to do this, but it really does destroy the actual
dive data: if you load both mine and Dirk's dive trips, you ended up
with a result that followed the above two technical rules, but that
didn't actually make any *sense*.
So this patch doesn't try to enforce the rules, and instead just changes
them to be more generic:
- the dive array is still sorted by dive time
- a dive trip is just an arbitrary collection of dives.
The relaxed rules means that mixing dives and dive trips for two people
is trivial, and we can easily handle any XML file. The dive trip is
defined by the XML nesting level, and is totally independent of any
date-based sorting.
It does require a few things:
- when we save our dive data, we have to do it hierarchically by dive
trip, not just by walking the dive array linearly.
- similarly, when we create the dive tree model, we can't just blindly
walk the array of dives one by one, we have to look up the correct
trip (parent)
- when we try to merge two dives that are adjacent (by date sorting),
we can't do it if they are in different trips.
but apart from that, nothing else really changes.
NOTE! Despite the new relaxed model, creating totally disjoing dive
trips is not all that easy (nor is there any *reason* for it to be
easty). Our GUI interfaces still are "add dive to trip above" etc, and
the automatic adding of dives to dive trips is obviously still based on
date.
So this does not really change the expected normal usage, the relaxed
data structure rules just mean that we don't need to worry about the odd
cases as much, because we can just let them be.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-30 19:00:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Incredibly cheesy: we want to save the dives sorted, and they
|
|
|
|
* are sorted in the dive array.. So instead of using the dive
|
|
|
|
* list in the trip, we just traverse the global dive array and
|
|
|
|
* check the divetrip pointer..
|
|
|
|
*/
|
|
|
|
for_each_dive(i, dive) {
|
|
|
|
if (dive->divetrip == trip)
|
2015-04-28 18:27:36 +00:00
|
|
|
save_one_dive_to_mb(b, dive);
|
Allow overlapping (and disjoint) dive trips
We used to have the rule that a dive trip has to have all dives in it in
sequential order, even though our XML file really is much more flexible,
and allows arbitrary nesting of dives within a dive trip.
Put another way, the old model had fairly inflexible rules:
- the dive array is sorted by time
- a dive trip is always a contiguous slice of this sorted array
which makes perfect sense when you think of the dive and trip list as a
physical activity by one person, but leads to various very subtle issues
in the general case when there are no guarantees that the user then uses
subsurface that way.
In particular, if you load the XML files of two divers that have
overlapping dive trips, the end result is incredibly messy, and does not
conform to the above model at all.
There's two ways to enforce such conformance:
- disallow that kind of behavior entirely.
This is actually hard. Our XML files aren't date-based, they are
based on XML nesting rules, and even a single XML file can have
nesting that violates the date ordering. With multiple XML files,
it's trivial to do in practice, and while we could just fail at
loading, the failure would have to be a hard failure that leaves the
user no way to use the data at all.
- try to "fix it up" by sorting, splitting, and combining dive trips
automatically.
Dirk had a patch to do this, but it really does destroy the actual
dive data: if you load both mine and Dirk's dive trips, you ended up
with a result that followed the above two technical rules, but that
didn't actually make any *sense*.
So this patch doesn't try to enforce the rules, and instead just changes
them to be more generic:
- the dive array is still sorted by dive time
- a dive trip is just an arbitrary collection of dives.
The relaxed rules means that mixing dives and dive trips for two people
is trivial, and we can easily handle any XML file. The dive trip is
defined by the XML nesting level, and is totally independent of any
date-based sorting.
It does require a few things:
- when we save our dive data, we have to do it hierarchically by dive
trip, not just by walking the dive array linearly.
- similarly, when we create the dive tree model, we can't just blindly
walk the array of dives one by one, we have to look up the correct
trip (parent)
- when we try to merge two dives that are adjacent (by date sorting),
we can't do it if they are in different trips.
but apart from that, nothing else really changes.
NOTE! Despite the new relaxed model, creating totally disjoing dive
trips is not all that easy (nor is there any *reason* for it to be
easty). Our GUI interfaces still are "add dive to trip above" etc, and
the automatic adding of dives to dive trips is obviously still based on
date.
So this does not really change the expected normal usage, the relaxed
data structure rules just mean that we don't need to worry about the odd
cases as much, because we can just let them be.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-30 19:00:37 +00:00
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, "</trip>\n");
|
Allow overlapping (and disjoint) dive trips
We used to have the rule that a dive trip has to have all dives in it in
sequential order, even though our XML file really is much more flexible,
and allows arbitrary nesting of dives within a dive trip.
Put another way, the old model had fairly inflexible rules:
- the dive array is sorted by time
- a dive trip is always a contiguous slice of this sorted array
which makes perfect sense when you think of the dive and trip list as a
physical activity by one person, but leads to various very subtle issues
in the general case when there are no guarantees that the user then uses
subsurface that way.
In particular, if you load the XML files of two divers that have
overlapping dive trips, the end result is incredibly messy, and does not
conform to the above model at all.
There's two ways to enforce such conformance:
- disallow that kind of behavior entirely.
This is actually hard. Our XML files aren't date-based, they are
based on XML nesting rules, and even a single XML file can have
nesting that violates the date ordering. With multiple XML files,
it's trivial to do in practice, and while we could just fail at
loading, the failure would have to be a hard failure that leaves the
user no way to use the data at all.
- try to "fix it up" by sorting, splitting, and combining dive trips
automatically.
Dirk had a patch to do this, but it really does destroy the actual
dive data: if you load both mine and Dirk's dive trips, you ended up
with a result that followed the above two technical rules, but that
didn't actually make any *sense*.
So this patch doesn't try to enforce the rules, and instead just changes
them to be more generic:
- the dive array is still sorted by dive time
- a dive trip is just an arbitrary collection of dives.
The relaxed rules means that mixing dives and dive trips for two people
is trivial, and we can easily handle any XML file. The dive trip is
defined by the XML nesting level, and is totally independent of any
date-based sorting.
It does require a few things:
- when we save our dive data, we have to do it hierarchically by dive
trip, not just by walking the dive array linearly.
- similarly, when we create the dive tree model, we can't just blindly
walk the array of dives one by one, we have to look up the correct
trip (parent)
- when we try to merge two dives that are adjacent (by date sorting),
we can't do it if they are in different trips.
but apart from that, nothing else really changes.
NOTE! Despite the new relaxed model, creating totally disjoing dive
trips is not all that easy (nor is there any *reason* for it to be
easty). Our GUI interfaces still are "add dive to trip above" etc, and
the automatic adding of dives to dive trips is obviously still based on
date.
So this does not really change the expected normal usage, the relaxed
data structure rules just mean that we don't need to worry about the odd
cases as much, because we can just let them be.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-30 19:00:37 +00:00
|
|
|
}
|
|
|
|
|
2014-02-16 23:42:56 +00:00
|
|
|
static void save_one_device(void *_f, const char *model, uint32_t deviceid,
|
2013-06-17 22:58:26 +00:00
|
|
|
const char *nickname, const char *serial_nr, const char *firmware)
|
2012-12-28 16:38:47 +00:00
|
|
|
{
|
2014-01-16 02:03:11 +00:00
|
|
|
struct membuffer *b = _f;
|
|
|
|
|
Assemble the actual Suunto serial number
It turns out that the serial number returned by libdivecomputer isn't
really the serial number as interpreted by the vendor. Those tend to be
strings, but libdivecomputer gives us a 32bit number.
Some experimenting showed that for the Suunto devies tested the serial
number is encoded in that 32bit number:
It so happens that the Suunto serial number strings are strings that have
all numbers, but they aren't *one* number. They are four bytes
representing two numbers each, and the "23500027" string is actually the
four bytes 23 50 00 27 (0x17 0x32 0x00 0x1b). And libdivecomputer has
incorrectly parsed those four bytes as one number, not as the encoded
serial number string it is. So the value 389152795 is actually hex
0x1732001b, which is 0x17 0x32 0x00 0x1b, which is - 23 50 00 27.
This should be done by libdivecomputer, but hey, in the meantime this at
least shows the concept. And helps test the XML save/restore code.
It depends on the two patches that create the whole "device.c"
infrastructure, of course. With this, my dive file ends up having the
settings section look like this:
<divecomputerid model='Suunto Vyper Air' deviceid='d4629110'
serial='01201094' firmware='1.1.22'/>
<divecomputerid model='Suunto HelO2' deviceid='995dd566'
serial='23500027' firmware='1.0.4'/>
where the format of the firmware version is something I guessed at,
but it was the obvious choice (again, it's byte-based, I'm ignoring
the high byte that is zero for both of my Suuntos).
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-01-10 00:14:21 +00:00
|
|
|
/* Nicknames that are empty or the same as the device model are not interesting */
|
|
|
|
if (nickname) {
|
2013-06-17 22:58:26 +00:00
|
|
|
if (!*nickname || !strcmp(model, nickname))
|
Assemble the actual Suunto serial number
It turns out that the serial number returned by libdivecomputer isn't
really the serial number as interpreted by the vendor. Those tend to be
strings, but libdivecomputer gives us a 32bit number.
Some experimenting showed that for the Suunto devies tested the serial
number is encoded in that 32bit number:
It so happens that the Suunto serial number strings are strings that have
all numbers, but they aren't *one* number. They are four bytes
representing two numbers each, and the "23500027" string is actually the
four bytes 23 50 00 27 (0x17 0x32 0x00 0x1b). And libdivecomputer has
incorrectly parsed those four bytes as one number, not as the encoded
serial number string it is. So the value 389152795 is actually hex
0x1732001b, which is 0x17 0x32 0x00 0x1b, which is - 23 50 00 27.
This should be done by libdivecomputer, but hey, in the meantime this at
least shows the concept. And helps test the XML save/restore code.
It depends on the two patches that create the whole "device.c"
infrastructure, of course. With this, my dive file ends up having the
settings section look like this:
<divecomputerid model='Suunto Vyper Air' deviceid='d4629110'
serial='01201094' firmware='1.1.22'/>
<divecomputerid model='Suunto HelO2' deviceid='995dd566'
serial='23500027' firmware='1.0.4'/>
where the format of the firmware version is something I guessed at,
but it was the obvious choice (again, it's byte-based, I'm ignoring
the high byte that is zero for both of my Suuntos).
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-01-10 00:14:21 +00:00
|
|
|
nickname = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Serial numbers that are empty are not interesting */
|
|
|
|
if (serial_nr && !*serial_nr)
|
|
|
|
serial_nr = NULL;
|
|
|
|
|
|
|
|
/* Firmware strings that are empty are not interesting */
|
|
|
|
if (firmware && !*firmware)
|
|
|
|
firmware = NULL;
|
2012-12-28 16:38:47 +00:00
|
|
|
|
Assemble the actual Suunto serial number
It turns out that the serial number returned by libdivecomputer isn't
really the serial number as interpreted by the vendor. Those tend to be
strings, but libdivecomputer gives us a 32bit number.
Some experimenting showed that for the Suunto devies tested the serial
number is encoded in that 32bit number:
It so happens that the Suunto serial number strings are strings that have
all numbers, but they aren't *one* number. They are four bytes
representing two numbers each, and the "23500027" string is actually the
four bytes 23 50 00 27 (0x17 0x32 0x00 0x1b). And libdivecomputer has
incorrectly parsed those four bytes as one number, not as the encoded
serial number string it is. So the value 389152795 is actually hex
0x1732001b, which is 0x17 0x32 0x00 0x1b, which is - 23 50 00 27.
This should be done by libdivecomputer, but hey, in the meantime this at
least shows the concept. And helps test the XML save/restore code.
It depends on the two patches that create the whole "device.c"
infrastructure, of course. With this, my dive file ends up having the
settings section look like this:
<divecomputerid model='Suunto Vyper Air' deviceid='d4629110'
serial='01201094' firmware='1.1.22'/>
<divecomputerid model='Suunto HelO2' deviceid='995dd566'
serial='23500027' firmware='1.0.4'/>
where the format of the firmware version is something I guessed at,
but it was the obvious choice (again, it's byte-based, I'm ignoring
the high byte that is zero for both of my Suuntos).
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-01-10 00:14:21 +00:00
|
|
|
/* Do we have anything interesting about this dive computer to save? */
|
|
|
|
if (!serial_nr && !nickname && !firmware)
|
2012-12-31 04:27:01 +00:00
|
|
|
return;
|
2012-12-28 16:38:47 +00:00
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, "<divecomputerid");
|
|
|
|
show_utf8(b, model, " model='", "'", 1);
|
|
|
|
put_format(b, " deviceid='%08x'", deviceid);
|
|
|
|
show_utf8(b, serial_nr, " serial='", "'", 1);
|
|
|
|
show_utf8(b, firmware, " firmware='", "'", 1);
|
|
|
|
show_utf8(b, nickname, " nickname='", "'", 1);
|
|
|
|
put_format(b, "/>\n");
|
2013-01-24 19:42:20 +00:00
|
|
|
}
|
|
|
|
|
2014-03-14 17:11:26 +00:00
|
|
|
int save_dives(const char *filename)
|
2013-02-01 08:28:33 +00:00
|
|
|
{
|
2014-03-14 17:11:26 +00:00
|
|
|
return save_dives_logic(filename, false);
|
2013-02-01 08:28:33 +00:00
|
|
|
}
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
void save_dives_buffer(struct membuffer *b, const bool select_only)
|
2011-09-01 23:27:52 +00:00
|
|
|
{
|
|
|
|
int i;
|
New XML format for saving dives
This patch makes the trips nest, and it also fixes the fact that you never
saved the trip notes (you could edit it, but saving would throw it away).
I did *not* change the indentation of the dives, so the trip stuff shows
up the the beginning of the line, at the same level as the <dive> and
<dives> thing. I think it's fairly readable xml, though, and we haven't
really had proper "indentation shows nesting" anyway, since the top-level
"<dives>" thing also didn't indent stuff inside of it.
Anyway, the way I wrote it, it still parses your old "INTRIP" stuff etc,
so as far as I know, it should happily read the old-style XML too. At
least it seemed to work with your xml file that already had the old-style
one (I haven't committed my divetrips, exactly because I didn't like the
new format).
It always saves in the new style, though.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-09-30 19:36:18 +00:00
|
|
|
struct dive *dive;
|
Allow overlapping (and disjoint) dive trips
We used to have the rule that a dive trip has to have all dives in it in
sequential order, even though our XML file really is much more flexible,
and allows arbitrary nesting of dives within a dive trip.
Put another way, the old model had fairly inflexible rules:
- the dive array is sorted by time
- a dive trip is always a contiguous slice of this sorted array
which makes perfect sense when you think of the dive and trip list as a
physical activity by one person, but leads to various very subtle issues
in the general case when there are no guarantees that the user then uses
subsurface that way.
In particular, if you load the XML files of two divers that have
overlapping dive trips, the end result is incredibly messy, and does not
conform to the above model at all.
There's two ways to enforce such conformance:
- disallow that kind of behavior entirely.
This is actually hard. Our XML files aren't date-based, they are
based on XML nesting rules, and even a single XML file can have
nesting that violates the date ordering. With multiple XML files,
it's trivial to do in practice, and while we could just fail at
loading, the failure would have to be a hard failure that leaves the
user no way to use the data at all.
- try to "fix it up" by sorting, splitting, and combining dive trips
automatically.
Dirk had a patch to do this, but it really does destroy the actual
dive data: if you load both mine and Dirk's dive trips, you ended up
with a result that followed the above two technical rules, but that
didn't actually make any *sense*.
So this patch doesn't try to enforce the rules, and instead just changes
them to be more generic:
- the dive array is still sorted by dive time
- a dive trip is just an arbitrary collection of dives.
The relaxed rules means that mixing dives and dive trips for two people
is trivial, and we can easily handle any XML file. The dive trip is
defined by the XML nesting level, and is totally independent of any
date-based sorting.
It does require a few things:
- when we save our dive data, we have to do it hierarchically by dive
trip, not just by walking the dive array linearly.
- similarly, when we create the dive tree model, we can't just blindly
walk the array of dives one by one, we have to look up the correct
trip (parent)
- when we try to merge two dives that are adjacent (by date sorting),
we can't do it if they are in different trips.
but apart from that, nothing else really changes.
NOTE! Despite the new relaxed model, creating totally disjoing dive
trips is not all that easy (nor is there any *reason* for it to be
easty). Our GUI interfaces still are "add dive to trip above" etc, and
the automatic adding of dives to dive trips is obviously still based on
date.
So this does not really change the expected normal usage, the relaxed
data structure rules just mean that we don't need to worry about the odd
cases as much, because we can just let them be.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-30 19:00:37 +00:00
|
|
|
dive_trip_t *trip;
|
2012-08-22 05:04:24 +00:00
|
|
|
|
2015-06-20 13:45:12 +00:00
|
|
|
put_format(b, "<divelog program='subsurface' version='%d'>\n<settings>\n", DATAFORMAT_VERSION);
|
2013-01-01 16:29:43 +00:00
|
|
|
|
2014-04-17 14:34:21 +00:00
|
|
|
if (prefs.save_userid_local)
|
2014-11-20 22:30:44 +00:00
|
|
|
put_format(b, " <userid>%30s</userid>\n", prefs.userid);
|
2014-04-11 06:17:35 +00:00
|
|
|
|
2013-01-01 16:29:43 +00:00
|
|
|
/* save the dive computer nicknames, if any */
|
2015-06-10 14:24:34 +00:00
|
|
|
call_for_each_dc(b, save_one_device, select_only);
|
2013-01-02 01:29:38 +00:00
|
|
|
if (autogroup)
|
2014-04-11 06:17:35 +00:00
|
|
|
put_format(b, " <autogroup state='1' />\n");
|
2015-02-12 05:46:02 +00:00
|
|
|
put_format(b, "</settings>\n");
|
|
|
|
|
2015-08-24 18:07:57 +00:00
|
|
|
/* save the dive sites - to make the output consistent let's sort the table, first */
|
|
|
|
dive_site_table_sort();
|
2015-02-12 05:46:02 +00:00
|
|
|
put_format(b, "<divesites>\n");
|
|
|
|
for (i = 0; i < dive_site_table.nr; i++) {
|
2015-06-10 14:13:00 +00:00
|
|
|
int j;
|
|
|
|
struct dive *d;
|
2015-02-12 05:46:02 +00:00
|
|
|
struct dive_site *ds = get_dive_site(i);
|
2015-02-14 07:22:40 +00:00
|
|
|
if (dive_site_is_empty(ds)) {
|
|
|
|
for_each_dive(j, d) {
|
|
|
|
if (d->dive_site_uuid == ds->uuid)
|
|
|
|
d->dive_site_uuid = 0;
|
|
|
|
}
|
2015-09-29 02:30:20 +00:00
|
|
|
delete_dive_site(ds->uuid);
|
2015-02-14 07:22:40 +00:00
|
|
|
i--; // since we just deleted that one
|
|
|
|
continue;
|
2015-09-29 02:30:20 +00:00
|
|
|
} else if (ds->name &&
|
|
|
|
(strncmp(ds->name, "Auto-created dive", 17) == 0 ||
|
|
|
|
strncmp(ds->name, "New Dive", 8) == 0)) {
|
|
|
|
// these are the two default names for sites from
|
|
|
|
// the web service; if the site isn't used in any
|
|
|
|
// dive (really? you didn't rename it?), delete it
|
|
|
|
if (!is_dive_site_used(ds->uuid, false)) {
|
|
|
|
if (verbose)
|
|
|
|
fprintf(stderr, "Deleted unused auto-created dive site %s\n", ds->name);
|
|
|
|
delete_dive_site(ds->uuid);
|
|
|
|
i--; // since we just deleted that one
|
|
|
|
continue;
|
|
|
|
}
|
2015-02-14 07:22:40 +00:00
|
|
|
}
|
2015-07-16 04:25:26 +00:00
|
|
|
if (select_only && !is_dive_site_used(ds->uuid, true))
|
2015-06-10 14:13:00 +00:00
|
|
|
continue;
|
2015-07-16 04:25:26 +00:00
|
|
|
|
2015-02-15 13:03:57 +00:00
|
|
|
put_format(b, "<site uuid='%8x'", ds->uuid);
|
2015-02-12 05:46:02 +00:00
|
|
|
show_utf8(b, ds->name, " name='", "'", 1);
|
|
|
|
if (ds->latitude.udeg || ds->longitude.udeg) {
|
|
|
|
put_degrees(b, ds->latitude, " gps='", " ");
|
|
|
|
put_degrees(b, ds->longitude, "", "'");
|
|
|
|
}
|
|
|
|
show_utf8(b, ds->description, " description='", "'", 1);
|
2015-10-04 09:17:25 +00:00
|
|
|
put_format(b, ">\n");
|
|
|
|
show_utf8(b, ds->notes, " <notes>", " </notes>\n", 0);
|
2015-08-20 18:05:07 +00:00
|
|
|
if (ds->taxonomy.nr) {
|
2015-07-01 19:30:33 +00:00
|
|
|
for (int j = 0; j < ds->taxonomy.nr; j++) {
|
|
|
|
struct taxonomy *t = &ds->taxonomy.category[j];
|
2015-07-02 17:21:35 +00:00
|
|
|
if (t->category != TC_NONE) {
|
2015-10-04 09:17:25 +00:00
|
|
|
put_format(b, " <geo cat='%d'", t->category);
|
2015-07-01 19:30:33 +00:00
|
|
|
put_format(b, " origin='%d'", t->origin);
|
|
|
|
show_utf8(b, t->value, " value='", "'/>\n", 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-10-04 09:17:25 +00:00
|
|
|
put_format(b, "</site>\n");
|
2015-02-12 05:46:02 +00:00
|
|
|
}
|
|
|
|
put_format(b, "</divesites>\n<dives>\n");
|
Allow overlapping (and disjoint) dive trips
We used to have the rule that a dive trip has to have all dives in it in
sequential order, even though our XML file really is much more flexible,
and allows arbitrary nesting of dives within a dive trip.
Put another way, the old model had fairly inflexible rules:
- the dive array is sorted by time
- a dive trip is always a contiguous slice of this sorted array
which makes perfect sense when you think of the dive and trip list as a
physical activity by one person, but leads to various very subtle issues
in the general case when there are no guarantees that the user then uses
subsurface that way.
In particular, if you load the XML files of two divers that have
overlapping dive trips, the end result is incredibly messy, and does not
conform to the above model at all.
There's two ways to enforce such conformance:
- disallow that kind of behavior entirely.
This is actually hard. Our XML files aren't date-based, they are
based on XML nesting rules, and even a single XML file can have
nesting that violates the date ordering. With multiple XML files,
it's trivial to do in practice, and while we could just fail at
loading, the failure would have to be a hard failure that leaves the
user no way to use the data at all.
- try to "fix it up" by sorting, splitting, and combining dive trips
automatically.
Dirk had a patch to do this, but it really does destroy the actual
dive data: if you load both mine and Dirk's dive trips, you ended up
with a result that followed the above two technical rules, but that
didn't actually make any *sense*.
So this patch doesn't try to enforce the rules, and instead just changes
them to be more generic:
- the dive array is still sorted by dive time
- a dive trip is just an arbitrary collection of dives.
The relaxed rules means that mixing dives and dive trips for two people
is trivial, and we can easily handle any XML file. The dive trip is
defined by the XML nesting level, and is totally independent of any
date-based sorting.
It does require a few things:
- when we save our dive data, we have to do it hierarchically by dive
trip, not just by walking the dive array linearly.
- similarly, when we create the dive tree model, we can't just blindly
walk the array of dives one by one, we have to look up the correct
trip (parent)
- when we try to merge two dives that are adjacent (by date sorting),
we can't do it if they are in different trips.
but apart from that, nothing else really changes.
NOTE! Despite the new relaxed model, creating totally disjoing dive
trips is not all that easy (nor is there any *reason* for it to be
easty). Our GUI interfaces still are "add dive to trip above" etc, and
the automatic adding of dives to dive trips is obviously still based on
date.
So this does not really change the expected normal usage, the relaxed
data structure rules just mean that we don't need to worry about the odd
cases as much, because we can just let them be.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-30 19:00:37 +00:00
|
|
|
for (trip = dive_trip_list; trip != NULL; trip = trip->next)
|
|
|
|
trip->index = 0;
|
|
|
|
|
2012-08-22 05:04:24 +00:00
|
|
|
/* save the dives */
|
New XML format for saving dives
This patch makes the trips nest, and it also fixes the fact that you never
saved the trip notes (you could edit it, but saving would throw it away).
I did *not* change the indentation of the dives, so the trip stuff shows
up the the beginning of the line, at the same level as the <dive> and
<dives> thing. I think it's fairly readable xml, though, and we haven't
really had proper "indentation shows nesting" anyway, since the top-level
"<dives>" thing also didn't indent stuff inside of it.
Anyway, the way I wrote it, it still parses your old "INTRIP" stuff etc,
so as far as I know, it should happily read the old-style XML too. At
least it seemed to work with your xml file that already had the old-style
one (I haven't committed my divetrips, exactly because I didn't like the
new format).
It always saves in the new style, though.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-09-30 19:36:18 +00:00
|
|
|
for_each_dive(i, dive) {
|
2013-02-01 08:28:33 +00:00
|
|
|
if (select_only) {
|
|
|
|
|
2014-02-16 23:42:56 +00:00
|
|
|
if (!dive->selected)
|
2013-02-01 08:28:33 +00:00
|
|
|
continue;
|
2015-04-28 18:27:36 +00:00
|
|
|
save_one_dive_to_mb(b, dive);
|
Allow overlapping (and disjoint) dive trips
We used to have the rule that a dive trip has to have all dives in it in
sequential order, even though our XML file really is much more flexible,
and allows arbitrary nesting of dives within a dive trip.
Put another way, the old model had fairly inflexible rules:
- the dive array is sorted by time
- a dive trip is always a contiguous slice of this sorted array
which makes perfect sense when you think of the dive and trip list as a
physical activity by one person, but leads to various very subtle issues
in the general case when there are no guarantees that the user then uses
subsurface that way.
In particular, if you load the XML files of two divers that have
overlapping dive trips, the end result is incredibly messy, and does not
conform to the above model at all.
There's two ways to enforce such conformance:
- disallow that kind of behavior entirely.
This is actually hard. Our XML files aren't date-based, they are
based on XML nesting rules, and even a single XML file can have
nesting that violates the date ordering. With multiple XML files,
it's trivial to do in practice, and while we could just fail at
loading, the failure would have to be a hard failure that leaves the
user no way to use the data at all.
- try to "fix it up" by sorting, splitting, and combining dive trips
automatically.
Dirk had a patch to do this, but it really does destroy the actual
dive data: if you load both mine and Dirk's dive trips, you ended up
with a result that followed the above two technical rules, but that
didn't actually make any *sense*.
So this patch doesn't try to enforce the rules, and instead just changes
them to be more generic:
- the dive array is still sorted by dive time
- a dive trip is just an arbitrary collection of dives.
The relaxed rules means that mixing dives and dive trips for two people
is trivial, and we can easily handle any XML file. The dive trip is
defined by the XML nesting level, and is totally independent of any
date-based sorting.
It does require a few things:
- when we save our dive data, we have to do it hierarchically by dive
trip, not just by walking the dive array linearly.
- similarly, when we create the dive tree model, we can't just blindly
walk the array of dives one by one, we have to look up the correct
trip (parent)
- when we try to merge two dives that are adjacent (by date sorting),
we can't do it if they are in different trips.
but apart from that, nothing else really changes.
NOTE! Despite the new relaxed model, creating totally disjoing dive
trips is not all that easy (nor is there any *reason* for it to be
easty). Our GUI interfaces still are "add dive to trip above" etc, and
the automatic adding of dives to dive trips is obviously still based on
date.
So this does not really change the expected normal usage, the relaxed
data structure rules just mean that we don't need to worry about the odd
cases as much, because we can just let them be.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-30 19:00:37 +00:00
|
|
|
|
2013-02-01 08:28:33 +00:00
|
|
|
} else {
|
|
|
|
trip = dive->divetrip;
|
|
|
|
|
|
|
|
/* Bare dive without a trip? */
|
|
|
|
if (!trip) {
|
2015-04-28 18:27:36 +00:00
|
|
|
save_one_dive_to_mb(b, dive);
|
2013-02-01 08:28:33 +00:00
|
|
|
continue;
|
|
|
|
}
|
Allow overlapping (and disjoint) dive trips
We used to have the rule that a dive trip has to have all dives in it in
sequential order, even though our XML file really is much more flexible,
and allows arbitrary nesting of dives within a dive trip.
Put another way, the old model had fairly inflexible rules:
- the dive array is sorted by time
- a dive trip is always a contiguous slice of this sorted array
which makes perfect sense when you think of the dive and trip list as a
physical activity by one person, but leads to various very subtle issues
in the general case when there are no guarantees that the user then uses
subsurface that way.
In particular, if you load the XML files of two divers that have
overlapping dive trips, the end result is incredibly messy, and does not
conform to the above model at all.
There's two ways to enforce such conformance:
- disallow that kind of behavior entirely.
This is actually hard. Our XML files aren't date-based, they are
based on XML nesting rules, and even a single XML file can have
nesting that violates the date ordering. With multiple XML files,
it's trivial to do in practice, and while we could just fail at
loading, the failure would have to be a hard failure that leaves the
user no way to use the data at all.
- try to "fix it up" by sorting, splitting, and combining dive trips
automatically.
Dirk had a patch to do this, but it really does destroy the actual
dive data: if you load both mine and Dirk's dive trips, you ended up
with a result that followed the above two technical rules, but that
didn't actually make any *sense*.
So this patch doesn't try to enforce the rules, and instead just changes
them to be more generic:
- the dive array is still sorted by dive time
- a dive trip is just an arbitrary collection of dives.
The relaxed rules means that mixing dives and dive trips for two people
is trivial, and we can easily handle any XML file. The dive trip is
defined by the XML nesting level, and is totally independent of any
date-based sorting.
It does require a few things:
- when we save our dive data, we have to do it hierarchically by dive
trip, not just by walking the dive array linearly.
- similarly, when we create the dive tree model, we can't just blindly
walk the array of dives one by one, we have to look up the correct
trip (parent)
- when we try to merge two dives that are adjacent (by date sorting),
we can't do it if they are in different trips.
but apart from that, nothing else really changes.
NOTE! Despite the new relaxed model, creating totally disjoing dive
trips is not all that easy (nor is there any *reason* for it to be
easty). Our GUI interfaces still are "add dive to trip above" etc, and
the automatic adding of dives to dive trips is obviously still based on
date.
So this does not really change the expected normal usage, the relaxed
data structure rules just mean that we don't need to worry about the odd
cases as much, because we can just let them be.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-30 19:00:37 +00:00
|
|
|
|
2013-02-01 08:28:33 +00:00
|
|
|
/* Have we already seen this trip (and thus saved this dive?) */
|
|
|
|
if (trip->index)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* We haven't seen this trip before - save it and all dives */
|
|
|
|
trip->index = 1;
|
2014-01-16 02:03:11 +00:00
|
|
|
save_trip(b, trip);
|
2013-02-01 08:28:33 +00:00
|
|
|
}
|
New XML format for saving dives
This patch makes the trips nest, and it also fixes the fact that you never
saved the trip notes (you could edit it, but saving would throw it away).
I did *not* change the indentation of the dives, so the trip stuff shows
up the the beginning of the line, at the same level as the <dive> and
<dives> thing. I think it's fairly readable xml, though, and we haven't
really had proper "indentation shows nesting" anyway, since the top-level
"<dives>" thing also didn't indent stuff inside of it.
Anyway, the way I wrote it, it still parses your old "INTRIP" stuff etc,
so as far as I know, it should happily read the old-style XML too. At
least it seemed to work with your xml file that already had the old-style
one (I haven't committed my divetrips, exactly because I didn't like the
new format).
It always saves in the new style, though.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-09-30 19:36:18 +00:00
|
|
|
}
|
2014-01-16 02:03:11 +00:00
|
|
|
put_format(b, "</dives>\n</divelog>\n");
|
|
|
|
}
|
|
|
|
|
2014-02-16 21:25:02 +00:00
|
|
|
static void save_backup(const char *name, const char *ext, const char *new_ext)
|
|
|
|
{
|
|
|
|
int len = strlen(name);
|
|
|
|
int a = strlen(ext), b = strlen(new_ext);
|
|
|
|
char *newname;
|
|
|
|
|
|
|
|
/* len up to and including the final '.' */
|
|
|
|
len -= a;
|
|
|
|
if (len <= 1)
|
|
|
|
return;
|
2014-02-16 23:42:56 +00:00
|
|
|
if (name[len - 1] != '.')
|
2014-02-16 21:25:02 +00:00
|
|
|
return;
|
|
|
|
/* msvc doesn't have strncasecmp, has _strnicmp instead - crazy */
|
2014-02-16 23:42:56 +00:00
|
|
|
if (strncasecmp(name + len, ext, a))
|
2014-02-16 21:25:02 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
newname = malloc(len + b + 1);
|
|
|
|
if (!newname)
|
|
|
|
return;
|
|
|
|
|
|
|
|
memcpy(newname, name, len);
|
2014-02-16 23:42:56 +00:00
|
|
|
memcpy(newname + len, new_ext, b + 1);
|
2014-02-16 21:25:02 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Ignore errors. Maybe we can't create the backup file,
|
|
|
|
* maybe no old file existed. Regardless, we'll write the
|
|
|
|
* new file.
|
|
|
|
*/
|
2014-03-06 02:36:20 +00:00
|
|
|
(void) subsurface_rename(name, newname);
|
2014-02-16 21:25:02 +00:00
|
|
|
free(newname);
|
|
|
|
}
|
|
|
|
|
Initial implementation of git save format
This saves the dive data into a git object repository instead of a
single XML file.
We create a git object tree with each dive as a separate file,
hierarchically by trip and date.
NOTE 1: This largely duplicates the XML saving code, because trying to
share it seemed just too painful: the logic is very similar, but the
details of the actual strings end up differing sufficiently that there
are tons of trivial differences.
The git save format is line-based with minimal quoting, while XML quotes
everything with either "<..\>" or using single quotes around attributes.
NOTE 2: You currently need a dummy "file" to save to, which points to
the real save location: the git repository and branch to be used. We
should make this a config thing, but for testing, do something like
this:
echo git /home/torvalds/scuba:linus > git-test
to create that git information file, and when you use "Save To" and
specify "git-test" as the file to save to, subsurface will use the new
git save logic to save to the branch "linus" in the repository found at
"/home/torvalds/scuba".
NOTE 3: The git save format uses just the git object directory, it does
*not* check out the result in any git working tree or index. So after
you do a save, you can do
git log -p linus
to see what actually happened in that branch, but it will not affect any
actual checked-out state in the repository.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-03-06 21:28:39 +00:00
|
|
|
static void try_to_backup(const char *filename)
|
2014-01-16 02:03:11 +00:00
|
|
|
{
|
2014-02-16 23:42:56 +00:00
|
|
|
char extension[][5] = { "xml", "ssrf", "" };
|
2014-02-16 23:19:24 +00:00
|
|
|
int i = 0;
|
|
|
|
int flen = strlen(filename);
|
2014-01-16 02:03:11 +00:00
|
|
|
|
2014-02-16 21:25:02 +00:00
|
|
|
/* Maybe we might want to make this configurable? */
|
2014-02-16 23:19:24 +00:00
|
|
|
while (extension[i][0] != '\0') {
|
|
|
|
int elen = strlen(extension[i]);
|
|
|
|
if (strcasecmp(filename + flen - elen, extension[i]) == 0) {
|
2015-06-20 13:45:12 +00:00
|
|
|
if (last_xml_version < DATAFORMAT_VERSION) {
|
2015-02-13 07:35:52 +00:00
|
|
|
int se_len = strlen(extension[i]) + 5;
|
|
|
|
char *special_ext = malloc(se_len);
|
|
|
|
snprintf(special_ext, se_len, "%s.v%d", extension[i], last_xml_version);
|
|
|
|
save_backup(filename, extension[i], special_ext);
|
|
|
|
free(special_ext);
|
|
|
|
} else {
|
|
|
|
save_backup(filename, extension[i], "bak");
|
|
|
|
}
|
2014-02-16 23:19:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
Initial implementation of git save format
This saves the dive data into a git object repository instead of a
single XML file.
We create a git object tree with each dive as a separate file,
hierarchically by trip and date.
NOTE 1: This largely duplicates the XML saving code, because trying to
share it seemed just too painful: the logic is very similar, but the
details of the actual strings end up differing sufficiently that there
are tons of trivial differences.
The git save format is line-based with minimal quoting, while XML quotes
everything with either "<..\>" or using single quotes around attributes.
NOTE 2: You currently need a dummy "file" to save to, which points to
the real save location: the git repository and branch to be used. We
should make this a config thing, but for testing, do something like
this:
echo git /home/torvalds/scuba:linus > git-test
to create that git information file, and when you use "Save To" and
specify "git-test" as the file to save to, subsurface will use the new
git save logic to save to the branch "linus" in the repository found at
"/home/torvalds/scuba".
NOTE 3: The git save format uses just the git object directory, it does
*not* check out the result in any git working tree or index. So after
you do a save, you can do
git log -p linus
to see what actually happened in that branch, but it will not affect any
actual checked-out state in the repository.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-03-06 21:28:39 +00:00
|
|
|
}
|
|
|
|
|
2014-03-14 17:11:26 +00:00
|
|
|
int save_dives_logic(const char *filename, const bool select_only)
|
Initial implementation of git save format
This saves the dive data into a git object repository instead of a
single XML file.
We create a git object tree with each dive as a separate file,
hierarchically by trip and date.
NOTE 1: This largely duplicates the XML saving code, because trying to
share it seemed just too painful: the logic is very similar, but the
details of the actual strings end up differing sufficiently that there
are tons of trivial differences.
The git save format is line-based with minimal quoting, while XML quotes
everything with either "<..\>" or using single quotes around attributes.
NOTE 2: You currently need a dummy "file" to save to, which points to
the real save location: the git repository and branch to be used. We
should make this a config thing, but for testing, do something like
this:
echo git /home/torvalds/scuba:linus > git-test
to create that git information file, and when you use "Save To" and
specify "git-test" as the file to save to, subsurface will use the new
git save logic to save to the branch "linus" in the repository found at
"/home/torvalds/scuba".
NOTE 3: The git save format uses just the git object directory, it does
*not* check out the result in any git working tree or index. So after
you do a save, you can do
git log -p linus
to see what actually happened in that branch, but it will not affect any
actual checked-out state in the repository.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-03-06 21:28:39 +00:00
|
|
|
{
|
|
|
|
struct membuffer buf = { 0 };
|
|
|
|
FILE *f;
|
2014-03-12 21:12:58 +00:00
|
|
|
void *git;
|
2015-06-12 19:32:12 +00:00
|
|
|
const char *branch, *remote;
|
2014-03-14 17:11:26 +00:00
|
|
|
int error;
|
Initial implementation of git save format
This saves the dive data into a git object repository instead of a
single XML file.
We create a git object tree with each dive as a separate file,
hierarchically by trip and date.
NOTE 1: This largely duplicates the XML saving code, because trying to
share it seemed just too painful: the logic is very similar, but the
details of the actual strings end up differing sufficiently that there
are tons of trivial differences.
The git save format is line-based with minimal quoting, while XML quotes
everything with either "<..\>" or using single quotes around attributes.
NOTE 2: You currently need a dummy "file" to save to, which points to
the real save location: the git repository and branch to be used. We
should make this a config thing, but for testing, do something like
this:
echo git /home/torvalds/scuba:linus > git-test
to create that git information file, and when you use "Save To" and
specify "git-test" as the file to save to, subsurface will use the new
git save logic to save to the branch "linus" in the repository found at
"/home/torvalds/scuba".
NOTE 3: The git save format uses just the git object directory, it does
*not* check out the result in any git working tree or index. So after
you do a save, you can do
git log -p linus
to see what actually happened in that branch, but it will not affect any
actual checked-out state in the repository.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-03-06 21:28:39 +00:00
|
|
|
|
2015-09-23 09:13:07 +00:00
|
|
|
git = is_git_repository(filename, &branch, &remote, false);
|
2014-03-14 17:11:26 +00:00
|
|
|
if (git)
|
2015-06-12 19:32:12 +00:00
|
|
|
return git_save_dives(git, branch, remote, select_only);
|
2014-03-15 04:01:13 +00:00
|
|
|
|
2014-03-12 21:12:58 +00:00
|
|
|
try_to_backup(filename);
|
Initial implementation of git save format
This saves the dive data into a git object repository instead of a
single XML file.
We create a git object tree with each dive as a separate file,
hierarchically by trip and date.
NOTE 1: This largely duplicates the XML saving code, because trying to
share it seemed just too painful: the logic is very similar, but the
details of the actual strings end up differing sufficiently that there
are tons of trivial differences.
The git save format is line-based with minimal quoting, while XML quotes
everything with either "<..\>" or using single quotes around attributes.
NOTE 2: You currently need a dummy "file" to save to, which points to
the real save location: the git repository and branch to be used. We
should make this a config thing, but for testing, do something like
this:
echo git /home/torvalds/scuba:linus > git-test
to create that git information file, and when you use "Save To" and
specify "git-test" as the file to save to, subsurface will use the new
git save logic to save to the branch "linus" in the repository found at
"/home/torvalds/scuba".
NOTE 3: The git save format uses just the git object directory, it does
*not* check out the result in any git working tree or index. So after
you do a save, you can do
git log -p linus
to see what actually happened in that branch, but it will not affect any
actual checked-out state in the repository.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-03-06 21:28:39 +00:00
|
|
|
|
|
|
|
save_dives_buffer(&buf, select_only);
|
|
|
|
|
2014-03-14 17:11:26 +00:00
|
|
|
error = -1;
|
2014-01-16 02:03:11 +00:00
|
|
|
f = subsurface_fopen(filename, "w");
|
|
|
|
if (f) {
|
|
|
|
flush_buffer(&buf, f);
|
2014-03-14 17:11:26 +00:00
|
|
|
error = fclose(f);
|
2014-01-16 02:03:11 +00:00
|
|
|
}
|
2014-03-14 17:11:26 +00:00
|
|
|
if (error)
|
|
|
|
report_error("Save failed (%s)", strerror(errno));
|
|
|
|
|
2014-01-16 02:03:11 +00:00
|
|
|
free_buffer(&buf);
|
2014-03-14 17:11:26 +00:00
|
|
|
return error;
|
2011-09-01 23:27:52 +00:00
|
|
|
}
|
2013-10-19 17:35:36 +00:00
|
|
|
|
2014-12-31 20:09:34 +00:00
|
|
|
int export_dives_xslt(const char *filename, const bool selected, const int units, const char *export_xslt)
|
2013-10-19 17:35:36 +00:00
|
|
|
{
|
|
|
|
FILE *f;
|
2014-02-16 23:42:56 +00:00
|
|
|
struct membuffer buf = { 0 };
|
2013-10-19 17:35:36 +00:00
|
|
|
xmlDoc *doc;
|
|
|
|
xsltStylesheetPtr xslt = NULL;
|
|
|
|
xmlDoc *transformed;
|
2014-07-16 08:57:29 +00:00
|
|
|
int res = 0;
|
2014-12-31 20:09:34 +00:00
|
|
|
char *params[3];
|
|
|
|
int pnr = 0;
|
|
|
|
char unitstr[3];
|
2014-04-26 07:55:41 +00:00
|
|
|
|
2014-12-22 01:53:18 +00:00
|
|
|
if (verbose)
|
|
|
|
fprintf(stderr, "export_dives_xslt with stylesheet %s\n", export_xslt);
|
|
|
|
|
2013-10-19 17:35:36 +00:00
|
|
|
if (!filename)
|
2014-04-26 07:55:41 +00:00
|
|
|
return report_error("No filename for export");
|
2013-10-19 17:35:36 +00:00
|
|
|
|
|
|
|
/* Save XML to file and convert it into a memory buffer */
|
2014-01-16 02:03:11 +00:00
|
|
|
save_dives_buffer(&buf, selected);
|
2013-10-19 17:35:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse the memory buffer into XML document and
|
2014-04-26 07:55:41 +00:00
|
|
|
* transform it to selected export format, finally dumping
|
2013-10-19 17:35:36 +00:00
|
|
|
* the XML into a character buffer.
|
|
|
|
*/
|
2014-02-09 17:40:49 +00:00
|
|
|
doc = xmlReadMemory(buf.buffer, buf.len, "divelog", NULL, 0);
|
2014-01-16 02:03:11 +00:00
|
|
|
free_buffer(&buf);
|
2014-03-14 17:11:26 +00:00
|
|
|
if (!doc)
|
|
|
|
return report_error("Failed to read XML memory");
|
2013-10-19 17:35:36 +00:00
|
|
|
|
2014-04-26 07:55:41 +00:00
|
|
|
/* Convert to export format */
|
|
|
|
xslt = get_stylesheet(export_xslt);
|
2014-03-14 17:11:26 +00:00
|
|
|
if (!xslt)
|
2014-04-26 07:55:41 +00:00
|
|
|
return report_error("Failed to open export conversion stylesheet");
|
2013-10-19 17:35:36 +00:00
|
|
|
|
2014-12-31 20:09:34 +00:00
|
|
|
snprintf(unitstr, 3, "%d", units);
|
|
|
|
params[pnr++] = "units";
|
|
|
|
params[pnr++] = unitstr;
|
|
|
|
params[pnr++] = NULL;
|
|
|
|
|
|
|
|
transformed = xsltApplyStylesheet(xslt, doc, (const char **)params);
|
2013-10-19 17:35:36 +00:00
|
|
|
xmlFreeDoc(doc);
|
|
|
|
|
2014-04-26 07:55:41 +00:00
|
|
|
/* Write the transformed export to file */
|
2013-12-19 13:00:51 +00:00
|
|
|
f = subsurface_fopen(filename, "w");
|
2014-07-16 08:57:29 +00:00
|
|
|
if (f) {
|
|
|
|
xsltSaveResultToFile(f, transformed, xslt);
|
|
|
|
fclose(f);
|
|
|
|
/* Check write errors? */
|
|
|
|
} else {
|
|
|
|
res = report_error("Failed to open %s for writing (%s)", filename, strerror(errno));
|
|
|
|
}
|
|
|
|
xsltFreeStylesheet(xslt);
|
2013-10-19 17:35:36 +00:00
|
|
|
xmlFreeDoc(transformed);
|
|
|
|
|
2014-07-16 08:57:29 +00:00
|
|
|
return res;
|
2013-10-19 17:35:36 +00:00
|
|
|
}
|