Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix mkshort unique #1168

Merged
merged 5 commits into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ using ff_readposn = Waypoint* (*)(posn_status*);
struct mkshort_handle_imp; // forward declare, definition in mkshort.cc
using short_handle = mkshort_handle_imp*;

QByteArray mkshort(short_handle, const char*, bool);
QByteArray mkshort(short_handle, const QByteArray&, bool);
QString mkshort(short_handle, const QString&);
short_handle mkshort_new_handle();
QString mkshort_from_wpt(short_handle h, const Waypoint* wpt);
Expand Down
4 changes: 2 additions & 2 deletions garmin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -890,8 +890,8 @@ waypoint_prepare()
*/
QByteArray ident = mkshort(mkshort_handle,
global_opts.synthesize_shortnames ?
str_from_unicode(src).constData() :
str_from_unicode(wpt->shortname).constData(),
str_from_unicode(src) :
str_from_unicode(wpt->shortname),
false);
/* Should not be a strcpy as 'ident' isn't really a C string,
* but rather a garmin "fixed length" buffer that's padded
Expand Down
55 changes: 31 additions & 24 deletions mkshort.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@

*/

#include <cassert> // for assert
#include <cctype> // for isspace, toupper, isdigit
#include <cstdio> // for snprintf, size_t
#include <climits> // for INT_MAX
#include <cstring> // for strlen, memmove, strchr, strcpy, strncmp, strcat, strncpy

#include <QByteArray> // for QByteArray
Expand Down Expand Up @@ -49,7 +50,7 @@ class ShortNameKey;
using ShortNameHash = QHash<ShortNameKey, uniq_shortname*>;
class ShortNameKey {
public:
ShortNameKey(char* name) : shortname(name) {} /* converting constructor */
ShortNameKey(const QByteArray& name) : shortname(name) {} /* converting constructor */

friend qhash_result_t qHash(const ShortNameKey &key, qhash_result_t seed = 0) noexcept
{
Expand Down Expand Up @@ -109,7 +110,7 @@ mkshort_new_handle()

static
uniq_shortname*
is_unique(mkshort_handle_imp* h, char* name)
is_unique(mkshort_handle_imp* h, const QByteArray& name)
{
if (h->namelist.contains(name)) {
return h->namelist.value(name);
Expand All @@ -119,34 +120,38 @@ is_unique(mkshort_handle_imp* h, char* name)

static
void
add_to_hashlist(mkshort_handle_imp* h, char* name)
add_to_hashlist(mkshort_handle_imp* h, const QByteArray& name)
{
h->namelist.insert(name, new uniq_shortname);
}

char*
mkshort_add_to_list(mkshort_handle_imp* h, char* name)
static
void
mkshort_add_to_list(mkshort_handle_imp* h, QByteArray& name)
{
uniq_shortname* s;
static_assert(!std::is_signed<decltype(h->target_len)>::value,
"simplify the following logic if target length is signed.");
assert(h->target_len <= INT_MAX);
int target_len = h->target_len;

uniq_shortname* s;
while ((s = is_unique(h, name))) {
char tbuf[13];
size_t l = strlen(name);

s->conflictctr++;
QByteArray suffix(".");
suffix.append(QByteArray::number(++s->conflictctr));

int dl = snprintf(tbuf, sizeof(tbuf), ".%d", s->conflictctr);

if (l + dl < h->target_len) {
name = (char*) xrealloc(name, l + dl + 1);
strcat(name, tbuf);
if (name.size() + suffix.size() <= target_len) {
name.append(suffix);
} else if (suffix.size() <= target_len) {
// FIXME: utf8 => grapheme truncate
name.truncate(target_len - suffix.size());
name.append(suffix);
} else {
strcpy(&name[l-dl], tbuf);
fatal("mkshort failure, the specified short length is insufficient.\n");
}
}

add_to_hashlist(h, name);
return name;
}

void
Expand Down Expand Up @@ -249,7 +254,9 @@ void
setshort_length(short_handle h, int l)
{
auto* hdl = (mkshort_handle_imp*) h;
if (l == 0) {
if (l < 0) {
fatal("mkshort: short length must be non-negative.\n");
} else if (l == 0) {
hdl->target_len = default_target_len;
} else {
hdl->target_len = l;
Expand Down Expand Up @@ -354,7 +361,7 @@ setshort_mustuniq(short_handle h, int i)
}

QByteArray
mkshort(short_handle h, const char* istring, bool is_utf8)
mkshort(short_handle h, const QByteArray& istring, bool is_utf8)
{
char* ostring;
char* tstring;
Expand All @@ -370,7 +377,7 @@ mkshort(short_handle h, const char* istring, bool is_utf8)
result.remove(QChar::ReplacementCharacter);
ostring = xstrdup(result.toUtf8().constData());
} else {
ostring = xstrdup(istring);
ostring = xstrdup(istring.constData());
}

/*
Expand Down Expand Up @@ -555,18 +562,18 @@ mkshort(short_handle h, const char* istring, bool is_utf8)
ostring = xstrdup(hdl->defname);
}

if (hdl->must_uniq) {
ostring = mkshort_add_to_list(hdl, ostring);
}
QByteArray rval(ostring);
xfree(ostring);
if (hdl->must_uniq) {
mkshort_add_to_list(hdl, rval);
}
return rval;
}

QString
mkshort(short_handle h, const QString& istring)
{
return mkshort(h, CSTR(istring), true);
return mkshort(h, istring.toUtf8(), true);
}

/*
Expand Down
151 changes: 151 additions & 0 deletions reference/mkshort.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
lat,lon,name
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
0,0,wp
17 changes: 17 additions & 0 deletions reference/mkshort.style
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# gpsbabel XCSV style file
#
DESCRIPTION Comma separated values
SHORTLEN 4
#
# FILE LAYOUT DEFINITIIONS:
#
FIELD_ENCLOSER DOUBLEQUOTE
FIELD_DELIMITER COMMASPACE
RECORD_DELIMITER NEWLINE
BADCHARS COMMA
#
# INDIVIDUAL DATA FIELDS, IN ORDER OF APPEARANCE:
#
IFIELD LAT_DECIMAL, "", "%8.5f"
IFIELD LON_DECIMAL, "", "%8.5f"
IFIELD SHORTNAME, "", "%s"
1 change: 1 addition & 0 deletions reference/mkshort3.log
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mkshort failure, the specified short length is insufficient.
Loading