Be more careful about dive computer selection

The selection logic was a bit random: some places would return NULL if
the dive computer index was out of range, others would return the
primary dive computer, and actually moving between dive computers would
just blindly increment and decrement the number.

This always selects the primary computer if the index is out of bounds,
and makes sure we stay in bound when switching beteen dive computers
(but switching between dives can then turn an in-bound number into an
out-of-bounds one)

Fixes #464

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
Linus Torvalds 2014-03-17 08:19:09 -07:00 committed by Dirk Hohndel
parent 60ceb8ebc1
commit 37794e2e23
8 changed files with 41 additions and 38 deletions

View file

@ -32,7 +32,7 @@ typedef enum {
SC_PRINT SC_PRINT
} scale_mode_t; } scale_mode_t;
extern struct divecomputer *select_dc(struct divecomputer *main); extern struct divecomputer *select_dc(struct dive *);
struct options { struct options {
enum { enum {
@ -46,7 +46,7 @@ struct options {
int profile_height, notes_height, tanks_height; int profile_height, notes_height, tanks_height;
}; };
extern char dc_number; extern unsigned int dc_number;
extern unsigned int amount_selected; extern unsigned int amount_selected;

25
dive.h
View file

@ -600,13 +600,30 @@ static inline struct dive *get_dive(int nr)
return dive_table.dives[nr]; return dive_table.dives[nr];
} }
static inline unsigned int number_of_computers(struct dive *dive)
{
unsigned int total_number = 0;
struct divecomputer *dc = &dive->dc;
if (!dive)
return 1;
do {
total_number++;
dc = dc->next;
} while (dc);
return total_number;
}
static inline struct divecomputer *get_dive_dc(struct dive *dive, int nr) static inline struct divecomputer *get_dive_dc(struct dive *dive, int nr)
{ {
struct divecomputer *dc = NULL; struct divecomputer *dc = &dive->dc;
if (nr >= 0)
dc = &dive->dc; while (nr-- > 0) {
while (nr-- > 0)
dc = dc->next; dc = dc->next;
if (!dc)
return &dive->dc;
}
return dc; return dc;
} }

View file

@ -16,7 +16,7 @@
#include "membuffer.h" #include "membuffer.h"
int selected_dive = -1; /* careful: 0 is a valid value */ int selected_dive = -1; /* careful: 0 is a valid value */
char dc_number = 0; unsigned int dc_number = 0;
static struct plot_data *last_pi_entry_new = NULL; static struct plot_data *last_pi_entry_new = NULL;
@ -1193,32 +1193,16 @@ void create_plot_info_new(struct dive *dive, struct divecomputer *dc, struct plo
analyze_plot_info(pi); analyze_plot_info(pi);
} }
/* make sure you pass this the FIRST dc - it just walks the list */ struct divecomputer *select_dc(struct dive *dive)
static int nr_dcs(struct divecomputer *main)
{ {
int i = 1; unsigned int max = number_of_computers(dive);
struct divecomputer *dc = main; unsigned int i = dc_number;
while ((dc = dc->next) != NULL) /* Reset 'dc_number' if we've switched dives and it is now out of range */
i++; if (i >= max)
return i; dc_number = i = 0;
}
struct divecomputer *select_dc(struct divecomputer *main) return get_dive_dc(dive, i);
{
int i = dc_number;
struct divecomputer *dc = main;
while (i < 0)
i += nr_dcs(main);
do {
if (--i < 0)
return dc;
} while ((dc = dc->next) != NULL);
/* If we switched dives to one with fewer DC's, reset the dive computer counter */
dc_number = 0;
return main;
} }
static void plot_string(struct plot_data *entry, struct membuffer *b, bool has_ndl) static void plot_string(struct plot_data *entry, struct membuffer *b, bool has_ndl)

View file

