diff --git a/cores/arduino/Stream.cpp b/cores/arduino/Stream.cpp index 9c581bee1b4e87d001e551423bdb64caf2b382ac..14f972a8037e05f9187b9f56d1c0da0cda873672 100644 --- a/cores/arduino/Stream.cpp +++ b/cores/arduino/Stream.cpp @@ -18,6 +18,8 @@ Created July 2011 parsing functions based on TextFinder library by Michael Margolis + + findMulti/findUntil routines written by Jim Leonard/Xuth */ #include "Arduino.h" @@ -75,7 +77,7 @@ void Stream::setTimeout(unsigned long timeout) // sets the maximum number of mi // find returns true if the target string is found bool Stream::find(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 @@ -96,32 +98,13 @@ bool Stream::findUntil(char *target, char *terminator) // returns true if target string is found, false if terminated or timed out bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen) { - size_t index = 0; // maximum target string length is 64k bytes! - size_t termIndex = 0; - int c; - - if( *target == 0) - return true; // return true if target is a null string - while( (c = timedRead()) > 0){ - - if(c != target[index]) - index = 0; // reset index if any char does not match - - 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; - } - } - - if(termLen > 0 && c == terminator[termIndex]){ - if(++termIndex >= termLen) - return false; // return false if terminate string found before target string - } - else - termIndex = 0; + 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; } - return false; } @@ -137,7 +120,7 @@ long Stream::parseInt() // this allows format characters (typically commas) in values to be ignored long Stream::parseInt(char skipChar) { - boolean isNegative = false; + bool isNegative = false; long value = 0; int c; @@ -173,10 +156,10 @@ float Stream::parseFloat() // as above but the given skipChar is ignored // this allows format characters (typically commas) in values to be ignored float Stream::parseFloat(char skipChar){ - boolean isNegative = false; - boolean isFraction = false; + bool isNegative = false; + bool isFraction = false; long value = 0; - int c; + char c; float fraction = 1.0; c = peekNextDigit(); @@ -268,3 +251,62 @@ String Stream::readStringUntil(char terminator) return ret; } +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; + + 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; + } + + // otherwise we need to check the rest of the found string + int diff = origIndex - t->index; + int i; + for (i = 0; i < t->index; ++i) + if (t->str[i] != t->str[i + diff]) + break; + // 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); + } + } + // unreachable + return -1; +} \ No newline at end of file diff --git a/cores/arduino/Stream.h b/cores/arduino/Stream.h index 97da9f91240866d87b027bc743b84da779abdb2c..0d9a49aca3a49e85ca61268228f9664357e4a212 100644 --- a/cores/arduino/Stream.h +++ b/cores/arduino/Stream.h @@ -1,5 +1,6 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Stream.h - base class for character-based streams. + Copyright (c) 2010 David A. Mellis. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -8,12 +9,14 @@ This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + parsing functions based on TextFinder library by Michael Margolis */ #ifndef Stream_h @@ -94,6 +97,16 @@ 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