Skip to content

Commit c25dc61

Browse files
committed
Merge pull request #2814 from facchinm/test_pr2696
Fix findUntil in Stream library
2 parents 948bf20 + f43a7a6 commit c25dc61

File tree

4 files changed

+171
-60
lines changed

4 files changed

+171
-60
lines changed

hardware/arduino/avr/cores/arduino/Stream.cpp

Lines changed: 72 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
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"
@@ -75,7 +77,7 @@ void Stream::setTimeout(unsigned long timeout) // sets the maximum number of mi
7577
// find returns true if the target string is found
7678
bool Stream::find(char *target)
7779
{
78-
return findUntil(target, (char*)"");
80+
return findUntil(target, strlen(target), NULL, 0);
7981
}
8082

8183
// reads data from the stream until the target string of given length is found
@@ -96,32 +98,13 @@ bool Stream::findUntil(char *target, char *terminator)
9698
// returns true if target string is found, false if terminated or timed out
9799
bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen)
98100
{
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;
101+
if (terminator == NULL) {
102+
MultiTarget t[1] = {{target, targetLen, 0}};
103+
return findMulti(t, 1) == 0 ? true : false;
104+
} else {
105+
MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
106+
return findMulti(t, 2) == 0 ? true : false;
123107
}
124-
return false;
125108
}
126109

127110

@@ -137,7 +120,7 @@ long Stream::parseInt()
137120
// this allows format characters (typically commas) in values to be ignored
138121
long Stream::parseInt(char skipChar)
139122
{
140-
boolean isNegative = false;
123+
bool isNegative = false;
141124
long value = 0;
142125
int c;
143126

@@ -173,10 +156,10 @@ float Stream::parseFloat()
173156
// as above but the given skipChar is ignored
174157
// this allows format characters (typically commas) in values to be ignored
175158
float Stream::parseFloat(char skipChar){
176-
boolean isNegative = false;
177-
boolean isFraction = false;
159+
bool isNegative = false;
160+
bool isFraction = false;
178161
long value = 0;
179-
int c;
162+
char c;
180163
float fraction = 1.0;
181164

182165
c = peekNextDigit();
@@ -268,3 +251,62 @@ String Stream::readStringUntil(char terminator)
268251
return ret;
269252
}
270253

254+
int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) {
255+
// any zero length target string automatically matches and would make
256+
// a mess of the rest of the algorithm.
257+
for (struct MultiTarget *t = targets; t < targets+tCount; ++t)
258+
if (t->len <= 0)
259+
return t - targets;
260+
261+
while(1) {
262+
int c = timedRead();
263+
if (c < 0)
264+
return -1;
265+
266+
for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
267+
// the simple case is if we match, deal with that first.
268+
if (c == t->str[t->index])
269+
if (++t->index == t->len)
270+
return t - targets;
271+
else
272+
continue;
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+
int origIndex = t->index;
282+
do {
283+
--t->index;
284+
// first check if current char works against the new current index
285+
if (c != t->str[t->index])
286+
continue;
287+
288+
// if it's the only char then we're good, nothing more to check
289+
if (t->index == 0) {
290+
t->index++;
291+
break;
292+
}
293+
294+
// otherwise we need to check the rest of the found string
295+
int diff = origIndex - t->index;
296+
int i;
297+
for (i = 0; i < t->index; ++i)
298+
if (t->str[i] != t->str[i + diff])
299+
break;
300+
// if we successfully got through the previous loop then our current
301+
// index is good.
302+
if (i == t->index) {
303+
t->index++;
304+
break;
305+
}
306+
// otherwise we just try the next index
307+
} while (t->index);
308+
}
309+
}
310+
// unreachable
311+
return -1;
312+
}

hardware/arduino/avr/cores/arduino/Stream.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,20 @@ class Stream : public Print
9797
// this allows format characters (typically commas) in values to be ignored
9898

9999
float parseFloat(char skipChar); // as above but the given skipChar is ignored
100+
101+
public:
102+
struct MultiTarget {
103+
const char *str; // string you're searching for
104+
size_t len; // length of string you're searching for
105+
size_t index; // index used by the search routine.
106+
};
107+
108+
// This allows you to search for an arbitrary number of strings.
109+
// Returns index of the target that is found first or -1 if timeout occurs.
110+
int findMulti(struct MultiTarget *targets, int tCount);
111+
112+
100113
};
101114

