Directory: | ./ |
---|---|
File: | pdserv/src/msrproto/XmlParser.cpp |
Date: | 2024-12-15 04:08:34 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 155 | 195 | 79.5% |
Branches: | 127 | 229 | 55.5% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /***************************************************************************** | ||
2 | * | ||
3 | * $Id$ | ||
4 | * | ||
5 | * Copyright 2010 Richard Hacker (lerichi at gmx dot net) | ||
6 | * | ||
7 | * This file is part of the pdserv library. | ||
8 | * | ||
9 | * The pdserv library is free software: you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU Lesser General Public License as published | ||
11 | * by the Free Software Foundation, either version 3 of the License, or (at | ||
12 | * your option) any later version. | ||
13 | * | ||
14 | * The pdserv library is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
17 | * License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU Lesser General Public License | ||
20 | * along with the pdserv library. If not, see <http://www.gnu.org/licenses/>. | ||
21 | * | ||
22 | *****************************************************************************/ | ||
23 | |||
24 | #include "XmlParser.h" | ||
25 | #include "Session.h" | ||
26 | #include "../Debug.h" | ||
27 | |||
28 | #include <algorithm> | ||
29 | #include <cstring> | ||
30 | #include <sstream> | ||
31 | |||
32 | #undef log_debug | ||
33 | #define log_debug(...) | ||
34 | |||
35 | using namespace MsrProto; | ||
36 | |||
37 | ///////////////////////////////////////////////////////////////////////////// | ||
38 | 144 | XmlParser::XmlParser(size_t bufMax): bufLenMax(bufMax) | |
39 | { | ||
40 | 144 | parseState = FindElementStart; | |
41 | 144 | buf = 0; | |
42 | 144 | bufEnd = 0; | |
43 | 144 | inputEnd = 0; | |
44 | 144 | parsePos = 0; | |
45 | 144 | name = 0; | |
46 | 144 | } | |
47 | |||
48 | ///////////////////////////////////////////////////////////////////////////// | ||
49 | 288 | XmlParser::~XmlParser() | |
50 | { | ||
51 |
1/2✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
|
144 | delete[] buf; |
52 | 144 | } | |
53 | |||
54 | ///////////////////////////////////////////////////////////////////////////// | ||
55 | 8779 | std::streamsize XmlParser::read(std::streambuf* sb) | |
56 | { | ||
57 |
2/2✓ Branch 2 taken 144 times.
✓ Branch 3 taken 8635 times.
|
8779 | if (bufEnd == inputEnd) { |
58 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 144 times.
|
144 | if (name > buf + 1) { |
59 | // Name is not the second character in the buffer. | ||
60 | log_debug("shift up data"); | ||
61 | |||
62 | ✗ | moveData(buf); | |
63 | } | ||
64 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 144 times.
|
144 | else if (bufEnd >= buf + bufLenMax) { |
65 | ✗ | inputEnd = 0; | |
66 | ✗ | return 0; | |
67 | } | ||
68 | else { | ||
69 | log_debug("allocate new buffer"); | ||
70 | 144 | size_t bufLen = (bufEnd - buf) + bufIncrement; | |
71 | 144 | char *newBuf = new char[bufLen]; | |
72 | |||
73 | 144 | moveData(newBuf); | |
74 | |||
75 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 144 times.
|
144 | delete[] buf; |
76 | 144 | buf = newBuf; | |
77 | 144 | bufEnd = buf + bufLen; | |
78 | } | ||
79 | } | ||
80 |
5/6✗ Branch 1 not taken.
✓ Branch 2 taken 8635 times.
✓ Branch 3 taken 817 times.
✓ Branch 4 taken 7818 times.
✓ Branch 7 taken 519 times.
✓ Branch 8 taken 298 times.
|
8635 | else if (parseState == FindElementStart and parsePos == inputEnd) { |
81 | 519 | inputEnd = buf; | |
82 | 519 | parsePos = buf; | |
83 | } | ||
84 | |||
85 | 8779 | std::streamsize n = sb->sgetn(inputEnd, bufEnd - inputEnd); | |
86 |
2/2✓ Branch 0 taken 8674 times.
✓ Branch 1 taken 105 times.
|
8779 | if (n > 0) |
87 | 8674 | inputEnd += n; | |
88 | |||
89 | // log_debug("string is %zi %zi %p %s", count, n, name, std::string(name, inputEnd - name).c_str()); | ||
90 | |||
91 | 8779 | return n; | |
92 | } | ||
93 | |||
94 | ///////////////////////////////////////////////////////////////////////////// | ||
95 | 144 | void XmlParser::moveData(char* dst) | |
96 | { | ||
97 | // Move data to new location | ||
98 | 144 | std::copy(name, const_cast<const char*>(inputEnd), dst); | |
99 | |||
100 | // Update pointers | ||
101 | 144 | const ssize_t diff = dst - name; | |
102 | 144 | parsePos += diff; | |
103 | 144 | inputEnd += diff; | |
104 | 144 | name += diff; | |
105 | 144 | argument += diff; | |
106 | |||
107 | 144 | for (AttributeList::iterator it = attribute.begin(); | |
108 |
1/2✗ Branch 6 not taken.
✓ Branch 7 taken 144 times.
|
144 | it != attribute.end(); ++it) { |
109 | ✗ | it->first += diff; | |
110 | ✗ | it->second += diff; | |
111 | } | ||
112 | 144 | } | |
113 | |||
114 | ///////////////////////////////////////////////////////////////////////////// | ||
115 | ✗ | bool XmlParser::invalid() const | |
116 | { | ||
117 | ✗ | return !inputEnd; | |
118 | } | ||
119 | |||
120 | ///////////////////////////////////////////////////////////////////////////// | ||
121 | 11487 | XmlParser::operator bool() | |
122 | { | ||
123 |
1/2✓ Branch 2 taken 11487 times.
✗ Branch 3 not taken.
|
13696 | while (parsePos < inputEnd) { |
124 | // log_debug("parsepos=%zi state=%i \"%s\"", | ||
125 | // parsePos - buf, parseState, | ||
126 | // std::string(name, inputEnd - name).c_str() | ||
127 | // ); | ||
128 |
5/9✗ Branch 1 not taken.
✓ Branch 2 taken 11487 times.
✓ Branch 3 taken 1467 times.
✓ Branch 4 taken 2908 times.
✓ Branch 5 taken 2269 times.
✓ Branch 6 taken 4843 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
11487 | switch (parseState) { |
129 | 1467 | case FindElementStart: | |
130 | // At the end of this state, name set up correctly | ||
131 | // and there is at least one valid character following name | ||
132 | |||
133 |
1/2✓ Branch 4 taken 1467 times.
✗ Branch 5 not taken.
|
1467 | parsePos = std::find(parsePos, inputEnd, '<'); |
134 | |||
135 |
2/2✓ Branch 2 taken 854 times.
✓ Branch 3 taken 613 times.
|
1467 | if (parsePos + 2 >= inputEnd) { |
136 | // Smallest element needs at least 2 more characters, | ||
137 | // one for name and at least one for closing '>' | ||
138 | 854 | return false; | |
139 | } | ||
140 | |||
141 | 613 | name = ++parsePos; | |
142 | |||
143 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 613 times.
|
613 | if (!isalpha(*name)) { |
144 | // Name must start with an alpha character | ||
145 | ✗ | break; | |
146 | } | ||
147 | |||
148 | 613 | attribute.clear(); | |
149 | |||
150 | 613 | parseState = FindElementEnd; | |
151 | |||
152 | /* FALLTHRU */ | ||
153 | |||
154 | 3521 | case FindElementEnd: | |
155 | // Clobber white space | ||
156 |
2/2✓ Branch 2 taken 1605 times.
✓ Branch 3 taken 2822 times.
|
5333 | while (*parsePos == ' ') { |
157 | 1605 | *parsePos++ = '\0'; | |
158 |
2/2✓ Branch 2 taken 699 times.
✓ Branch 3 taken 906 times.
|
1605 | if (parsePos == inputEnd) |
159 | 699 | return false; | |
160 | } | ||
161 | |||
162 | // Element that ends in /> | ||
163 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 2822 times.
|
2822 | if (*parsePos == '/') { |
164 | ✗ | if (parsePos + 1 >= inputEnd) | |
165 | ✗ | return false; | |
166 | ✗ | *parsePos++ = '\0'; | |
167 | |||
168 | ✗ | parseState = FindElementStart; | |
169 | |||
170 | ✗ | if (*parsePos++ == '>') { | |
171 | ✗ | return true; | |
172 | } | ||
173 | ✗ | break; | |
174 | } | ||
175 | |||
176 | // Element that ends in > | ||
177 |
2/2✓ Branch 2 taken 604 times.
✓ Branch 3 taken 2218 times.
|
2822 | if (!isalpha(*parsePos)) { |
178 | 604 | parseState = FindElementStart; | |
179 |
1/2✓ Branch 2 taken 604 times.
✗ Branch 3 not taken.
|
604 | if (*parsePos == '>') { |
180 | 604 | *parsePos++ = '\0'; | |
181 | |||
182 | 604 | return true; | |
183 | } | ||
184 | ✗ | break; | |
185 | } | ||
186 | |||
187 | 2218 | argument = parsePos; | |
188 | |||
189 | 2218 | parseState = FindArgumentName; | |
190 | |||
191 | /* FALLTHRU */ | ||
192 | |||
193 | 4487 | case FindArgumentName: | |
194 | // In this state, the argument name is searched for. It is | ||
195 | // terminated by a '=', ' ', '/' or '>' | ||
196 |
2/2✓ Branch 2 taken 12685 times.
✓ Branch 3 taken 3456 times.
|
27795 | while (!strchr("= />", *parsePos)) |
197 |
2/2✓ Branch 4 taken 1031 times.
✓ Branch 5 taken 11654 times.
|
12685 | if (++parsePos == inputEnd) |
198 | 1031 | return false; | |
199 | |||
200 |
2/2✓ Branch 2 taken 613 times.
✓ Branch 3 taken 2843 times.
|
3456 | if (*parsePos != '=') { |
201 | // Found an attribute without a value. Consider it to | ||
202 | // be a boolean which evaluates to true | ||
203 |
1/2✓ Branch 4 taken 613 times.
✗ Branch 5 not taken.
|
1226 | attribute.push_back( |
204 |
1/2✓ Branch 4 taken 613 times.
✗ Branch 5 not taken.
|
1226 | std::make_pair(argument, (const char*)0)); |
205 | |||
206 | 613 | parseState = FindElementEnd; | |
207 | 613 | break; | |
208 | } | ||
209 | |||
210 | // parsePos points to the '=' | ||
211 | |||
212 | // Need at least one following character to continue | ||
213 |
2/2✓ Branch 2 taken 260 times.
✓ Branch 3 taken 2583 times.
|
2843 | if (parsePos + 1 >= inputEnd) |
214 | 260 | return false; | |
215 | |||
216 | 2583 | quote = parsePos[1]; | |
217 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 2583 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
2583 | if (quote != '"' and quote != '\'') { |
218 | // Argument value is not surrounded with quotes | ||
219 | ✗ | *parsePos++ = '\0'; | |
220 | ✗ | attribute.push_back(std::make_pair(argument, parsePos++)); | |
221 | ✗ | parseState = FindArgumentValue; | |
222 | ✗ | break; | |
223 | } | ||
224 |
2/2✓ Branch 2 taken 978 times.
✓ Branch 3 taken 1605 times.
|
2583 | else if (parsePos + 2 >= inputEnd) |
225 | // Quoted argument value. Need at least 2 following chars | ||
226 | // to continue | ||
227 | 978 | return false; | |
228 | |||
229 | 1605 | *parsePos = '\0'; // Clobber '=' | |
230 |
2/4✓ Branch 8 taken 1605 times.
✗ Branch 9 not taken.
✓ Branch 14 taken 1605 times.
✗ Branch 15 not taken.
|
1605 | attribute.push_back(std::make_pair(argument, parsePos + 2)); |
231 | 1605 | parsePos += 2; | |
232 | 1605 | parseState = FindQuotedArgumentValue; | |
233 | |||
234 | /* FALLTHRU */ | ||
235 | |||
236 | 6448 | case FindQuotedArgumentValue: | |
237 | 6448 | parsePos = std::find(parsePos, inputEnd, quote); | |
238 |
2/2✓ Branch 2 taken 4852 times.
✓ Branch 3 taken 1596 times.
|
6448 | if (parsePos + 1 >= inputEnd) |
239 | 4852 | return false; | |
240 | |||
241 | 1596 | *parsePos++ = '\0'; | |
242 | 1596 | parseState = FindElementEnd; | |
243 | |||
244 | /* FALLTHRU */ | ||
245 | |||
246 | 1596 | case FindArgumentValue: | |
247 |
3/4✓ Branch 2 taken 566 times.
✓ Branch 3 taken 1030 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 566 times.
|
1596 | while (*parsePos != ' ' and *parsePos != '>') { |
248 | ✗ | if (++parsePos == inputEnd) | |
249 | ✗ | return false; | |
250 | } | ||
251 | |||
252 | 1596 | parseState = FindElementEnd; | |
253 | 1596 | break; | |
254 | |||
255 | ✗ | case FindNameEnd: | |
256 | // At the end of this state, name is terminated with a | ||
257 | // closing \0 | ||
258 | |||
259 | // Name is any set of characters not in " />" | ||
260 | ✗ | while (!strchr(" />", *parsePos)) { | |
261 | ✗ | if (++parsePos == inputEnd) | |
262 | ✗ | return false; | |
263 | } | ||
264 | |||
265 | ✗ | parseState = FindElementEnd; | |
266 | |||
267 | ✗ | break; | |
268 | } | ||
269 | } | ||
270 | |||
271 | ✗ | return false; | |
272 | } | ||
273 | |||
274 | ///////////////////////////////////////////////////////////////////////////// | ||
275 | 604 | const char *XmlParser::tag() const | |
276 | { | ||
277 | 604 | return name; | |
278 | } | ||
279 | |||
280 | ///////////////////////////////////////////////////////////////////////////// | ||
281 | 3017 | bool XmlParser::find(const char *name, const char **value) const | |
282 | { | ||
283 |
4/4✓ Branch 4 taken 1376 times.
✓ Branch 5 taken 1641 times.
✓ Branch 7 taken 1376 times.
✓ Branch 8 taken 1641 times.
|
11590 | for (AttributeList::const_iterator it = attribute.begin(); |
284 |
2/2✓ Branch 6 taken 10214 times.
✓ Branch 7 taken 1376 times.
|
11590 | it != attribute.end(); ++it) { |
285 |
4/6✗ Branch 2 not taken.
✓ Branch 3 taken 10214 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 10214 times.
✓ Branch 6 taken 1641 times.
✓ Branch 7 taken 8573 times.
|
10214 | if (!strcasecmp(name, it->first)) { |
286 |
2/2✓ Branch 0 taken 1502 times.
✓ Branch 1 taken 139 times.
|
1641 | if (value) |
287 | 1502 | *value = it->second; | |
288 | 1641 | return true; | |
289 | } | ||
290 | } | ||
291 | |||
292 | 1376 | return false; | |
293 | } | ||
294 | |||
295 | ///////////////////////////////////////////////////////////////////////////// | ||
296 | 183 | bool XmlParser::isEqual(const char *name, const char *s) const | |
297 | { | ||
298 | 183 | const char *value; | |
299 | |||
300 |
3/6✓ Branch 2 taken 183 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 183 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 183 times.
✗ Branch 7 not taken.
|
183 | if (find(name, &value) and value) |
301 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 183 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 183 times.
|
183 | return !strcasecmp(value, s); |
302 | |||
303 | ✗ | return false; | |
304 | } | ||
305 | |||
306 | ///////////////////////////////////////////////////////////////////////////// | ||
307 | 688 | bool XmlParser::isTrue(const char *name) const | |
308 | { | ||
309 | 688 | bool val; | |
310 |
4/6✓ Branch 2 taken 114 times.
✓ Branch 3 taken 574 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 114 times.
✓ Branch 6 taken 114 times.
✗ Branch 7 not taken.
|
688 | return getBool(name, &val) and val; |
311 | } | ||
312 | |||
313 | ///////////////////////////////////////////////////////////////////////////// | ||
314 | 837 | bool XmlParser::getBool(const char *name, bool* val) const | |
315 | { | ||
316 | 837 | const char *str; | |
317 | |||
318 |
2/2✓ Branch 2 taken 713 times.
✓ Branch 3 taken 124 times.
|
837 | if (!(find(name, &str))) |
319 | 713 | return false; | |
320 | |||
321 | // Binary attribute, e.g <xsad sync> | ||
322 |
1/4✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
124 | *val = !(str |
323 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 124 times.
|
248 | and strcasecmp(str, "1") // Binary attribute, e.g <xsad sync="1"> |
324 | ✗ | and strcasecmp(str, "true") // Binary attribute, e.g <xsad sync="true"> | |
325 | ✗ | and strcasecmp(str, "on")); // Binary attribute, e.g <xsad sync="on"> | |
326 | |||
327 | 124 | return true; | |
328 | } | ||
329 | |||
330 | ///////////////////////////////////////////////////////////////////////////// | ||
331 | 1279 | bool XmlParser::getString(const char *name, std::string &s) const | |
332 | { | ||
333 | 1279 | const char *value; | |
334 | |||
335 | 1279 | s.clear(); | |
336 | |||
337 |
5/6✓ Branch 2 taken 793 times.
✓ Branch 3 taken 486 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 793 times.
✓ Branch 6 taken 486 times.
✓ Branch 7 taken 793 times.
|
1279 | if (!(find(name, &value) and value)) |
338 | 486 | return false; | |
339 | |||
340 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 793 times.
|
793 | const char *pptr, *eptr = value + strlen(value); |
341 |
3/4✓ Branch 2 taken 847 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 54 times.
✓ Branch 6 taken 793 times.
|
901 | while ((pptr = std::find(value, eptr, '&')) != eptr) { |
342 | // FIXME: maybe also check for escape char, e.g. \" ?? | ||
343 | // this is difficult, because the quote character is not available | ||
344 | // here any more :( | ||
345 | |||
346 |
1/2✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
|
54 | s.append(value, pptr - value); |
347 | 54 | size_t len = eptr - pptr; | |
348 |
3/6✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 54 times.
|
54 | if (len >= 4 and !strncmp(pptr, ">", 4)) { |
349 | ✗ | s.append(1, '>'); | |
350 | ✗ | value = pptr + 4; | |
351 | } | ||
352 |
4/6✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 36 times.
|
54 | else if (len >= 4 and !strncmp(pptr, "<", 4)) { |
353 |
1/2✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | s.append(1, '<'); |
354 | 18 | value = pptr + 4; | |
355 | } | ||
356 |
4/6✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 18 times.
|
36 | else if (len >= 5 and !strncmp(pptr, "&", 5)) { |
357 |
1/2✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | s.append(1, '&'); |
358 | 18 | value = pptr + 5; | |
359 | } | ||
360 |
3/6✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | else if (len >= 6 and !strncmp(pptr, """, 6)) { |
361 |
1/2✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | s.append(1, '"'); |
362 | 18 | value = pptr + 6; | |
363 | } | ||
364 | ✗ | else if (len >= 6 and !strncmp(pptr, "'", 6)) { | |
365 | ✗ | s.append(1, '\''); | |
366 | ✗ | value = pptr + 6; | |
367 | } | ||
368 | else { | ||
369 | ✗ | s.append(1, '&'); | |
370 | ✗ | value = pptr + 1; | |
371 | } | ||
372 | } | ||
373 | |||
374 |
1/2✓ Branch 2 taken 793 times.
✗ Branch 3 not taken.
|
793 | s.append(value, eptr - value); |
375 | 793 | return true; | |
376 | } | ||
377 | |||
378 | ///////////////////////////////////////////////////////////////////////////// | ||
379 | 354 | bool XmlParser::getUnsigned(const char *name, unsigned int &i) const | |
380 | { | ||
381 | 354 | const char *value; | |
382 | |||
383 |
5/6✓ Branch 2 taken 246 times.
✓ Branch 3 taken 108 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 246 times.
✓ Branch 6 taken 108 times.
✓ Branch 7 taken 246 times.
|
354 | if (!(find(name, &value)) or !value) |
384 | 108 | return false; | |
385 | |||
386 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 246 times.
|
246 | i = strtoul(value, 0, 0); |
387 | 246 | return true; | |
388 | } | ||
389 | |||
390 | ///////////////////////////////////////////////////////////////////////////// | ||
391 | 44 | bool XmlParser::getUnsignedList(const char *name, | |
392 | std::list<unsigned int> &intList) const | ||
393 | { | ||
394 | 44 | const char *value; | |
395 | |||
396 |
3/6✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 44 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 44 times.
|
44 | if (!(find(name, &value)) or !value) |
397 | ✗ | return false; | |
398 | |||
399 |
2/4✓ Branch 5 taken 44 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 44 times.
✗ Branch 10 not taken.
|
88 | std::istringstream is(value); |
400 |
2/4✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 44 times.
✗ Branch 6 not taken.
|
44 | is.imbue(std::locale::classic()); |
401 | |||
402 |
3/4✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 44 times.
✓ Branch 5 taken 44 times.
|
88 | while (is) { |
403 | 44 | unsigned int i; | |
404 | 44 | char comma; | |
405 | |||
406 |
1/2✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
|
44 | is >> i; |
407 |
2/4✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 44 times.
✗ Branch 5 not taken.
|
44 | if (is) |
408 |
1/2✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
|
44 | intList.push_back(i); |
409 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | is >> comma; |
410 | } | ||
411 | |||
412 | 44 | return true; | |
413 | } | ||
414 |