[PATCH 2/6] Add basic divecomputer info setup with xml parsing and saving

Linus Torvalds torvalds at linux-foundation.org
Sun Nov 25 11:53:21 PST 2012


From: Linus Torvalds <torvalds at linux-foundation.org>
Date: Sat, 24 Nov 2012 16:50:21 -1000
Subject: [PATCH 2/6] Add basic divecomputer info setup with xml parsing and saving

This also knows how to save and restore multiple dive computers in the
XML data, but there's no way to actually *create* that kind of
information yet (nor do we display it).  Tested by creating fake XML
files with multiple dive computers by hand so far.

The dive computer information right now contains (apart from the sample
and event data that we've always had):

 - the vendor and product name of the dive computer
 - the date of the dive according to the dive computer (so if you change
   the dive date manually, the dive computer date stays around)

Note that if the dive computer date matches the dive date, we won't
bother saving the redundant information in the XML file.

Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
---

The later patches expand on this and clean some of it up, and actually end 
up creating multi-computer dives with the merging. This is the base, 
though.

 dive.h            |  7 ++++--
 libdivecomputer.c |  4 +++-
 parse-xml.c       | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 save-xml.c        | 52 ++++++++++++++++++++++++++++++----------
 4 files changed, 115 insertions(+), 19 deletions(-)

diff --git a/dive.h b/dive.h
index 95f977da0ba5..2e7841b45e0e 100644
--- a/dive.h
+++ b/dive.h
@@ -43,6 +43,8 @@
  * We don't actually use these all yet, so maybe they'll change, but
  * I made a number of types as guidelines.
  */
+typedef gint64 timestamp_t;
+
 typedef struct {
 	int seconds;
 } duration_t;
@@ -238,10 +240,12 @@ struct event {
 };
 
 struct divecomputer {
+	timestamp_t when;
+	const char *vendor, *product;
 	int samples, alloc_samples;
 	struct sample *sample;
-
 	struct event *events;
+	struct divecomputer *next;
 };
 
 #define MAX_CYLINDERS (8)
@@ -249,7 +253,6 @@ struct divecomputer {
 #define W_IDX_PRIMARY 0
 #define W_IDX_SECONDARY 1
 
-typedef gint64 timestamp_t;
 typedef enum { TF_NONE, NO_TRIP, IN_TRIP, AUTOGEN_TRIP, ASSIGNED_TRIP, NUM_TRIPFLAGS } tripflag_t;
 extern const char *tripflag_names[NUM_TRIPFLAGS];
 
diff --git a/libdivecomputer.c b/libdivecomputer.c
index 27ce8458ec4d..48680c7ce49c 100644
--- a/libdivecomputer.c
+++ b/libdivecomputer.c
@@ -242,6 +242,8 @@ static int dive_cb(const unsigned char *data, unsigned int size,
 		dc_parser_destroy(parser);
 		return rc;
 	}
+	dive->dc.vendor = strdup(devdata->vendor);
+	dive->dc.product = strdup(devdata->product);
 
 	tm.tm_year = dt.year;
 	tm.tm_mon = dt.month-1;
@@ -249,7 +251,7 @@ static int dive_cb(const unsigned char *data, unsigned int size,
 	tm.tm_hour = dt.hour;
 	tm.tm_min = dt.minute;
 	tm.tm_sec = dt.second;
-	dive->when = utc_mktime(&tm);
+	dive->when = dive->dc.when = utc_mktime(&tm);
 
 	// Parse the divetime.
 	dev_info(devdata, _("Dive %d: %s %d %04d"), import_dive_number,
diff --git a/parse-xml.c b/parse-xml.c
index 0bf5a4a0429c..98e7fc9e48c3 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -157,6 +157,7 @@ const struct units IMPERIAL_units = {
 /*
  * Dive info as it is being built up..
  */
+static struct divecomputer *cur_dc;
 static struct dive *cur_dive;
 static dive_trip_t *cur_trip = NULL;
 static struct sample *cur_sample;
@@ -703,6 +704,25 @@ static void try_to_fill_event(const char *name, char *buf)
 	nonmatch("event", name, buf);
 }
 
+/* We're in the top-level dive xml. Try to convert whatever value to a dive value */
+static void try_to_fill_dc(struct divecomputer *dc, const char *name, char *buf)
+{
+	int len = strlen(name);
+
+	start_match("divecomputer", name, buf);
+
+	if (MATCH(".date", divedate, &dc->when))
+		return;
+	if (MATCH(".time", divetime, &dc->when))
+		return;
+	if (MATCH(".vendor", utf8_string, &dc->vendor))
+		return;
+	if (MATCH(".product", utf8_string, &dc->product))
+		return;
+
+	nonmatch("divecomputer", name, buf);
+}
+
 /* We're in samples - try to convert the random xml value to something useful */
 static void try_to_fill_sample(struct sample *sample, const char *name, char *buf)
 {
@@ -1224,6 +1244,7 @@ static void dive_end(void)
 	else
 		record_dive(cur_dive);
 	cur_dive = NULL;
+	cur_dc = NULL;
 	cur_cylinder_index = 0;
 	cur_ws_index = 0;
 }
@@ -1251,10 +1272,20 @@ static void event_start(void)
 	cur_event.active = 1;
 }
 
+/*
+ * If we don't have an explicit dive computer,
+ * we use the implicit one that every dive has..
+ */
+static struct divecomputer *get_dc(void)
+{
+	return cur_dc ? : &cur_dive->dc;
+}
+
 static void event_end(void)
 {
+	struct divecomputer *dc = get_dc();
 	if (cur_event.name && strcmp(cur_event.name, "surface") != 0)
-		add_event(&cur_dive->dc, cur_event.time.seconds,
+		add_event(dc, cur_event.time.seconds,
 			cur_event.type, cur_event.flags,
 			cur_event.value, cur_event.name);
 	cur_event.active = 0;
@@ -1280,7 +1311,7 @@ static void ws_end(void)
 
 static void sample_start(void)
 {
-	cur_sample = prepare_sample(&cur_dive->dc);
+	cur_sample = prepare_sample(get_dc());
 }
 
 static void sample_end(void)
@@ -1288,10 +1319,39 @@ static void sample_end(void)
 	if (!cur_dive)
 		return;
 
-	finish_sample(&cur_dive->dc);
+	finish_sample(get_dc());
 	cur_sample = NULL;
 }
 
+static void divecomputer_start(void)
+{
+	struct divecomputer *dc;
+
+	/* Start from the previous dive computer */
+	dc = &cur_dive->dc;
+	while (dc->next)
+		dc = dc->next;
+
+	/* Did we already fill that in? */
+	if (dc->samples || dc->vendor || dc->product || dc->when) {
+		struct divecomputer *newdc = calloc(1, sizeof(*newdc));
+		if (newdc) {
+			dc->next = newdc;
+			dc = newdc;
+		}
+	}
+
+	/* .. this is the one we'll use */
+	cur_dc = dc;
+}
+
+static void divecomputer_end(void)
+{
+	if (!cur_dc->when)
+		cur_dc->when = cur_dive->when;
+	cur_dc = NULL;
+}
+
 static void entry(const char *name, int size, const char *raw)
 {
 	char *buf = malloc(size+1);
@@ -1308,6 +1368,10 @@ static void entry(const char *name, int size, const char *raw)
 		try_to_fill_sample(cur_sample, name, buf);
 		return;
 	}
+	if (cur_dc) {
+		try_to_fill_dc(cur_dc, name, buf);
+		return;
+	}
 	if (cur_dive) {
 		try_to_fill_dive(cur_dive, name, buf);
 		return;
@@ -1447,6 +1511,7 @@ static struct nesting {
 	{ "gasmix", cylinder_start, cylinder_end },
 	{ "cylinder", cylinder_start, cylinder_end },
 	{ "weightsystem", ws_start, ws_end },
+	{ "divecomputer", divecomputer_start, divecomputer_end },
 	{ "P", sample_start, sample_end },
 
 	/* Import type recognition */
diff --git a/save-xml.c b/save-xml.c
index db7d321bde1a..a86cbd23c0dd 100644
--- a/save-xml.c
+++ b/save-xml.c
@@ -323,17 +323,22 @@ static void save_events(FILE *f, struct event *ev)
 	}
 }
 
-static void save_trip(FILE *f, dive_trip_t *trip)
+static void show_date(FILE *f, timestamp_t when)
 {
 	struct tm tm;
 
-	utc_mkdate(trip->when, &tm);
+	utc_mkdate(when, &tm);
 
-	fprintf(f, "<trip");
 	fprintf(f, " date='%04u-%02u-%02u'",
 		tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday);
 	fprintf(f, " time='%02u:%02u:%02u'",
 		tm.tm_hour, tm.tm_min, tm.tm_sec);
+}
+
+static void save_trip(FILE *f, dive_trip_t *trip)
+{
+	fprintf(f, "<trip");
+	show_date(f, trip->when);
 	if (trip->location)
 		show_utf8(f, trip->location, " location=\'","\'", 1);
 	fprintf(f, ">\n");
@@ -341,12 +346,31 @@ static void save_trip(FILE *f, dive_trip_t *trip)
 		show_utf8(f, trip->notes, "<notes>","</notes>\n", 0);
 }
 
-static void save_dive(FILE *f, struct dive *dive)
+static void save_dc(FILE *f, struct dive *dive, struct divecomputer *dc)
 {
 	int i;
-	struct tm tm;
+	const char *post = "";
+
+	if (dc->when || dc->vendor || dc->product) {
+		fprintf(f, "<divecomputer");
+		if (dc->vendor)
+			show_utf8(f, dc->vendor, " vendor='", "'", 1);
+		if (dc->product)
+			show_utf8(f, dc->product, " product='", "'", 1);
+		if (dc->when && dc->when != dive->when)
+			show_date(f, dc->when);
+		fprintf(f, ">\n");
+		post = "</divecomputer>\n";
+	}
+	save_events(f, dc->events);
+	for (i = 0; i < dc->samples; i++)
+		save_sample(f, dc->sample+i);
+	fprintf(f, post);
+}
 
-	utc_mkdate(dive->when, &tm);
+static void save_dive(FILE *f, struct dive *dive)
+{
+	struct divecomputer *dc;
 
 	fputs("<dive", f);
 	if (dive->number)
@@ -363,18 +387,20 @@ static void save_dive(FILE *f, struct dive *dive)
 		fprintf(f, " rating='%d'", dive->rating);
 	if (dive->visibility)
 		fprintf(f, " visibility='%d'", dive->visibility);
-	fprintf(f, " date='%04u-%02u-%02u'",
-		tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday);
-	fprintf(f, " time='%02u:%02u:%02u'",
-		tm.tm_hour, tm.tm_min, tm.tm_sec);
+	show_date(f, dive->when);
 	fprintf(f, " duration='%u:%02u min'>\n",
 		FRACTION(dive->duration.seconds, 60));
 	save_overview(f, dive);
 	save_cylinder_info(f, dive);
 	save_weightsystem_info(f, dive);
-	save_events(f, dive->dc.events);
-	for (i = 0; i < dive->dc.samples; i++)
-		save_sample(f, dive->dc.sample+i);
+
+	/* Save the dive computer data */
+	dc = &dive->dc;
+	do {
+		save_dc(f, dive, dc);
+		dc = dc->next;
+	} while (dc);
+
 	fprintf(f, "</dive>\n");
 }
 
-- 
1.8.0.dirty



More information about the subsurface mailing list