openMSX
AdhocCliCommParser.cc
Go to the documentation of this file.
2#include "utf8_unchecked.hh"
3#include "xrange.hh"
4
5
6AdhocCliCommParser::AdhocCliCommParser(std::function<void(const std::string&)> callback_)
7 : callback(std::move(callback_))
8{
9}
10
11void AdhocCliCommParser::parse(std::span<const char> buf)
12{
13 for (auto c : buf) {
14 parse(c);
15 }
16}
17
19{
20 // Whenever there is a parse error we return to the initial state
21 switch (state) {
22 case O0: // looking for opening tag
23 state = (c == '<') ? O1 : O0; break;
24 case O1: // matched <
25 state = (c == 'c') ? O2 : O0; break;
26 case O2: // matched <c
27 state = (c == 'o') ? O3 : O0; break;
28 case O3: // matched <co
29 state = (c == 'm') ? O4 : O0; break;
30 case O4: // matched <com
31 state = (c == 'm') ? O5 : O0; break;
32 case O5: // matched <comm
33 state = (c == 'a') ? O6 : O0; break;
34 case O6: // matched <comma
35 state = (c == 'n') ? O7 : O0; break;
36 case O7: // matched <comman
37 state = (c == 'd') ? O8 : O0; break;
38 case O8: // matched <command
39 if (c == '>') {
40 state = C0;
41 command.clear();
42 } else {
43 state = O0;
44 }
45 break;
46 case C0: // matched <command>, now parsing xml entities and </command>
47 if (c == '<') state = C1;
48 else if (c == '&') state = A1;
49 else command += c;
50 break;
51 case C1: // matched <
52 state = (c == '/') ? C2 : O0; break;
53 case C2: // matched </
54 state = (c == 'c') ? C3 : O0; break;
55 case C3: // matched </c
56 state = (c == 'o') ? C4 : O0; break;
57 case C4: // matched </co
58 state = (c == 'm') ? C5 : O0; break;
59 case C5: // matched </com
60 state = (c == 'm') ? C6 : O0; break;
61 case C6: // matched </comm
62 state = (c == 'a') ? C7 : O0; break;
63 case C7: // matched </comma
64 state = (c == 'n') ? C8 : O0; break;
65 case C8: // matched </comman
66 state = (c == 'd') ? C9 : O0; break;
67 case C9: // matched </command
68 if (c == '>') callback(command);
69 state = O0;
70 break;
71 case A1: // matched &
72 if (c == 'l') state = L2;
73 else if (c == 'a') state = A2;
74 else if (c == 'g') state = G2;
75 else if (c == 'q') state = Q2;
76 else if (c == '#') { state = H2; unicode = 0; }
77 else state = O0; // error
78 break;
79 case A2: // matched &a
80 if (c == 'm') state = A3;
81 else if (c == 'p') state = P3;
82 else state = O0; // error
83 break;
84 case A3: // matched &am
85 state = (c == 'p') ? A4 : O0; break;
86 case A4: // matched &amp
87 if (c == ';') {
88 command += '&';
89 state = C0;
90 } else {
91 state = O0; // error
92 }
93 break;
94 case P3: // matched &ap
95 state = (c == 'o') ? P4 : O0; break;
96 case P4: // matched &apo
97 state = (c == 's') ? P5 : O0; break;
98 case P5: // matched &apos
99 if (c == ';') {
100 command += '\'';
101 state = C0;
102 } else {
103 state = O0; // error
104 }
105 break;
106 case Q2: // matched &q
107 state = (c == 'u') ? Q3 : O0; break;
108 case Q3: // matched &qu
109 state = (c == 'o') ? Q4 : O0; break;
110 case Q4: // matched &quo
111 state = (c == 't') ? Q5 : O0; break;
112 case Q5: // matched &quot
113 if (c == ';') {
114 command += '"';
115 state = C0;
116 } else {
117 state = O0; // error
118 }
119 break;
120 case G2: // matched &g
121 state = (c == 't') ? G3 : O0; break;
122 case G3: // matched &gt
123 if (c == ';') {
124 command += '>';
125 state = C0;
126 } else {
127 state = O0; // error
128 }
129 break;
130 case L2: // matched &l
131 state = (c == 't') ? L3 : O0; break;
132 case L3: // matched &lt
133 if (c == ';') {
134 command += '<';
135 state = C0;
136 } else {
137 state = O0; // error
138 }
139 break;
140 case H2: // matched &#
141 // This also parses invalid input like '&#12xab;' but let's
142 // ignore that. It also doesn't check for overflow etc.
143 if (c == ';') {
144 utf8::unchecked::append(unicode, back_inserter(command));
145 state = C0;
146 } else if (c == 'x') {
147 state = H3;
148 } else {
149 unicode *= 10;
150 if (('0' <= c) && (c <= '9')) unicode += c - '0';
151 else state = O0;
152 }
153 break;
154 case H3: // matched &#x
155 if (c == ';') {
156 utf8::unchecked::append(unicode, back_inserter(command));
157 state = C0;
158 } else {
159 unicode *= 16;
160 if (('0' <= c) && (c <= '9')) unicode += c - '0';
161 else if (('a' <= c) && (c <= 'f')) unicode += c - 'a' + 10;
162 else if (('A' <= c) && (c <= 'F')) unicode += c - 'A' + 10;
163 else state = O0;
164 }
165 break;
166 }
167}
void parse(std::span< const char > buf)
AdhocCliCommParser(std::function< void(const std::string &)> callback)
STL namespace.
octet_iterator append(uint32_t cp, octet_iterator result)