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"
27
29
#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
28
30
29
31
// private method to read stream with timeout
30
- int Stream::timedRead ()
32
+
33
+ void Stream::startClock ()
31
34
{
32
- int c;
33
35
_startMillis = millis ();
36
+ }
37
+
38
+ bool Stream::checkClock ()
39
+ {
40
+ if (millis () - _startMillis < _timeout)
41
+ return true ;
42
+ return false ;
43
+ }
44
+
45
+ int Stream::_timedRead ()
46
+ {
34
47
do {
35
- c = read ();
48
+ int c = read ();
36
49
if (c >= 0 ) return c;
37
- } while (millis () - _startMillis < _timeout);
38
- return -1 ; // -1 indicates timeout
50
+ } while (checkClock ());
51
+ return - 1 ; // -1 is timeout
52
+ }
53
+
54
+ int Stream::timedRead ()
55
+ {
56
+ startClock ();
57
+ return _timedRead ();
39
58
}
40
59
41
60
// private method to peek stream with timeout
42
- int Stream::timedPeek ()
61
+ // callers must call startClock() first
62
+ int Stream::_timedPeek ()
43
63
{
44
64
int c;
45
- _startMillis = millis ();
46
65
do {
47
66
c = peek ();
48
67
if (c >= 0 ) return c;
49
- } while (millis () - _startMillis < _timeout );
68
+ } while (checkClock () );
50
69
return -1 ; // -1 indicates timeout
51
70
}
52
71
53
- // returns peek of the next digit in the stream or -1 if timeout
54
- // discards non-numeric characters
55
- int Stream::peekNextDigit ()
72
+ int Stream::timedPeek ()
73
+ {
74
+ startClock ();
75
+ return _timedPeek ();
76
+ }
77
+
78
+ // private method that assumes startClock() has already been called
79
+ int Stream::_peekNextDigit ()
56
80
{
57
81
int c;
58
82
while (1 ) {
59
- c = timedPeek ();
83
+ c = _timedPeek ();
60
84
if (c < 0 ) return c; // timeout
61
85
if (c == ' -' ) return c;
62
86
if (c >= ' 0' && c <= ' 9' ) return c;
63
87
read (); // discard non-numeric
64
88
}
65
89
}
66
90
91
+ // returns peek of the next digit in the stream or -1 if timeout
92
+ // discards non-numeric characters
93
+ int Stream::peekNextDigit ()
94
+ {
95
+ startClock ();
96
+ return _peekNextDigit ();
97
+ }
98
+
67
99
// Public Methods
68
100
// ////////////////////////////////////////////////////////////
69
101
@@ -75,7 +107,7 @@ void Stream::setTimeout(unsigned long timeout) // sets the maximum number of mi
75
107
// find returns true if the target string is found
76
108
bool Stream::find (char *target)
77
109
{
78
- return findUntil (target, ( char *) " " );
110
+ return findUntil (target, strlen (target), NULL , 0 );
79
111
}
80
112
81
113
// reads data from the stream until the target string of given length is found
@@ -96,32 +128,13 @@ bool Stream::findUntil(char *target, char *terminator)
96
128
// returns true if target string is found, false if terminated or timed out
97
129
bool Stream::findUntil (char *target, size_t targetLen, char *terminator, size_t termLen)
98
130
{
99
- size_t index = 0 ; // maximum target string length is 64k bytes!
100
- size_t termIndex = 0 ;
101
- int c;
102
-
103
- if ( *target == 0 )
104
- return true ; // return true if target is a null string
105
- while ( (c = timedRead ()) > 0 ){
106
-
107
- if (c != target[index ])
108
- index = 0 ; // reset index if any char does not match
109
-
110
- if ( c == target[index ]){
111
- // ////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
112
- if (++index >= targetLen){ // return true if all chars in the target match
113
- return true ;
114
- }
115
- }
116
-
117
- if (termLen > 0 && c == terminator[termIndex]){
118
- if (++termIndex >= termLen)
119
- return false ; // return false if terminate string found before target string
120
- }
121
- else
122
- termIndex = 0 ;
131
+ if (terminator == NULL ) {
132
+ MultiTarget t[1 ] = {{target, targetLen, 0 }};
133
+ return findMulti (t, 1 ) == 0 ? true : false ;
134
+ } else {
135
+ MultiTarget t[2 ] = {{target, targetLen, 0 }, {terminator, termLen, 0 }};
136
+ return findMulti (t, 2 ) == 0 ? true : false ;
123
137
}
124
- return false ;
125
138
}
126
139
127
140
@@ -137,11 +150,12 @@ long Stream::parseInt()
137
150
// this allows format characters (typically commas) in values to be ignored
138
151
long Stream::parseInt (char skipChar)
139
152
{
140
- boolean isNegative = false ;
153
+ bool isNegative = false ;
141
154
long value = 0 ;
142
155
int c;
143
156
144
- c = peekNextDigit ();
157
+ startClock ();
158
+ c = _peekNextDigit ();
145
159
// ignore non numeric leading characters
146
160
if (c < 0 )
147
161
return 0 ; // zero returned if timeout
@@ -173,13 +187,14 @@ float Stream::parseFloat()
173
187
// as above but the given skipChar is ignored
174
188
// this allows format characters (typically commas) in values to be ignored
175
189
float Stream::parseFloat (char skipChar){
176
- boolean isNegative = false ;
177
- boolean isFraction = false ;
190
+ bool isNegative = false ;
191
+ bool isFraction = false ;
178
192
long value = 0 ;
179
- int c;
193
+ char c;
180
194
float fraction = 1.0 ;
181
195
182
- c = peekNextDigit ();
196
+ startClock ();
197
+ c = _peekNextDigit ();
183
198
// ignore non numeric leading characters
184
199
if (c < 0 )
185
200
return 0 ; // zero returned if timeout
@@ -216,9 +231,10 @@ float Stream::parseFloat(char skipChar){
216
231
//
217
232
size_t Stream::readBytes (char *buffer, size_t length)
218
233
{
234
+ startClock ();
219
235
size_t count = 0 ;
220
236
while (count < length) {
221
- int c = timedRead ();
237
+ int c = _timedRead ();
222
238
if (c < 0 ) break ;
223
239
*buffer++ = (char )c;
224
240
count++;
@@ -233,10 +249,11 @@ size_t Stream::readBytes(char *buffer, size_t length)
233
249
234
250
size_t Stream::readBytesUntil (char terminator, char *buffer, size_t length)
235
251
{
252
+ startClock ();
236
253
if (length < 1 ) return 0 ;
237
254
size_t index = 0 ;
238
255
while (index < length) {
239
- int c = timedRead ();
256
+ int c = _timedRead ();
240
257
if (c < 0 || c == terminator) break ;
241
258
*buffer++ = (char )c;
242
259
index ++;
@@ -246,25 +263,88 @@ size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
246
263
247
264
String Stream::readString ()
248
265
{
266
+ startClock ();
249
267
String ret;
250
- int c = timedRead ();
268
+ int c = _timedRead ();
251
269
while (c >= 0 )
252
270
{
253
271
ret += (char )c;
254
- c = timedRead ();
272
+ c = _timedRead ();
255
273
}
256
274
return ret;
257
275
}
258
276
259
277
String Stream::readStringUntil (char terminator)
260
278
{
279
+ startClock ();
261
280
String ret;
262
- int c = timedRead ();
281
+ int c = _timedRead ();
263
282
while (c >= 0 && c != terminator)
264
283
{
265
284
ret += (char )c;
266
- c = timedRead ();
285
+ c = _timedRead ();
267
286
}
268
287
return ret;
269
288
}
270
289
290
+ int Stream::findMulti ( struct Stream ::MultiTarget *targets, int tCount) {
291
+ // any zero length target string automatically matches and would make
292
+ // a mess of the rest of the algorithm.
293
+ for (struct MultiTarget *t = targets; t < targets+tCount; ++t)
294
+ if (t->len <= 0 )
295
+ return t - targets;
296
+
297
+ startClock ();
298
+ while (1 ) {
299
+ int c = _timedRead ();
300
+ if (c < 0 )
301
+ return -1 ;
302
+
303
+ for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
304
+ // the simple case is if we match, deal with that first.
305
+ if (c == t->str [t->index ])
306
+ if (++t->index == t->len )
307
+ return t - targets;
308
+ else
309
+ continue ;
310
+
311
+ // if not we need to walk back and see if we could have matched further
312
+ // down the stream (ie '1112' doesn't match the first position in '11112'
313
+ // but it will match the second position so we can't just reset the current
314
+ // index to 0 when we find a mismatch.
315
+ if (t->index == 0 )
316
+ continue ;
317
+
318
+ int origIndex = t->index ;
319
+ do {
320
+ --t->index ;
321
+ // first check if current char works against the new current index
322
+ if (c != t->str [t->index ])
323
+ continue ;
324
+
325
+ // if it's the only char then we're good, nothing more to check
326
+ if (t->index == 0 ) {
327
+ t->index ++;
328
+ break ;
329
+ }
330
+
331
+ // otherwise we need to check the rest of the found string
332
+ int diff = origIndex - t->index ;
333
+ int i;
334
+ for (i = 0 ; i < t->index ; ++i)
335
+ if (t->str [i] != t->str [i + diff])
336
+ break ;
337
+ // if we successfully got through the previous loop then our current
338
+ // index is good.
339
+ if (i == t->index ) {
340
+ t->index ++;
341
+ break ;
342
+ }
343
+ // otherwise we just try the next index
344
+ } while (t->index );
345
+ }
346
+ }
347
+ // unreachable
348
+ return -1 ;
349
+ }
350
+
0 commit comments