18
18
19
19
Created July 2011
20
20
parsing functions based on TextFinder library by Michael Margolis
21
+
22
+ findMulti/findUntil routines written by Jim Leonard/Xuth
21
23
*/
22
24
23
25
#include " Arduino.h"
24
26
#include " Stream.h"
25
- #include " esp32-hal.h"
26
27
27
28
#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait
28
- #define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
29
29
30
30
// private method to read stream with timeout
31
31
int Stream::timedRead () {
@@ -55,18 +55,26 @@ int Stream::timedPeek() {
55
55
56
56
// returns peek of the next digit in the stream or -1 if timeout
57
57
// discards non-numeric characters
58
- int Stream::peekNextDigit () {
58
+ int Stream::peekNextDigit (LookaheadMode lookahead, bool detectDecimal ) {
59
59
int c;
60
60
while (1 ) {
61
61
c = timedPeek ();
62
- if (c < 0 ) {
63
- return c; // timeout
64
- }
65
- if (c == ' -' ) {
62
+
63
+ if (c < 0 || c == ' -' || (c >= ' 0' && c <= ' 9' ) || (detectDecimal && c == ' .' )) {
66
64
return c;
67
65
}
68
- if (c >= ' 0' && c <= ' 9' ) {
69
- return c;
66
+
67
+ switch (lookahead) {
68
+ case SKIP_NONE: return -1 ; // Fail code.
69
+ case SKIP_WHITESPACE:
70
+ switch (c) {
71
+ case ' ' :
72
+ case ' \t ' :
73
+ case ' \r ' :
74
+ case ' \n ' : break ;
75
+ default : return -1 ; // Fail code.
76
+ }
77
+ case SKIP_ALL: break ;
70
78
}
71
79
read (); // discard non-numeric
72
80
}
@@ -79,9 +87,6 @@ void Stream::setTimeout(unsigned long timeout) // sets the maximum number of mi
79
87
{
80
88
_timeout = timeout;
81
89
}
82
- unsigned long Stream::getTimeout (void ) {
83
- return _timeout;
84
- }
85
90
86
91
// find returns true if the target string is found
87
92
bool Stream::find (const char *target) {
@@ -105,115 +110,40 @@ bool Stream::findUntil(const char *target, const char *terminator) {
105
110
bool Stream::findUntil (const char *target, size_t targetLen, const char *terminator, size_t termLen) {
106
111
if (terminator == NULL ) {
107
112
MultiTarget t[1 ] = {{target, targetLen, 0 }};
108
- return findMulti (t, 1 ) == 0 ? true : false ;
113
+ return findMulti (t, 1 ) == 0 ;
109
114
} else {
110
115
MultiTarget t[2 ] = {{target, targetLen, 0 }, {terminator, termLen, 0 }};
111
- return findMulti (t, 2 ) == 0 ? true : false ;
116
+ return findMulti (t, 2 ) == 0 ;
112
117
}
113
118
}
114
119
115
- int Stream::findMulti (struct Stream ::MultiTarget *targets, int tCount) {
116
- // any zero length target string automatically matches and would make
117
- // a mess of the rest of the algorithm.
118
- for (struct MultiTarget *t = targets; t < targets + tCount; ++t) {
119
- if (t->len <= 0 ) {
120
- return t - targets;
121
- }
122
- }
123
-
124
- while (1 ) {
125
- int c = timedRead ();
126
- if (c < 0 ) {
127
- return -1 ;
128
- }
129
-
130
- for (struct MultiTarget *t = targets; t < targets + tCount; ++t) {
131
- // the simple case is if we match, deal with that first.
132
- if (c == t->str [t->index ]) {
133
- if (++t->index == t->len ) {
134
- return t - targets;
135
- } else {
136
- continue ;
137
- }
138
- }
139
-
140
- // if not we need to walk back and see if we could have matched further
141
- // down the stream (ie '1112' doesn't match the first position in '11112'
142
- // but it will match the second position so we can't just reset the current
143
- // index to 0 when we find a mismatch.
144
- if (t->index == 0 ) {
145
- continue ;
146
- }
147
-
148
- int origIndex = t->index ;
149
- do {
150
- --t->index ;
151
- // first check if current char works against the new current index
152
- if (c != t->str [t->index ]) {
153
- continue ;
154
- }
155
-
156
- // if it's the only char then we're good, nothing more to check
157
- if (t->index == 0 ) {
158
- t->index ++;
159
- break ;
160
- }
161
-
162
- // otherwise we need to check the rest of the found string
163
- int diff = origIndex - t->index ;
164
- size_t i;
165
- for (i = 0 ; i < t->index ; ++i) {
166
- if (t->str [i] != t->str [i + diff]) {
167
- break ;
168
- }
169
- }
170
-
171
- // if we successfully got through the previous loop then our current
172
- // index is good.
173
- if (i == t->index ) {
174
- t->index ++;
175
- break ;
176
- }
177
-
178
- // otherwise we just try the next index
179
- } while (t->index );
180
- }
181
- }
182
- // unreachable
183
- return -1 ;
184
- }
185
-
186
120
// returns the first valid (long) integer value from the current position.
187
- // initial characters that are not digits (or the minus sign) are skipped
188
- // function is terminated by the first character that is not a digit.
189
- long Stream::parseInt () {
190
- return parseInt (NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
191
- }
192
-
193
- // as above but a given skipChar is ignored
194
- // this allows format characters (typically commas) in values to be ignored
195
- long Stream::parseInt (char skipChar) {
196
- boolean isNegative = false ;
121
+ // lookahead determines how parseInt looks ahead in the stream.
122
+ // See LookaheadMode enumeration at the top of the file.
123
+ // Lookahead is terminated by the first character that is not a valid part of an integer.
124
+ // Once parsing commences, 'ignore' will be skipped in the stream.
125
+ long Stream::parseInt (LookaheadMode lookahead, char ignore) {
126
+ bool isNegative = false ;
197
127
long value = 0 ;
198
128
int c;
199
129
200
- c = peekNextDigit ();
130
+ c = peekNextDigit (lookahead, false );
201
131
// ignore non numeric leading characters
202
132
if (c < 0 ) {
203
133
return 0 ; // zero returned if timeout
204
134
}
205
135
206
136
do {
207
- if (c == skipChar) {
208
- } // ignore this character
137
+ if (( char ) c == ignore)
138
+ ; // ignore this character
209
139
else if (c == ' -' ) {
210
140
isNegative = true ;
211
141
} else if (c >= ' 0' && c <= ' 9' ) { // is c a digit?
212
142
value = value * 10 + c - ' 0' ;
213
143
}
214
144
read (); // consume the character we got with peek
215
145
c = timedPeek ();
216
- } while ((c >= ' 0' && c <= ' 9' ) || c == skipChar );
146
+ } while ((c >= ' 0' && c <= ' 9' ) || ( char ) c == ignore );
217
147
218
148
if (isNegative) {
219
149
value = -value;
@@ -222,50 +152,43 @@ long Stream::parseInt(char skipChar) {
222
152
}
223
153
224
154
// as parseInt but returns a floating point value
225
- float Stream::parseFloat () {
226
- return parseFloat (NO_SKIP_CHAR);
227
- }
228
-
229
- // as above but the given skipChar is ignored
230
- // this allows format characters (typically commas) in values to be ignored
231
- float Stream::parseFloat (char skipChar) {
232
- boolean isNegative = false ;
233
- boolean isFraction = false ;
234
- long value = 0 ;
155
+ float Stream::parseFloat (LookaheadMode lookahead, char ignore) {
156
+ bool isNegative = false ;
157
+ bool isFraction = false ;
158
+ double value = 0.0 ;
235
159
int c;
236
- float fraction = 1.0 ;
160
+ double fraction = 1.0 ;
237
161
238
- c = peekNextDigit ();
162
+ c = peekNextDigit (lookahead, true );
239
163
// ignore non numeric leading characters
240
164
if (c < 0 ) {
241
165
return 0 ; // zero returned if timeout
242
166
}
243
167
244
168
do {
245
- if (c == skipChar) {
246
- } // ignore
169
+ if (( char ) c == ignore)
170
+ ; // ignore
247
171
else if (c == ' -' ) {
248
172
isNegative = true ;
249
173
} else if (c == ' .' ) {
250
174
isFraction = true ;
251
175
} else if (c >= ' 0' && c <= ' 9' ) { // is c a digit?
252
- value = value * 10 + c - ' 0' ;
253
176
if (isFraction) {
254
- fraction *= 0 .1f ;
177
+ fraction *= 0.1 ;
178
+ value = value + fraction * (c - ' 0' );
179
+ } else {
180
+ value = value * 10 + c - ' 0' ;
255
181
}
256
182
}
257
183
read (); // consume the character we got with peek
258
184
c = timedPeek ();
259
- } while ((c >= ' 0' && c <= ' 9' ) || c == ' .' || c == skipChar );
185
+ } while ((c >= ' 0' && c <= ' 9' ) || ( c == ' .' && !isFraction) || ( char ) c == ignore );
260
186
261
187
if (isNegative) {
262
188
value = -value;
263
189
}
264
- if (isFraction) {
265
- return value * fraction;
266
- } else {
267
- return value;
268
- }
190
+
191
+ return value;
269
192
}
270
193
271
194
// read characters from stream into buffer
@@ -291,13 +214,10 @@ size_t Stream::readBytes(char *buffer, size_t length) {
291
214
// returns the number of characters placed in the buffer (0 means no valid data found)
292
215
293
216
size_t Stream::readBytesUntil (char terminator, char *buffer, size_t length) {
294
- if (length < 1 ) {
295
- return 0 ;
296
- }
297
217
size_t index = 0 ;
298
218
while (index < length) {
299
219
int c = timedRead ();
300
- if (c < 0 || c == terminator) {
220
+ if (c < 0 || ( char ) c == terminator) {
301
221
break ;
302
222
}
303
223
*buffer++ = (char )c;
@@ -319,9 +239,80 @@ String Stream::readString() {
319
239
String Stream::readStringUntil (char terminator) {
320
240
String ret;
321
241
int c = timedRead ();
322
- while (c >= 0 && c != terminator) {
242
+ while (c >= 0 && ( char ) c != terminator) {
323
243
ret += (char )c;
324
244
c = timedRead ();
325
245
}
326
246
return ret;
327
247
}
248
+
249
+ int Stream::findMulti (struct Stream ::MultiTarget *targets, int tCount) {
250
+ // any zero length target string automatically matches and would make
251
+ // a mess of the rest of the algorithm.
252
+ for (struct MultiTarget *t = targets; t < targets + tCount; ++t) {
253
+ if (t->len <= 0 ) {
254
+ return t - targets;
255
+ }
256
+ }
257
+
258
+ while (1 ) {
259
+ int c = timedRead ();
260
+ if (c < 0 ) {
261
+ return -1 ;
262
+ }
263
+
264
+ for (struct MultiTarget *t = targets; t < targets + tCount; ++t) {
265
+ // the simple case is if we match, deal with that first.
266
+ if ((char )c == t->str [t->index ]) {
267
+ if (++t->index == t->len ) {
268
+ return t - targets;
269
+ } else {
270
+ continue ;
271
+ }
272
+ }
273
+
274
+ // if not we need to walk back and see if we could have matched further
275
+ // down the stream (ie '1112' doesn't match the first position in '11112'
276
+ // but it will match the second position so we can't just reset the current
277
+ // index to 0 when we find a mismatch.
278
+ if (t->index == 0 ) {
279
+ continue ;
280
+ }
281
+
282
+ int origIndex = t->index ;
283
+ do {
284
+ --t->index ;
285
+ // first check if current char works against the new current index
286
+ if ((char )c != t->str [t->index ]) {
287
+ continue ;
288
+ }
289
+
290
+ // if it's the only char then we're good, nothing more to check
291
+ if (t->index == 0 ) {
292
+ t->index ++;
293
+ break ;
294
+ }
295
+
296
+ // otherwise we need to check the rest of the found string
297
+ int diff = origIndex - t->index ;
298
+ size_t i;
299
+ for (i = 0 ; i < t->index ; ++i) {
300
+ if (t->str [i] != t->str [i + diff]) {
301
+ break ;
302
+ }
303
+ }
304
+
305
+ // if we successfully got through the previous loop then our current
306
+ // index is good.
307
+ if (i == t->index ) {
308
+ t->index ++;
309
+ break ;
310
+ }
311
+
312
+ // otherwise we just try the next index
313
+ } while (t->index );
314
+ }
315
+ }
316
+ // unreachable
317
+ return -1 ;
318
+ }
0 commit comments