Undo: don't modify source-dives on merge

For undo, it is crucial that commands don't modify existing dives.
Unfortunately, dive merging would write into the data-structures
of the to-be-merged dives. To prevent it from doing so, make the
input dives const-pointers.

This led to a whole cascade of functions that had to take const
and significant churn.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2018-08-12 22:47:07 -04:00 committed by Dirk Hohndel
parent 1afd295c41
commit 8c2383b495
2 changed files with 259 additions and 153 deletions

View file

@ -488,6 +488,18 @@ static void copy_dc(const struct divecomputer *sdc, struct divecomputer *ddc)
copy_events(sdc, ddc); copy_events(sdc, ddc);
} }
static void dc_cylinder_renumber(struct dive *dive, struct divecomputer *dc, const int mapping[]);
/* copy dive computer and renumber the cylinders */
static void copy_dc_renumber(struct dive *d, const struct divecomputer *sdc, struct divecomputer *ddc, const int cylinders_map[])
{
*ddc = *sdc;
ddc->model = copy_string(sdc->model);
copy_samples(sdc, ddc);
copy_events(sdc, ddc);
dc_cylinder_renumber(d, ddc, cylinders_map);
}
/* copy an element in a list of pictures */ /* copy an element in a list of pictures */
static void copy_pl(struct picture *sp, struct picture *dp) static void copy_pl(struct picture *sp, struct picture *dp)
{ {
@ -1389,12 +1401,15 @@ static void fixup_airtemp(struct dive *dive)
dive->airtemp.mkelvin = dc_airtemp(&dive->dc); dive->airtemp.mkelvin = dc_airtemp(&dive->dc);
} }
/* zero out the airtemp in the dive structure if it was just created by /* if the air temperature in the dive data is redundant to the one in its
* running fixup on the dive. keep it if it had been edited by hand */ * first divecomputer (i.e., it was added by running fixup on the dive)
static void un_fixup_airtemp(struct dive *a) * return 0, otherwise return the air temperature given in the dive */
static temperature_t un_fixup_airtemp(const struct dive *a)
{ {
temperature_t res = a->airtemp;
if (a->airtemp.mkelvin && a->airtemp.mkelvin == dc_airtemp(&a->dc)) if (a->airtemp.mkelvin && a->airtemp.mkelvin == dc_airtemp(&a->dc))
a->airtemp.mkelvin = 0; res.mkelvin = 0;
return res;
} }
/* /*
@ -1837,7 +1852,7 @@ struct sample *add_sample(const struct sample *sample, int time, struct divecomp
* that the time in between the dives is at the surface, not some "last * that the time in between the dives is at the surface, not some "last
* sample that happened to be at a depth of 1.2m". * sample that happened to be at a depth of 1.2m".
*/ */
static void merge_one_sample(struct sample *sample, int time, struct divecomputer *dc) static void merge_one_sample(const struct sample *sample, int time, struct divecomputer *dc)
{ {
int last = dc->samples - 1; int last = dc->samples - 1;
if (last >= 0) { if (last >= 0) {
@ -1863,11 +1878,16 @@ static void merge_one_sample(struct sample *sample, int time, struct divecompute
add_sample(sample, time, dc); add_sample(sample, time, dc);
} }
static void renumber_last_sample(struct divecomputer *dc, const int mapping[]);
static void sample_renumber(struct sample *s, int i, const int mapping[]);
/* /*
* Merge samples. Dive 'a' is "offset" seconds before Dive 'b' * Merge samples. Dive 'a' is "offset" seconds before Dive 'b'
*/ */
static void merge_samples(struct divecomputer *res, struct divecomputer *a, struct divecomputer *b, int offset) static void merge_samples(struct divecomputer *res,
const struct divecomputer *a, const struct divecomputer *b,
const int *cylinders_map_a, const int *cylinders_map_b,
int offset)
{ {
int asamples = a->samples; int asamples = a->samples;
int bsamples = b->samples; int bsamples = b->samples;
@ -1882,14 +1902,19 @@ static void merge_samples(struct divecomputer *res, struct divecomputer *a, stru
* the reverse offset. * the reverse offset.
*/ */
if (offset < 0) { if (offset < 0) {
const int *cylinders_map_tmp;
offset = -offset; offset = -offset;
asamples = bsamples; asamples = bsamples;
bsamples = a->samples; bsamples = a->samples;
as = bs; as = bs;
bs = a->sample; bs = a->sample;
cylinders_map_tmp = cylinders_map_a;
cylinders_map_a = cylinders_map_b;
cylinders_map_b = cylinders_map_tmp;
} }
for (;;) { for (;;) {
int j;
int at, bt; int at, bt;
struct sample sample = { .bearing.degrees = -1, .ndl.seconds = -1 }; struct sample sample = { .bearing.degrees = -1, .ndl.seconds = -1 };
@ -1907,6 +1932,7 @@ static void merge_samples(struct divecomputer *res, struct divecomputer *a, stru
if (bt < 0) { if (bt < 0) {
add_sample_a: add_sample_a:
merge_one_sample(as, at, res); merge_one_sample(as, at, res);
renumber_last_sample(res, cylinders_map_a);
as++; as++;
asamples--; asamples--;
continue; continue;
@ -1916,6 +1942,7 @@ static void merge_samples(struct divecomputer *res, struct divecomputer *a, stru
if (at < 0) { if (at < 0) {
add_sample_b: add_sample_b:
merge_one_sample(bs, bt, res); merge_one_sample(bs, bt, res);
renumber_last_sample(res, cylinders_map_b);
bs++; bs++;
bsamples--; bsamples--;
continue; continue;
@ -1928,18 +1955,23 @@ static void merge_samples(struct divecomputer *res, struct divecomputer *a, stru
/* same-time sample: add a merged sample. Take the non-zero ones */ /* same-time sample: add a merged sample. Take the non-zero ones */
sample = *bs; sample = *bs;
sample_renumber(&sample, 0, cylinders_map_b);
if (as->depth.mm) if (as->depth.mm)
sample.depth = as->depth; sample.depth = as->depth;
if (as->temperature.mkelvin) if (as->temperature.mkelvin)
sample.temperature = as->temperature; sample.temperature = as->temperature;
if (as->pressure[0].mbar) for (j = 0; j < MAX_SENSORS; ++j) {
sample.pressure[0] = as->pressure[0]; int sensor_id;
if (as->sensor[0])
sample.sensor[0] = as->sensor[0]; sensor_id = cylinders_map_a[as->sensor[j]];
if (as->pressure[1].mbar) if (sensor_id < 0)
sample.pressure[1] = as->pressure[1]; continue;
if (as->sensor[1])
sample.sensor[1] = as->sensor[1]; if (as->pressure[j].mbar)
sample.pressure[j] = as->pressure[j];
if (as->sensor[j])
sample.sensor[j] = sensor_id;
}
if (as->cns) if (as->cns)
sample.cns = as->cns; sample.cns = as->cns;
if (as->setpoint.mbar) if (as->setpoint.mbar)
@ -1980,16 +2012,17 @@ static char *merge_text(const char *a, const char *b, const char *sep)
return res; return res;
} }
#define SORT(a, b, field) \ #define SORT(a, b) \
if (a->field != b->field) \ if (a != b) \
return a->field < b->field ? -1 : 1 return a < b ? -1 : 1
#define SORT_FIELD(a, b, field) SORT(a->field, b->field)
static int sort_event(const struct event *a, const struct event *b) static int sort_event(const struct event *a, const struct event *b, int time_a, int time_b)
{ {
SORT(a, b, time.seconds); SORT(time_a, time_b);
SORT(a, b, type); SORT_FIELD(a, b, type);
SORT(a, b, flags); SORT_FIELD(a, b, flags);
SORT(a, b, value); SORT_FIELD(a, b, value);
return strcmp(a->name, b->name); return strcmp(a->name, b->name);
} }
@ -2002,43 +2035,54 @@ static int same_gas(const struct event *a, const struct event *b)
return false; return false;
} }
static void merge_events(struct divecomputer *res, struct divecomputer *src1, struct divecomputer *src2, int offset) static void event_renumber(struct event *ev, const int mapping[]);
static void add_initial_gaschange(struct dive *dive, struct divecomputer *dc, int offset, int idx);
static void merge_events(struct dive *d, struct divecomputer *res,
const struct divecomputer *src1, const struct divecomputer *src2,
const int *cylinders_map1, const int *cylinders_map2,
int offset)
{ {
struct event *a, *b; const struct event *a, *b;
struct event **p = &res->events; struct event **p = &res->events;
struct event *last_gas = NULL; const struct event *last_gas = NULL;
/* Always use positive offsets */ /* Always use positive offsets */
if (offset < 0) { if (offset < 0) {
struct divecomputer *tmp; const struct divecomputer *tmp;
const int *cylinders_map_tmp;
offset = -offset; offset = -offset;
tmp = src1; tmp = src1;
src1 = src2; src1 = src2;
src2 = tmp; src2 = tmp;
cylinders_map_tmp = cylinders_map1;
cylinders_map1 = cylinders_map2;
cylinders_map2 = cylinders_map_tmp;
} }
a = src1->events; a = src1->events;
b = src2->events; b = src2->events;
while (b) {
b->time.seconds += offset;
b = b->next;
}
b = src2->events;
while (a || b) { while (a || b) {
int s; int s;
struct event *pick; const struct event *pick;
const int *cylinders_map;
int event_offset;
if (!b) { if (!b) {
*p = a; *p = clone_event(a);
event_renumber(*p, cylinders_map1);
break; break;
} }
if (!a) { if (!a) {
*p = b; *p = clone_event(b);
(*p)->time.seconds += offset;
event_renumber(*p, cylinders_map2);
break; break;
} }
s = sort_event(a, b); s = sort_event(a, b, a->time.seconds, b->time.seconds + offset);
/* Identical events? Just skip one of them (we pick a) */ /* Identical events? Just skip one of them (we pick a) */
if (!s) { if (!s) {
@ -2050,9 +2094,13 @@ static void merge_events(struct divecomputer *res, struct divecomputer *src1, st
if (s < 0) { if (s < 0) {
pick = a; pick = a;
a = a->next; a = a->next;
event_offset = 0;
cylinders_map = cylinders_map1;
} else { } else {
pick = b; pick = b;
b = b->next; b = b->next;
event_offset = offset;
cylinders_map = cylinders_map2;
} }
/* /*
@ -2066,9 +2114,17 @@ static void merge_events(struct divecomputer *res, struct divecomputer *src1, st
} }
/* Add it to the target list */ /* Add it to the target list */
*p = pick; *p = clone_event(pick);
p = &pick->next; (*p)->time.seconds += event_offset;
event_renumber(*p, cylinders_map);
p = &(*p)->next;
} }
/* If the initial cylinder of a divecomputer was remapped, add a gas change event to that cylinder */
if (cylinders_map1[0] > 0)
add_initial_gaschange(d, res, 0, cylinders_map1[0]);
if (cylinders_map2[0] > 0)
add_initial_gaschange(d, res, offset, cylinders_map2[0]);
} }
static void merge_weightsystem_info(weightsystem_t *res, const weightsystem_t *a, const weightsystem_t *b) static void merge_weightsystem_info(weightsystem_t *res, const weightsystem_t *a, const weightsystem_t *b)
@ -2151,58 +2207,81 @@ extern void fill_pressures(struct gas_pressures *pressures, const double amb_pre
} }
/* Force an initial gaschange event to the (old) gas #0 */ /* Force an initial gaschange event to the (old) gas #0 */
static void add_initial_gaschange(struct dive *dive, struct divecomputer *dc) static void add_initial_gaschange(struct dive *dive, struct divecomputer *dc, int offset, int idx)
{ {
const struct event *ev = get_next_event(dc->events, "gaschange"); /* if there is a gaschange event up to 30 sec after the initial event,
* refrain from adding the initial event */
if (ev && ev->time.seconds < 30) const struct event *ev = dc->events;
return; while(ev && (ev = get_next_event(ev, "gaschange")) != NULL) {
if (ev->time.seconds > offset + 30)
break;
else if (ev->time.seconds > offset)
return;
ev = ev->next;
}
/* Old starting gas mix */ /* Old starting gas mix */
add_gas_switch_event(dive, dc, 0, 0); add_gas_switch_event(dive, dc, offset, idx);
} }
static void dc_cylinder_renumber(struct dive *dive, struct divecomputer *dc, int mapping[]) static void sample_renumber(struct sample *s, int i, const int mapping[])
{
int j;
for (j = 0; j < MAX_SENSORS; j++) {
int sensor;
sensor = mapping[s->sensor[j]];
if (sensor == -1) {
// Remove sensor and gas pressure info
if (i == 0) {
s->sensor[j] = 0;
s->pressure[j].mbar = 0;
} else {
s->sensor[j] = s[-1].sensor[j];
s->pressure[j].mbar = s[-1].pressure[j].mbar;
}
} else {
s->sensor[j] = sensor;
}
}
}
static void renumber_last_sample(struct divecomputer *dc, const int mapping[])
{
int idx;
if (dc->samples <= 0)
return;
idx = dc->samples - 1;
sample_renumber(dc->sample + idx, idx, mapping);
}
static void event_renumber(struct event *ev, const int mapping[])
{
if (!event_is_gaschange(ev))
return;
if (ev->gas.index < 0)
return;
ev->gas.index = mapping[ev->gas.index];
}
static void dc_cylinder_renumber(struct dive *dive, struct divecomputer *dc, const int mapping[])
{ {
int i; int i;
struct event *ev; struct event *ev;
/* Did the first gas get remapped? Add gas switch event */
if (mapping[0] > 0)
add_initial_gaschange(dive, dc);
/* Remap or delete the sensor indexes */ /* Remap or delete the sensor indexes */
for (i = 0; i < dc->samples; i++) { for (i = 0; i < dc->samples; i++)
struct sample *s = dc->sample + i; sample_renumber(dc->sample + i, i, mapping);
int j;
for (j = 0; j < MAX_SENSORS; j++) {
int sensor;
sensor = mapping[s->sensor[j]];
if (sensor == -1) {
// Remove sensor and gas pressure info
if (i == 0) {
s->sensor[j] = 0;
s->pressure[j].mbar = 0;
} else {
s->sensor[j] = s[-1].sensor[j];
s->pressure[j].mbar = s[-1].pressure[j].mbar;
}
} else {
s->sensor[j] = sensor;
}
}
}
/* Remap the gas change indexes */ /* Remap the gas change indexes */
for (ev = dc->events; ev; ev = ev->next) { for (ev = dc->events; ev; ev = ev->next)
if (!event_is_gaschange(ev)) event_renumber(ev, mapping);
continue;
if (ev->gas.index < 0) /* If the initial cylinder of a dive was remapped, add a gas change event to that cylinder */
continue; if (mapping[0] > 0)
ev->gas.index = mapping[ev->gas.index]; add_initial_gaschange(dive, dc, 0, mapping[0]);
}
} }
/* /*
@ -2307,28 +2386,61 @@ static int find_unused_cylinder(unsigned int used_map)
return -1; return -1;
} }
/*
* Copy a single cylinder
*/
static void copy_cylinder(const cylinder_t *s, cylinder_t *d)
{
d->type.size.mliter = s->type.size.mliter;
d->type.workingpressure.mbar = s->type.workingpressure.mbar;
d->type.description = copy_string(s->type.description);
d->gasmix = s->gasmix;
d->start.mbar = s->start.mbar;
d->end.mbar = s->end.mbar;
d->sample_start.mbar = s->sample_start.mbar;
d->sample_end.mbar = s->sample_end.mbar;
d->depth = s->depth;
d->manually_added = s->manually_added;
d->gas_used.mliter = s->gas_used.mliter;
d->deco_gas_used.mliter = s->deco_gas_used.mliter;
d->bestmix_o2 = s->bestmix_o2;
d->bestmix_he = s->bestmix_he;
}
/* /*
* We matched things up so that they have the same gasmix and * We matched things up so that they have the same gasmix and
* use, but we might want to fill in any missing cylinder details * use, but we might want to fill in any missing cylinder details
* in 'a' if we had it from 'b'. * in 'a' if we had it from 'b'.
*/ */
static void merge_one_cylinder(cylinder_t *a, cylinder_t *b) static void merge_one_cylinder(cylinder_t *res, const cylinder_t *a, const cylinder_t *b)
{ {
if (!a->type.size.mliter) res->type.size.mliter = a->type.size.mliter ?
a->type.size.mliter = b->type.size.mliter; a->type.size.mliter : b->type.size.mliter;
if (!a->type.workingpressure.mbar) res->type.workingpressure.mbar = a->type.workingpressure.mbar ?
a->type.workingpressure.mbar = b->type.workingpressure.mbar; a->type.workingpressure.mbar : b->type.workingpressure.mbar;
if (!a->type.description && b->type.description) res->type.description = !empty_string(a->type.description) ?
a->type.description = strdup(b->type.description); copy_string(a->type.description) : copy_string(b->type.description);
if (!a->start.mbar) res->gasmix = a->gasmix;
a->start.mbar = b->start.mbar; res->start.mbar = a->start.mbar ?
if (!a->end.mbar) a->start.mbar : b->start.mbar;
a->end.mbar = b->end.mbar; res->end.mbar = a->end.mbar ?
a->end.mbar : b->end.mbar;
if (a->sample_start.mbar && b->sample_start.mbar) if (a->sample_start.mbar && b->sample_start.mbar)
a->sample_start.mbar = a->sample_start.mbar > b->sample_start.mbar ? a->sample_start.mbar : b->sample_start.mbar; res->sample_start.mbar = a->sample_start.mbar > b->sample_start.mbar ? a->sample_start.mbar : b->sample_start.mbar;
else
res->sample_start.mbar = 0;
if (a->sample_end.mbar && b->sample_end.mbar) if (a->sample_end.mbar && b->sample_end.mbar)
a->sample_end.mbar = a->sample_end.mbar < b->sample_end.mbar ? a->sample_end.mbar : b->sample_end.mbar; res->sample_end.mbar = a->sample_end.mbar < b->sample_end.mbar ? a->sample_end.mbar : b->sample_end.mbar;
else
res->sample_end.mbar = 0;
res->depth = a->depth;
res->manually_added = a->manually_added;
res->gas_used.mliter = a->gas_used.mliter + b->gas_used.mliter;
res->deco_gas_used.mliter = a->deco_gas_used.mliter + b->deco_gas_used.mliter;
res->bestmix_o2 = a->bestmix_o2 && b->bestmix_o2;
res->bestmix_he = a->bestmix_he && b->bestmix_he;
} }
/* /*
@ -2338,13 +2450,19 @@ static void merge_one_cylinder(cylinder_t *a, cylinder_t *b)
* Logic: take all the cylinder information from the preferred dive ('a'), and * Logic: take all the cylinder information from the preferred dive ('a'), and
* then try to match each of the cylinders in the other dive by the gasmix that * then try to match each of the cylinders in the other dive by the gasmix that
* is the best match and hasn't been used yet. * is the best match and hasn't been used yet.
*
* For each dive, a cylinder-renumbering table is returned. Currently, only
* cylinders of dive 'b' are renumbered.
*/ */
static void merge_cylinders(struct dive *res, struct dive *a, struct dive *b) static void merge_cylinders(struct dive *res, const struct dive *a, const struct dive *b,
int mapping_a[], int mapping_b[])
{ {
int i, renumber = 0; int i;
int mapping[MAX_CYLINDERS];
unsigned int used_in_a = 0, used_in_b = 0, matched = 0; unsigned int used_in_a = 0, used_in_b = 0, matched = 0;
/* First, clear all cylinders in destination */
memset(res->cylinder, 0, sizeof(res->cylinder));
/* Calculate usage map of cylinders */ /* Calculate usage map of cylinders */
for (i = 0; i < MAX_CYLINDERS; i++) { for (i = 0; i < MAX_CYLINDERS; i++) {
if (!cylinder_none(a->cylinder+i) || is_cylinder_used(a, i)) if (!cylinder_none(a->cylinder+i) || is_cylinder_used(a, i))
@ -2357,7 +2475,8 @@ static void merge_cylinders(struct dive *res, struct dive *a, struct dive *b)
for (i = 0; i < MAX_CYLINDERS; i++) { for (i = 0; i < MAX_CYLINDERS; i++) {
int j; int j;
mapping[i] = -1; mapping_a[i] = i;
mapping_b[i] = -1;
if (!(used_in_b & (1u << i))) if (!(used_in_b & (1u << i)))
continue; continue;
@ -2377,11 +2496,15 @@ static void merge_cylinders(struct dive *res, struct dive *a, struct dive *b)
* *
* - mark 'b' as needing renumbering if the index changed * - mark 'b' as needing renumbering if the index changed
*/ */
merge_one_cylinder(a->cylinder + j, b->cylinder + i); merge_one_cylinder(res->cylinder + j, a->cylinder + j, b->cylinder + i);
mapping[i] = j; mapping_b[i] = j;
matched |= 1u << j; matched |= 1u << j;
if (j != i) }
renumber = 1;
/* Now copy all the used cylinders from 'a' which are used, but have not been matched */
for (i = 0; i < MAX_CYLINDERS; i++) {
if (used_in_a & (1u << i) && !(matched & (1u << i)))
copy_cylinder(a->cylinder + i, res->cylinder + i);
} }
/* /*
@ -2390,10 +2513,6 @@ static void merge_cylinders(struct dive *res, struct dive *a, struct dive *b)
*/ */
used_in_a |= matched; used_in_a |= matched;
/* Now copy all the cylinder info raw from 'a' (whether used/matched or not) */
memcpy(res->cylinder, a->cylinder, sizeof(res->cylinder));
memset(a->cylinder, 0, sizeof(a->cylinder));
/* /*
* Go back to 'b' and remap any remaining cylinders that didn't * Go back to 'b' and remap any remaining cylinders that didn't
* match completely. * match completely.
@ -2402,7 +2521,7 @@ static void merge_cylinders(struct dive *res, struct dive *a, struct dive *b)
int j; int j;
/* Already remapped, or not interesting? */ /* Already remapped, or not interesting? */
if (mapping[i] >= 0) if (mapping_b[i] >= 0)
continue; continue;
if (!(used_in_b & (1u << i))) if (!(used_in_b & (1u << i)))
continue; continue;
@ -2411,32 +2530,24 @@ static void merge_cylinders(struct dive *res, struct dive *a, struct dive *b)
if (j < 0) if (j < 0)
continue; continue;
res->cylinder[j] = b->cylinder[i]; copy_cylinder(b->cylinder + i, res->cylinder + j);
memset(b->cylinder+i, 0, sizeof(cylinder_t)); mapping_b[i] = j;
mapping[i] = j;
used_in_a |= 1u << j; used_in_a |= 1u << j;
if (i != j)
renumber = 1;
} }
if (renumber)
cylinder_renumber(b, mapping);
} }
static void merge_equipment(struct dive *res, struct dive *a, struct dive *b) static void merge_equipment(struct dive *res, const struct dive *a, const struct dive *b)
{ {
int i; int i;
merge_cylinders(res, a, b);
for (i = 0; i < MAX_WEIGHTSYSTEMS; i++) for (i = 0; i < MAX_WEIGHTSYSTEMS; i++)
merge_weightsystem_info(res->weightsystem + i, a->weightsystem + i, b->weightsystem + i); merge_weightsystem_info(res->weightsystem + i, a->weightsystem + i, b->weightsystem + i);
} }
static void merge_temperatures(struct dive *res, struct dive *a, struct dive *b) static void merge_temperatures(struct dive *res, const struct dive *a, const struct dive *b)
{ {
un_fixup_airtemp(a); temperature_t airtemp_a = un_fixup_airtemp(a);
un_fixup_airtemp(b); temperature_t airtemp_b = un_fixup_airtemp(b);
MERGE_NONZERO(res, a, b, airtemp.mkelvin); res->airtemp = airtemp_a.mkelvin ? airtemp_a : airtemp_b;
MERGE_NONZERO(res, a, b, watertemp.mkelvin); MERGE_NONZERO(res, a, b, watertemp.mkelvin);
} }
@ -2459,7 +2570,7 @@ static void pick_trip(struct dive *res, const struct dive *pick)
/* /*
* Pick a trip for a dive * Pick a trip for a dive
*/ */
static struct dive *get_preferred_trip(struct dive *a, struct dive *b) static const struct dive *get_preferred_trip(const struct dive *a, const struct dive *b)
{ {
dive_trip_t *atrip, *btrip; dive_trip_t *atrip, *btrip;
@ -2953,14 +3064,9 @@ static void remove_redundant_dc(struct divecomputer *dc, int prefer_downloaded)
} while (dc); } while (dc);
} }
static void clear_dc(struct divecomputer *dc) static const struct divecomputer *find_matching_computer(const struct divecomputer *match, const struct divecomputer *list)
{ {
memset(dc, 0, sizeof(*dc)); const struct divecomputer *p;
}
static struct divecomputer *find_matching_computer(struct divecomputer *match, struct divecomputer *list)
{
struct divecomputer *p;
while ((p = list) != NULL) { while ((p = list) != NULL) {
list = list->next; list = list->next;
@ -2990,28 +3096,25 @@ static void copy_dive_computer(struct divecomputer *res, const struct divecomput
* to match them up. If we find a matching dive computer, we * to match them up. If we find a matching dive computer, we
* merge them. If not, we just take the data from 'a'. * merge them. If not, we just take the data from 'a'.
*/ */
static void interleave_dive_computers(struct divecomputer *res, static void interleave_dive_computers(struct dive *d, struct divecomputer *res,
struct divecomputer *a, struct divecomputer *b, int offset) const struct divecomputer *a, const struct divecomputer *b,
const int cylinders_map_a[], const int cylinders_map_b[],
int offset)
{ {
do { do {
struct divecomputer *match; const struct divecomputer *match;
copy_dive_computer(res, a); copy_dive_computer(res, a);
match = find_matching_computer(a, b); match = find_matching_computer(a, b);
if (match) { if (match) {
merge_events(res, a, match, offset); merge_events(d, res, a, match, cylinders_map_a, cylinders_map_b, offset);
merge_samples(res, a, match, offset); merge_samples(res, a, match, cylinders_map_a, cylinders_map_b, offset);
/* Use the diveid of the later dive! */ /* Use the diveid of the later dive! */
if (offset > 0) if (offset > 0)
res->diveid = match->diveid; res->diveid = match->diveid;
} else { } else {
res->sample = a->sample; copy_dc_renumber(d, a, res, cylinders_map_a);
res->samples = a->samples;
res->events = a->events;
a->sample = NULL;
a->samples = 0;
a->events = NULL;
} }
a = a->next; a = a->next;
if (!a) if (!a)
@ -3035,30 +3138,29 @@ static void interleave_dive_computers(struct divecomputer *res,
* try to throw out old information that *might* be from * try to throw out old information that *might* be from
* that one. * that one.
*/ */
static void join_dive_computers(struct divecomputer *res, struct divecomputer *a, struct divecomputer *b, int prefer_downloaded) static void join_dive_computers(struct dive *d, struct divecomputer *res,
const struct divecomputer *a, const struct divecomputer *b,
const int cylinders_map_a[], const int cylinders_map_b[],
int prefer_downloaded)
{ {
struct divecomputer *tmp; struct divecomputer *tmp;
if (a->model && !b->model) { if (a->model && !b->model) {
*res = *a; copy_dc_renumber(d, a, res, cylinders_map_a);
clear_dc(a);
return; return;
} }
if (b->model && !a->model) { if (b->model && !a->model) {
*res = *b; copy_dc_renumber(d, b, res, cylinders_map_b);
clear_dc(b);
return; return;
} }
*res = *a; copy_dc_renumber(d, a, res, cylinders_map_a);
clear_dc(a);
tmp = res; tmp = res;
while (tmp->next) while (tmp->next)
tmp = tmp->next; tmp = tmp->next;
tmp->next = calloc(1, sizeof(*tmp)); tmp->next = calloc(1, sizeof(*tmp));
*tmp->next = *b; copy_dc_renumber(d, b, tmp->next, cylinders_map_b);
clear_dc(b);
remove_redundant_dc(res, prefer_downloaded); remove_redundant_dc(res, prefer_downloaded);
} }
@ -3335,10 +3437,12 @@ int count_dives_with_suit(const char *suit)
* in the "trip" output paramater. If "trip" is NULL, then the dive will * in the "trip" output paramater. If "trip" is NULL, then the dive will
* instead be added to this trip. * instead be added to this trip.
*/ */
struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer_downloaded, struct dive_trip **trip) struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset, bool prefer_downloaded, struct dive_trip **trip)
{ {
struct dive *res = alloc_dive(); struct dive *res = alloc_dive();
struct dive *preferred_trip; const struct dive *dl = NULL;
const struct dive *preferred_trip;
int cylinders_map_a[MAX_CYLINDERS], cylinders_map_b[MAX_CYLINDERS];
if (offset) { if (offset) {
/* /*
@ -3352,7 +3456,7 @@ struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer
} }
if (same_string(a->dc.model, "planned dive")) { if (same_string(a->dc.model, "planned dive")) {
struct dive *tmp = a; const struct dive *tmp = a;
a = b; a = b;
b = tmp; b = tmp;
} }
@ -3373,15 +3477,17 @@ struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer
MERGE_NONZERO(res, a, b, visibility); MERGE_NONZERO(res, a, b, visibility);
MERGE_NONZERO(res, a, b, picture_list); MERGE_NONZERO(res, a, b, picture_list);
taglist_merge(&res->tag_list, a->tag_list, b->tag_list); taglist_merge(&res->tag_list, a->tag_list, b->tag_list);
merge_cylinders(res, a, b, cylinders_map_a, cylinders_map_b);
merge_equipment(res, a, b); merge_equipment(res, a, b);
merge_temperatures(res, a, b); merge_temperatures(res, a, b);
if (prefer_downloaded) { if (prefer_downloaded) {
/* If we prefer downloaded, do those first, and get rid of "might be same" computers */ /* If we prefer downloaded, do those first, and get rid of "might be same" computers */
join_dive_computers(&res->dc, &b->dc, &a->dc, 1); join_dive_computers(res, &res->dc, &dl->dc, &a->dc, cylinders_map_b, cylinders_map_a, 1);
} else if (offset && might_be_same_device(&a->dc, &b->dc)) } else if (offset && might_be_same_device(&a->dc, &b->dc))
interleave_dive_computers(&res->dc, &a->dc, &b->dc, offset); interleave_dive_computers(res, &res->dc, &a->dc, &b->dc, cylinders_map_a, cylinders_map_b, offset);
else else
join_dive_computers(&res->dc, &a->dc, &b->dc, 0); join_dive_computers(res, &res->dc, &a->dc, &b->dc, cylinders_map_a, cylinders_map_b, 0);
/* we take the first dive site, unless it's empty */ /* we take the first dive site, unless it's empty */
if (a->dive_site_uuid && !dive_site_is_empty(get_dive_site_by_uuid(a->dive_site_uuid))) if (a->dive_site_uuid && !dive_site_is_empty(get_dive_site_by_uuid(a->dive_site_uuid)))
res->dive_site_uuid = a->dive_site_uuid; res->dive_site_uuid = a->dive_site_uuid;

View file

@ -573,7 +573,7 @@ extern int split_dive_dont_insert(const struct dive *dive, struct dive **new1, s
extern void split_dive(struct dive *); extern void split_dive(struct dive *);
extern int split_dive_at_time_dont_insert(const struct dive *dive, duration_t time, struct dive **new1, struct dive **new2); extern int split_dive_at_time_dont_insert(const struct dive *dive, duration_t time, struct dive **new1, struct dive **new2);
extern void split_dive_at_time(struct dive *dive, duration_t time); extern void split_dive_at_time(struct dive *dive, duration_t time);
extern struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer_downloaded, struct dive_trip **trip); extern struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset, bool prefer_downloaded, struct dive_trip **trip);
extern struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded); extern struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded);
extern struct event *clone_event(const struct event *src_ev); extern struct event *clone_event(const struct event *src_ev);
extern void copy_events(const struct divecomputer *s, struct divecomputer *d); extern void copy_events(const struct divecomputer *s, struct divecomputer *d);