2 Stream.cpp - adds parsing methods to Stream class
3 Copyright (c) 2008 David A. Mellis. All right reserved.
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 parsing functions based on TextFinder library by Michael Margolis
22 findMulti/findUntil routines written by Jim Leonard/Xuth
28 #define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait
30 // protected method to read stream with timeout
31 int Stream::timedRead()
34 _startMillis = millis();
38 } while(millis() - _startMillis < _timeout);
39 return -1; // -1 indicates timeout
42 // protected method to peek stream with timeout
43 int Stream::timedPeek()
46 _startMillis = millis();
50 } while(millis() - _startMillis < _timeout);
51 return -1; // -1 indicates timeout
54 // returns peek of the next digit in the stream or -1 if timeout
55 // discards non-numeric characters
56 int Stream::peekNextDigit(LookaheadMode lookahead, bool detectDecimal)
64 (c >= '0' && c <= '9') ||
65 (detectDecimal && c == '.')) return c;
68 case SKIP_NONE: return -1; // Fail code.
75 default: return -1; // Fail code.
80 read(); // discard non-numeric
85 //////////////////////////////////////////////////////////////
87 void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait
92 // find returns true if the target string is found
93 bool Stream::find(char *target)
95 return findUntil(target, strlen(target), NULL, 0);
98 // reads data from the stream until the target string of given length is found
99 // returns true if target string is found, false if timed out
100 bool Stream::find(char *target, size_t length)
102 return findUntil(target, length, NULL, 0);
105 // as find but search ends if the terminator string is found
106 bool Stream::findUntil(char *target, char *terminator)
108 return findUntil(target, strlen(target), terminator, strlen(terminator));
111 // reads data from the stream until the target string of the given length is found
112 // search terminated if the terminator string is found
113 // returns true if target string is found, false if terminated or timed out
114 bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen)
116 if (terminator == NULL) {
117 MultiTarget t[1] = {{target, targetLen, 0}};
118 return findMulti(t, 1) == 0 ? true : false;
120 MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
121 return findMulti(t, 2) == 0 ? true : false;
125 // returns the first valid (long) integer value from the current position.
126 // lookahead determines how parseInt looks ahead in the stream.
127 // See LookaheadMode enumeration at the top of the file.
128 // Lookahead is terminated by the first character that is not a valid part of an integer.
129 // Once parsing commences, 'ignore' will be skipped in the stream.
130 long Stream::parseInt(LookaheadMode lookahead, char ignore)
132 bool isNegative = false;
136 c = peekNextDigit(lookahead, false);
137 // ignore non numeric leading characters
139 return 0; // zero returned if timeout
143 ; // ignore this character
146 else if(c >= '0' && c <= '9') // is c a digit?
147 value = value * 10 + c - '0';
148 read(); // consume the character we got with peek
151 while( (c >= '0' && c <= '9') || c == ignore );
158 // as parseInt but returns a floating point value
159 float Stream::parseFloat(LookaheadMode lookahead, char ignore)
161 bool isNegative = false;
162 bool isFraction = false;
165 float fraction = 1.0;
167 c = peekNextDigit(lookahead, true);
168 // ignore non numeric leading characters
170 return 0; // zero returned if timeout
179 else if(c >= '0' && c <= '9') { // is c a digit?
180 value = value * 10 + c - '0';
184 read(); // consume the character we got with peek
187 while( (c >= '0' && c <= '9') || (c == '.' && !isFraction) || c == ignore );
192 return value * fraction;
197 // read characters from stream into buffer
198 // terminates if length characters have been read, or timeout (see setTimeout)
199 // returns the number of characters placed in the buffer
200 // the buffer is NOT null terminated.
202 size_t Stream::readBytes(char *buffer, size_t length)
205 while (count < length) {
215 // as readBytes with terminator character
216 // terminates if length characters have been read, timeout, or if the terminator character detected
217 // returns the number of characters placed in the buffer (0 means no valid data found)
219 size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
222 while (index < length) {
224 if (c < 0 || c == terminator) break;
228 return index; // return number of characters, not including null terminator
231 String Stream::readString()
243 String Stream::readStringUntil(char terminator)
247 while (c >= 0 && c != terminator)
255 int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) {
256 // any zero length target string automatically matches and would make
257 // a mess of the rest of the algorithm.
258 for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
268 for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
269 // the simple case is if we match, deal with that first.
270 if (c == t->str[t->index]) {
271 if (++t->index == t->len)
277 // if not we need to walk back and see if we could have matched further
278 // down the stream (ie '1112' doesn't match the first position in '11112'
279 // but it will match the second position so we can't just reset the current
280 // index to 0 when we find a mismatch.
284 int origIndex = t->index;
287 // first check if current char works against the new current index
288 if (c != t->str[t->index])
291 // if it's the only char then we're good, nothing more to check
297 // otherwise we need to check the rest of the found string
298 int diff = origIndex - t->index;
300 for (i = 0; i < t->index; ++i) {
301 if (t->str[i] != t->str[i + diff])
305 // if we successfully got through the previous loop then our current
312 // otherwise we just try the next index