diff --git a/dive.c b/dive.c index d0e7c490f..5d86630cf 100644 --- a/dive.c +++ b/dive.c @@ -255,16 +255,106 @@ struct dive *alloc_dive(void) return dive; } +static void free_dc(struct divecomputer *dc); +static void free_pic(struct picture *picture); + +#define STRDUP(_ptr) ((_ptr) ? strdup(_ptr) : NULL) + +/* this is very different from the copy_divecomputer later in this file; + * this function actually makes full copies of the content */ +static void copy_dc(struct divecomputer *sdc, struct divecomputer *ddc) +{ + *ddc = *sdc; + ddc->model = STRDUP(sdc->model); + copy_samples(sdc, ddc); + copy_events(sdc, ddc); +} + +/* copy an element in a list of pictures */ +static void copy_pl(struct picture *sp, struct picture *dp) +{ + *dp = *sp; + dp->filename = STRDUP(sp->filename); +} + +/* copy an element in a list of tags */ +static void copy_tl(struct tag_entry *st, struct tag_entry *dt) +{ + dt->tag = malloc(sizeof(struct divetag)); + dt->tag->name = STRDUP(st->tag->name); + dt->tag->source = STRDUP(st->tag->source); +} + +/* Clear everything but the first element; + * this works for taglist, picturelist, even dive computers */ +#define STRUCTURED_LIST_FREE(_type, _start, _free) {\ + _type *_ptr = _start; \ + while(_ptr) { \ + _type *_next = _ptr->next; \ + _free(_ptr); \ + _ptr = _next; \ + }} + +#define STRUCTURED_LIST_COPY(_type, _first, _dest, _cpy) {\ + _type *_sptr = _first; \ + _type **_dptr = &_dest; \ + while(_sptr) { \ + *_dptr = malloc(sizeof(_type)); \ + _cpy(_sptr, *_dptr); \ + _sptr = _sptr->next; \ + _dptr = &(*_dptr)->next; \ + } \ + *_dptr = 0; \ + } + +/* copy_dive makes duplicates of many components of a dive; + * in order not to leak memory, we need to free those . + * copy_dive doesn't play with the divetrip and forward/backward pointers + * so we can ignore those */ +void clear_dive(struct dive *d) +{ + if (!d) + return; + /* free the strings */ + free(d->buddy); + free(d->divemaster); + free(d->location); + free(d->notes); + free(d->suit); + /* free tags, additional dive computers, and pictures */ + taglist_free(d->tag_list); + STRUCTURED_LIST_FREE(struct divecomputer, d->dc.next, free_dc); + STRUCTURED_LIST_FREE(struct picture, d->picture_list, free_pic); + memset(d, 0, sizeof(struct dive)); +} + +void copy_dive(struct dive *s, struct dive *d) +{ + clear_dive(d); + /* simply copy things over, but then make actual copies of the + * relevant components that are referenced through pointers, + * so all the strings and the structured lists */ + *d = *s; + d->buddy = STRDUP(s->buddy); + d->divemaster = STRDUP(s->divemaster); + d->location = STRDUP(s->location); + d->notes = STRDUP(s->notes); + d->suit = STRDUP(s->suit); + STRUCTURED_LIST_COPY(struct divecomputer, s->dc.next, d->dc.next, copy_dc); + STRUCTURED_LIST_COPY(struct picture, s->picture_list, d->picture_list, copy_pl); + STRUCTURED_LIST_COPY(struct tag_entry, s->tag_list, d->tag_list, copy_tl); +} + /* only copies events from the first dive computer */ -void copy_events(struct dive *s, struct dive *d) +void copy_events(struct divecomputer *s, struct divecomputer *d) { struct event *ev; if (!s || !d) return; - ev = s->dc.events; - d->dc.events = NULL; + ev = s->events; + d->events = NULL; while (ev != NULL) { - add_event(&d->dc, ev->time.seconds, ev->type, ev->flags, ev->value, ev->name); + add_event(d, ev->time.seconds, ev->type, ev->flags, ev->value, ev->name); ev = ev->next; } } @@ -305,17 +395,17 @@ void copy_cylinders(struct dive *s, struct dive *d, bool used_only) memset(&d->cylinder[i], 0, sizeof(cylinder_t)); } -void copy_samples(struct dive *s, struct dive *d) +void copy_samples(struct divecomputer *s, struct divecomputer *d) { /* instead of carefully copying them one by one and calling add_sample * over and over again, let's just copy the whole blob */ if (!s || !d) return; - int nr = s->dc.samples; - d->dc.samples = nr; - d->dc.sample = malloc(nr * sizeof(struct sample)); - if (d->dc.sample) - memcpy(d->dc.sample, s->dc.sample, nr * sizeof(struct sample)); + int nr = s->samples; + d->samples = nr; + d->sample = malloc(nr * sizeof(struct sample)); + if (d->sample) + memcpy(d->sample, s->sample, nr * sizeof(struct sample)); } struct sample *prepare_sample(struct divecomputer *dc) @@ -1771,6 +1861,14 @@ static void free_dc(struct divecomputer *dc) free(dc); } +static void free_pic(struct picture *picture) +{ + if (picture) { + free(picture->filename); + free(picture); + } +} + static int same_event(struct event *a, struct event *b) { if (a->time.seconds != b->time.seconds) @@ -2075,14 +2173,9 @@ struct divetag *taglist_add_tag(struct tag_entry **tag_list, const char *tag) return ret_tag; } -/* Clear everything but the first element */ void taglist_free(struct tag_entry *entry) { - while (entry) { - struct tag_entry *next = entry->next; - free(entry); - entry = next; - } + STRUCTURED_LIST_FREE(struct tag_entry, entry, free) } /* Merge src1 and src2, write to *dst */ diff --git a/dive.h b/dive.h index b325f11fa..a13c4fd3b 100644 --- a/dive.h +++ b/dive.h @@ -598,6 +598,8 @@ extern void utc_mkdate(timestamp_t, struct tm *tm); extern struct dive *alloc_dive(void); extern void record_dive(struct dive *dive); +extern void clear_dive(struct dive *dive); +extern void copy_dive(struct dive *s, struct dive *d); extern struct sample *prepare_sample(struct divecomputer *dc); extern void finish_sample(struct divecomputer *dc); @@ -612,9 +614,9 @@ extern unsigned int dc_watertemp(struct divecomputer *dc); extern struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer_downloaded); extern struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded); extern void renumber_dives(int start_nr, bool selected_only); -extern void copy_events(struct dive *s, struct dive *d); +extern void copy_events(struct divecomputer *s, struct divecomputer *d); extern void copy_cylinders(struct dive *s, struct dive *d, bool used_only); -extern void copy_samples(struct dive *s, struct dive *d); +extern void copy_samples(struct divecomputer *s, struct divecomputer *d); extern bool cylinder_is_used(struct dive *d, cylinder_t *cyl); extern void fill_default_cylinder(cylinder_t *cyl); extern void add_gas_switch_event(struct dive *dive, struct divecomputer *dc, int time, int idx); diff --git a/qt-ui/diveplanner.cpp b/qt-ui/diveplanner.cpp index 44449a52a..7d8416e88 100644 --- a/qt-ui/diveplanner.cpp +++ b/qt-ui/diveplanner.cpp @@ -103,8 +103,13 @@ void DivePlannerPointsModel::loadFromDive(dive *d) // We need to make a copy, because as soon as the model is modified, it will // remove all samples from the dive. memcpy(&backupDive, d, sizeof(struct dive)); - copy_samples(d, &backupDive); - copy_events(d, &backupDive); + + // this code is just adjusted for the new API, it continues to just copy the first + // DC (which here is almost certainly sufficient) + // but it should most likely use copy_dive() instead + // but this whole section needs to be rewritten, anyway + copy_samples(&d->dc, &backupDive.dc); + copy_events(&d->dc, &backupDive.dc); copy_cylinders(d, stagingDive, false); // this way the correct cylinder data is shown CylindersModel::instance()->setDive(stagingDive); int lasttime = 0; @@ -1046,9 +1051,10 @@ void DivePlannerPointsModel::createTemporaryPlan() plan(&diveplan, &cache, &tempDive, stagingDive, isPlanner(), false); MainWindow::instance()->setPlanNotes(tempDive->notes); if (mode == ADD || mode == PLAN) { - // copy the samples and events, but don't overwrite the cylinders - copy_samples(tempDive, current_dive); - copy_events(tempDive, current_dive); + // copy the samples and events of the first dive computer, but don't overwrite the cylinders + // FIXME this needs to be rewritten + copy_samples(&tempDive->dc, ¤t_dive->dc); + copy_events(&tempDive->dc, ¤t_dive->dc); copy_cylinders(tempDive, current_dive, false); } }