FlightGear next
LauncherArgumentTokenizer.cxx
Go to the documentation of this file.
2
3#include <algorithm>
4#include <set>
5
6#include <QVariantMap>
7#include <QJSEngine>
8
13
14void LauncherArgumentTokenizer::tokenize(QString in)
15{
16 m_tokens.clear();
17 m_valid = false;
18
19 int index = 0;
20 const int len = in.count();
21 QChar c, nc;
22 State state = Start;
23 QString key, value;
24 std::vector<ArgumentToken> result;
25
26 for (; index < len; ++index) {
27 c = in.at(index);
28 nc = index < (len - 1) ? in.at(index + 1) : QChar();
29
30 switch (state) {
31 case Start:
32 if (c == QChar('-')) {
33 if (nc == QChar('-')) {
34 state = Key;
35 key.clear();
36 ++index;
37 } else {
38 // should we pemit single hyphen arguments?
39 // choosing to fail for now
40 return;
41 }
42 } else if (c == QChar('#')) {
43 state = Comment;
44 break;
45 } else if (c.isSpace()) {
46 break;
47 }
48 break;
49
50 case Key:
51 if (c == QChar('=') || (c.isSpace() && nc != QChar('-'))) {
52 state = Value;
53 value.clear();
54 } else if (c.isSpace() && nc == QChar('-')) {
55 state = Start;
56 result.emplace_back(key);
57 } else {
58 // could check for illegal charatcers here
59 key.append(c);
60 }
61 break;
62
63 case Value:
64 if (c == QChar('"')) {
65 state = Quoted;
66 } else if (c.isSpace()) {
67 state = Start;
68 result.emplace_back(key, value);
69 } else {
70 value.append(c);
71 }
72 break;
73
74 case Quoted:
75 if (c == QChar('\\')) {
76 // check for escaped double-quote inside quoted value
77 if (nc == QChar('"')) {
78 ++index;
79 } else {
80 value.append(c); // normal '\' inside quoted
81 }
82 } else if (c == QChar('"')) {
83 state = Value;
84 } else {
85 value.append(c);
86 }
87 break;
88
89 case Comment:
90 if ((c == QChar('\n')) || (c == QChar('\r'))) {
91 state = Start;
92 break;
93 } else {
94 // nothing to do, eat comment chars
95 }
96 break;
97 } // of state switch
98 } // of character loop
99
100 // ensure last argument isn't lost
101 if (state == Key) {
102 result.emplace_back(key);
103 } else if (state == Value) {
104 result.emplace_back(key, value);
105 }
106
107 m_valid = true;
108 m_tokens = result;
109}
110
112{
113 if (!m_valid)
114 return {};
115
116 QVariantList result;
117 for (auto tk : m_tokens) {
118 QVariantMap m;
119 m["arg"] = tk.arg;
120 m["value"] = tk.value;
121 result.append(m);
122 }
123 return result;
124}
125
127{
128 return m_valid;
129}
130
131const std::set<std::string> unsupportedArgs({
132 "fg-aircraft", "fg-root", "fg-home", "aircraft-dir"});
133
135{
136 return haveArgsIn(unsupportedArgs);
137}
138
140{
141 if (m_argString == argString)
142 return;
143
144 m_argString = argString;
145 tokenize(m_argString);
146 emit argStringChanged(m_argString);
147}
148
149const std::set<std::string> positionalArgs({
150 "lat", "lon", "vor", "ndb", "fix", "parkpos",
151 "airport", "parking-id", "runway", "carrier", "carrier-position"
152});
153
154bool LauncherArgumentTokenizer::haveArgsIn(const std::set<std::string>& args) const
155{
156 if (!m_valid)
157 return false;
158
159 auto n = std::count_if(m_tokens.begin(), m_tokens.end(),
160 [&args](const ArgumentToken& tk)
161 {
162 return (args.find(tk.arg.toStdString()) != args.end());
163 });
164
165 return (n > 0);
166}
167
168
170{
171 return haveArgsIn(positionalArgs);
172}
173
174const std::set<std::string> aircraftArgs({"state", "aircraft", "aircraft-dir", "vehicle"});
175
177{
178 return haveArgsIn(aircraftArgs);
179}
const std::set< std::string > unsupportedArgs({ "fg-aircraft", "fg-root", "fg-home", "aircraft-dir"})
const std::set< std::string > positionalArgs({ "lat", "lon", "vor", "ndb", "fix", "parkpos", "airport", "parking-id", "runway", "carrier", "carrier-position" })
const std::set< std::string > aircraftArgs({"state", "aircraft", "aircraft-dir", "vehicle"})
void argStringChanged(QString argString)