1
0
mirror of https://github.com/arduino/Arduino.git synced 2024-11-29 10:24:12 +01:00

This adds control of Stream::parseInt/float lookahead.

Its default is SKIP_ALL which reflects previous versions.
However SKIP_NONE, and SKIP_WHITESPACE can refine this behaviour.

A parameter used in the protected overloads of parseInt/Float has been
changed from `skipChar` to `ignore`.
This commit is contained in:
Chris--A 2015-06-16 22:50:59 +10:00 committed by Sandeep Mistry
parent 12d0487258
commit 7857216e69
4 changed files with 93 additions and 49 deletions

View File

@ -54,7 +54,7 @@ int Stream::timedPeek()
// returns peek of the next digit in the stream or -1 if timeout // returns peek of the next digit in the stream or -1 if timeout
// discards non-numeric characters // discards non-numeric characters
int Stream::peekNextDigit( bool detectDecimal ) int Stream::peekNextDigit(LookaheadMode lookahead, bool detectDecimal)
{ {
int c; int c;
while (1) { while (1) {
@ -65,6 +65,17 @@ int Stream::peekNextDigit( bool detectDecimal )
c >= '0' && c <= '9' || c >= '0' && c <= '9' ||
detectDecimal && c == '.') return c; detectDecimal && c == '.') return c;
switch( lookahead ){
case SKIP_NONE: return -1; // Fail code.
case SKIP_WHITESPACE:
switch( c ){
case ' ':
case '\t':
case '\r':
case '\n': break;
default: return -1; // Fail code.
}
}
read(); // discard non-numeric read(); // discard non-numeric
} }
} }
@ -114,26 +125,26 @@ bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t
// returns the first valid (long) integer value from the current position. // returns the first valid (long) integer value from the current position.
// initial characters that are not digits (or the minus sign) are skipped // initial characters that are not digits (or the minus sign) are skipped
// function is terminated by the first character that is not a digit. // function is terminated by the first character that is not a digit.
long Stream::parseInt() long Stream::parseInt(LookaheadMode lookahead)
{ {
return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout) return parseInt(lookahead, NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
} }
// as above but a given skipChar is ignored // as above but 'ignore' is ignored
// this allows format characters (typically commas) in values to be ignored // this allows format characters (typically commas) in values to be ignored
long Stream::parseInt(char skipChar) long Stream::parseInt(LookaheadMode lookahead, char ignore)
{ {
bool isNegative = false; bool isNegative = false;
long value = 0; long value = 0;
int c; int c;
c = peekNextDigit(false); c = peekNextDigit(lookahead, false);
// ignore non numeric leading characters // ignore non numeric leading characters
if(c < 0) if(c < 0)
return 0; // zero returned if timeout return 0; // zero returned if timeout
do{ do{
if(c == skipChar) if(c == ignore)
; // ignore this charactor ; // ignore this charactor
else if(c == '-') else if(c == '-')
isNegative = true; isNegative = true;
@ -142,7 +153,7 @@ long Stream::parseInt(char skipChar)
read(); // consume the character we got with peek read(); // consume the character we got with peek
c = timedPeek(); c = timedPeek();
} }
while( (c >= '0' && c <= '9') || c == skipChar ); while( (c >= '0' && c <= '9') || c == ignore );
if(isNegative) if(isNegative)
value = -value; value = -value;
@ -151,27 +162,27 @@ long Stream::parseInt(char skipChar)
// as parseInt but returns a floating point value // as parseInt but returns a floating point value
float Stream::parseFloat() float Stream::parseFloat(LookaheadMode lookahead)
{ {
return parseFloat(NO_SKIP_CHAR); return parseFloat(lookahead, NO_SKIP_CHAR);
} }
// as above but the given skipChar is ignored // as above but the given ignore is ignored
// this allows format characters (typically commas) in values to be ignored // this allows format characters (typically commas) in values to be ignored
float Stream::parseFloat(char skipChar){ float Stream::parseFloat(LookaheadMode lookahead, char ignore){
bool isNegative = false; bool isNegative = false;
bool isFraction = false; bool isFraction = false;
long value = 0; long value = 0;
char c; char c;
float fraction = 1.0; float fraction = 1.0;
c = peekNextDigit(true); c = peekNextDigit(lookahead, true);
// ignore non numeric leading characters // ignore non numeric leading characters
if(c < 0) if(c < 0)
return 0; // zero returned if timeout return 0; // zero returned if timeout
do{ do{
if(c == skipChar) if(c == ignore)
; // ignore ; // ignore
else if(c == '-') else if(c == '-')
isNegative = true; isNegative = true;
@ -185,7 +196,7 @@ float Stream::parseFloat(char skipChar){
read(); // consume the character we got with peek read(); // consume the character we got with peek
c = timedPeek(); c = timedPeek();
} }
while( (c >= '0' && c <= '9') || c == '.' && !isFraction || c == skipChar ); while( (c >= '0' && c <= '9') || c == '.' && !isFraction || c == ignore );
if(isNegative) if(isNegative)
value = -value; value = -value;

View File

@ -28,13 +28,22 @@
// compatability macros for testing // compatability macros for testing
/* /*
#define getInt() parseInt() #define getInt() parseInt()
#define getInt(skipChar) parseInt(skipchar) #define getInt(ignore) parseInt(ignore)
#define getFloat() parseFloat() #define getFloat() parseFloat()
#define getFloat(skipChar) parseFloat(skipChar) #define getFloat(ignore) parseFloat(ignore)
#define getString( pre_string, post_string, buffer, length) #define getString( pre_string, post_string, buffer, length)
readBytesBetween( pre_string, terminator, buffer, length) readBytesBetween( pre_string, terminator, buffer, length)
*/ */
// This enumeration provides the lookahead options for parseInt(), parseFloat()
// The rules set out here are used until either the first valid character is found
// or a time out occurs due to lack of input.
enum LookaheadMode{
SKIP_ALL, // All invalid characters are ignored.
SKIP_NONE, // Nothing is skipped, and the stream is not touched unless the first waiting character is valid.
SKIP_WHITESPACE // Only tabs, spaces, line feeds & carriage returns are skipped.
};
class Stream : public Print class Stream : public Print
{ {
protected: protected:
@ -42,7 +51,7 @@ class Stream : public Print
unsigned long _startMillis; // used for timeout measurement unsigned long _startMillis; // used for timeout measurement
int timedRead(); // private method to read stream with timeout int timedRead(); // private method to read stream with timeout
int timedPeek(); // private method to peek stream with timeout int timedPeek(); // private method to peek stream with timeout
int peekNextDigit( bool detectDecimal ); // returns the next numeric digit in the stream or -1 if timeout int peekNextDigit(LookaheadMode lookahead, bool detectDecimal); // returns the next numeric digit in the stream or -1 if timeout
public: public:
virtual int available() = 0; virtual int available() = 0;
@ -73,11 +82,11 @@ class Stream : public Print
bool findUntil(uint8_t *target, size_t targetLen, char *terminate, size_t termLen) {return findUntil((char *)target, targetLen, terminate, termLen); } bool findUntil(uint8_t *target, size_t targetLen, char *terminate, size_t termLen) {return findUntil((char *)target, targetLen, terminate, termLen); }
long parseInt(); // returns the first valid (long) integer value from the current position. long parseInt(LookaheadMode lookahead = SKIP_ALL); // returns the first valid (long) integer value from the current position.
// initial characters that are not digits (or the minus sign) are skipped // initial characters that are not digits (or the minus sign) are skipped
// integer is terminated by the first character that is not a digit. // integer is terminated by the first character that is not a digit.
float parseFloat(); // float version of parseInt float parseFloat(LookaheadMode lookahead = SKIP_ALL); // float version of parseInt
size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer
size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); } size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); }
@ -94,11 +103,13 @@ class Stream : public Print
String readStringUntil(char terminator); String readStringUntil(char terminator);
protected: protected:
long parseInt(char skipChar); // as above but the given skipChar is ignored long parseInt(char ignore) { return parseInt(SKIP_ALL, ignore); }
// as above but the given skipChar is ignored long parseInt(LookaheadMode lookahead, char ignore); // as above but the given ignore is ignored
// as above but 'ignore' is ignored
// this allows format characters (typically commas) in values to be ignored // this allows format characters (typically commas) in values to be ignored
float parseFloat(char skipChar); // as above but the given skipChar is ignored float parseFloat(char ignore) { return parseFloat(SKIP_ALL, ignore); }
float parseFloat(LookaheadMode lookahead, char ignore); // as above but the given ignore is ignored
struct MultiTarget { struct MultiTarget {
const char *str; // string you're searching for const char *str; // string you're searching for

View File

@ -54,7 +54,7 @@ int Stream::timedPeek()
// returns peek of the next digit in the stream or -1 if timeout // returns peek of the next digit in the stream or -1 if timeout
// discards non-numeric characters // discards non-numeric characters
int Stream::peekNextDigit( bool detectDecimal ) int Stream::peekNextDigit(LookaheadMode lookahead, bool detectDecimal )
{ {
int c; int c;
while (1) { while (1) {
@ -65,6 +65,17 @@ int Stream::peekNextDigit( bool detectDecimal )
c >= '0' && c <= '9' || c >= '0' && c <= '9' ||
detectDecimal && c == '.') return c; detectDecimal && c == '.') return c;
switch( lookahead ){
case SKIP_NONE: return -1; // Fail code.
case SKIP_WHITESPACE:
switch( c ){
case ' ':
case '\t':
case '\r':
case '\n': break;
default: return -1; // Fail code.
}
}
read(); // discard non-numeric read(); // discard non-numeric
} }
} }
@ -114,27 +125,27 @@ bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t
// returns the first valid (long) integer value from the current position. // returns the first valid (long) integer value from the current position.
// initial characters that are not digits (or the minus sign) are skipped // initial characters that are not digits (or the minus sign) are skipped
// function is terminated by the first character that is not a digit. // function is terminated by the first character that is not a digit.
long Stream::parseInt() long Stream::parseInt(LookaheadMode lookahead)
{ {
return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout) return parseInt(lookahead, NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
} }
// as above but a given skipChar is ignored // as above but 'ignore' is ignored
// this allows format characters (typically commas) in values to be ignored // this allows format characters (typically commas) in values to be ignored
long Stream::parseInt(char skipChar) long Stream::parseInt(LookaheadMode lookahead, char ignore)
{ {
bool isNegative = false; bool isNegative = false;
long value = 0; long value = 0;
int c; int c;
c = peekNextDigit(false); c = peekNextDigit(lookahead, false);
// ignore non numeric leading characters // ignore non numeric leading characters
if(c < 0) if(c < 0)
return 0; // zero returned if timeout return 0; // zero returned if timeout
do{ do{
if(c == skipChar) if(c == ignore)
; // ignore this charactor ; // ignore this character
else if(c == '-') else if(c == '-')
isNegative = true; isNegative = true;
else if(c >= '0' && c <= '9') // is c a digit? else if(c >= '0' && c <= '9') // is c a digit?
@ -142,7 +153,7 @@ long Stream::parseInt(char skipChar)
read(); // consume the character we got with peek read(); // consume the character we got with peek
c = timedPeek(); c = timedPeek();
} }
while( (c >= '0' && c <= '9') || c == skipChar ); while( (c >= '0' && c <= '9') || c == ignore );
if(isNegative) if(isNegative)
value = -value; value = -value;
@ -151,27 +162,27 @@ long Stream::parseInt(char skipChar)
// as parseInt but returns a floating point value // as parseInt but returns a floating point value
float Stream::parseFloat() float Stream::parseFloat(LookaheadMode lookahead)
{ {
return parseFloat(NO_SKIP_CHAR); return parseFloat(lookahead, NO_SKIP_CHAR);
} }
// as above but the given skipChar is ignored // as above but the given ignore is ignored
// this allows format characters (typically commas) in values to be ignored // this allows format characters (typically commas) in values to be ignored
float Stream::parseFloat(char skipChar){ float Stream::parseFloat(LookaheadMode lookahead, char ignore){
bool isNegative = false; bool isNegative = false;
bool isFraction = false; bool isFraction = false;
long value = 0; long value = 0;
char c; char c;
float fraction = 1.0; float fraction = 1.0;
c = peekNextDigit(true); c = peekNextDigit(lookahead, true);
// ignore non numeric leading characters // ignore non numeric leading characters
if(c < 0) if(c < 0)
return 0; // zero returned if timeout return 0; // zero returned if timeout
do{ do{
if(c == skipChar) if(c == ignore)
; // ignore ; // ignore
else if(c == '-') else if(c == '-')
isNegative = true; isNegative = true;
@ -185,7 +196,7 @@ float Stream::parseFloat(char skipChar){
read(); // consume the character we got with peek read(); // consume the character we got with peek
c = timedPeek(); c = timedPeek();
} }
while( (c >= '0' && c <= '9') || c == '.' && !isFraction || c == skipChar ); while( (c >= '0' && c <= '9') || c == '.' && !isFraction || c == ignore );
if(isNegative) if(isNegative)
value = -value; value = -value;

View File

@ -28,13 +28,22 @@
// compatability macros for testing // compatability macros for testing
/* /*
#define getInt() parseInt() #define getInt() parseInt()
#define getInt(skipChar) parseInt(skipchar) #define getInt(ignore) parseInt(ignore)
#define getFloat() parseFloat() #define getFloat() parseFloat()
#define getFloat(skipChar) parseFloat(skipChar) #define getFloat(ignore) parseFloat(ignore)
#define getString( pre_string, post_string, buffer, length) #define getString( pre_string, post_string, buffer, length)
readBytesBetween( pre_string, terminator, buffer, length) readBytesBetween( pre_string, terminator, buffer, length)
*/ */
// This enumeration provides the lookahead options for parseInt(), parseFloat()
// The rules set out here are used until either the first valid character is found
// or a time out occurs due to lack of input.
enum LookaheadMode{
SKIP_ALL, // All invalid characters are ignored.
SKIP_NONE, // Nothing is skipped, and the stream is not touched unless the first waiting character is valid.
SKIP_WHITESPACE // Only tabs, spaces, line feeds & carriage returns are skipped.
};
class Stream : public Print class Stream : public Print
{ {
protected: protected:
@ -42,7 +51,7 @@ class Stream : public Print
unsigned long _startMillis; // used for timeout measurement unsigned long _startMillis; // used for timeout measurement
int timedRead(); // private method to read stream with timeout int timedRead(); // private method to read stream with timeout
int timedPeek(); // private method to peek stream with timeout int timedPeek(); // private method to peek stream with timeout
int peekNextDigit( bool detectDecimal ); // returns the next numeric digit in the stream or -1 if timeout int peekNextDigit(LookaheadMode lookahead, bool detectDecimal); // returns the next numeric digit in the stream or -1 if timeout
public: public:
virtual int available() = 0; virtual int available() = 0;
@ -71,11 +80,11 @@ class Stream : public Print
bool findUntil(uint8_t *target, size_t targetLen, char *terminate, size_t termLen) {return findUntil((char *)target, targetLen, terminate, termLen); } bool findUntil(uint8_t *target, size_t targetLen, char *terminate, size_t termLen) {return findUntil((char *)target, targetLen, terminate, termLen); }
long parseInt(); // returns the first valid (long) integer value from the current position. long parseInt(LookaheadMode lookahead = SKIP_ALL); // returns the first valid (long) integer value from the current position.
// initial characters that are not digits (or the minus sign) are skipped // initial characters that are not digits (or the minus sign) are skipped
// integer is terminated by the first character that is not a digit. // integer is terminated by the first character that is not a digit.
float parseFloat(); // float version of parseInt float parseFloat(LookaheadMode lookahead = SKIP_ALL); // float version of parseInt
size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer
size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); } size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); }
@ -92,11 +101,13 @@ class Stream : public Print
String readStringUntil(char terminator); String readStringUntil(char terminator);
protected: protected:
long parseInt(char skipChar); // as above but the given skipChar is ignored long parseInt(char ignore) { return parseInt(SKIP_ALL, ignore); }
// as above but the given skipChar is ignored long parseInt(LookaheadMode lookahead, char ignore); // as above but the given ignore is ignored
// as above but 'ignore' is ignored
// this allows format characters (typically commas) in values to be ignored // this allows format characters (typically commas) in values to be ignored
float parseFloat(char skipChar); // as above but the given skipChar is ignored float parseFloat(char ignore) { return parseFloat(SKIP_ALL, ignore); }
float parseFloat(LookaheadMode lookahead, char ignore); // as above but the given ignore is ignored
struct MultiTarget { struct MultiTarget {
const char *str; // string you're searching for const char *str; // string you're searching for