Skip to content

Corrections of Stream.Find, FindUntil and added FindMulti - like AVR-Core Libraries #3442

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 69 additions & 26 deletions cores/esp32/Stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,58 +87,101 @@ unsigned long Stream::getTimeout(void) {
}

// find returns true if the target string is found
bool Stream::find(const char *target)
bool Stream::find(const char *target)
{
return findUntil(target, (char*) "");
return findUntil(target, strlen(target), NULL, 0);
}

// reads data from the stream until the target string of given length is found
// returns true if target string is found, false if timed out
bool Stream::find(const char *target, size_t length)
{
return findUntil(target, length, NULL, 0);
return findUntil(target, length, NULL, 0);
}

// as find but search ends if the terminator string is found
bool Stream::findUntil(const char *target, const char *terminator)
bool Stream::findUntil(const char *target, const char *terminator)
{
return findUntil(target, strlen(target), terminator, strlen(terminator));
return findUntil(target, strlen(target), terminator, strlen(terminator));
}

// reads data from the stream until the target string of the given length is found
// search terminated if the terminator string is found
// returns true if target string is found, false if terminated or timed out
bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen)
{
size_t index = 0; // maximum target string length is 64k bytes!
size_t termIndex = 0;
int c;
if (terminator == NULL) {
MultiTarget t[1] = {{target, targetLen, 0}};
return findMulti(t, 1) == 0 ? true : false;
} else {
MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
return findMulti(t, 2) == 0 ? true : false;
}
}

if(*target == 0) {
return true; // return true if target is a null string
}
while((c = timedRead()) > 0) {
int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) {
// any zero length target string automatically matches and would make
// a mess of the rest of the algorithm.
for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
if (t->len <= 0)
return t - targets;
}

if(c != target[index]) {
index = 0; // reset index if any char does not match
while (1) {
int c = timedRead();
if (c < 0)
return -1;

for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
// the simple case is if we match, deal with that first.
if (c == t->str[t->index]) {
if (++t->index == t->len)
return t - targets;
else
continue;
}

// if not we need to walk back and see if we could have matched further
// down the stream (ie '1112' doesn't match the first position in '11112'
// but it will match the second position so we can't just reset the current
// index to 0 when we find a mismatch.
if (t->index == 0)
continue;

int origIndex = t->index;
do {
--t->index;
// first check if current char works against the new current index
if (c != t->str[t->index])
continue;

// if it's the only char then we're good, nothing more to check
if (t->index == 0) {
t->index++;
break;
}

if(c == target[index]) {
//////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
if(++index >= targetLen) { // return true if all chars in the target match
return true;
}
// otherwise we need to check the rest of the found string
int diff = origIndex - t->index;
size_t i;
for (i = 0; i < t->index; ++i) {
if (t->str[i] != t->str[i + diff])
break;
}

if(termLen > 0 && c == terminator[termIndex]) {
if(++termIndex >= termLen) {
return false; // return false if terminate string found before target string
}
} else {
termIndex = 0;
// if we successfully got through the previous loop then our current
// index is good.
if (i == t->index) {
t->index++;
break;
}

// otherwise we just try the next index
} while (t->index);
}
return false;
}
// unreachable
return -1;
}

// returns the first valid (long) integer value from the current position.
Expand Down
12 changes: 12 additions & 0 deletions cores/esp32/Stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class Stream: public Print

void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
unsigned long getTimeout(void);

bool find(const char *target); // reads data from the stream until the target string is found
bool find(uint8_t *target)
{
Expand Down Expand Up @@ -123,6 +124,17 @@ class Stream: public Print
// this allows format characters (typically commas) in values to be ignored

float parseFloat(char skipChar); // as above but the given skipChar is ignored

struct MultiTarget {
const char *str; // string you're searching for
size_t len; // length of string you're searching for
size_t index; // index used by the search routine.
};

// This allows you to search for an arbitrary number of strings.
// Returns index of the target that is found first or -1 if timeout occurs.
int findMulti(struct MultiTarget *targets, int tCount);

};

#endif