arduino-esp32/cores/esp32/Stream.cpp
Lucas Saavedra Vaz da5c6ab9ae
Refactor repository with pre-commit hooks (#9515)
* Add Config

* Add Cache and remove pre-commit action

* [pre-commit.ci lite] apply automatic fixes

* Remove freeze

* Fix

* Update action

* Use latest stable Python 3 version

* Improve caching

* Improve cache tag

* Improve bot message

* fix(typos): Fix typos

* fix(typos): Fix more typos

* refactor(udp_server): Convert script from Python 2 to 3

* Fix whitespace

* Clang-format fixes

* Prettier fixes

* Black formatting

* Manual fixes

* Line endings

* Fix flake and make Vale manual

* Fix flake and reformat

---------

Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Rodrigo Garcia <rodrigo.garcia@espressif.com>
2024-04-15 19:40:56 +03:00

321 lines
8.7 KiB
C++

/*
Stream.cpp - adds parsing methods to Stream class
Copyright (c) 2008 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
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
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.
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
Created July 2011
parsing functions based on TextFinder library by Michael Margolis
*/
#include "Arduino.h"
#include "Stream.h"
#include "esp32-hal.h"
#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait
#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
// private method to read stream with timeout
int Stream::timedRead() {
int c;
_startMillis = millis();
do {
c = read();
if (c >= 0) {
return c;
}
} while (millis() - _startMillis < _timeout);
return -1; // -1 indicates timeout
}
// private method to peek stream with timeout
int Stream::timedPeek() {
int c;
_startMillis = millis();
do {
c = peek();
if (c >= 0) {
return c;
}
} while (millis() - _startMillis < _timeout);
return -1; // -1 indicates timeout
}
// returns peek of the next digit in the stream or -1 if timeout
// discards non-numeric characters
int Stream::peekNextDigit() {
int c;
while (1) {
c = timedPeek();
if (c < 0) {
return c; // timeout
}
if (c == '-') {
return c;
}
if (c >= '0' && c <= '9') {
return c;
}
read(); // discard non-numeric
}
}
// Public Methods
//////////////////////////////////////////////////////////////
void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait
{
_timeout = timeout;
}
unsigned long Stream::getTimeout(void) {
return _timeout;
}
// find returns true if the target string is found
bool Stream::find(const char *target) {
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);
}
// as find but search ends if the terminator string is found
bool Stream::findUntil(const char *target, const char *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) {
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;
}
}
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;
size_t 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;
}
// returns the first valid (long) integer value from the current position.
// initial characters that are not digits (or the minus sign) are skipped
// function is terminated by the first character that is not a digit.
long Stream::parseInt() {
return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
}
// as above but a given skipChar is ignored
// this allows format characters (typically commas) in values to be ignored
long Stream::parseInt(char skipChar) {
boolean isNegative = false;
long value = 0;
int c;
c = peekNextDigit();
// ignore non numeric leading characters
if (c < 0) {
return 0; // zero returned if timeout
}
do {
if (c == skipChar) {
} // ignore this character
else if (c == '-') {
isNegative = true;
} else if (c >= '0' && c <= '9') { // is c a digit?
value = value * 10 + c - '0';
}
read(); // consume the character we got with peek
c = timedPeek();
} while ((c >= '0' && c <= '9') || c == skipChar);
if (isNegative) {
value = -value;
}
return value;
}
// as parseInt but returns a floating point value
float Stream::parseFloat() {
return parseFloat(NO_SKIP_CHAR);
}
// 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;
long value = 0;
int c;
float fraction = 1.0;
c = peekNextDigit();
// ignore non numeric leading characters
if (c < 0) {
return 0; // zero returned if timeout
}
do {
if (c == skipChar) {
} // ignore
else if (c == '-') {
isNegative = true;
} else if (c == '.') {
isFraction = true;
} else if (c >= '0' && c <= '9') { // is c a digit?
value = value * 10 + c - '0';
if (isFraction) {
fraction *= 0.1f;
}
}
read(); // consume the character we got with peek
c = timedPeek();
} while ((c >= '0' && c <= '9') || c == '.' || c == skipChar);
if (isNegative) {
value = -value;
}
if (isFraction) {
return value * fraction;
} else {
return value;
}
}
// read characters from stream into buffer
// terminates if length characters have been read, or timeout (see setTimeout)
// returns the number of characters placed in the buffer
// the buffer is NOT null terminated.
//
size_t Stream::readBytes(char *buffer, size_t length) {
size_t count = 0;
while (count < length) {
int c = timedRead();
if (c < 0) {
break;
}
*buffer++ = (char)c;
count++;
}
return count;
}
// as readBytes with terminator character
// terminates if length characters have been read, timeout, or if the terminator character detected
// returns the number of characters placed in the buffer (0 means no valid data found)
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) {
if (length < 1) {
return 0;
}
size_t index = 0;
while (index < length) {
int c = timedRead();
if (c < 0 || c == terminator) {
break;
}
*buffer++ = (char)c;
index++;
}
return index; // return number of characters, not including null terminator
}
String Stream::readString() {
String ret;
int c = timedRead();
while (c >= 0) {
ret += (char)c;
c = timedRead();
}
return ret;
}
String Stream::readStringUntil(char terminator) {
String ret;
int c = timedRead();
while (c >= 0 && c != terminator) {
ret += (char)c;
c = timedRead();
}
return ret;
}