core: use C++-primitives for g_tag_list

The old code was leaking memory. Use std::unique_ptr<> for
ownership management.

This is still very primitive and divetags are kept during
application lifetime. There should probably be some form
of reference counting. And the taglist should not be global,
but attached to the divelog.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2024-03-26 21:06:13 +01:00 committed by bstoeger
parent b320942343
commit 556ecd5a9b
23 changed files with 92 additions and 125 deletions

View file

@ -191,14 +191,8 @@ void export_TeX(const char *filename, bool selected_only, bool plain, ExportCall
dive->maxdepth.mm ? put_format(&buf, "\\def\\%smaximumdepth{%.1f\\%sdepthunit}\n", ssrf, get_depth_units(dive->maxdepth.mm, NULL, &unit), ssrf) : put_format(&buf, "\\def\\%smaximumdepth{}\n", ssrf); dive->maxdepth.mm ? put_format(&buf, "\\def\\%smaximumdepth{%.1f\\%sdepthunit}\n", ssrf, get_depth_units(dive->maxdepth.mm, NULL, &unit), ssrf) : put_format(&buf, "\\def\\%smaximumdepth{}\n", ssrf);
dive->meandepth.mm ? put_format(&buf, "\\def\\%smeandepth{%.1f\\%sdepthunit}\n", ssrf, get_depth_units(dive->meandepth.mm, NULL, &unit), ssrf) : put_format(&buf, "\\def\\%smeandepth{}\n", ssrf); dive->meandepth.mm ? put_format(&buf, "\\def\\%smeandepth{%.1f\\%sdepthunit}\n", ssrf, get_depth_units(dive->meandepth.mm, NULL, &unit), ssrf) : put_format(&buf, "\\def\\%smeandepth{}\n", ssrf);
struct tag_entry *tag = dive->tag_list; std::string tags = taglist_get_tagstring(dive->tag_list);
QString tags; put_format(&buf, "\\def\\%stype{%s}\n", ssrf, tags.c_str());
if (tag) {
tags = tag->tag->name;
while ((tag = tag->next))
tags += QString(", ") + QString(tag->tag->name);
}
put_format(&buf, "\\def\\%stype{%s}\n", ssrf, qPrintable(tags));
put_format(&buf, "\\def\\%sviz{%s}\n", ssrf, qPrintable(viz)); put_format(&buf, "\\def\\%sviz{%s}\n", ssrf, qPrintable(viz));
put_format(&buf, "\\def\\%srating{%s}\n", ssrf, qPrintable(rating)); put_format(&buf, "\\def\\%srating{%s}\n", ssrf, qPrintable(rating));
put_format(&buf, "\\def\\%splot{\\includegraphics[width=9cm,height=4cm]{profile%d}}\n", ssrf, dive->number); put_format(&buf, "\\def\\%splot{\\includegraphics[width=9cm,height=4cm]{profile%d}}\n", ssrf, dive->number);

View file

@ -566,7 +566,7 @@ QStringList EditTags::data(struct dive *d) const
{ {
QStringList res; QStringList res;
for (const struct tag_entry *tag = d->tag_list; tag; tag = tag->next) for (const struct tag_entry *tag = d->tag_list; tag; tag = tag->next)
res.push_back(tag->tag->name); res.push_back(QString::fromStdString(tag->tag->name));
return res; return res;
} }
@ -1426,7 +1426,7 @@ EditDive::EditDive(dive *oldDiveIn, dive *newDiveIn, dive_site *createDs, dive_s
changedFields |= DiveField::CHILL; changedFields |= DiveField::CHILL;
if (!same_string(oldDive->suit, newDive->suit)) if (!same_string(oldDive->suit, newDive->suit))
changedFields |= DiveField::SUIT; changedFields |= DiveField::SUIT;
if (get_taglist_string(oldDive->tag_list) != get_taglist_string(newDive->tag_list)) // This is cheating. Do we have a taglist comparison function? if (taglist_get_tagstring(oldDive->tag_list) != taglist_get_tagstring(newDive->tag_list)) // This is cheating. Do we have a taglist comparison function?
changedFields |= DiveField::TAGS; changedFields |= DiveField::TAGS;
if (oldDive->dc.divemode != newDive->dc.divemode) if (oldDive->dc.divemode != newDive->dc.divemode)
changedFields |= DiveField::MODE; changedFields |= DiveField::MODE;

View file

@ -721,7 +721,6 @@ int datatrak_import(std::string &mem, std::string &wl_mem, struct divelog *log)
i++; i++;
} }
out: out:
taglist_cleanup(&g_tag_list);
sort_dive_table(log->dives); sort_dive_table(log->dives);
return rc; return rc;
bail: bail:

