1818
1919 Created July 2011
2020 parsing functions based on TextFinder library by Michael Margolis
21+
22+ findMulti/findUntil routines written by Jim Leonard/Xuth
2123 */
2224
2325#include " Arduino.h"
2426#include " Stream.h"
25- #include " esp32-hal.h"
2627
2728#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
2929
3030// private method to read stream with timeout
3131int Stream::timedRead () {
@@ -55,18 +55,26 @@ int Stream::timedPeek() {
5555
5656// returns peek of the next digit in the stream or -1 if timeout
5757// discards non-numeric characters
58- int Stream::peekNextDigit () {
58+ int Stream::peekNextDigit (LookaheadMode lookahead, bool detectDecimal ) {
5959 int c;
6060 while (1 ) {
6161 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 == ' .' )) {
6664 return c;
6765 }
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 ;
7078 }
7179 read (); // discard non-numeric
7280 }
@@ -79,9 +87,6 @@ void Stream::setTimeout(unsigned long timeout) // sets the maximum number of mi
7987{
8088 _timeout = timeout;
8189}
82- unsigned long Stream::getTimeout (void ) {
83- return _timeout;
84- }
8590
8691// find returns true if the target string is found
8792bool Stream::find (const char *target) {
@@ -105,115 +110,40 @@ bool Stream::findUntil(const char *target, const char *terminator) {
105110bool Stream::findUntil (const char *target, size_t targetLen, const char *terminator, size_t termLen) {
106111 if (terminator == NULL ) {
107112 MultiTarget t[1 ] = {{target, targetLen, 0 }};
108- return findMulti (t, 1 ) == 0 ? true : false ;
113+ return findMulti (t, 1 ) == 0 ;
109114 } else {
110115 MultiTarget t[2 ] = {{target, targetLen, 0 }, {terminator, termLen, 0 }};
111- return findMulti (t, 2 ) == 0 ? true : false ;
116+ return findMulti (t, 2 ) == 0 ;
112117 }
113118}
114119
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-
186120// 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 ;
197127 long value = 0 ;
198128 int c;
199129
200- c = peekNextDigit ();
130+ c = peekNextDigit (lookahead, false );
201131 // ignore non numeric leading characters
202132 if (c < 0 ) {
203133 return 0 ; // zero returned if timeout
204134 }
205135
206136 do {
207- if (c == skipChar) {
208- } // ignore this character
137+ if (( char ) c == ignore)
138+ ; // ignore this character
209139 else if (c == ' -' ) {
210140 isNegative = true ;
211141 } else if (c >= ' 0' && c <= ' 9' ) { // is c a digit?
212142 value = value * 10 + c - ' 0' ;
213143 }
214144 read (); // consume the character we got with peek
215145 c = timedPeek ();
216- } while ((c >= ' 0' && c <= ' 9' ) || c == skipChar );
146+ } while ((c >= ' 0' && c <= ' 9' ) || ( char ) c == ignore );
217147
218148 if (isNegative) {
219149 value = -value;
@@ -222,50 +152,43 @@ long Stream::parseInt(char skipChar) {
222152}
223153
224154// 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 ;
235159 int c;
236- float fraction = 1.0 ;
160+ double fraction = 1.0 ;
237161
238- c = peekNextDigit ();
162+ c = peekNextDigit (lookahead, true );
239163 // ignore non numeric leading characters
240164 if (c < 0 ) {
241165 return 0 ; // zero returned if timeout
242166 }
243167
244168 do {
245- if (c == skipChar) {
246- } // ignore
169+ if (( char ) c == ignore)
170+ ; // ignore
247171 else if (c == ' -' ) {
248172 isNegative = true ;
249173 } else if (c == ' .' ) {
250174 isFraction = true ;
251175 } else if (c >= ' 0' && c <= ' 9' ) { // is c a digit?
252- value = value * 10 + c - ' 0' ;
253176 if (isFraction) {
254- fraction *= 0 .1f ;
177+ fraction *= 0.1 ;
178+ value = value + fraction * (c - ' 0' );
179+ } else {
180+ value = value * 10 + c - ' 0' ;
255181 }
256182 }
257183 read (); // consume the character we got with peek
258184 c = timedPeek ();
259- } while ((c >= ' 0' && c <= ' 9' ) || c == ' .' || c == skipChar );
185+ } while ((c >= ' 0' && c <= ' 9' ) || ( c == ' .' && !isFraction) || ( char ) c == ignore );
260186
261187 if (isNegative) {
262188 value = -value;
263189 }
264- if (isFraction) {
265- return value * fraction;
266- } else {
267- return value;
268- }
190+
191+ return value;
269192}
270193
271194// read characters from stream into buffer
@@ -291,13 +214,10 @@ size_t Stream::readBytes(char *buffer, size_t length) {
291214// returns the number of characters placed in the buffer (0 means no valid data found)
292215
293216size_t Stream::readBytesUntil (char terminator, char *buffer, size_t length) {
294- if (length < 1 ) {
295- return 0 ;
296- }
297217 size_t index = 0 ;
298218 while (index < length) {
299219 int c = timedRead ();
300- if (c < 0 || c == terminator) {
220+ if (c < 0 || ( char ) c == terminator) {
301221 break ;
302222 }
303223 *buffer++ = (char )c;
@@ -319,9 +239,80 @@ String Stream::readString() {
319239String Stream::readStringUntil (char terminator) {
320240 String ret;
321241 int c = timedRead ();
322- while (c >= 0 && c != terminator) {
242+ while (c >= 0 && ( char ) c != terminator) {
323243 ret += (char )c;
324244 c = timedRead ();
325245 }
326246 return ret;
327247}
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