summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Linus Torvalds <torvalds@linux-foundation.org>2011-09-02 16:40:28 -0700
committerGravatar Linus Torvalds <torvalds@linux-foundation.org>2011-09-02 16:40:28 -0700
commit5f05173e793d49319c727240014b59a04bd4075c (patch)
tree166aa17ed74dadf70b9a78cb3385d92d610a7e41
parentef0d00e76a2343f5d730eff3381d6715e3134ae8 (diff)
downloadsubsurface-5f05173e793d49319c727240014b59a04bd4075c.tar.gz
Do a dive de-dup pass
If given multiple dives at the same time, just de-dup the dives. This happens when you've dumped the whole dive-computer several times, and some dives show up in multiple dumps. When de-duping, try to avoid dropping data. So if one dive has notes attached to it, and the other one does not, pick the notes from the dive that does have them. Obvious stuff like that. The sample merge is also written so that it should be possible to merge two dives. Which we don't actually do yet. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--dive.h5
-rw-r--r--main.c176
-rw-r--r--parse-xml.c5
3 files changed, 181 insertions, 5 deletions
diff --git a/dive.h b/dive.h
index c1b95e3f6..eaafe8aeb 100644
--- a/dive.h
+++ b/dive.h
@@ -138,4 +138,9 @@ extern void parse_xml_file(const char *filename);
extern void flush_dive_info_changes(void);
extern void save_dives(const char *filename);
+static inline unsigned int dive_size(int samples)
+{
+ return sizeof(struct dive) + samples*sizeof(struct sample);
+}
+
#endif /* DIVE_H */
diff --git a/main.c b/main.c
index 96eca191f..96149d38c 100644
--- a/main.c
+++ b/main.c
@@ -1,4 +1,5 @@
#include <stdio.h>
+#include <string.h>
#include <stdlib.h>
#include <time.h>
@@ -19,13 +20,188 @@ static int sortfn(const void *_a, const void *_b)
return 0;
}
+static int alloc_samples;
+
+/* Don't pick a zero for MERGE_MIN() */
+#define MERGE_MAX(res, a, b, n) res->n = MAX(a->n, b->n)
+#define MERGE_MIN(res, a, b, n) res->n = (a->n)?(b->n)?MIN(a->n, b->n):(a->n):(b->n)
+
+static struct dive *add_sample(struct sample *sample, int time, struct dive *dive)
+{
+ int nr = dive->samples;
+ struct sample *d;
+
+ if (nr >= alloc_samples) {
+ alloc_samples = (alloc_samples + 64) * 3 / 2;
+ dive = realloc(dive, dive_size(alloc_samples));
+ if (!dive)
+ return NULL;
+ }
+ dive->samples = nr+1;
+ d = dive->sample + nr;
+
+ *d = *sample;
+ d->time.seconds = time;
+ return dive;
+}
+
+/*
+ * Merge samples. Dive 'a' is "offset" seconds before Dive 'b'
+ */
+static struct dive *merge_samples(struct dive *res, struct dive *a, struct dive *b, int offset)
+{
+ int asamples = a->samples;
+ int bsamples = b->samples;
+ struct sample *as = a->sample;
+ struct sample *bs = b->sample;
+
+ for (;;) {
+ int at, bt;
+ struct sample sample;
+
+ if (!res)
+ return NULL;
+
+ at = asamples ? as->time.seconds : -1;
+ bt = bsamples ? bs->time.seconds + offset : -1;
+
+ /* No samples? All done! */
+ if (at < 0 && bt < 0)
+ return res;
+
+ /* Only samples from a? */
+ if (bt < 0) {
+add_sample_a:
+ res = add_sample(as, at, res);
+ as++;
+ asamples--;
+ continue;
+ }
+
+ /* Only samples from b? */
+ if (at < 0) {
+add_sample_b:
+ res = add_sample(bs, bt, res);
+ bs++;
+ bsamples--;
+ continue;
+ }
+
+ if (at < bt)
+ goto add_sample_a;
+ if (at > bt)
+ goto add_sample_b;
+
+ /* same-time sample: add a merged sample. Take the non-zero ones */
+ sample = *bs;
+ if (as->depth.mm)
+ sample.depth = as->depth;
+ if (as->temperature.mkelvin)
+ sample.temperature = as->temperature;
+ if (as->tankpressure.mbar)
+ sample.tankpressure = as->tankpressure;
+ if (as->tankindex)
+ sample.tankindex = as->tankindex;
+
+ res = add_sample(&sample, at, res);
+
+ as++;
+ bs++;
+ asamples--;
+ bsamples--;
+ }
+}
+
+static char *merge_text(const char *a, const char *b)
+{
+ char *res;
+
+ if (!a || !*a)
+ return (char *)b;
+ if (!b || !*b)
+ return (char *)a;
+ if (!strcmp(a,b))
+ return (char *)a;
+ res = malloc(strlen(a) + strlen(b) + 9);
+ if (!res)
+ return (char *)a;
+ sprintf(res, "(%s) or (%s)", a, b);
+ return res;
+}
+
+/*
+ * This could do a lot more merging. Right now it really only
+ * merges almost exact duplicates - something that happens easily
+ * with overlapping dive downloads.
+ */
+static struct dive *try_to_merge(struct dive *a, struct dive *b)
+{
+ int i;
+ struct dive *res;
+
+ if (a->when != b->when)
+ return NULL;
+
+ alloc_samples = 5;
+ res = malloc(dive_size(alloc_samples));
+ if (!res)
+ return NULL;
+ memset(res, 0, dive_size(alloc_samples));
+
+ res->when = a->when;
+ res->name = merge_text(a->name, b->name);
+ res->location = merge_text(a->location, b->location);
+ res->notes = merge_text(a->notes, b->notes);
+ MERGE_MAX(res, a, b, maxdepth.mm);
+ MERGE_MAX(res, a, b, meandepth.mm); /* recalc! */
+ MERGE_MAX(res, a, b, duration.seconds);
+ MERGE_MAX(res, a, b, surfacetime.seconds);
+ MERGE_MAX(res, a, b, airtemp.mkelvin);
+ MERGE_MIN(res, a, b, watertemp.mkelvin);
+ MERGE_MAX(res, a, b, beginning_pressure.mbar);
+ MERGE_MAX(res, a, b, end_pressure.mbar);
+ for (i = 0; i < MAX_MIXES; i++) {
+ if (a->gasmix[i].o2.permille) {
+ res->gasmix[i] = a->gasmix[i];
+ continue;
+ }
+ res->gasmix[i] = b->gasmix[i];
+ }
+ return merge_samples(res, a, b, 0);
+}
+
/*
* This doesn't really report anything at all. We just sort the
* dives, the GUI does the reporting
*/
static void report_dives(void)
{
+ int i;
+
qsort(dive_table.dives, dive_table.nr, sizeof(struct dive *), sortfn);
+
+ for (i = 1; i < dive_table.nr; i++) {
+ struct dive **pp = &dive_table.dives[i-1];
+ struct dive *prev = pp[0];
+ struct dive *dive = pp[1];
+ struct dive *merged;
+
+ if (prev->when + prev->duration.seconds < dive->when)
+ continue;
+
+ merged = try_to_merge(prev, dive);
+ if (!merged)
+ continue;
+
+ free(prev);
+ free(dive);
+ *pp = merged;
+ dive_table.nr--;
+ memmove(pp+1, pp+2, sizeof(*pp)*(dive_table.nr - i));
+
+ /* Redo the new 'i'th dive */
+ i--;
+ }
}
static void parse_argument(const char *arg)
diff --git a/parse-xml.c b/parse-xml.c
index 5a1a1601e..3a84e2963 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -636,11 +636,6 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf)
nonmatch("dive", name, buf);
}
-static unsigned int dive_size(int samples)
-{
- return sizeof(struct dive) + samples*sizeof(struct sample);
-}
-
/*
* File boundaries are dive boundaries. But sometimes there are
* multiple dives per file, so there can be other events too that