@ -1472,7 +1472,7 @@ void DivePlannerPointsModel::createPlan()
plan(&diveplan, &cache, &tempDive, isPlanner()); plan(&diveplan, &cache, &tempDive, isPlanner());
copy_cylinders(stagingDive, tempDive); copy_cylinders(stagingDive, tempDive);
int mean[MAX_CYLINDERS], duration[MAX_CYLINDERS]; int mean[MAX_CYLINDERS], duration[MAX_CYLINDERS];
per_cylinder_mean_depth(tempDive, select_dc(&tempDive->dc), mean, duration); per_cylinder_mean_depth(tempDive, select_dc(tempDive), mean, duration);
for (int i = 0; i < MAX_CYLINDERS; i++) { for (int i = 0; i < MAX_CYLINDERS; i++) {
cylinder_t *cyl = tempDive->cylinder + i; cylinder_t *cyl = tempDive->cylinder + i;
if (cylinder_none(cyl)) if (cylinder_none(cyl))

View file

@ -483,7 +483,7 @@ void MainTab::updateDiveInfo(int dive)
get_gas_used(d, gases); get_gas_used(d, gases);
QString volumes = get_volume_string(gases[0], true); QString volumes = get_volume_string(gases[0], true);
int mean[MAX_CYLINDERS], duration[MAX_CYLINDERS]; int mean[MAX_CYLINDERS], duration[MAX_CYLINDERS];
per_cylinder_mean_depth(d, select_dc(&d->dc), mean, duration); per_cylinder_mean_depth(d, select_dc(d), mean, duration);
volume_t sac; volume_t sac;
QString SACs; QString SACs;
if (mean[0] && duration[0]) { if (mean[0] && duration[0]) {
@ -864,13 +864,13 @@ void MainTab::on_divemaster_textChanged()
void MainTab::on_airtemp_textChanged(const QString &text) void MainTab::on_airtemp_textChanged(const QString &text)
{ {
EDIT_SELECTED_DIVES(select_dc(&mydive->dc)->airtemp.mkelvin = parseTemperatureToMkelvin(text)); EDIT_SELECTED_DIVES(select_dc(mydive)->airtemp.mkelvin = parseTemperatureToMkelvin(text));
markChangedWidget(ui.airtemp); markChangedWidget(ui.airtemp);
} }
void MainTab::on_watertemp_textChanged(const QString &text) void MainTab::on_watertemp_textChanged(const QString &text)
{ {
EDIT_SELECTED_DIVES(select_dc(&mydive->dc)->watertemp.mkelvin = parseTemperatureToMkelvin(text)); EDIT_SELECTED_DIVES(select_dc(mydive)->watertemp.mkelvin = parseTemperatureToMkelvin(text));
markChangedWidget(ui.watertemp); markChangedWidget(ui.watertemp);
} }

View file

@ -507,14 +507,16 @@ void MainWindow::saveSplitterSizes()
void MainWindow::on_actionPreviousDC_triggered() void MainWindow::on_actionPreviousDC_triggered()
{ {
dc_number--; unsigned nrdc = number_of_computers(current_dive);
dc_number = (dc_number + nrdc - 1) % nrdc;
ui.InfoWidget->updateDiveInfo(selected_dive); ui.InfoWidget->updateDiveInfo(selected_dive);
ui.newProfile->plotDives(QList<struct dive *>() << (current_dive)); ui.newProfile->plotDives(QList<struct dive *>() << (current_dive));
} }
void MainWindow::on_actionNextDC_triggered() void MainWindow::on_actionNextDC_triggered()
{ {
dc_number++; unsigned nrdc = number_of_computers(current_dive);
dc_number = (dc_number + 1) % nrdc;
ui.InfoWidget->updateDiveInfo(selected_dive); ui.InfoWidget->updateDiveInfo(selected_dive);
ui.newProfile->plotDives(QList<struct dive *>() << (current_dive)); ui.newProfile->plotDives(QList<struct dive *>() << (current_dive));
} }

View file

@ -183,7 +183,7 @@ void DivePlotDataModel::calculateDecompression()
struct dive *d = getDiveById(id()); struct dive *d = getDiveById(id());
if (!d) if (!d)
return; return;
struct divecomputer *dc = select_dc(&d->dc); struct divecomputer *dc = select_dc(d);
init_decompression(d); init_decompression(d);
calculate_deco_information(d, dc, &pInfo, false); calculate_deco_information(d, dc, &pInfo, false);
dataChanged(index(0, CEILING), index(pInfo.nr - 1, TISSUE_16)); dataChanged(index(0, CEILING), index(pInfo.nr - 1, TISSUE_16));

View file

@ -358,7 +358,7 @@ void ProfileWidget2::plotDives(QList<dive *> dives)
// next get the dive computer structure - if there are no samples // next get the dive computer structure - if there are no samples
// let's create a fake profile that's somewhat reasonable for the // let's create a fake profile that's somewhat reasonable for the
// data that we have // data that we have
struct divecomputer *currentdc = select_dc(&d->dc); struct divecomputer *currentdc = select_dc(d);
Q_ASSERT(currentdc); Q_ASSERT(currentdc);
if (!currentdc || !currentdc->samples) { if (!currentdc || !currentdc->samples) {
currentdc = fake_dc(currentdc); currentdc = fake_dc(currentdc);