diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 176 |
1 files changed, 176 insertions, 0 deletions
@@ -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) |