View file

@ -819,7 +819,7 @@ static bool has_tags(const filter_constraint &c, const struct dive *d)
{ {
QStringList dive_tags; QStringList dive_tags;
for (const tag_entry *tag = d->tag_list; tag; tag = tag->next) for (const tag_entry *tag = d->tag_list; tag; tag = tag->next)
dive_tags.push_back(QString(tag->tag->name).trimmed()); dive_tags.push_back(QString::fromStdString(tag->tag->name).trimmed());
dive_tags.append(gettextFromC::tr(divemode_text_ui[d->dc.divemode]).trimmed()); dive_tags.append(gettextFromC::tr(divemode_text_ui[d->dc.divemode]).trimmed());
return check(c, dive_tags); return check(c, dive_tags);
} }

View file

@ -128,7 +128,7 @@ static std::vector<QString> getWords(const dive *d)
tokenize(QString(d->buddy), res); tokenize(QString(d->buddy), res);
tokenize(QString(d->suit), res); tokenize(QString(d->suit), res);
for (const tag_entry *tag = d->tag_list; tag; tag = tag->next) for (const tag_entry *tag = d->tag_list; tag; tag = tag->next)
tokenize(QString(tag->tag->name), res); tokenize(QString::fromStdString(tag->tag->name), res);
for (int i = 0; i < d->cylinders.nr; ++i) { for (int i = 0; i < d->cylinders.nr; ++i) {
const cylinder_t &cyl = *get_cylinder(d, i); const cylinder_t &cyl = *get_cylinder(d, i);
tokenize(QString(cyl.type.description), res); tokenize(QString(cyl.type.description), res);

View file

@ -1229,12 +1229,6 @@ QStringList get_dive_gas_list(const struct dive *d)
return list; return list;
} }
QString get_taglist_string(struct tag_entry *tag_list)
{
std::string tags = taglist_get_tagstring(tag_list);
return QString::fromStdString(tags);
}
QStringList stringToList(const QString &s) QStringList stringToList(const QString &s)
{ {
QStringList res = s.split(",", SKIP_EMPTY); QStringList res = s.split(",", SKIP_EMPTY);

View file

@ -36,7 +36,6 @@ QString distance_string(int distanceInMeters);
bool gpsHasChanged(struct dive *dive, struct dive *master, const QString &gps_text, bool *parsed_out = 0); bool gpsHasChanged(struct dive *dive, struct dive *master, const QString &gps_text, bool *parsed_out = 0);
QString get_gas_string(struct gasmix gas); QString get_gas_string(struct gasmix gas);
QStringList get_dive_gas_list(const struct dive *d); QStringList get_dive_gas_list(const struct dive *d);
QString get_taglist_string(struct tag_entry *tag_list);
QStringList stringToList(const QString &s); QStringList stringToList(const QString &s);
void read_hashes(); void read_hashes();
void write_hashes(); void write_hashes();

View file

@ -113,7 +113,7 @@ static void save_tags(struct membuffer *b, struct tag_entry *tags)
return; return;
put_string(b, "tags"); put_string(b, "tags");
while (tags) { while (tags) {
show_utf8(b, sep, tags->tag->source ? : tags->tag->name, ""); show_utf8(b, sep, tags->tag->source.empty() ? tags->tag->name.c_str() : tags->tag->source.c_str(), "");
sep = ", "; sep = ", ";
tags = tags->next; tags = tags->next;
} }

View file

@ -339,7 +339,7 @@ static void put_HTML_tags(struct membuffer *b, struct dive *dive, const char *pr
while (tag) { while (tag) {
put_format(b, "%s\"", separator); put_format(b, "%s\"", separator);
separator = ", "; separator = ", ";
put_HTML_quoted(b, tag->tag->name); put_HTML_quoted(b, tag->tag->name.c_str());
put_string(b, "\""); put_string(b, "\"");
tag = tag->next; tag = tag->next;
} }

View file

@ -387,10 +387,10 @@ static void save_tags(struct membuffer *b, struct tag_entry *entry)
if (entry) { if (entry) {
const char *sep = " tags='"; const char *sep = " tags='";
do { do {
struct divetag *tag = entry->tag; const struct divetag *tag = entry->tag;
put_string(b, sep); put_string(b, sep);
/* If the tag has been translated, write the source to the xml file */ /* If the tag has been translated, write the source to the xml file */
quote(b, tag->source ?: tag->name, 1); quote(b, tag->source.empty() ? tag->name.c_str() : tag->source.c_str(), 1);
sep = ", "; sep = ", ";
} while ((entry = entry->next) != NULL); } while ((entry = entry->next) != NULL);
put_string(b, "'"); put_string(b, "'");

View file

@ -7,9 +7,10 @@
#include "gettext.h" #include "gettext.h"
#include <stdlib.h> #include <stdlib.h>
#include <algorithm>
#include <QtGlobal> // for QT_TRANSLATE_NOOP #include <QtGlobal> // for QT_TRANSLATE_NOOP
struct tag_entry *g_tag_list = NULL; std::vector<std::unique_ptr<divetag>> g_tag_list;
static const char *default_tags[] = { static const char *default_tags[] = {
QT_TRANSLATE_NOOP("gettextFromC", "boat"), QT_TRANSLATE_NOOP("gettextFromC", "shore"), QT_TRANSLATE_NOOP("gettextFromC", "drift"), QT_TRANSLATE_NOOP("gettextFromC", "boat"), QT_TRANSLATE_NOOP("gettextFromC", "shore"), QT_TRANSLATE_NOOP("gettextFromC", "drift"),
@ -24,15 +25,13 @@ static const char *default_tags[] = {
/* copy an element in a list of tags */ /* copy an element in a list of tags */
static void copy_tl(struct tag_entry *st, struct tag_entry *dt) static void copy_tl(struct tag_entry *st, struct tag_entry *dt)
{ {
dt->tag = (divetag *)malloc(sizeof(struct divetag)); dt->tag = st->tag;
dt->tag->name = copy_string(st->tag->name);
dt->tag->source = copy_string(st->tag->source);
} }
static bool tag_seen_before(struct tag_entry *start, struct tag_entry *before) static bool tag_seen_before(struct tag_entry *start, struct tag_entry *before)
{ {
while (start && start != before) { while (start && start != before) {
if (same_string(start->tag->name, before->tag->name)) if (start->tag->name == before->tag->name)
return true; return true;
start = start->next; start = start->next;
} }
@ -45,7 +44,7 @@ extern "C" void taglist_cleanup(struct tag_entry **tag_list)
struct tag_entry **tl = tag_list; struct tag_entry **tl = tag_list;
while (*tl) { while (*tl) {
/* skip tags that are empty or that we have seen before */ /* skip tags that are empty or that we have seen before */
if (empty_string((*tl)->tag->name) || tag_seen_before(*tag_list, *tl)) { if ((*tl)->tag->name.empty() || tag_seen_before(*tag_list, *tl)) {
*tl = (*tl)->next; *tl = (*tl)->next;
continue; continue;
} }
@ -57,39 +56,28 @@ std::string taglist_get_tagstring(struct tag_entry *tag_list)
{ {
bool first_tag = true; bool first_tag = true;
std::string res; std::string res;
struct tag_entry *tmp = tag_list; for (struct tag_entry *tmp = tag_list; tmp != NULL; tmp = tmp->next) {
while (tmp != NULL) { if (tmp->tag->name.empty())
if (!empty_string(tmp->tag->name)) { continue;
if (!first_tag) if (!first_tag)
res += ", "; res += ", ";
res += tmp->tag->name; res += tmp->tag->name;
first_tag = false; first_tag = false;
} }
tmp = tmp->next; return res;
}
return strdup(res.c_str());
}
static inline void taglist_free_divetag(struct divetag *tag)
{
if (tag->name != NULL)
free(tag->name);
if (tag->source != NULL)
free(tag->source);
free(tag);
} }
/* Add a tag to the tag_list, keep the list sorted */ /* Add a tag to the tag_list, keep the list sorted */
static struct divetag *taglist_add_divetag(struct tag_entry **tag_list, struct divetag *tag) static void taglist_add_divetag(struct tag_entry **tag_list, const struct divetag *tag)
{ {
struct tag_entry *next, *entry; struct tag_entry *next, *entry;
while ((next = *tag_list) != NULL) { while ((next = *tag_list) != NULL) {
int cmp = strcmp(next->tag->name, tag->name); int cmp = next->tag->name.compare(tag->name);
/* Already have it? */ /* Already have it? */
if (!cmp) if (!cmp)
return next->tag; return;
/* Is the entry larger? If so, insert here */ /* Is the entry larger? If so, insert here */
if (cmp > 0) if (cmp > 0)
break; break;
@ -102,48 +90,33 @@ static struct divetag *taglist_add_divetag(struct tag_entry **tag_list, struct d
entry->next = next; entry->next = next;
entry->tag = tag; entry->tag = tag;
*tag_list = entry; *tag_list = entry;
return tag;
} }
extern "C" struct divetag *taglist_add_tag(struct tag_entry **tag_list, const char *tag) static const divetag *register_tag(const char *s, const char *source)
{ {
size_t i = 0; // binary search
int is_default_tag = 0; auto it = std::lower_bound(g_tag_list.begin(), g_tag_list.end(), s,
struct divetag *ret_tag, *new_tag; [](const std::unique_ptr<divetag> &tag, const char *s)
const char *translation; { return tag->name < s; });
new_tag = (divetag *)malloc(sizeof(struct divetag)); if (it == g_tag_list.end() || (*it)->name != s) {
std::string source_s = empty_string(source) ? std::string() : std::string(source);
it = g_tag_list.insert(it, std::make_unique<divetag>(s, source));
}
return it->get();
}
extern "C" void taglist_add_tag(struct tag_entry **tag_list, const char *tag)
{
bool is_default_tag = std::find_if(std::begin(default_tags), std::end(default_tags),
[&tag] (const char *default_tag) { return tag == default_tag; });
for (i = 0; i < std::size(default_tags); i++) {
if (strcmp(default_tags[i], tag) == 0) {
is_default_tag = 1;
break;
}
}
/* Only translate default tags */ /* Only translate default tags */
if (is_default_tag) { /* TODO: Do we really want to translate user-supplied tags if they happen to be known!? */
translation = translate("gettextFromC", tag); const char *translation = is_default_tag ? translate("gettextFromC", tag) : tag;
new_tag->name = (char *)malloc(strlen(translation) + 1); const char *source = is_default_tag ? tag : nullptr;
memcpy(new_tag->name, translation, strlen(translation) + 1); const struct divetag *d_tag = register_tag(translation, source);
new_tag->source = (char *)malloc(strlen(tag) + 1);
memcpy(new_tag->source, tag, strlen(tag) + 1); taglist_add_divetag(tag_list, d_tag);
} else {
new_tag->source = NULL;
new_tag->name = (char *)malloc(strlen(tag) + 1);
memcpy(new_tag->name, tag, strlen(tag) + 1);
}
/* Try to insert new_tag into g_tag_list if we are not operating on it */
if (tag_list != &g_tag_list) {
ret_tag = taglist_add_divetag(&g_tag_list, new_tag);
/* g_tag_list already contains new_tag, free the duplicate */
if (ret_tag != new_tag)
taglist_free_divetag(new_tag);
ret_tag = taglist_add_divetag(tag_list, ret_tag);
} else {
ret_tag = taglist_add_divetag(tag_list, new_tag);
if (ret_tag != new_tag)
taglist_free_divetag(new_tag);
}
return ret_tag;
} }
extern "C" void taglist_free(struct tag_entry *entry) extern "C" void taglist_free(struct tag_entry *entry)
@ -171,8 +144,6 @@ extern "C" void taglist_merge(struct tag_entry **dst, struct tag_entry *src1, st
extern "C" void taglist_init_global() extern "C" void taglist_init_global()
{ {
size_t i; for (const char *s: default_tags)
register_tag(translate("gettextFromC", s), s);
for (i = 0; i < std::size(default_tags); i++)
taglist_add_tag(&g_tag_list, default_tags[i]);
} }

View file

@ -6,35 +6,37 @@
#include <stdbool.h> #include <stdbool.h>
#ifdef __cplusplus #ifdef __cplusplus
#include <memory>
#include <string>
#include <vector>
extern "C" { extern "C" {
#endif #endif
struct divetag { struct divetag {
#ifdef __cplusplus
/* /*
* The name of the divetag. If a translation is available, name contains * The name of the divetag. If a translation is available, name contains
* the translated tag * the translated tag
*/ */
char *name; std::string name;
/* /*
* If a translation is available, we write the original tag to source. * If a translation is available, we write the original tag to source.
* This enables us to write a non-localized tag to the xml file. * This enables us to write a non-localized tag to the xml file.
*/ */
char *source; std::string source;
divetag(const char *n, const char *s) : name(n), source(s)
{
}
#endif
}; };
struct tag_entry { struct tag_entry {
struct divetag *tag; const struct divetag *tag;
struct tag_entry *next; struct tag_entry *next;
}; };
/* void taglist_add_tag(struct tag_entry **tag_list, const char *tag);
* divetags are only stored once, each dive only contains
* a list of tag_entries which then point to the divetags
* in the global g_tag_list
*/
extern struct tag_entry *g_tag_list;
struct divetag *taglist_add_tag(struct tag_entry **tag_list, const char *tag);
/* cleans up a list: removes empty tags and duplicates */ /* cleans up a list: removes empty tags and duplicates */
void taglist_cleanup(struct tag_entry **tag_list); void taglist_cleanup(struct tag_entry **tag_list);
@ -45,6 +47,21 @@ struct tag_entry *taglist_copy(struct tag_entry *s);
void taglist_merge(struct tag_entry **dst, struct tag_entry *src1, struct tag_entry *src2); void taglist_merge(struct tag_entry **dst, struct tag_entry *src1, struct tag_entry *src2);
#ifdef __cplusplus #ifdef __cplusplus
/*
* divetags are only stored once, each dive only contains
* a list of tag_entries which then point to the divetags
* in the global g_tag_list
*/
extern std::vector<std::unique_ptr<divetag>> g_tag_list;
/*
* Writes all divetags form tag_list into internally allocated buffer
* Function returns pointer to allocated buffer
* Buffer contains comma separated list of tags names or null terminated string
*/
extern std::string taglist_get_tagstring(struct tag_entry *tag_list);
} }
// C++ only functions // C++ only functions

View file

@ -342,7 +342,7 @@ void DiveComponentSelection::buttonClicked(QAbstractButton *button)
text << tr("Tags: "); text << tr("Tags: ");
tag_entry *entry = current_dive->tag_list; tag_entry *entry = current_dive->tag_list;
while (entry) { while (entry) {
text << entry->tag->name << " "; text << entry->tag->name.c_str() << " ";
entry = entry->next; entry = entry->next;
} }
text << "\n"; text << "\n";

View file

@ -5,6 +5,7 @@
#include "core/qthelper.h" #include "core/qthelper.h"
#include "core/selection.h" #include "core/selection.h"
#include "core/subsurface-string.h" #include "core/subsurface-string.h"
#include "core/tag.h"
#include "core/trip.h" #include "core/trip.h"
#include "desktop-widgets/mainwindow.h" #include "desktop-widgets/mainwindow.h"
#include "desktop-widgets/mapwidget.h" #include "desktop-widgets/mapwidget.h"
@ -117,7 +118,7 @@ void TabDiveNotes::divesChanged(const QVector<dive *> &dives, DiveField field)
if (field.divesite) if (field.divesite)
updateDiveSite(currentDive); updateDiveSite(currentDive);
if (field.tags) if (field.tags)
ui.tagWidget->setText(get_taglist_string(currentDive->tag_list)); ui.tagWidget->setText(QString::fromStdString(taglist_get_tagstring(currentDive->tag_list)));
if (field.buddy) if (field.buddy)
ui.buddy->setText(currentDive->buddy); ui.buddy->setText(currentDive->buddy);
if (field.diveguide) if (field.diveguide)
@ -252,7 +253,7 @@ void TabDiveNotes::updateData(const std::vector<dive *> &, dive *currentDive, in
// reset labels in case we last displayed trip notes // reset labels in case we last displayed trip notes
ui.LocationLabel->setText(tr("Location")); ui.LocationLabel->setText(tr("Location"));
ui.NotesLabel->setText(tr("Notes")); ui.NotesLabel->setText(tr("Notes"));
ui.tagWidget->setText(get_taglist_string(currentDive->tag_list)); ui.tagWidget->setText(QString::fromStdString(taglist_get_tagstring(currentDive->tag_list)));
bool isManual = is_manually_added_dc(&currentDive->dc); bool isManual = is_manually_added_dc(&currentDive->dc);
ui.depth->setVisible(isManual); ui.depth->setVisible(isManual);
ui.depthLabel->setVisible(isManual); ui.depthLabel->setVisible(isManual);

View file

@ -10,6 +10,7 @@
#include "printoptions.h" #include "printoptions.h"
#include "core/divelist.h" #include "core/divelist.h"
#include "core/selection.h" #include "core/selection.h"
#include "core/tag.h"
#include "core/qthelper.h" #include "core/qthelper.h"
#include "core/string-format.h" #include "core/string-format.h"
@ -552,7 +553,7 @@ QVariant TemplateLayout::getValue(QString list, QString property, const State &s
} else if (property == "notes") { } else if (property == "notes") {
return formatNotes(d); return formatNotes(d);
} else if (property == "tags") { } else if (property == "tags") {
return get_taglist_string(d->tag_list); return QString::fromStdString(taglist_get_tagstring(d->tag_list));
} else if (property == "gas") { } else if (property == "gas") {
return formatGas(d); return formatGas(d);
} else if (property == "sac") { } else if (property == "sac") {

View file

@ -1325,7 +1325,7 @@ void QMLManager::commitChanges(QString diveId, QString number, QString date, QSt
} }
// normalize the tag list we have and the one we get from the UI // normalize the tag list we have and the one we get from the UI
// try hard to deal with accidental white space issues // try hard to deal with accidental white space issues
QStringList existingTagList = get_taglist_string(d->tag_list).split(",", SKIP_EMPTY); QStringList existingTagList = QString::fromStdString(taglist_get_tagstring(d->tag_list)).split(",", SKIP_EMPTY);
QStringList newTagList = tags.split(",", SKIP_EMPTY); QStringList newTagList = tags.split(",", SKIP_EMPTY);
QStringList newCleanTagList; QStringList newCleanTagList;
for (QString s: newTagList) { for (QString s: newTagList) {

View file

@ -84,14 +84,9 @@ bool SuitCompletionModel::relevantDiveField(const DiveField &f)
QStringList TagCompletionModel::getStrings() QStringList TagCompletionModel::getStrings()
{ {
if (g_tag_list == NULL)
return {};
QStringList list; QStringList list;
struct tag_entry *current_tag_entry = g_tag_list; for (const std::unique_ptr<divetag> &tag: g_tag_list)
while (current_tag_entry != NULL) { list.append(QString::fromStdString(tag->name));
list.append(QString(current_tag_entry->tag->name));
current_tag_entry = current_tag_entry->next;
}
std::sort(list.begin(), list.end()); std::sort(list.begin(), list.end());
return list; return list;
} }

View file

@ -294,7 +294,7 @@ QVariant DiveTripModelBase::diveData(const struct dive *d, int column, int role)
case MobileListModel::SumWeightRole: return formatSumWeight(d); case MobileListModel::SumWeightRole: return formatSumWeight(d);
case MobileListModel::DiveGuideRole: return QString(d->diveguide); case MobileListModel::DiveGuideRole: return QString(d->diveguide);
case MobileListModel::BuddyRole: return QString(d->buddy); case MobileListModel::BuddyRole: return QString(d->buddy);
case MobileListModel::TagsRole: return get_taglist_string(d->tag_list); case MobileListModel::TagsRole: return QString::fromStdString(taglist_get_tagstring(d->tag_list));
case MobileListModel::NotesRole: return formatNotes(d); case MobileListModel::NotesRole: return formatNotes(d);
case MobileListModel::GpsRole: return formatDiveGPS(d); case MobileListModel::GpsRole: return formatDiveGPS(d);
case MobileListModel::GpsDecimalRole: return format_gps_decimal(d); case MobileListModel::GpsDecimalRole: return format_gps_decimal(d);
@ -347,7 +347,7 @@ QVariant DiveTripModelBase::diveData(const struct dive *d, int column, int role)
else else
return d->maxcns; return d->maxcns;
case TAGS: case TAGS:
return get_taglist_string(d->tag_list); return QString::fromStdString(taglist_get_tagstring(d->tag_list));
case PHOTOS: case PHOTOS:
break; break;
case COUNTRY: case COUNTRY:

View file

@ -1502,7 +1502,7 @@ struct TagBinner : public StringBinner<TagBinner, StringBin> {
std::vector<QString> to_bin_values(const dive *d) const { std::vector<QString> to_bin_values(const dive *d) const {
std::vector<QString> tags; std::vector<QString> tags;
for (const tag_entry *tag = d->tag_list; tag; tag = tag->next) for (const tag_entry *tag = d->tag_list; tag; tag = tag->next)
tags.push_back(QString(tag->tag->name).trimmed()); tags.push_back(QString::fromStdString(tag->tag->name).trimmed());
return tags; return tags;
} }
}; };
@ -1513,7 +1513,7 @@ struct TagVariable : public StatsVariableTemplate<StatsVariable::Type::Discrete>
return StatsTranslations::tr("Tags"); return StatsTranslations::tr("Tags");
} }
QString diveCategories(const dive *d) const override { QString diveCategories(const dive *d) const override {
return get_taglist_string(d->tag_list); return QString::fromStdString(taglist_get_tagstring(d->tag_list));
} }
std::vector<const StatsBinner *> binners() const override { std::vector<const StatsBinner *> binners() const override {
return { &tag_binner }; return { &tag_binner };

View file

@ -107,7 +107,6 @@ int main(int argc, char **argv)
run_ui(); run_ui();
exit_ui(); exit_ui();
clear_divelog(&divelog); clear_divelog(&divelog);
taglist_free(g_tag_list);
parse_xml_exit(); parse_xml_exit();
subsurface_console_exit(); subsurface_console_exit();

View file

@ -110,7 +110,6 @@ int main(int argc, char **argv)
printf("Give a log file name as argument, or configure a cloud URL.\n"); printf("Give a log file name as argument, or configure a cloud URL.\n");
} }
clear_divelog(&divelog); clear_divelog(&divelog);
taglist_free(g_tag_list);
parse_xml_exit(); parse_xml_exit();
// Sync struct preferences to disk // Sync struct preferences to disk

View file

@ -94,7 +94,6 @@ int main(int argc, char **argv)
run_mobile_ui(initial_font_size); run_mobile_ui(initial_font_size);
exit_ui(); exit_ui();
clear_divelog(&divelog); clear_divelog(&divelog);
taglist_free(g_tag_list);
parse_xml_exit(); parse_xml_exit();
subsurface_console_exit(); subsurface_console_exit();

View file

@ -10,8 +10,7 @@ void TestTagList::initTestCase()
void TestTagList::cleanupTestCase() void TestTagList::cleanupTestCase()
{ {
taglist_free(g_tag_list); g_tag_list.clear();
g_tag_list = NULL;
} }
void TestTagList::testGetTagstringNoTags() void TestTagList::testGetTagstringNoTags()