Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.bak
3 changes: 3 additions & 0 deletions .mbedignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
./examples/*
./keywords.txt
./library.properties
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ This library has a higher RAM footprint compared to similar libraries, because i
Quickstart
----------

Search for "CommandParser" in the Arduino Library Manager, and install it. Now you can try a quick example sketch:
Search for "CommandParser" in the Arduino Library Manager, and install it. Now you can try a quick example sketch that accepts commands over serial:

```cpp
#include <CommandParser.h>
Expand Down Expand Up @@ -65,7 +65,7 @@ More examples:
Grammar
-------

Commands are null-terminated strings that largely follow this PEG grammar:
Commands are null-terminated strings that largely follow this [PEG grammar](https://en.wikipedia.org/wiki/Parsing_expression_grammar):

```
COMMAND <- COMMAND_NAME (' '+ (ARG_STRING / ARG_DOUBLE / ARG_INT64 / ARG_UINT64))* ' '*
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=CommandParser
version=1.1.0
version=1.1.1
author=Anthony Zhang (Uberi) <me@anthonyz.ca>
maintainer=Anthony Zhang (Uberi) <me@anthonyz.ca>
sentence=An Arduino library for parsing commands of the form COMMAND_NAME ARG1 ARG2 ARG3.
Expand Down
22 changes: 19 additions & 3 deletions src/CommandParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,18 @@ size_t strlcpy(char *dst, const char *src, size_t size) {
}
*/

// avr-libc lacks strtoll and strtoull (see https://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html), so we'll implement our own to be compatible with AVR boards such as the Arduino Uno
// typically you would use this like: `int64_t result; size_t bytesRead = strToInt<int64_t>("-0x123", &result, std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max())`
// avr-libc lacks strtoll and strtoull (see https://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html),
// so we'll implement our own to be compatible with AVR boards such as the Arduino Uno
// typically you would use this like:
// `int64_t result; size_t bytesRead = strToInt<int64_t>("-0x123", &result, std::numeric_limits<int64_t>::min(),
// std::numeric_limits<int64_t>::max())`
// if an error occurs during parsing, `bytesRead` will be 0 and `result` will be an arbitrary value
template<typename T> size_t strToInt(const char* buf, T *value, T min_value, T max_value) {
size_t position = 0;

// parse sign if necessary
bool isNegative = false;
if (min_value < 0 && buf[position] == '+' || buf[position] == '-') {
if (min_value < 0 && (buf[position] == '+' || buf[position] == '-')) {
isNegative = buf[position] == '-';
position ++;
}
Expand Down Expand Up @@ -68,6 +71,7 @@ template<typename T> size_t strToInt(const char* buf, T *value, T min_value, T m

position ++;
}
if(isNegative) *value *= -1;
return digit == -1 ? 0 : position; // ensure that there is at least one digit
}

Expand Down Expand Up @@ -212,7 +216,13 @@ class CommandParser {
break;
}
case 'u': { // uint64_t argument
#if defined ULONG_LONG_MAX // GNU style
size_t bytesRead = strToInt<uint64_t>(command, &commandArgs[i].asUInt64, 0, ULONG_LONG_MAX);
#elif defined ULLONG_MAX // ISO C style
size_t bytesRead = strToInt<uint64_t>(command, &commandArgs[i].asUInt64, 0, ULLONG_MAX);
#else
#error "ULONG_LONG_MAX not defined"
#endif
if (bytesRead == 0 || (command[bytesRead] != ' ' && command[bytesRead] != '\0')) {
snprintf(response, MAX_RESPONSE_SIZE, "parse error: invalid uint64_t for arg %d", i + 1);
return false;
Expand All @@ -221,7 +231,13 @@ class CommandParser {
break;
}
case 'i': { // int64_t argument
#if defined LONG_LONG_MAX // GNU style
size_t bytesRead = strToInt<int64_t>(command, &commandArgs[i].asInt64, LONG_LONG_MIN, LONG_LONG_MAX);
#elif defined LLONG_MAX // ISO C style
size_t bytesRead = strToInt<int64_t>(command, &commandArgs[i].asInt64, LLONG_MIN, LLONG_MAX);
#else
#error "LONG_LONG_MAX not defined"
#endif
if (bytesRead == 0 || (command[bytesRead] != ' ' && command[bytesRead] != '\0')) {
snprintf(response, MAX_RESPONSE_SIZE, "parse error: invalid int64_t for arg %d", i + 1);
return false;
Expand Down