core: allow separators ,; after degree-style coord

Tweak the Lat/Long coordinate parser to allow coordinates of the form:

12.1049° N, 68.2296° W

The coordinate parser works by tokenizing coordinates one at a time.
Consequently it is invoked twice on user input to get latitude and then
longitude. Normally, after parsing the first coordinate, intervening
characters such as , or ; and any whitespace would be discarded from the
input before parsing the second coordinate. Prior to this patch, if the
coordinate format was in degrees followed by a sign (N is a sign in this
example), the parser would skip the bit of code that fast forwards past
any intervening separators and whitespace (, in this example). This
resulted in coordinates of this form not being accepted, because the
second parse would start with , 68.2296° W and reject this as an invalid
coordinate.

To rectify this, the bit of code that fast forwards past separators and
whitespace has been broken out from the tokenization loop and performed
as a final step after a single coordinate has been completely parsed and
validated. Doing it this way makes it independent of the state of the
tokenizer, so that the fast-forward code will always execute once a
coordinate has been successfully parsed.

I've also centralized the list of allowed separators into its own static
string; this is necessary as part of the patch but should also make
allowing additional separator characters between coordinates trivial in
the future, if needed.

Signed-off-by: Quentin Young <qlyoung@qlyoung.net>
This commit is contained in:
Quentin Young 2022-03-26 22:58:08 -04:00 committed by Dirk Hohndel
parent dbbb39e0f7
commit 7136ee463c
2 changed files with 10 additions and 5 deletions

View file

@ -1,3 +1,4 @@
- core: add support for separator characters when using degree-style coordinates
- profile: include profile editing in undo system
- mobile: Add a dark theme for statistics
- core: avoid crash with corrupted cloud storage

View file

@ -129,6 +129,7 @@ static bool parseCoord(const QString &txt, int &pos, const QString &positives,
const QString &negatives, const QString &others,
double &value)
{
static const QString separators = QString(",;");
bool numberDefined = false, degreesDefined = false,
minutesDefined = false, secondsDefined = false;
double number = 0.0;
@ -200,11 +201,8 @@ static bool parseCoord(const QString &txt, int &pos, const QString &positives,
numberDefined = false;
secondsDefined = true;
} else if ((numberDefined || minutesDefined || secondsDefined) &&
(txt[pos] == ',' || txt[pos] == ';')) {
// next coordinate coming up
// eat the ',' and any subsequent white space
while (++pos < txt.size() && txt[pos].isSpace())
/* nothing */ ;
separators.indexOf(txt[pos]) >= 0) {
// separator; this coordinate is finished
break;
} else {
return false;
@ -219,6 +217,12 @@ static bool parseCoord(const QString &txt, int &pos, const QString &positives,
value += number / 3600.0;
else if (numberDefined)
return false;
// We parsed a valid coordinate; eat any subsequent separators and/or
// whitespace
while (pos < txt.size() && (txt[pos].isSpace() || separators.indexOf(txt[pos]) >= 0))
pos++;
if (sign == -1) value *= -1.0;
return true;
}