diff options
Diffstat (limited to 'core/dive.c')
-rw-r--r-- | core/dive.c | 282 |
1 files changed, 112 insertions, 170 deletions
diff --git a/core/dive.c b/core/dive.c index 6043845f6..0b68819fa 100644 --- a/core/dive.c +++ b/core/dive.c @@ -150,7 +150,8 @@ struct event *add_event(struct divecomputer *dc, unsigned int time, int type, in ev->gas.mix.he.permille = (value >> 16) * 10; /* Extension to the GASCHANGE2 format: cylinder index in 'flags' */ - if (flags > 0 && flags <= MAX_CYLINDERS) + /* TODO: verify that gas_index < num_cylinders. */ + if (flags > 0) gas_index = flags-1; /* Fallthrough */ case SAMPLE_EVENT_GASCHANGE: @@ -262,8 +263,8 @@ struct gasmix get_gasmix_from_event(const struct dive *dive, const struct event struct gasmix dummy = { 0 }; if (ev && event_is_gaschange(ev)) { int index = ev->gas.index; - if (index >= 0 && index < MAX_CYLINDERS) - return dive->cylinder[index].gasmix; + if (index >= 0 && index < dive->cylinders.nr) + return dive->cylinders.cylinders[index].gasmix; return ev->gas.mix; } return dummy; @@ -360,8 +361,8 @@ static void free_dive_structures(struct dive *d) taglist_free(d->tag_list); free_dive_dcs(&d->dc); STRUCTURED_LIST_FREE(struct picture, d->picture_list, free_picture); - for (int i = 0; i < MAX_CYLINDERS; i++) - free((void *)d->cylinder[i].type.description); + clear_cylinder_table(&d->cylinders); + free(d->cylinders.cylinders); clear_weightsystem_table(&d->weightsystems); free(d->weightsystems.weightsystems); } @@ -394,14 +395,14 @@ static void copy_dive_nodc(const struct dive *s, struct dive *d) * relevant components that are referenced through pointers, * so all the strings and the structured lists */ *d = *s; + memset(&d->cylinders, 0, sizeof(d->cylinders)); memset(&d->weightsystems, 0, sizeof(d->weightsystems)); invalidate_dive_cache(d); d->buddy = copy_string(s->buddy); d->divemaster = copy_string(s->divemaster); d->notes = copy_string(s->notes); d->suit = copy_string(s->suit); - for (int i = 0; i < MAX_CYLINDERS; i++) - d->cylinder[i].type.description = copy_string(s->cylinder[i].type.description); + copy_cylinders(&s->cylinders, &d->cylinders); copy_weights(&s->weightsystems, &d->weightsystems); STRUCTURED_LIST_COPY(struct picture, s->picture_list, d->picture_list, copy_pl); d->tag_list = taglist_copy(s->tag_list); @@ -501,14 +502,7 @@ void copy_events(const struct divecomputer *s, struct divecomputer *d) int nr_cylinders(const struct dive *dive) { - int nr; - - for (nr = MAX_CYLINDERS; nr; --nr) { - const cylinder_t *cylinder = dive->cylinder + nr - 1; - if (!cylinder_nodata(cylinder)) - break; - } - return nr; + return dive->cylinders.nr; } int nr_weightsystems(const struct dive *dive) @@ -516,24 +510,24 @@ int nr_weightsystems(const struct dive *dive) return dive->weightsystems.nr; } -void copy_cylinders(const struct dive *s, struct dive *d, bool used_only) +void copy_cylinders(const struct cylinder_table *s, struct cylinder_table *d) +{ + int i; + clear_cylinder_table(d); + for (i = 0; i < s->nr; i++) + add_cloned_cylinder(d, s->cylinders[i]); +} + +void copy_used_cylinders(const struct dive *s, struct dive *d, bool used_only) { - int i, j; + int i; if (!s || !d) return; - for (i = 0, j = 0; i < MAX_CYLINDERS; i++) { - if (!used_only || is_cylinder_used(s, i) || s->cylinder[i].cylinder_use == NOT_USED) { - free((void *)d->cylinder[j].type.description); - d->cylinder[j] = s->cylinder[i]; - if (d->cylinder[j].type.description) - d->cylinder[j].type.description = strdup(d->cylinder[j].type.description); - j++; - } - } - for ( ; j < MAX_CYLINDERS; j++) { - free((void *)d->cylinder[j].type.description); - memset(d->cylinder + j, 0, sizeof(d->cylinder[j])); + clear_cylinder_table(&d->cylinders); + for (i = 0; i < s->cylinders.nr; i++) { + if (!used_only || is_cylinder_used(s, i) || s->cylinders.cylinders[i].cylinder_use == NOT_USED) + add_cloned_cylinder(&d->cylinders, s->cylinders.cylinders[i]); } } @@ -688,8 +682,6 @@ static bool cylinder_used(const cylinder_t *cyl) { int start_mbar, end_mbar; - if (cylinder_nodata(cyl)) - return false; start_mbar = cyl->start.mbar ?: cyl->sample_start.mbar; end_mbar = cyl->end.mbar ?: cyl->sample_end.mbar; @@ -703,8 +695,8 @@ static int get_cylinder_used(const struct dive *dive, bool used[]) { int i, num = 0; - for (i = 0; i < MAX_CYLINDERS; i++) { - used[i] = cylinder_used(dive->cylinder + i); + for (i = 0; i < dive->cylinders.nr; i++) { + used[i] = cylinder_used(dive->cylinders.cylinders + i); if (used[i]) num++; } @@ -717,8 +709,8 @@ static bool has_unknown_used_cylinders(const struct dive *dive, const struct div { int idx; const struct event *ev; - bool *used_and_unknown = malloc(MAX_CYLINDERS * sizeof(bool)); - memcpy(used_and_unknown, used_cylinders, MAX_CYLINDERS * sizeof(bool)); + bool *used_and_unknown = malloc(dive->cylinders.nr * sizeof(bool)); + memcpy(used_and_unknown, used_cylinders, dive->cylinders.nr * sizeof(bool)); /* We know about using the O2 cylinder in a CCR dive */ if (dc->divemode == CCR) { @@ -761,7 +753,7 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i bool *used_cylinders; int num_used_cylinders; - for (i = 0; i < MAX_CYLINDERS; i++) + for (i = 0; i < dive->cylinders.nr; i++) mean[i] = duration[i] = 0; if (!dc) return; @@ -771,7 +763,7 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i * if we don't actually know about the usage of all the * used cylinders. */ - used_cylinders = malloc(MAX_CYLINDERS * sizeof(bool)); + used_cylinders = malloc(dive->cylinders.nr * sizeof(bool)); num_used_cylinders = get_cylinder_used(dive, used_cylinders); if (has_unknown_used_cylinders(dive, dc, used_cylinders, num_used_cylinders)) { /* @@ -788,7 +780,7 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i * For a single cylinder, use the overall mean * and duration */ - for (i = 0; i < MAX_CYLINDERS; i++) { + for (i = 0; i < dive->cylinders.nr; i++) { if (used_cylinders[i]) { mean[i] = dc->meandepth.mm; duration[i] = dc->duration.seconds; @@ -802,8 +794,8 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i if (!dc->samples) fake_dc(dc); const struct event *ev = get_next_event(dc->events, "gaschange"); - depthtime = malloc(MAX_CYLINDERS * sizeof(*depthtime)); - memset(depthtime, 0, MAX_CYLINDERS * sizeof(*depthtime)); + depthtime = malloc(dive->cylinders.nr * sizeof(*depthtime)); + memset(depthtime, 0, dive->cylinders.nr * sizeof(*depthtime)); for (i = 0; i < dc->samples; i++) { struct sample *sample = dc->sample + i; uint32_t time = sample->time.seconds; @@ -832,7 +824,7 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i lastdepth = depth; lasttime = time; } - for (i = 0; i < MAX_CYLINDERS; i++) { + for (i = 0; i < dive->cylinders.nr; i++) { if (duration[i]) mean[i] = (depthtime[i] + duration[i] / 2) / duration[i]; } @@ -1004,9 +996,9 @@ static void sanitize_cylinder_info(struct dive *dive) { int i; - for (i = 0; i < MAX_CYLINDERS; i++) { - sanitize_gasmix(&dive->cylinder[i].gasmix); - sanitize_cylinder_type(&dive->cylinder[i].type); + for (i = 0; i < dive->cylinders.nr; i++) { + sanitize_gasmix(&dive->cylinders.cylinders[i].gasmix); + sanitize_cylinder_type(&dive->cylinders.cylinders[i].type); } } @@ -1338,8 +1330,8 @@ static void simplify_dc_pressures(struct divecomputer *dc) /* Do we need a sensor -> cylinder mapping? */ static void fixup_start_pressure(struct dive *dive, int idx, pressure_t p) { - if (idx >= 0 && idx < MAX_CYLINDERS) { - cylinder_t *cyl = dive->cylinder + idx; + if (idx >= 0 && idx < dive->cylinders.nr) { + cylinder_t *cyl = dive->cylinders.cylinders + idx; if (p.mbar && !cyl->sample_start.mbar) cyl->sample_start = p; } @@ -1347,8 +1339,8 @@ static void fixup_start_pressure(struct dive *dive, int idx, pressure_t p) static void fixup_end_pressure(struct dive *dive, int idx, pressure_t p) { - if (idx >= 0 && idx < MAX_CYLINDERS) { - cylinder_t *cyl = dive->cylinder + idx; + if (idx >= 0 && idx < dive->cylinders.nr) { + cylinder_t *cyl = dive->cylinders.cylinders + idx; if (p.mbar && !cyl->sample_end.mbar) cyl->sample_end = p; } @@ -1414,13 +1406,13 @@ static bool validate_gaschange(struct dive *dive, struct event *event) if (event->gas.index >= 0) return true; - index = find_best_gasmix_match(event->gas.mix, dive->cylinder); - if (index < 0) + index = find_best_gasmix_match(event->gas.mix, &dive->cylinders); + if (index < 0 || index >= dive->cylinders.nr) return false; /* Fix up the event to have the right information */ event->gas.index = index; - event->gas.mix = dive->cylinder[index].gasmix; + event->gas.mix = dive->cylinders.cylinders[index].gasmix; /* Convert to odd libdivecomputer format */ o2 = get_o2(event->gas.mix); @@ -1544,8 +1536,8 @@ struct dive *fixup_dive(struct dive *dive) fixup_duration(dive); fixup_watertemp(dive); fixup_airtemp(dive); - for (i = 0; i < MAX_CYLINDERS; i++) { - cylinder_t *cyl = dive->cylinder + i; + for (i = 0; i < dive->cylinders.nr; i++) { + cylinder_t *cyl = dive->cylinders.cylinders + i; add_cylinder_description(&cyl->type); if (same_rounded_pressure(cyl->sample_start, cyl->start)) cyl->start.mbar = 0; @@ -1927,8 +1919,8 @@ static void merge_events(struct dive *d, struct divecomputer *res, extern int get_cylinder_idx_by_use(const struct dive *dive, enum cylinderuse cylinder_use_type) { int cylinder_index; - for (cylinder_index = 0; cylinder_index < MAX_CYLINDERS; cylinder_index++) { - if (dive->cylinder[cylinder_index].cylinder_use == cylinder_use_type) + for (cylinder_index = 0; cylinder_index < dive->cylinders.nr; cylinder_index++) { + if (dive->cylinders.cylinders[cylinder_index].cylinder_use == cylinder_use_type) return cylinder_index; // return the index of the cylinder with that cylinder use type } return -1; // negative number means cylinder_use_type not found in list of cylinders @@ -2072,13 +2064,13 @@ void cylinder_renumber(struct dive *dive, int mapping[]) dc_cylinder_renumber(dive, dc, mapping); } -int same_gasmix_cylinder(cylinder_t *cyl, int cylid, struct dive *dive, bool check_unused) +int same_gasmix_cylinder(const cylinder_t *cyl, int cylid, const struct dive *dive, bool check_unused) { struct gasmix mygas = cyl->gasmix; - for (int i = 0; i < MAX_CYLINDERS; i++) { - if (i == cylid || cylinder_none(&dive->cylinder[i])) + for (int i = 0; i < dive->cylinders.nr; i++) { + if (i == cylid) continue; - struct gasmix gas2 = dive->cylinder[i].gasmix; + struct gasmix gas2 = dive->cylinders.cylinders[i].gasmix; if (gasmix_distance(mygas, gas2) == 0 && (is_cylinder_used(dive, i) || check_unused)) return i; } @@ -2104,16 +2096,16 @@ static int different_manual_pressures(const cylinder_t *a, const cylinder_t *b) * same cylinder use (ie OC/Diluent/Oxygen), and if pressures * have been added manually they need to match. */ -static int match_cylinder(const cylinder_t *cyl, const struct dive *dive, bool *used_in_a, bool *matched) +static int match_cylinder(const cylinder_t *cyl, const struct dive *dive, const bool *used) { int i; - for (i = 0; i < MAX_CYLINDERS; i++) { + for (i = 0; i < dive->cylinders.nr; i++) { const cylinder_t *target; - if (!used_in_a[i] || matched[i]) + if (!used[i]) continue; - target = dive->cylinder + i; + target = dive->cylinders.cylinders + i; if (!same_gasmix(cyl->gasmix, target->gasmix)) continue; if (cyl->cylinder_use != target->cylinder_use) @@ -2128,50 +2120,15 @@ static int match_cylinder(const cylinder_t *cyl, const struct dive *dive, bool * } /* - * Note: we only allocate from the end, not in holes in the middle. - * So we don't look for empty bits, we look for "no more bits set". - */ -static int find_unused_cylinder(bool used_map[]) -{ - int i; - - if (used_map[MAX_CYLINDERS - 1]) - return -1; /* Maximum number of cylinders used! */ - for (i = MAX_CYLINDERS - 1; i > 0; i--) { - if (used_map[i - 1]) - return i; - } - return 0; /* Not a single cylinder used. */ -} - -/* - * 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 * use, but we might want to fill in any missing cylinder details * in 'a' if we had it from 'b'. */ -static void merge_one_cylinder(cylinder_t *res, const cylinder_t *a, const cylinder_t *b) +static void merge_one_cylinder(struct cylinder_table *t, const cylinder_t *a, const cylinder_t *b) { + cylinder_t *res; + add_empty_cylinder(t); + res = t->cylinders + (t->nr - 1); res->type.size.mliter = a->type.size.mliter ? a->type.size.mliter : b->type.size.mliter; res->type.workingpressure.mbar = a->type.workingpressure.mbar ? @@ -2209,37 +2166,37 @@ static void merge_one_cylinder(cylinder_t *res, const cylinder_t *a, const cylin * 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. * - * For each dive, a cylinder-renumbering table is returned. Currently, only - * cylinders of dive 'b' are renumbered. + * For each dive, a cylinder-renumbering table is returned. */ static void merge_cylinders(struct dive *res, const struct dive *a, const struct dive *b, int mapping_a[], int mapping_b[]) { int i; - bool *used_in_a = malloc(MAX_CYLINDERS * sizeof(bool)); - bool *used_in_b = malloc(MAX_CYLINDERS * sizeof(bool)); - bool *matched_in_a = malloc(MAX_CYLINDERS * sizeof(bool)); + bool *used_in_a = malloc(a->cylinders.nr * sizeof(bool)); + bool *used_in_b = malloc(b->cylinders.nr * sizeof(bool)); /* First, clear all cylinders in destination */ - memset(res->cylinder, 0, sizeof(res->cylinder)); + clear_cylinder_table(&res->cylinders); /* Calculate usage map of cylinders */ - for (i = 0; i < MAX_CYLINDERS; i++) { - used_in_a[i] = !cylinder_none(a->cylinder+i) || is_cylinder_used(a, i); - used_in_b[i] = !cylinder_none(b->cylinder+i) || is_cylinder_used(b, i); - matched_in_a[i] = false; + for (i = 0; i < a->cylinders.nr; i++) { + used_in_a[i] = is_cylinder_used(a, i); + mapping_a[i] = -1; + } + + for (i = 0; i < b->cylinders.nr; i++) { + used_in_b[i] = is_cylinder_used(b, i); + mapping_b[i] = -1; } /* For each cylinder in 'b', try to match up things */ - for (i = 0; i < MAX_CYLINDERS; i++) { + for (i = 0; i < b->cylinders.nr; i++) { int j; - mapping_a[i] = i; - mapping_b[i] = -1; if (!used_in_b[i]) continue; - j = match_cylinder(b->cylinder+i, a, used_in_a, matched_in_a); + j = match_cylinder(b->cylinders.cylinders + i, a, used_in_a); if (j < 0) continue; @@ -2250,54 +2207,35 @@ static void merge_cylinders(struct dive *res, const struct dive *a, const struct * * - save that in the mapping table * - * - mark it as matched so that another cylinder in 'b' - * will no longer match + * - remove it from the used array so that it will not be used later * - * - mark 'b' as needing renumbering if the index changed + * - mark as needing renumbering if the index changed */ - merge_one_cylinder(res->cylinder + j, a->cylinder + j, b->cylinder + i); - mapping_b[i] = j; - matched_in_a[j] = true; - } - - /* 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[i] && !matched_in_a[i]) - copy_cylinder(a->cylinder + i, res->cylinder + i); + mapping_b[i] = res->cylinders.nr; + mapping_a[j] = res->cylinders.nr; + used_in_a[i] = false; + used_in_b[j] = false; + merge_one_cylinder(&res->cylinders, a->cylinders.cylinders + j, b->cylinders.cylinders + i); + } + + /* Now copy all the used cylinders from 'a' that are used but have not been matched */ + for (i = 0; i < a->cylinders.nr; i++) { + if (used_in_a[i]) { + mapping_a[i] = res->weightsystems.nr; + add_cloned_cylinder(&res->cylinders, a->cylinders.cylinders[i]); + } } - /* - * Consider all the cylinders we matched as used, whether they - * originally were or not (either in 'a' or 'b'). - */ - for (i = 0; i < MAX_CYLINDERS; i++) - used_in_a[i] |= matched_in_a[i]; - - /* - * Go back to 'b' and remap any remaining cylinders that didn't - * match completely. - */ - for (i = 0; i < MAX_CYLINDERS; i++) { - int j; - - /* Already remapped, or not interesting? */ - if (mapping_b[i] >= 0) - continue; - if (!used_in_b[i]) - continue; - - j = find_unused_cylinder(used_in_a); - if (j < 0) - continue; - - copy_cylinder(b->cylinder + i, res->cylinder + j); - mapping_b[i] = j; - used_in_a[i] = true; + /* Finally, copy all the used cylinders from 'b' that are used but have not been matched */ + for (i = 0; i < b->cylinders.nr; i++) { + if (used_in_b[i]) { + mapping_b[i] = res->weightsystems.nr; + add_cloned_cylinder(&res->cylinders, b->cylinders.cylinders[i]); + } } free(used_in_a); free(used_in_b); - free(matched_in_a); } /* Check whether a weightsystem table contains a given weightsystem */ @@ -3022,8 +2960,8 @@ struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset, MERGE_NONZERO(res, a, b, visibility); STRUCTURED_LIST_COPY(struct picture, a->picture_list ? a->picture_list : b->picture_list, res->picture_list, copy_pl); taglist_merge(&res->tag_list, a->tag_list, b->tag_list); - cylinders_map_a = malloc(MAX_CYLINDERS * sizeof(*cylinders_map_a)); - cylinders_map_b = malloc(MAX_CYLINDERS * sizeof(*cylinders_map_b)); + cylinders_map_a = malloc(a->cylinders.nr * sizeof(*cylinders_map_a)); + cylinders_map_b = malloc(b->cylinders.nr * sizeof(*cylinders_map_b)); merge_cylinders(res, a, b, cylinders_map_a, cylinders_map_b); merge_equipment(res, a, b); merge_temperatures(res, a, b); @@ -3069,7 +3007,7 @@ static void force_fixup_dive(struct dive *d) int old_mintemp = d->mintemp.mkelvin; int old_maxtemp = d->maxtemp.mkelvin; duration_t old_duration = d->duration; - struct start_end_pressure *old_pressures = malloc(MAX_CYLINDERS * sizeof(*old_pressures)); + struct start_end_pressure *old_pressures = malloc(d->cylinders.nr * sizeof(*old_pressures)); d->maxdepth.mm = 0; dc->maxdepth.mm = 0; @@ -3078,11 +3016,11 @@ static void force_fixup_dive(struct dive *d) d->duration.seconds = 0; d->maxtemp.mkelvin = 0; d->mintemp.mkelvin = 0; - for (int i = 0; i < MAX_CYLINDERS; i++) { - old_pressures[i].start = d->cylinder[i].start; - old_pressures[i].end = d->cylinder[i].end; - d->cylinder[i].start.mbar = 0; - d->cylinder[i].end.mbar = 0; + for (int i = 0; i < d->cylinders.nr; i++) { + old_pressures[i].start = d->cylinders.cylinders[i].start; + old_pressures[i].end = d->cylinders.cylinders[i].end; + d->cylinders.cylinders[i].start.mbar = 0; + d->cylinders.cylinders[i].end.mbar = 0; } fixup_dive(d); @@ -3101,11 +3039,11 @@ static void force_fixup_dive(struct dive *d) if (!d->duration.seconds) d->duration = old_duration; - for (int i = 0; i < MAX_CYLINDERS; i++) { - if (!d->cylinder[i].start.mbar) - d->cylinder[i].start = old_pressures[i].start; - if (!d->cylinder[i].end.mbar) - d->cylinder[i].end = old_pressures[i].end; + for (int i = 0; i < d->cylinders.nr; i++) { + if (!d->cylinders.cylinders[i].start.mbar) + d->cylinders.cylinders[i].start = old_pressures[i].start; + if (!d->cylinders.cylinders[i].end.mbar) + d->cylinders.cylinders[i].end = old_pressures[i].end; } free(old_pressures); } @@ -4063,10 +4001,14 @@ struct gasmix get_gasmix(const struct dive *dive, const struct divecomputer *dc, const struct event *ev = *evp; struct gasmix res; + /* if there is no cylinder, return air */ + if (dive->cylinders.nr <= 0) + return gasmix_air; + if (!ev) { /* on first invocation, get initial gas mix and first event (if any) */ int cyl = explicit_first_cylinder(dive, dc); - res = dive->cylinder[cyl].gasmix; + res = dive->cylinders.cylinders[cyl].gasmix; ev = dc ? get_next_event(dc->events, "gaschange") : NULL; } else { res = gasmix; |