source: arduino-1-6-7/trunk/fuentes/arduino-ide-amd64/hardware/arduino/avr/cores/arduino/Stream.cpp @ 4837

Last change on this file since 4837 was 4837, checked in by daduve, 2 years ago

Adding new version

File size: 8.6 KB
Line 
1/*
2 Stream.cpp - adds parsing methods to Stream class
3 Copyright (c) 2008 David A. Mellis.  All right reserved.
4
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.
9
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.
14
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
18
19 Created July 2011
20 parsing functions based on TextFinder library by Michael Margolis
21
22 findMulti/findUntil routines written by Jim Leonard/Xuth
23 */
24
25#include "Arduino.h"
26#include "Stream.h"
27
28#define PARSE_TIMEOUT 1000  // default number of milli-seconds to wait
29
30// private method to read stream with timeout
31int Stream::timedRead()
32{
33  int c;
34  _startMillis = millis();
35  do {
36    c = read();
37    if (c >= 0) return c;
38  } while(millis() - _startMillis < _timeout);
39  return -1;     // -1 indicates timeout
40}
41
42// private method to peek stream with timeout
43int Stream::timedPeek()
44{
45  int c;
46  _startMillis = millis();
47  do {
48    c = peek();
49    if (c >= 0) return c;
50  } while(millis() - _startMillis < _timeout);
51  return -1;     // -1 indicates timeout
52}
53
54// returns peek of the next digit in the stream or -1 if timeout
55// discards non-numeric characters
56int Stream::peekNextDigit(LookaheadMode lookahead, bool detectDecimal)
57{
58  int c;
59  while (1) {
60    c = timedPeek();
61
62    if( c < 0 ||
63        c == '-' ||
64        (c >= '0' && c <= '9') ||
65        (detectDecimal && c == '.')) return c;
66
67    switch( lookahead ){
68        case SKIP_NONE: return -1; // Fail code.
69        case SKIP_WHITESPACE:
70            switch( c ){
71                case ' ':
72                case '\t':
73                case '\r':
74                case '\n': break;
75                default: return -1; // Fail code.
76            }
77        case SKIP_ALL:
78            break;
79    }
80    read();  // discard non-numeric
81  }
82}
83
84// Public Methods
85//////////////////////////////////////////////////////////////
86
87void Stream::setTimeout(unsigned long timeout)  // sets the maximum number of milliseconds to wait
88{
89  _timeout = timeout;
90}
91
92 // find returns true if the target string is found
93bool  Stream::find(char *target)
94{
95  return findUntil(target, strlen(target), NULL, 0);
96}
97
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
100bool Stream::find(char *target, size_t length)
101{
102  return findUntil(target, length, NULL, 0);
103}
104
105// as find but search ends if the terminator string is found
106bool  Stream::findUntil(char *target, char *terminator)
107{
108  return findUntil(target, strlen(target), terminator, strlen(terminator));
109}
110
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
114bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen)
115{
116  if (terminator == NULL) {
117    MultiTarget t[1] = {{target, targetLen, 0}};
118    return findMulti(t, 1) == 0 ? true : false;
119  } else {
120    MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
121    return findMulti(t, 2) == 0 ? true : false;
122  }
123}
124
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.
130long Stream::parseInt(LookaheadMode lookahead, char ignore)
131{
132  bool isNegative = false;
133  long value = 0;
134  int c;
135
136  c = peekNextDigit(lookahead, false);
137  // ignore non numeric leading characters
138  if(c < 0)
139    return 0; // zero returned if timeout
140
141  do{
142    if(c == ignore)
143      ; // ignore this character
144    else if(c == '-')
145      isNegative = true;
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
149    c = timedPeek();
150  }
151  while( (c >= '0' && c <= '9') || c == ignore );
152
153  if(isNegative)
154    value = -value;
155  return value;
156}
157
158// as parseInt but returns a floating point value
159float Stream::parseFloat(LookaheadMode lookahead, char ignore)
160{
161  bool isNegative = false;
162  bool isFraction = false;
163  long value = 0;
164  int c;
165  float fraction = 1.0;
166
167  c = peekNextDigit(lookahead, true);
168    // ignore non numeric leading characters
169  if(c < 0)
170    return 0; // zero returned if timeout
171
172  do{
173    if(c == ignore)
174      ; // ignore
175    else if(c == '-')
176      isNegative = true;
177    else if (c == '.')
178      isFraction = true;
179    else if(c >= '0' && c <= '9')  {      // is c a digit?
180      value = value * 10 + c - '0';
181      if(isFraction)
182         fraction *= 0.1;
183    }
184    read();  // consume the character we got with peek
185    c = timedPeek();
186  }
187  while( (c >= '0' && c <= '9')  || (c == '.' && !isFraction) || c == ignore );
188
189  if(isNegative)
190    value = -value;
191  if(isFraction)
192    return value * fraction;
193  else
194    return value;
195}
196
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.
201//
202size_t Stream::readBytes(char *buffer, size_t length)
203{
204  size_t count = 0;
205  while (count < length) {
206    int c = timedRead();
207    if (c < 0) break;
208    *buffer++ = (char)c;
209    count++;
210  }
211  return count;
212}
213
214
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)
218
219size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
220{
221  if (length < 1) return 0;
222  size_t index = 0;
223  while (index < length) {
224    int c = timedRead();
225    if (c < 0 || c == terminator) break;
226    *buffer++ = (char)c;
227    index++;
228  }
229  return index; // return number of characters, not including null terminator
230}
231
232String Stream::readString()
233{
234  String ret;
235  int c = timedRead();
236  while (c >= 0)
237  {
238    ret += (char)c;
239    c = timedRead();
240  }
241  return ret;
242}
243
244String Stream::readStringUntil(char terminator)
245{
246  String ret;
247  int c = timedRead();
248  while (c >= 0 && c != terminator)
249  {
250    ret += (char)c;
251    c = timedRead();
252  }
253  return ret;
254}
255
256int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) {
257  // any zero length target string automatically matches and would make
258  // a mess of the rest of the algorithm.
259  for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
260    if (t->len <= 0)
261      return t - targets;
262  }
263
264  while (1) {
265    int c = timedRead();
266    if (c < 0)
267      return -1;
268
269    for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
270      // the simple case is if we match, deal with that first.
271      if (c == t->str[t->index]) {
272        if (++t->index == t->len)
273          return t - targets;
274        else
275          continue;
276      }
277
278      // if not we need to walk back and see if we could have matched further
279      // down the stream (ie '1112' doesn't match the first position in '11112'
280      // but it will match the second position so we can't just reset the current
281      // index to 0 when we find a mismatch.
282      if (t->index == 0)
283        continue;
284
285      int origIndex = t->index;
286      do {
287        --t->index;
288        // first check if current char works against the new current index
289        if (c != t->str[t->index])
290          continue;
291
292        // if it's the only char then we're good, nothing more to check
293        if (t->index == 0) {
294          t->index++;
295          break;
296        }
297
298        // otherwise we need to check the rest of the found string
299        int diff = origIndex - t->index;
300        size_t i;
301        for (i = 0; i < t->index; ++i) {
302          if (t->str[i] != t->str[i + diff])
303            break;
304        }
305
306        // if we successfully got through the previous loop then our current
307        // index is good.
308        if (i == t->index) {
309          t->index++;
310          break;
311        }
312
313        // otherwise we just try the next index
314      } while (t->index);
315    }
316  }
317  // unreachable
318  return -1;
319}
Note: See TracBrowser for help on using the repository browser.