115+
102116
#endif

hardware/arduino/sam/cores/arduino/Stream.cpp

Lines changed: 72 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
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"
@@ -75,7 +77,7 @@ void Stream::setTimeout(unsigned long timeout) // sets the maximum number of mi
7577
// find returns true if the target string is found
7678
bool Stream::find(char *target)
7779
{
78-
return findUntil(target, (char*)"");
80+
return findUntil(target, strlen(target), NULL, 0);
7981
}
8082

8183
// reads data from the stream until the target string of given length is found
@@ -96,32 +98,13 @@ bool Stream::findUntil(char *target, char *terminator)
9698
// returns true if target string is found, false if terminated or timed out
9799
bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen)
98100
{
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;
101+
if (terminator == NULL) {
102+
MultiTarget t[1] = {{target, targetLen, 0}};
103+
return findMulti(t, 1) == 0 ? true : false;
104+
} else {
105+
MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
106+
return findMulti(t, 2) == 0 ? true : false;
123107
}
124-
return false;
125108
}
126109

127110

@@ -137,7 +120,7 @@ long Stream::parseInt()
137120
// this allows format characters (typically commas) in values to be ignored
138121
long Stream::parseInt(char skipChar)
139122
{
140-
boolean isNegative = false;
123+
bool isNegative = false;
141124
long value = 0;
142125
int c;
143126

@@ -173,10 +156,10 @@ float Stream::parseFloat()
173156
// as above but the given skipChar is ignored
174157
// this allows format characters (typically commas) in values to be ignored
175158
float Stream::parseFloat(char skipChar){
176-
boolean isNegative = false;
177-
boolean isFraction = false;
159+
bool isNegative = false;
160+
bool isFraction = false;
178161
long value = 0;
179-
int c;
162+
char c;
180163
float fraction = 1.0;
181164

182165
c = peekNextDigit();
@@ -268,3 +251,62 @@ String Stream::readStringUntil(char terminator)
268251
return ret;
269252
}
270253

254+
int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) {
255+
// any zero length target string automatically matches and would make
256+
// a mess of the rest of the algorithm.
257+
for (struct MultiTarget *t = targets; t < targets+tCount; ++t)
258+
if (t->len <= 0)
259+
return t - targets;
260+
261+
while(1) {
262+
int c = timedRead();
263+
if (c < 0)
264+
return -1;
265+
266+
for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
267+
// the simple case is if we match, deal with that first.
268+
if (c == t->str[t->index])
269+
if (++t->index == t->len)
270+
return t - targets;
271+
else
272+
continue;
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+
int origIndex = t->index;
282+
do {
283+
--t->index;
284+
// first check if current char works against the new current index
285+
if (c != t->str[t->index])
286+
continue;
287+
288+
// if it's the only char then we're good, nothing more to check
289+
if (t->index == 0) {
290+
t->index++;
291+
break;
292+
}
293+
294+
// otherwise we need to check the rest of the found string
295+
int diff = origIndex - t->index;
296+
int i;
297+
for (i = 0; i < t->index; ++i)
298+
if (t->str[i] != t->str[i + diff])
299+
break;
300+
// if we successfully got through the previous loop then our current
301+
// index is good.
302+
if (i == t->index) {
303+
t->index++;
304+
break;
305+
}
306+
// otherwise we just try the next index
307+
} while (t->index);
308+
}
309+
}
310+
// unreachable
311+
return -1;
312+
}

hardware/arduino/sam/cores/arduino/Stream.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,19 @@ class Stream : public Print
9797
// this allows format characters (typically commas) in values to be ignored
9898

9999
float parseFloat(char skipChar); // as above but the given skipChar is ignored
100+
101+
public:
102+
struct MultiTarget {
103+
const char *str; // string you're searching for
104+
size_t len; // length of string you're searching for
105+
size_t index; // index used by the search routine.
106+
};
107+
108+
// This allows you to search for an arbitrary number of strings.
109+
// Returns index of the target that is found first or -1 if timeout occurs.
110+
int findMulti(struct MultiTarget *targets, int tCount);
111+
112+
100113
};
101114

102115
#endif

0 commit comments

Comments
 (0)