]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - tmk_core/protocol/usb_hid/arduino-1.8.13/cores/arduino/Stream.cpp
usb_hid: Update arduino cores to 1.8.13
[max/tmk_keyboard.git] / tmk_core / protocol / usb_hid / arduino-1.8.13 / cores / arduino / Stream.cpp
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 // protected method to read stream with timeout
31 int 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 // protected method to peek stream with timeout
43 int 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
56 int 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
87 void 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
93 bool  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
100 bool 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
106 bool  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
114 bool 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.
130 long 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
159 float 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 //
202 size_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
219 size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
220 {
221   size_t index = 0;
222   while (index < length) {
223     int c = timedRead();
224     if (c < 0 || c == terminator) break;
225     *buffer++ = (char)c;
226     index++;
227   }
228   return index; // return number of characters, not including null terminator
229 }
230
231 String Stream::readString()
232 {
233   String ret;
234   int c = timedRead();
235   while (c >= 0)
236   {
237     ret += (char)c;
238     c = timedRead();
239   }
240   return ret;
241 }
242
243 String Stream::readStringUntil(char terminator)
244 {
245   String ret;
246   int c = timedRead();
247   while (c >= 0 && c != terminator)
248   {
249     ret += (char)c;
250     c = timedRead();
251   }
252   return ret;
253 }
254
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) {
259     if (t->len <= 0)
260       return t - targets;
261   }
262
263   while (1) {
264     int c = timedRead();
265     if (c < 0)
266       return -1;
267
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)
272           return t - targets;
273         else
274           continue;
275       }
276
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.
281       if (t->index == 0)
282         continue;
283
284       int origIndex = t->index;
285       do {
286         --t->index;
287         // first check if current char works against the new current index
288         if (c != t->str[t->index])
289           continue;
290
291         // if it's the only char then we're good, nothing more to check
292         if (t->index == 0) {
293           t->index++;
294           break;
295         }
296
297         // otherwise we need to check the rest of the found string
298         int diff = origIndex - t->index;
299         size_t i;
300         for (i = 0; i < t->index; ++i) {
301           if (t->str[i] != t->str[i + diff])
302             break;
303         }
304
305         // if we successfully got through the previous loop then our current
306         // index is good.
307         if (i == t->index) {
308           t->index++;
309           break;
310         }
311
312         // otherwise we just try the next index
313       } while (t->index);
314     }
315   }
316   // unreachable
317   return -1;
318 }