{"id":16131908,"url":"https://github.com/uberi/arduino-commandparser","last_synced_at":"2025-03-18T14:31:29.264Z","repository":{"id":48519237,"uuid":"249643808","full_name":"Uberi/Arduino-CommandParser","owner":"Uberi","description":"Complete command parser library for Arduino-compatibles.","archived":false,"fork":false,"pushed_at":"2021-04-30T08:05:09.000Z","size":11,"stargazers_count":47,"open_issues_count":8,"forks_count":20,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-02-28T10:18:07.799Z","etag":null,"topics":["arduino","arduino-library"],"latest_commit_sha":null,"homepage":"https://www.arduinolibraries.info/libraries/command-parser","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Uberi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-24T07:45:04.000Z","updated_at":"2024-12-09T22:23:47.000Z","dependencies_parsed_at":"2022-08-25T15:11:52.913Z","dependency_job_id":null,"html_url":"https://github.com/Uberi/Arduino-CommandParser","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Uberi%2FArduino-CommandParser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Uberi%2FArduino-CommandParser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Uberi%2FArduino-CommandParser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Uberi%2FArduino-CommandParser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Uberi","download_url":"https://codeload.github.com/Uberi/Arduino-CommandParser/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243933429,"owners_count":20370986,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","arduino-library"],"created_at":"2024-10-09T22:28:12.265Z","updated_at":"2025-03-18T14:31:28.994Z","avatar_url":"https://github.com/Uberi.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"CommandParser\n=============\n\nAn Arduino library for parsing commands of the form `COMMAND_NAME ARG1 ARG2 ARG3 ...`.\n\nFeatures:\n\n* **No dynamic memory allocation**.\n* Compile-time-**configurable resource limits**.\n* Strongly typed arguments with **strict input validation** (including integer overflow detection!).\n* Friendly **error messages** for invalid inputs (e.g., `parse error: invalid double for arg 2` if the command's second argument cannot be parsed as a double).\n* Support for **escape sequences** in string arguments (e.g., `SOME_COMMAND \"\\\"\\x41\\r\\n\\t\\\\\"`).\n\nThis library works with all Arduino-compatible boards.\n\nThis library has a higher RAM footprint compared to similar libraries, because it fully parses each argument instead of leaving them as strings. An instance of `CommandParser\u003c\u003e` in RAM is 456 bytes on a 32-bit Arduino Nano 33 BLE.\n\nQuickstart\n----------\n\nSearch for \"CommandParser\" in the Arduino Library Manager, and install it. Now you can try a quick example sketch:\n\n```cpp\n#include \u003cCommandParser.h\u003e\n\ntypedef CommandParser\u003c\u003e MyCommandParser;\n\nMyCommandParser parser;\n\nvoid cmd_test(MyCommandParser::Argument *args, char *response) {\n  Serial.print(\"string: \"); Serial.println(args[0].asString);\n  Serial.print(\"double: \"); Serial.println(args[1].asDouble);\n  Serial.print(\"int64: \"); Serial.println(args[2].asInt64);\n  Serial.print(\"uint64: \"); Serial.println(args[3].asUInt64);\n  strlcpy(response, \"success\", MyCommandParser::MAX_RESPONSE_SIZE);\n}\n\nvoid setup() {\n  Serial.begin(9600);\n  while (!Serial);\n\n  parser.registerCommand(\"TEST\", \"sdiu\", \u0026cmd_test);\n  Serial.println(\"registered command: TEST \u003cstring\u003e \u003cdouble\u003e \u003cint64\u003e \u003cuint64\u003e\");\n  Serial.println(\"example: TEST \\\"\\\\x41bc\\\\ndef\\\" -1.234e5 -123 123\");\n}\n\nvoid loop() {\n  if (Serial.available()) {\n    char line[128];\n    size_t lineLength = Serial.readBytesUntil('\\n', line, 127);\n    line[lineLength] = '\\0';\n\n    char response[MyCommandParser::MAX_RESPONSE_SIZE];\n    parser.processCommand(line, response);\n    Serial.println(response);\n  }\n}\n```\n\nMore examples:\n\n* [Parsing commands over Serial](examples/SerialCommands/SerialCommands.ino)\n* [Customizing resource limits](examples/CustomizeParameters/CustomizeParameters.ino)\n\nGrammar\n-------\n\nCommands are null-terminated strings that largely follow this PEG grammar:\n\n```\nCOMMAND \u003c- COMMAND_NAME (' '+ (ARG_STRING / ARG_DOUBLE / ARG_INT64 / ARG_UINT64))* ' '*\nCOMMAND_NAME \u003c- (!' ')+\nARG_STRING \u003c- ('\"' STRING_CHAR_QUOTED* '\"') / (STRING_CHAR_UNQUOTED+)\nARG_DOUBLE \u003c- SIGN? ((DEC+ '.' DEC*) / ('.' DEC+)) (('e' / 'E') SIGN? DEC+)?\nARG_INT64 \u003c- SIGN? ARG_UINT64\nARG_UINT64 \u003c- ('0x' HEX+) / ('0o' OCT+) / ('0b' BIN+) / DEC+\nSTRING_CHAR_QUOTED \u003c- STRING_CHAR_ESCAPE / (!'\"')\nSTRING_CHAR_UNQUOTED \u003c- STRING_CHAR_ESCAPE / (!' ')\nSTRING_CHAR_ESCAPE \u003c- ( '\\\\x' HEX HEX ) / '\\\\n' / '\\\\r' / '\\\\t' / '\\\\\"' / '\\\\\\\\'\nHEX \u003c- [0-9a-fA-F]\nDEC \u003c- [0-9]\nOCT \u003c- [0-7]\nBIN \u003c- [0-1]\nSIGN \u003c- '+' / '-'\n```\n\nThis grammar is a superset of what the parser will actually accept, since the `ARG_STRING / ARG_DOUBLE / ARG_INT64 / ARG_UINT64` choice is predetermined when `COMMAND_NAME` is registered (i.e., a given command always accepts the same number and types of arguments). Additionally, there are other limits (string arguments that are longer than `COMMAND_ARG_SIZE`, int64 arguments that would underflow/overflow a 64-bit signed integer, and so on) that further restrict what inputs are accepted.\n\nHere are some examples of strings that match the `COMMAND` rule in the above grammar:\n\n* `test_command \"Hello, \\\"World\\\"! \\\\\\x31\\x32\\x33\"` where `test_command` is registered with arg types `s`: one string argument with value `Hello, \"World\"! \\123`.\n* `! yes no` where `!` is registered with arg types `ss`: two string arguments, one with value `yes` and the other `no`.\n* `ABC 0.1 +.1 -123 0. 0 12.3e-1 1E10` where `ABC` is registered with arg types `dddddd`: six double arguments with values `0.1`, `0.1`, `-123`, `0`, `0`, `1.23`, `10000000000`.\n* `SomeCommand 0 +0x1F 0b101 0o77 -26` where `SomeCommand` is registered with arg types `iiiii`: five int64 arguments with values `0`, `31`, `5`, `63`, `-26`.\n* `SomeCommand 0 0x1F 0b101 0o77 26` where `SomeCommand` is registered with arg types `uuuuu`: five uint64 arguments with values `0`, `31`, `5`, `63`, `26`.\n\nComparison\n----------\n\nOther libraries for parsing commands:\n\n* [CmdArduino](https://github.com/joshmarinacci/CmdArduino):\n    * CmdArduino has hardcoded size limits for arguments/commands, only supports string arguments, and doesn't support string escape sequences. It works well as the most minimal option.\n    * CommandParser has configurable size limits, supports multiple argument types, and supports string escape sequences.\n* [CmdParser](https://github.com/pvizeli/CmdParser):\n    * CmdParser's command syntax is more configurable, with options such as setting the separator character, named parameters, and quoting behaviour. It works well as the most configurable option.\n    * CommandParser's command syntax is not configurable, but additionally supports escape sequences in string arguments, non-string arguments such as doubles and integers that are automatically parsed/validated, and empty string arguments.\n    * Also, CommandParser checks all inputs for validity (including syntax errors when invalid input is given), and doesn't assume the use of Serial.\n* [SerialCommand](https://github.com/kroimon/Arduino-SerialCommand):\n    * SerialCommand only accepts input from Serial, only supports string arguments, doesn't validate that the number of arguments, and doesn't support strings that contain the argument delimiter or any escape sequences. It works well for simpler Serial-specific use cases.\n    * CommandParser accepts input from any char array, supports multiple argument types, validates that all arguments parse correctly and that the correct syntax is used, and supports escape sequences in strings.\n\nCommandParser is likely the best choice when you need strict input validation, error checking, and configurable resource usage.\n\nCommandParser is likely not the best choice when you need to customize the command syntax, use optional/named arguments, or are very tight on RAM.\n\nReference\n---------\n\n### `CommandParser\u003cCOMMANDS, COMMAND_ARGS, COMMAND_NAME_LENGTH, COMMAND_ARG_SIZE, RESPONSE_SIZE\u003e`\n\nThis accepts several template arguments that limit how much RAM is required:\n\n* `size_t COMMANDS = 16` - up to 16 commands can be registered. Past this limit, `registerCommand` will return `false`.\n* `size_t COMMAND_ARGS = 4` - up to 4 arguments are supported for any given command. Past this limit, `registerCommand` will return `false`.\n* `size_t COMMAND_NAME_LENGTH = 10` - command names can be up to 10 bytes. Past this limit, `registerCommand` will return `false`.\n* `size_t COMMAND_ARG_SIZE = 32` - arguments passed to commands can be up to 32 bytes in size. Note that there may be more than 32 characters used to represent the argument; for example, a string argument `\"\\x41\\x42\\x43\"` is 14 characters but the argument would only be 3 bytes, 0x41, 0x42, and 0x43. Past this limit, `processCommand` will return `false`.\n* `size_t RESPONSE_SIZE = 64` - responses from command callback can be up to 64 characters in length. Past this limit, there is a risk of buffer overflow - always use bounded string handling functions such as `strlcpy` and `snprintf` when writing responses.\n\nTo avoid writing these arguments in multiple places in your code, typically you'll want to do something like `typedef CommandParser\u003c16, 4, 10, 32, 64\u003e MyCommandParser;`, and then use `MyCommandParser` everywhere else in your code.\n\nThese properties are then also available as static class variables: `CommandParser::MAX_COMMANDS`. `CommandParser::MAX_COMMAND_ARGS`, `CommandParser\u003c...\u003e::MAX_COMMAND_NAME_LENGTH`, `CommandParser\u003c...\u003e::MAX_COMMAND_ARG_SIZE`, `CommandParser\u003c...\u003e::MAX_RESPONSE_SIZE`.\n\n### `CommandParser\u003c...\u003e::Argument`\n\nThis union struct represents a single argument value. Access the correct field to get the right value out - if `arg` is a `CommandParser\u003c...\u003e::Argument` representing an `int64_t` argument, then `arg.asInt64` is the `int64_t` value that it contains.\n\nCommand callbacks are passed an array of these, as well as a buffer to write their response into.\n\n### `bool CommandParser\u003c...\u003e::registerCommand(const char *name, const char *argTypes, void (*callback)(union Argument *args, char *response))`\n\nRegisters a new command with name `name` and argument types `argTypes`. When `CommandParser\u003c...\u003e::processCommand` processes input containing this command, it calls `callback` with the parsed arguments.\n\nEach character in `argTypes` represents the type of its corresponding positional argument:\n\n* `d` represents a `double`.\n* `i` represents an `int64_t`.\n* `u` represents an `uint64_t`.\n* `s` represents a `char *` (as a null-terminated string).\n\nSo if `argTypes` is `\"sdiu\"`, that represents four arguments, where the first is a string, the second is a double, the third is a 64-bit signed integer, and the fourth is a 64-bit unsigned integer.\n\nReturns `true` if the command was successfully registered, `false` otherwise (usually because it exceeds the `CommandParser\u003c...\u003e` limits).\n\n### `bool CommandParser\u003c...\u003e::processCommand(const char *command, char *response)`\n\nProcesses a string `command` that contains a command previously registed using `CommandParser\u003c...\u003e::registerCommand`, parsing any arguments and looking up the command's callback.\n\nIf `command` is fully parsed, this calls the command's callback with an array of `CommandParser\u003c...\u003e::Argument` instances, as well as a response buffer `response`, which the callback may choose to write in (`response` is initialized to an empty string before the callback is called), then returns `true`.\n\nOtherwise, `command` could not be fully parsed, so `processCommand` will write a descriptive error message to `response`, no callbacks will be called, and this returns `false`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuberi%2Farduino-commandparser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuberi%2Farduino-commandparser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuberi%2Farduino-commandparser/lists"}