2017-02-19 22:59:39 +00:00
|
|
|
#include "LauncherArgumentTokenizer.hxx"
|
|
|
|
|
2018-06-03 08:07:21 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <set>
|
|
|
|
|
2017-12-15 15:42:36 +00:00
|
|
|
#include <QVariantMap>
|
|
|
|
#include <QJSEngine>
|
|
|
|
|
2017-02-19 22:59:39 +00:00
|
|
|
LauncherArgumentTokenizer::LauncherArgumentTokenizer()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-06-03 08:07:21 +00:00
|
|
|
void LauncherArgumentTokenizer::tokenize(QString in)
|
2017-02-19 22:59:39 +00:00
|
|
|
{
|
2018-06-03 08:07:21 +00:00
|
|
|
m_tokens.clear();
|
|
|
|
m_valid = false;
|
|
|
|
|
2017-02-19 22:59:39 +00:00
|
|
|
int index = 0;
|
|
|
|
const int len = in.count();
|
|
|
|
QChar c, nc;
|
|
|
|
State state = Start;
|
|
|
|
QString key, value;
|
2018-06-03 08:07:21 +00:00
|
|
|
std::vector<ArgumentToken> result;
|
2017-02-19 22:59:39 +00:00
|
|
|
|
|
|
|
for (; index < len; ++index) {
|
|
|
|
c = in.at(index);
|
|
|
|
nc = index < (len - 1) ? in.at(index + 1) : QChar();
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
case Start:
|
|
|
|
if (c == QChar('-')) {
|
|
|
|
if (nc == QChar('-')) {
|
|
|
|
state = Key;
|
|
|
|
key.clear();
|
|
|
|
++index;
|
|
|
|
} else {
|
|
|
|
// should we pemit single hyphen arguments?
|
|
|
|
// choosing to fail for now
|
2018-06-03 08:07:21 +00:00
|
|
|
return;
|
2017-02-19 22:59:39 +00:00
|
|
|
}
|
|
|
|
} else if (c == QChar('#')) {
|
|
|
|
state = Comment;
|
|
|
|
break;
|
|
|
|
} else if (c.isSpace()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Key:
|
|
|
|
if (c == QChar('=')) {
|
|
|
|
state = Value;
|
|
|
|
value.clear();
|
|
|
|
} else if (c.isSpace()) {
|
|
|
|
state = Start;
|
2018-06-03 08:07:21 +00:00
|
|
|
result.emplace_back(key);
|
2017-02-19 22:59:39 +00:00
|
|
|
} else {
|
|
|
|
// could check for illegal charatcers here
|
|
|
|
key.append(c);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Value:
|
|
|
|
if (c == QChar('"')) {
|
|
|
|
state = Quoted;
|
|
|
|
} else if (c.isSpace()) {
|
|
|
|
state = Start;
|
2018-06-03 08:07:21 +00:00
|
|
|
result.emplace_back(key, value);
|
2017-02-19 22:59:39 +00:00
|
|
|
} else {
|
|
|
|
value.append(c);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Quoted:
|
|
|
|
if (c == QChar('\\')) {
|
|
|
|
// check for escaped double-quote inside quoted value
|
|
|
|
if (nc == QChar('"')) {
|
|
|
|
++index;
|
2017-07-25 09:00:19 +00:00
|
|
|
} else {
|
|
|
|
value.append(c); // normal '\' inside quoted
|
2017-02-19 22:59:39 +00:00
|
|
|
}
|
|
|
|
} else if (c == QChar('"')) {
|
|
|
|
state = Value;
|
|
|
|
} else {
|
|
|
|
value.append(c);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Comment:
|
|
|
|
if ((c == QChar('\n')) || (c == QChar('\r'))) {
|
|
|
|
state = Start;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
// nothing to do, eat comment chars
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
} // of state switch
|
|
|
|
} // of character loop
|
|
|
|
|
|
|
|
// ensure last argument isn't lost
|
|
|
|
if (state == Key) {
|
2018-06-03 08:07:21 +00:00
|
|
|
result.emplace_back(key);
|
2017-02-19 22:59:39 +00:00
|
|
|
} else if (state == Value) {
|
2018-06-03 08:07:21 +00:00
|
|
|
result.emplace_back(key, value);
|
2017-02-19 22:59:39 +00:00
|
|
|
}
|
|
|
|
|
2018-06-03 08:07:21 +00:00
|
|
|
m_valid = true;
|
|
|
|
m_tokens = result;
|
2017-02-19 22:59:39 +00:00
|
|
|
}
|
2017-12-15 15:42:36 +00:00
|
|
|
|
|
|
|
QVariantList LauncherArgumentTokenizer::tokens() const
|
|
|
|
{
|
2018-06-03 08:07:21 +00:00
|
|
|
if (!m_valid)
|
|
|
|
return {};
|
|
|
|
|
2017-12-15 15:42:36 +00:00
|
|
|
QVariantList result;
|
2018-06-03 08:07:21 +00:00
|
|
|
for (auto tk : m_tokens) {
|
2017-12-15 15:42:36 +00:00
|
|
|
QVariantMap m;
|
|
|
|
m["arg"] = tk.arg;
|
|
|
|
m["value"] = tk.value;
|
|
|
|
result.append(m);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-06-03 08:07:21 +00:00
|
|
|
bool LauncherArgumentTokenizer::isValid() const
|
|
|
|
{
|
|
|
|
return m_valid;
|
|
|
|
}
|
|
|
|
|
2018-06-25 22:06:20 +00:00
|
|
|
const std::set<std::string> unsupportedArgs({
|
2018-06-29 13:56:05 +00:00
|
|
|
"fg-aircraft", "fg-root", "fg-home", "aircraft-dir"});
|
2018-06-25 22:06:20 +00:00
|
|
|
|
|
|
|
bool LauncherArgumentTokenizer::haveUnsupportedArgs() const
|
|
|
|
{
|
|
|
|
return haveArgsIn(unsupportedArgs);
|
|
|
|
}
|
|
|
|
|
2017-12-15 15:42:36 +00:00
|
|
|
void LauncherArgumentTokenizer::setArgString(QString argString)
|
|
|
|
{
|
|
|
|
if (m_argString == argString)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_argString = argString;
|
2018-06-03 08:07:21 +00:00
|
|
|
tokenize(m_argString);
|
2017-12-15 15:42:36 +00:00
|
|
|
emit argStringChanged(m_argString);
|
|
|
|
}
|
2018-06-03 08:07:21 +00:00
|
|
|
|
2018-06-25 22:06:20 +00:00
|
|
|
const std::set<std::string> positionalArgs({
|
2018-06-29 13:56:05 +00:00
|
|
|
"lat", "lon", "vor", "ndb", "fix"
|
2020-04-17 19:25:18 +00:00
|
|
|
"airport", "parking-id", "runway", "carrier", "carrier-position"
|
2018-06-29 13:56:05 +00:00
|
|
|
});
|
2018-06-03 08:07:21 +00:00
|
|
|
|
2018-06-25 22:06:20 +00:00
|
|
|
bool LauncherArgumentTokenizer::haveArgsIn(const std::set<std::string>& args) const
|
2018-06-03 08:07:21 +00:00
|
|
|
{
|
|
|
|
if (!m_valid)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
auto n = std::count_if(m_tokens.begin(), m_tokens.end(),
|
2018-06-25 22:06:20 +00:00
|
|
|
[&args](const ArgumentToken& tk)
|
2018-06-03 08:07:21 +00:00
|
|
|
{
|
2018-06-25 22:06:20 +00:00
|
|
|
return (args.find(tk.arg.toStdString()) != args.end());
|
2018-06-03 08:07:21 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
return (n > 0);
|
|
|
|
}
|
2018-06-25 22:06:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
bool LauncherArgumentTokenizer::havePositionalArgs() const
|
|
|
|
{
|
|
|
|
return haveArgsIn(positionalArgs);
|
|
|
|
}
|