Repository: jbtronics/ESP32Console
Branch: master
Commit: ceb313606151
Files: 40
Total size: 187.1 KB
Directory structure:
gitextract_h38c8r86/
├── .github/
│ └── workflows/
│ ├── arduino-ci.yaml
│ └── arduino-lint.yaml
├── LICENSE
├── README.md
├── commands.md
├── examples/
│ ├── argparser/
│ │ └── argparser.ino
│ ├── basic/
│ │ └── basic.ino
│ ├── gpio/
│ │ └── gpio.ino
│ ├── network/
│ │ └── network.ino
│ ├── other_uart_channel/
│ │ └── other_uart_channel.ino
│ └── vfs/
│ └── vfs.ino
├── library.json
├── library.properties
└── src/
├── ESP32Console/
│ ├── Commands/
│ │ ├── CoreCommands.cpp
│ │ ├── CoreCommands.h
│ │ ├── GPIOCommands.cpp
│ │ ├── GPIOCommands.h
│ │ ├── NetworkCommands.cpp
│ │ ├── NetworkCommands.h
│ │ ├── SystemCommands.cpp
│ │ ├── SystemCommands.h
│ │ ├── VFSCommands.cpp
│ │ └── VFSCommands.h
│ ├── Console.cpp
│ ├── Console.h
│ ├── ConsoleCommand.h
│ ├── ConsoleCommandBase.h
│ ├── ConsoleCommandD.cpp
│ ├── ConsoleCommandD.h
│ ├── Helpers/
│ │ ├── InputParser.cpp
│ │ ├── InputParser.h
│ │ ├── PWDHelpers.cpp
│ │ └── PWDHelpers.h
│ ├── OptionsConsoleCommand.cpp
│ └── OptionsConsoleCommand.h
├── ESP32Console.h
├── cxxopts/
│ └── cxxopts.hpp
└── kilo/
├── CREDITS
├── kilo.cpp
└── kilo.h
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/arduino-ci.yaml
================================================
name: Arduino Library CI
on: [pull_request, push, repository_dispatch]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
repository: adafruit/ci-arduino
path: ci
- name: pre-install
run: bash ci/actions_install.sh
- name: test platforms
run: python3 ci/build_platform.py --no_warn esp32
#- name: clang
# run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r .
- name: doxygen
env:
GH_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PRETTYNAME : "ESP32Console Library"
run: bash ci/doxy_gen_and_deploy.sh
================================================
FILE: .github/workflows/arduino-lint.yaml
================================================
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: arduino/arduino-lint-action@v1
with:
library-manager: update
compliance: strict
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2022 Jan Böhmer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# ESP32Console
[](https://registry.platformio.org/libraries/jbtronics/ESP32Console)
Arduino library to add a serial console to your ESP32 console. It includes some useful commands and allows to easily add your own custom commands.
This easily allows you to control and configure your control via serial console in a comfortable and easy way.
This library encapsulates the Console component included in the ESP-IDF and allows to use it in an easy "Arduino-way".

## Features
* Simple to use
* Navigatable history, autocompletion with tab for commands (when using an ANSI terminal)
* Persistent history if wished (history gets saved across reboots)
* Many useful commands included like showing infos about system, memory, network and more (see [commands.md](commands.md) for more info)
* Console works in its own asynchronous task, so you can use your arduino loop() function as you like
* Support for environment variables and variable interpolation in commands
* Easy to implement own commands
* Easy to use argument parsing using cxxopts (see `argparser` example)
* Customizable prompt
* Ships a simple file editor to modify and create files locally on system if wanted
## Usage
### Installation
This library is available via Arduino Library Manager and [PlatformIO registry](https://registry.platformio.org/libraries/jbtronics/ESP32Console). So just install it via your preferred IDE's library manager and you are ready to start.
### Basic
To use this library you have to do an `#include <ESP32Console.h>` to import all needed files into your project. This library uses namespaces, so you have to do an `using namespace ESP32Console` to not having to prefix all classes (see example below).
You instantiate an `Console` object and initialize it with `Console.begin(BAUD)`. You can specifiy the baud rate and rx/tx pins similar to `Serial.begin`. Please note that you can use EITHER `Serial` OR `Console`. If you try to start ESP32Console after Serial was inited you will get an error.
Using `Console.registerCommand()` you can register your own custom commands. You have to pass a command object (see example below), which contains the name of the command, a little help text and the function which should be executed, when this command is executed. There are different types of commands:
* `ConsoleCommand`: The "default" console command, which takes a pointer to a function which is executed on call (similar to arduinos `attachInterrupt` function). The function receives an `int argc` which contains the number of arguments and `char** argv` which contains the arguments itself. The function MUST return an integer. Return 0 if everything was successfull, return something else (e.g. 1) if an error happened. This command type has the lowest memory usage.
* `ConsoleCommandD`: Similar to `ConsoleCommand` but allows to pass an `std::function` object as handler. This allows you to use lambda-functions and `std::bind`
* `OptionsConsoleCommand`: Allows you to define and parse command options and arguments in an easy way. Uses [cxxopts](https://github.com/jarro2783/cxxopts) for arguments parsing. Every command of this type has an `--help` and `--version` option. See `examples/argparser` for usage.
### Included commands
ESP32Console includes many useful commands, which can be registered using their respective `registerXXX()` functions. See [commands.md](commands.md) for a detailed list of the commands.
### Environment variables
The ESP32Console supports environment variables and string interpolation in the console. You can use `env` command to list all existing environment variables and `declare [VAR] [VALUE]` to change one. In the console prompt `$ENV` and `${ENV}` will get replaced by the value of the defined env value. With that you can for example define a variable with `declare HOST www.github.com` and access it in other commands: `ping $HOST`.
You can change and predefine env variables from your code. See `examples/gpio` for more info.
### Computer side
You can use almost any terminal software on PC for connecting with ESP32Console. You can use a simple terminal like the one included in Arduino but it is highly recommended to use a VT100 compatible terminal (e.g. PuTTY on windows).
This kind of terminal is needed for more complex functions like auto-complete with TAB, history scrolling, colors and more.
If you use a VT100 compatible terminal you can use the keybinds, when in prompt:
* `Ctrl + L`: Clear screen
* `Ctrl + A`: Jump cursor to begin of line
* `Ctrl + E`: Jump cursor to end of line
* `Ctrl + U`: Delete whole line
* `Ctrl + K`: Delete from current position to end of line
* `Ctrl + W`: Delete previous word
* `Ctrl + T`: Swap current character with previous one
## Examples
A simple usage can be seen here (see `examples/simple.ino`):
More advanced usages can be found in `examples/` folder.
```
#include <Arduino.h>
#include "ESP32Console.h"
using namespace ESP32Console;
Console console;
constexpr int LED = 2;
int led(int argc, char **argv)
{
//Ensure that we have an argument to parse
if (argc != 2)
{
printf("You have to give 'on' or 'off' as a argument (e.g. 'led on')\n");
//Return EXIT_FAILURE if something did not worked.
return EXIT_FAILURE;
}
//Take the first argument...
auto arg = String(argv[1]);
//and use it to decide what to do with the LED
if (arg == "on") {
digitalWrite(LED, HIGH);
printf("LED is now on\n");
} else if(arg == "off") {
digitalWrite(LED, LOW);
printf("LED is now off\n");
} else {
printf("Unknown argument!\n");
return EXIT_FAILURE;
}
//Return EXIT_SUCCESS if everything worked as intended.
return EXIT_SUCCESS;
}
void setup()
{
pinMode(LED, OUTPUT);
//You can change the console prompt before calling begin(). By default it is "ESP32>"
console.setPrompt("MyConsole> ");
//You can change the baud rate and pin numbers similar to Serial.begin() here.
console.begin(115200);
//Register builtin commands like 'reboot', 'sysinfo', or 'meminfo'
console.registerSystemCommands();
//Register our own command
//First argument is the name with which the command can be executed, second argument is the function to execute and third one is the description shown in help command.
console.registerCommand(ConsoleCommand("led", &led, "Turn the LED on or off"));
//With ConsoleCommandD you can use lambda functions (and anything else that can be cast to std::function). This needs a bit more memory and CPU time than the normal ConsoleCommand.
console.registerCommand(ConsoleCommandD("test", [](int argc, char **argv) -> int {
printf("Lambda function test\n");
return EXIT_SUCCESS;
}, "Just a test command!"));
//When console is in use, we can not use Serial.print but you can use printf to output text
printf("\n\nWelcome to ESP32Console example. Try out typing 'led off' and 'led on' (without quotes) or see 'help' for all commands.");
}
void loop()
{
//Console works async in its own task, so you can do whatever you want in your loop() function.
}
```
## Credits
* This library utilizes the console component of ESP-IDF written by Espressif at core.
* Argument parsing is done by [cxxopts](https://github.com/jarro2783/cxxopts).
* As editor a modified version of [kilo](https://github.com/antirez/kilo) is used.
## LICENSE
ESP32Console is licensed under MIT LICENSE. See [LICENSE file](LICENSE) for more info.
kilo shipped with ESP32Console is licensed under BSD-2 clause license. See the respective file for more info.
## TODO
* Add more useful commands
* Easy integration of colors and console styles
* Support of command batch files
* Add support for ESP8266 (this should be possible in theory as the old RTOS-SDK already ships the console parts)
* Check if more complex terminal stuff, like pipes, output redirection and similar is possible (difficult due only having one global stdout)
================================================
FILE: commands.md
================================================
# Included command reference
## Core commands (automatically loaded, when begin() is called)
* `help`: Show a list of all possible commands with descriptions
* `clear`: Clear terminal screen using ANSI commands (only working when using an ANSI compatible terminal)
* `echo`: Echo the parameter strings
* `history`: Show the recent command history
* `multiline_mode`: Switch multiline mode on or off. When it is on, lines get break into a second line, if it gets too long.
* `env`: List all environment variables
* `declare`: Change the value of an environment variable (syntax: `declare VARIABLE Value` or `declare VARIABLE "Long Value"`)
## System commands (loaded by calling registerSystemCommands())
* `sysinfo`: Prints info about the chip model, revision, ESP-IDF version, EFuse MAC, flash and PSRAM
* `restart`: Restarts the system
* `meminfo`: Show informations about used and free Heap
* `date`: Shows and set the current system time. Change time with `date -s "2022-07-13 22:47:00"`. Timezone can be set by changing the `TZ` env variable (e.g. `declare TZ CET-1`).
## Network commands (loaded by calling registerNetworkCommands())
* `ipconfig`: Shows information about WiFi connection
* `ping [HOST]`: Pings a hostname. You can change the number of pings done with `-n`parameter. Use `-n 0` for infinite pinging. You can stop the ping by `Strg + C` or `Strg + D`.
## VFS commands (loaded by calling registerVFSCommands())
This functions allows you to navigate through and edit files in ESP-IDFs Virtual Filesystem. Things likes SPIFF, SDCards, some hardware and more are getting mounted into VFS with different prefixes.
The following commands allow an unified access on it.
* `pwd`: Show the current working directory (the directory we are currently in)
* `cd [PATH]`: Change the current directory
* `ls [PATH]`: List the contents of the current or given directory
* `cat [FILES...]`: Show the content of the given files
* `rm [FILE]`: Delete the given file
* `rmdir [DIR]`: Delete the given director
* `mv [ORIGIN] [TARGET]`: Moves/Rename the file to new name/posiion
* `cp [ORIGIN] [TARGET]`: Copies the contents of origin to target file
* `edit [FILE]`: Opens a file editor with a visual editor. Use `Strg + S` to save, `Strg + Q` to quit and `Strg + F` to search in file.
## GPIO commands (loaded by calling registerGPIOCommands())
The commands allow you to read and change the states of the ESPs GPIO pins. They are similar to the arduino included functions:
* `pinMode [PIN] [MODE]`: Change the pinMode of an GPIO
* `digitalRead [PIN]`: Reads the state of an digital GPIO
* `digitalWrite [PIN] [LEVEL]`: Changes the state of an digital GPIO
* `analogRead [PIN]`: Reads the voltage applied to an analog GPIO in millivolts
================================================
FILE: examples/argparser/argparser.ino
================================================
/**
* This example demonstrates the usage of OptionsConsoleCommand, which allows you to easily build commands with complex options and argument parsing.
*/
#include <Arduino.h>
#include "ESP32Console.h"
using namespace ESP32Console;
Console console;
void setup()
{
console.begin(115200);
// Define a new command. Every command has an --option argument which shows the possible arguments and (if defined) a --version option which shows the version of this command.
OptionsConsoleCommand test(
"test", // The command name
[](int argc, char **argv, ParseResult result, Options options) -> int { // The function which is called when command is called. You get the parsed arguments and the options object
printf("Lambda function test\n");
// Check if argument was passed, then print it:
if (result.count("i"))
{
int i = result["i"].as<int>();
printf("Selected mode: %d\n", i);
}
return EXIT_SUCCESS;
},
"Just a test command!",
"v1.0.0"); //You can define a version number which is shown when the command is called with --version
//Customize the options of the console object. See https://github.com/jarro2783/cxxopts for explaination
test.options.add_options()("i,integer", "Int param", cxxopts::value<int>());
//Register it like any other command
console.registerCommand(test);
}
void loop()
{
// Console works async in its own task, so you can do whatever you want in your loop() function.
}
================================================
FILE: examples/basic/basic.ino
================================================
#include <Arduino.h>
#include "ESP32Console.h"
using namespace ESP32Console;
Console console;
constexpr int LED = 2;
int led(int argc, char **argv)
{
//Ensure that we have an argument to parse
if (argc != 2)
{
printf("You have to give 'on' or 'off' as a argument (e.g. 'led on')\n");
//Return EXIT_FAILURE if something did not worked.
return EXIT_FAILURE;
}
//Take the first argument...
auto arg = String(argv[1]);
//and use it to decide what to do with the LED
if (arg == "on") {
digitalWrite(LED, HIGH);
printf("LED is now on\n");
} else if(arg == "off") {
digitalWrite(LED, LOW);
printf("LED is now off\n");
} else {
printf("Unknown argument!\n");
return EXIT_FAILURE;
}
//Return EXIT_SUCCESS if everything worked as intended.
return EXIT_SUCCESS;
}
void setup()
{
pinMode(LED, OUTPUT);
//You can change the console prompt before calling begin(). By default it is "ESP32>"
console.setPrompt("MyConsole> ");
//You can change the baud rate and pin numbers similar to Serial.begin() here.
console.begin(115200);
//Register builtin commands like 'reboot', 'version', or 'meminfo'
console.registerSystemCommands();
//Register our own command
//First argument is the name with which the command can be executed, second argument is the function to execute and third one is the description shown in help command.
console.registerCommand(ConsoleCommand("led", &led, "Turn the LED on or off"));
//With ConsoleCommandD you can use lambda functions (and anything else that can be cast to std::function). This needs a bit more memory and CPU time than the normal ConsoleCommand.
console.registerCommand(ConsoleCommandD("test", [](int argc, char **argv) -> int {
printf("Lambda function test\n");
return EXIT_SUCCESS;
}, "Just a test command!"));
//When console is in use, we can not use Serial.print but you can use printf to output text
printf("\n\nWelcome to ESP32Console example. Try out typing 'led off' and 'led on' (without quotes) or see 'help' for all commands.");
}
void loop()
{
//Console works async in its own task, so you can do whatever you want in your loop() function.
}
================================================
FILE: examples/gpio/gpio.ino
================================================
/**
* This example demonstrates the usage of the internal GPIO functions and the env variables interpolation
*/
#include <Arduino.h>
#include "ESP32Console.h"
#include "ESP32Console/Helpers/PWDHelpers.h"
using namespace ESP32Console;
Console console;
void setup()
{
console.begin(115200);
console.registerSystemCommands();
/**
* Set environment variables, so users can access pin numbers easily in console.
* Users can do commands like `digitalWrite $LED HIGH` which will then be expanded to `digitalWrite 10 HIGH`.
* Users can change these env variables or create new ones dynamically in the console by `declare LED 10`.
*/
setenv("LED", "10", 1);
setenv("BUTTON", "4", 1);
/**
* Users can list all defined env variables and their values by `env` command
*/
//Register GPIO commands
console.registerGPIOCommands();
}
void loop()
{
}
================================================
FILE: examples/network/network.ino
================================================
/**
* This example demonstrates the usage of the builtin network functions
*/
#include <Arduino.h>
#include "ESP32Console.h"
#include <WiFi.h>
#include "ESP32Console/Helpers/PWDHelpers.h"
using namespace ESP32Console;
Console console;
const char *ssid = "yourSSID";
const char *password = "yourWLAN";
void setup()
{
//Connect to WiFi
WiFi.begin(ssid, password);
console.begin(115200);
console.registerSystemCommands();
//Register network commands
console.registerNetworkCommands();
}
void loop()
{
}
================================================
FILE: examples/other_uart_channel/other_uart_channel.ino
================================================
/**
* This example demonstrates the usage of ESP32Console on a seperate UART channel, using its own Pins, which allows you to use
* the console besides normal Serial.* commands
*/
#include <Arduino.h>
#include "ESP32Console.h"
using namespace ESP32Console;
Console console;
void setup()
{
//Initialize Serial port on UART0 (the onboard USB Serial Converter)
Serial.begin(115200);
//Enable ESP32Console on Pin 12 & 14 on UART1
console.begin(115200, 12, 14, 1);
console.registerSystemCommands();
console.registerNetworkCommands();
}
void loop()
{
//We can use Serial on UART0 as usual, while ESP32Console is available on the Pins above.
Serial.println("Test");
delay(1000);
}
================================================
FILE: examples/vfs/vfs.ino
================================================
/**
* This example demonstrates the usage of the builtin VFS commands and persistent history
*/
#include <Arduino.h>
#include "ESP32Console.h"
#include <FS.h>
#include "SPIFFS.h"
#include "ESP32Console/Helpers/PWDHelpers.h"
using namespace ESP32Console;
Console console;
void setup()
{
//Initalize SPIFFS and mount it on /spiffs
SPIFFS.begin(true, "/spiffs");
//Modify prompt to show current file path (%pwd% get replaced by the filepath)
console.setPrompt("ESP32 %pwd%> ");
//Set HOME env for easier navigating (type cd to jump to home)
setenv("HOME", "/spiffs", 1);
//Set PWD to env
console_chdir("/spiffs");
console.begin(115200);
//Enable the saving of our command history to SPIFFS. You will be able to see it, when you type ls in your console.
console.enablePersistentHistory("/spiffs/.history.txt");
console.registerSystemCommands();
//Register the VFS specific commands
console.registerVFSCommands();
}
void loop()
{
}
================================================
FILE: library.json
================================================
{
"name": "ESP32Console",
"version": "1.3.0",
"description": "Extensible UART console for ESP32 with useful included commands. This library encapsules the console component of ESP-IDF and make them easy to use in an Arduino environment.",
"keywords": "esp32, console, ping, ifconfig, sysinfo, editor, file",
"repository":
{
"type": "git",
"url": "https://github.com/jbtronics/ESP32Console"
},
"authors":
[
{
"name": "Jan Böhmer",
"email": "mail@jan-boehmer.de",
"url": "https://github.com/jbtronics",
"maintainer": true
}
],
"license": "MIT",
"homepage": "https://github.com/jbtronics/ESP32Console",
"dependencies": {
},
"exclude": [
".github",
"extras"
],
"frameworks": "arduino",
"platforms": "espressif32"
}
================================================
FILE: library.properties
================================================
name=ESP32Console
version=1.3.0
author=Jan Böhmer <mail@jan-boehmer.de>
maintainer=Jan Böhmer <mail@jan-boehmer.de>
sentence=Extensible UART console for ESP32 with useful included commands.
paragraph=This library encapsules the console component of ESP-IDF and make them easy to use in an Arduino environment
category=Communication
url=https://github.com/jbtronics/ESP32Console
architectures=esp32
================================================
FILE: src/ESP32Console/Commands/CoreCommands.cpp
================================================
#include "./CoreCommands.h"
#include "linenoise/linenoise.h"
#include "Arduino.h"
#include "soc/soc_caps.h"
//#include "argparse/argparse.hpp"
static int clear(int argc, char **argv)
{
// If we are on a dumb erminal clearing does not work
if (linenoiseProbe())
{
printf("\nYour terminal does not support escape sequences. Clearing screen does not work!\n");
return EXIT_FAILURE;
}
linenoiseClearScreen();
return EXIT_SUCCESS;
}
static int echo(int argc, char **argv)
{
for (int n = 1; n<argc; n++)
{
printf("%s ", argv[n]);
}
printf("\n");
return EXIT_SUCCESS;
}
static int set_multiline_mode(int argc, char **argv)
{
if (argc != 2)
{
printf("You have to give 'on' or 'off' as an argument!\n");
return EXIT_FAILURE;
}
// Get argument
auto mode = String(argv[1]);
// Normalize
mode.toLowerCase();
if (mode == "on")
{
linenoiseSetMultiLine(1);
}
else if (mode == "off")
{
linenoiseSetMultiLine(0);
}
else
{
printf("Unknown option. Pass 'on' or 'off' (without quotes)!\n");
return EXIT_FAILURE;
}
printf("Multiline mode set.\n");
return EXIT_SUCCESS;
}
static int history_channel = 0;
static int history(int argc, char **argv)
{
// If arguments were passed check for clearing
/*if (argc > 1)
{
if (strcasecmp(argv[1], "-c"))
{ // When -c option was detected clear history.
linenoiseHistorySetMaxLen(0);
printf("History cleared!\n");
linenoiseHistorySetMaxLen(10);
return EXIT_SUCCESS;
}
else
{
printf("Invalid argument. Use -c to clear history.\n");
return EXIT_FAILURE;
}
}
else*/
{ // Without arguments we just output the history
// We use the ESP-IDF VFS to directly output the file to an UART. UART channel 0 has the path /dev/uart/0 and so on.
char path[12] = {0};
snprintf(path, 12, "/dev/uart/%d", history_channel);
// If we found the correct one, let linoise save (output) them.
linenoiseHistorySave(path);
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
extern char **environ;
static int env(int argc, char **argv)
{
char **s = environ;
for (; *s; s++)
{
printf("%s\n", *s);
}
return EXIT_SUCCESS;
}
static int declare(int argc, char **argv)
{
if (argc != 3) {
fprintf(stderr, "Syntax: declare VAR short OR declare VARIABLE \"Long Value\"\n");
return EXIT_FAILURE;
}
setenv(argv[1], argv[2], 1);
return EXIT_SUCCESS;
}
namespace ESP32Console::Commands
{
const ConsoleCommand getClearCommand()
{
return ConsoleCommand("clear", &clear, "Clears the screen using ANSI codes");
}
const ConsoleCommand getEchoCommand()
{
return ConsoleCommand("echo", &echo, "Echos the text supplied as argument");
}
const ConsoleCommand getSetMultilineCommand()
{
return ConsoleCommand("multiline_mode", &set_multiline_mode, "Sets the multiline mode of the console");
}
const ConsoleCommand getHistoryCommand(int uart_channel)
{
history_channel = uart_channel;
return ConsoleCommand("history", &history, "Shows and clear command history (using -c parameter)");
}
const ConsoleCommand getEnvCommand()
{
return ConsoleCommand("env", &env, "List all environment variables.");
}
const ConsoleCommand getDeclareCommand()
{
return ConsoleCommand("declare", &declare, "Change enviroment variables");
}
}
================================================
FILE: src/ESP32Console/Commands/CoreCommands.h
================================================
#pragma once
#include "ESP32Console/ConsoleCommand.h"
namespace ESP32Console::Commands
{
const ConsoleCommand getClearCommand();
const ConsoleCommand getEchoCommand();
const ConsoleCommand getSetMultilineCommand();
const ConsoleCommand getHistoryCommand(int uart_channel=0);
const ConsoleCommand getEnvCommand();
const ConsoleCommand getDeclareCommand();
}
================================================
FILE: src/ESP32Console/Commands/GPIOCommands.cpp
================================================
#include "./GPIOCommands.h"
#include "Arduino.h"
#include <string>
#include <stdexcept>
static int _pinmode(int argc, char **argv)
{
if (argc != 3)
{
printf("You have to pass a pin number and mode. Syntax: pinMode [GPIO] [MODE]\n");
return 1;
}
char *pin_str = argv[1];
String mode_str = String(argv[2]);
unsigned long pin = 0;
try
{
pin = std::stoul(pin_str);
}
catch (std::invalid_argument ex)
{
fprintf(stderr, "Invalid argument for pin: %s\n", ex.what());
return 1;
}
if (pin > 255 || !digitalPinIsValid(pin)) {
fprintf(stderr, "%d is not a GPIO pin\n", pin);
return 1;
}
int mode = INPUT;
if (mode_str.equalsIgnoreCase("INPUT"))
{
mode = INPUT;
}
else if (mode_str.equalsIgnoreCase("OUTPUT"))
{
mode = OUTPUT;
}
else if (mode_str.equalsIgnoreCase("INPUT_PULLUP"))
{
mode = INPUT_PULLUP;
}
else if (mode_str.equalsIgnoreCase("INPUT_PULLDOWN"))
{
mode = INPUT_PULLDOWN;
}
else if (mode_str.equalsIgnoreCase("OUTPUT_OPEN_DRAIN"))
{
mode = OUTPUT_OPEN_DRAIN;
}
else
{
fprintf(stderr, "Invalid mode: Allowed modes are INPUT, OUTPUT, INPUT_PULLUP, INPUT_PULLDOWN, OUTPUT_OPEN_DRAIN\n");
}
pinMode(pin, mode);
printf("Mode set successful.\n");
return 0;
}
static int _digitalWrite(int argc, char** argv)
{
if (argc != 3)
{
printf("You have to pass an pin number and level. Syntax: digitalWrite [GPIO] [Level]\n");
return 1;
}
char *pin_str = argv[1];
String mode_str = String(argv[2]);
unsigned long pin = 0;
try
{
pin = std::stoul(pin_str);
}
catch (std::invalid_argument ex)
{
fprintf(stderr, "Invalid argument for pin: %s\n", ex.what());
return 1;
}
if (pin > 255 || !digitalPinCanOutput(pin)) {
fprintf(stderr, "%d is not a GPIO pin\n", pin);
return 1;
}
int mode = LOW;
if (mode_str.equalsIgnoreCase("HIGH") || mode_str.equalsIgnoreCase("1"))
{
mode = HIGH;
}
else if (mode_str.equalsIgnoreCase("LOW") || mode_str.equalsIgnoreCase("0"))
{
mode = LOW;
} else
{
fprintf(stderr, "Invalid mode: Allowed levels are HIGH, LOW, 0 and 1\n");
}
pinMode(pin, mode);
printf("Output set successful.\n");
return 0;
}
static int _digitalRead(int argc, char** argv)
{
if (argc != 2)
{
printf("You have to pass an pin number to read\n");
return 1;
}
char *pin_str = argv[1];
unsigned long pin = 0;
try
{
pin = std::stoul(pin_str);
}
catch (std::invalid_argument ex)
{
fprintf(stderr, "Invalid argument for pin: %s\n", ex.what());
return 1;
}
if (pin > 255 || !digitalPinCanOutput(pin)) {
fprintf(stderr, "%d is not a GPIO pin\n", pin);
return 1;
}
auto level = digitalRead(pin);
if(level == HIGH) {
printf("HIGH\n");
} else if(level == LOW) {
printf("LOW\n");
} else {
fprintf(stderr, "Unknown state (%u) of pin %u!\n", level, pin);
return 1;
}
return 0;
}
static int _analogRead(int argc, char** argv)
{
if (argc != 2)
{
printf("You have to pass an pin number to read\n");
return 1;
}
char *pin_str = argv[1];
unsigned long pin = 0;
try
{
pin = std::stoul(pin_str);
}
catch (std::invalid_argument ex)
{
fprintf(stderr, "Invalid argument for pin: %s\n", ex.what());
return 1;
}
if (pin > 255 || digitalPinToAnalogChannel(pin) == -1) {
fprintf(stderr, "%d is not a ADC pin\n", pin);
return 1;
}
auto value = analogReadMilliVolts(pin);
printf("%u mV\n", value);
return 0;
}
namespace ESP32Console::Commands
{
const ConsoleCommand getPinModeCommand()
{
return ConsoleCommand("pinMode", &_pinmode, "Changes the pinmode of an GPIO pin (similar to Arduino function)");
}
const ConsoleCommand getDigitalWriteCommand()
{
return ConsoleCommand("digitalWrite", &_digitalWrite, "Writes the state of an ouput pin (similar to Arduino function)");
}
const ConsoleCommand getDigitalReadCommand()
{
return ConsoleCommand("digitalRead", &_digitalRead, "Reads the state of an input pin (similar to Arduino function)");
}
const ConsoleCommand getAnalogReadCommand()
{
return ConsoleCommand("analogRead", &_analogRead, "Show the voltage at an analog pin in millivollts.");
}
}
================================================
FILE: src/ESP32Console/Commands/GPIOCommands.h
================================================
#pragma once
#include "ESP32Console/ConsoleCommand.h"
namespace ESP32Console::Commands
{
const ConsoleCommand getPinModeCommand();
const ConsoleCommand getDigitalWriteCommand();
const ConsoleCommand getDigitalReadCommand();
const ConsoleCommand getAnalogReadCommand();
}
================================================
FILE: src/ESP32Console/Commands/NetworkCommands.cpp
================================================
#include "./NetworkCommands.h"
#include <Arduino.h>
#include <esp_ping.h>
#include <ping/ping.h>
#include <ping/ping_sock.h>
#include "lwip/inet.h"
#include "lwip/netdb.h"
#include "lwip/sockets.h"
#include <unistd.h>
#include "WiFi.h"
static const char *wlstatus2string(wl_status_t status)
{
switch (status)
{
case WL_NO_SHIELD:
return "Not initialized";
case WL_CONNECT_FAILED:
return "Connection failed";
case WL_CONNECTED:
return "Connected";
case WL_CONNECTION_LOST:
return "Connection lost";
case WL_DISCONNECTED:
return "Disconnected";
case WL_IDLE_STATUS:
return "Idle status";
case WL_NO_SSID_AVAIL:
return "No SSID available";
case WL_SCAN_COMPLETED:
return "Scan completed";
default:
return "Unknown";
}
}
const char* wlmode2string(wifi_mode_t mode)
{
switch(mode) {
case WIFI_MODE_NULL:
return "Not initialized";
case WIFI_MODE_AP:
return "Accesspoint";
case WIFI_MODE_STA:
return "Station";
case WIFI_MODE_APSTA:
return "Station + Accesspoint";
default:
return "Unknown";
}
}
static void on_ping_success(esp_ping_handle_t hdl, void *args)
{
uint8_t ttl;
uint16_t seqno;
uint32_t elapsed_time, recv_len;
ip_addr_t target_addr;
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
esp_ping_get_profile(hdl, ESP_PING_PROF_TTL, &ttl, sizeof(ttl));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
printf("%u bytes from %s icmp_seq=%d ttl=%d time=%u ms\n",
recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time);
}
static void on_ping_timeout(esp_ping_handle_t hdl, void *args)
{
uint16_t seqno;
ip_addr_t target_addr;
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
printf("From %s icmp_seq=%u timeout\n", inet_ntoa(target_addr.u_addr.ip4), seqno);
}
static void on_ping_end(esp_ping_handle_t hdl, void *args)
{
}
static int ping(int argc, char **argv)
{
//By default do 5 pings
int number_of_pings = 5;
int opt;
while ((opt = getopt(argc, argv, "n:")) != -1) {
switch(opt) {
case 'n':
number_of_pings = atoi(optarg);
break;
case '?':
printf("Unknown option: %c\n", optopt);
break;
case ':':
printf("Missing arg for %c\n", optopt);
break;
default:
fprintf(stderr, "Usage: ping -n 5 [HOSTNAME]\n");
fprintf(stderr, "-n: The number of pings. 0 means infinite. Can be aborted with Ctrl+D or Ctrl+C.");
return 1;
}
}
int argind = optind;
//Get hostname
if (argind >= argc) {
fprintf(stderr, "You need to pass an hostname!\n");
return EXIT_FAILURE;
}
char* hostname = argv[argind];
/* convert hostname to IP address */
ip_addr_t target_addr;
struct addrinfo hint;
struct addrinfo *res = NULL;
memset(&hint, 0, sizeof(hint));
memset(&target_addr, 0, sizeof(target_addr));
auto result = getaddrinfo(hostname, NULL, &hint, &res);
if (result) {
fprintf(stderr, "Could not resolve hostname! (getaddrinfo returned %d)\n", result);
return 1;
}
struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr;
inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4);
freeaddrinfo(res);
//Configure ping session
esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG();
ping_config.task_stack_size = 4096;
ping_config.target_addr = target_addr; // target IP address
ping_config.count = number_of_pings; // 0 means infinite ping
/* set callback functions */
esp_ping_callbacks_t cbs;
cbs.on_ping_success = on_ping_success;
cbs.on_ping_timeout = on_ping_timeout;
cbs.on_ping_end = on_ping_end;
//Pass a variable as pointer so the sub tasks can decrease it
//cbs.cb_args = &number_of_pings_remaining;
esp_ping_handle_t ping;
esp_ping_new_session(&ping_config, &cbs, &ping);
esp_ping_start(ping);
char c = 0;
uint16_t seqno;
esp_ping_get_profile(ping, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
//Make stdin input non blocking so we can query for input AND check ping seqno
int flags = fcntl(fileno(stdin), F_GETFL, 0);
fcntl(fileno(stdin), F_SETFL, flags | O_NONBLOCK);
//Wait for Ctrl+D or Ctr+C or that our task finishes
//The async tasks decrease number_of_pings, so wait for it to get to 0
while((number_of_pings == 0 || seqno < number_of_pings) && c != 4 && c != 3) {
esp_ping_get_profile(ping, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
c = getc(stdin);
delay(50);
}
//Reset flags, so we dont end up destroying our terminal env later, when linenoise takes over again
fcntl(fileno(stdin), F_SETFL, flags);
esp_ping_stop(ping);
//Print total statistics
uint32_t transmitted;
uint32_t received;
uint32_t total_time_ms;
esp_ping_get_profile(ping, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted));
esp_ping_get_profile(ping, ESP_PING_PROF_REPLY, &received, sizeof(received));
esp_ping_get_profile(ping, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms));
printf("%u packets transmitted, %u received, time %u ms\n", transmitted, received, total_time_ms);
esp_ping_delete_session(ping);
return EXIT_SUCCESS;
}
static void ipconfig_wlan()
{
printf("==== WLAN ====\n");
auto status = WiFi.status();
printf("Mode: %s\n", wlmode2string(WiFi.getMode()));
printf("Status: %s\n", wlstatus2string(status));
if (status == WL_NO_SHIELD) {
return;
}
printf("\n");
printf("SSID: %s\n", WiFi.SSID().c_str());
printf("BSSID: %s\n", WiFi.BSSIDstr().c_str());
printf("Channel: %d\n", WiFi.channel());
printf("\n");
printf("IP: %s\n", WiFi.localIP().toString().c_str());
printf("Subnet Mask: %s (/%d)\n", WiFi.subnetMask().toString().c_str(), WiFi.subnetCIDR());
printf("Gateway: %s\n", WiFi.gatewayIP().toString().c_str());
#if !defined(ESP_ARDUINO_VERSION_MAJOR) || ESP_ARDUINO_VERSION_MAJOR < 3
printf("IPv6: %s\n", WiFi.localIPv6().toString().c_str());
#endif
printf("\n");
printf("Hostname: %s\n", WiFi.getHostname());
printf("DNS1: %s\n", WiFi.dnsIP(0).toString().c_str());
printf("DNS2: %s\n", WiFi.dnsIP(0).toString().c_str());
}
static int ipconfig(int argc, char **argv)
{
ipconfig_wlan();
return EXIT_SUCCESS;
}
namespace ESP32Console::Commands
{
const ConsoleCommand getPingCommand()
{
return ConsoleCommand("ping", &ping, "Ping host");
}
const ConsoleCommand getIpconfigCommand()
{
return ConsoleCommand("ipconfig", &ipconfig, "Show IP and connection informations");
}
}
================================================
FILE: src/ESP32Console/Commands/NetworkCommands.h
================================================
#pragma once
#include "ESP32Console/ConsoleCommand.h"
namespace ESP32Console::Commands
{
const ConsoleCommand getPingCommand();
const ConsoleCommand getIpconfigCommand();
}
================================================
FILE: src/ESP32Console/Commands/SystemCommands.cpp
================================================
#include "./SystemCommands.h"
#include "ESP32Console.h"
#include <Arduino.h>
#include <esp_partition.h>
#include <esp_ota_ops.h>
#include <esp_system.h>
#if __has_include(<esp_chip_info.h>)
#include <esp_chip_info.h>
#endif
#if __has_include(<core_version.h>)
#include <core_version.h>
#endif
#include <getopt.h>
// For XTSTR macros (Xtensa-specific)
#if __has_include(<xtensa/xtruntime.h>)
#include <xtensa/xtruntime.h>
#else
// Provide a fallback stringification macro for non-Xtensa architectures (e.g. RISC-V)
#ifndef XTSTR
#define _XTSTR(x) #x
#define XTSTR(x) _XTSTR(x)
#endif
#endif
static String mac2String(uint64_t mac)
{
byte *ar = (byte *)&mac;
String s;
for (byte i = 0; i < 6; ++i)
{
char buf[3];
sprintf(buf, "%02X", ar[i]); // J-M-L: slight modification, added the 0 in the format for padding
s += buf;
if (i < 5)
s += ':';
}
return s;
}
static const char *getFlashModeStr()
{
switch (ESP.getFlashChipMode())
{
case FM_DIO:
return "DIO";
case FM_DOUT:
return "DOUT";
case FM_FAST_READ:
return "FAST READ";
case FM_QIO:
return "QIO";
case FM_QOUT:
return "QOUT";
case FM_SLOW_READ:
return "SLOW READ";
case FM_UNKNOWN:
default:
return "UNKNOWN";
}
}
static const char *getResetReasonStr()
{
switch (esp_reset_reason())
{
case ESP_RST_BROWNOUT:
return "Brownout reset (software or hardware)";
case ESP_RST_DEEPSLEEP:
return "Reset after exiting deep sleep mode";
case ESP_RST_EXT:
return "Reset by external pin (not applicable for ESP32)";
case ESP_RST_INT_WDT:
return "Reset (software or hardware) due to interrupt watchdog";
case ESP_RST_PANIC:
return "Software reset due to exception/panic";
case ESP_RST_POWERON:
return "Reset due to power-on event";
case ESP_RST_SDIO:
return "Reset over SDIO";
case ESP_RST_SW:
return "Software reset via esp_restart";
case ESP_RST_TASK_WDT:
return "Reset due to task watchdog";
case ESP_RST_WDT:
return "ESP_RST_WDT";
case ESP_RST_UNKNOWN:
default:
return "Unknown";
}
}
static int sysInfo(int argc, char **argv)
{
esp_chip_info_t info;
esp_chip_info(&info);
printf("ESP32Console version: %s\n", ESP32CONSOLE_VERSION);
#if defined(ARDUINO_ESP32_GIT_DESC)
printf("Arduino Core version: %s (%x)\n", XTSTR(ARDUINO_ESP32_GIT_DESC), ARDUINO_ESP32_GIT_VER);
#endif
printf("ESP-IDF Version: %s\n", ESP.getSdkVersion());
printf("\n");
printf("Chip info:\n");
printf("\tModel: %s\n", ESP.getChipModel());
printf("\tRevison number: %d\n", ESP.getChipRevision());
printf("\tCores: %d\n", ESP.getChipCores());
printf("\tClock: %d MHz\n", ESP.getCpuFreqMHz());
printf("\tFeatures:%s%s%s%s%s\r\n",
info.features & CHIP_FEATURE_WIFI_BGN ? " 802.11bgn " : "",
info.features & CHIP_FEATURE_BLE ? " BLE " : "",
info.features & CHIP_FEATURE_BT ? " BT " : "",
info.features & CHIP_FEATURE_EMB_FLASH ? " Embedded-Flash " : " External-Flash ",
info.features & CHIP_FEATURE_EMB_PSRAM ? " Embedded-PSRAM" : "");
printf("EFuse MAC: %s\n", mac2String(ESP.getEfuseMac()).c_str());
printf("Flash size: %d MB (mode: %s, speed: %d MHz)\n", ESP.getFlashChipSize() / (1024 * 1024), getFlashModeStr(), ESP.getFlashChipSpeed() / (1024 * 1024));
printf("PSRAM size: %d MB\n", ESP.getPsramSize() / (1024 * 1024));
printf("Sketch size: %d KB\n", ESP.getSketchSize() / (1024));
printf("Sketch MD5: %s\n", ESP.getSketchMD5().c_str());
#ifndef CONFIG_APP_REPRODUCIBLE_BUILD
printf("Compilation datetime: " __DATE__ " " __TIME__ "\n");
#endif
printf("\nReset reason: %s\n", getResetReasonStr());
printf("\n");
printf("CPU temperature: %.01f °C\n", temperatureRead());
return EXIT_SUCCESS;
}
static int restart(int argc, char **argv)
{
printf("Restarting...");
ESP.restart();
return EXIT_SUCCESS;
}
static int meminfo(int argc, char **argv)
{
uint32_t free = ESP.getFreeHeap() / 1024;
uint32_t total = ESP.getHeapSize() / 1024;
uint32_t used = total - free;
uint32_t min = ESP.getMinFreeHeap() / 1024;
printf("Heap: %u KB free, %u KB used, (%u KB total)\n", free, used, total);
printf("Minimum free heap size during uptime was: %u KB\n", min);
return EXIT_SUCCESS;
}
static int date(int argc, char **argv)
{
bool set_time = false;
char *target = nullptr;
int c;
opterr = 0;
// Set timezone from env variable
tzset();
while ((c = getopt(argc, argv, "s")) != -1)
switch (c)
{
case 's':
set_time = true;
break;
case '?':
printf("Unknown option: %c\n", optopt);
return 1;
case ':':
printf("Missing arg for %c\n", optopt);
return 1;
}
if (optind < argc)
{
target = argv[optind];
}
if (set_time)
{
if (!target)
{
fprintf(stderr, "Set option requires an datetime as argument in format '%Y-%m-%d %H:%M:%S' (e.g. 'date -s \"2022-07-13 22:47:00\"'\n");
return 1;
}
tm t;
if (!strptime(target, "%Y-%m-%d %H:%M:%S", &t))
{
fprintf(stderr, "Set option requires an datetime as argument in format '%Y-%m-%d %H:%M:%S' (e.g. 'date -s \"2022-07-13 22:47:00\"'\n");
return 1;
}
timeval tv = {
.tv_sec = mktime(&t),
.tv_usec = 0};
if (settimeofday(&tv, nullptr))
{
fprintf(stderr, "Could not set system time: %s", strerror(errno));
return 1;
}
time_t tmp = time(nullptr);
constexpr int buffer_size = 100;
char buffer[buffer_size];
strftime(buffer, buffer_size, "%a %b %e %H:%M:%S %Z %Y", localtime(&tmp));
printf("Time set: %s\n", buffer);
return 0;
}
// If no target was supplied put a default one (similar to coreutils date)
if (!target)
{
target = (char*) "+%a %b %e %H:%M:%S %Z %Y";
}
// Ensure the format string is correct
if (target[0] != '+')
{
fprintf(stderr, "Format string must start with an +!\n");
return 1;
}
// Ignore + by moving pointer one step forward
target++;
constexpr int buffer_size = 100;
char buffer[buffer_size];
time_t t = time(nullptr);
strftime(buffer, buffer_size, target, localtime(&t));
printf("%s\n", buffer);
return 0;
return EXIT_SUCCESS;
}
namespace ESP32Console::Commands
{
const ConsoleCommand getRestartCommand()
{
return ConsoleCommand("restart", &restart, "Restart / Reboot the system");
}
const ConsoleCommand getSysInfoCommand()
{
return ConsoleCommand("sysinfo", &sysInfo, "Shows informations about the system like chip model and ESP-IDF version");
}
const ConsoleCommand getMemInfoCommand()
{
return ConsoleCommand("meminfo", &meminfo, "Shows information about heap usage");
}
const ConsoleCommand getDateCommand()
{
return ConsoleCommand("date", &date, "Shows and modify the system time");
}
}
================================================
FILE: src/ESP32Console/Commands/SystemCommands.h
================================================
#pragma once
#include "ESP32Console/ConsoleCommand.h"
namespace ESP32Console::Commands
{
const ConsoleCommand getSysInfoCommand();
const ConsoleCommand getRestartCommand();
const ConsoleCommand getMemInfoCommand();
const ConsoleCommand getDateCommand();
};
================================================
FILE: src/ESP32Console/Commands/VFSCommands.cpp
================================================
#include "./VFSCommands.h"
#include <Arduino.h>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "ESP32Console/Helpers/PWDHelpers.h"
#include "kilo/kilo.h"
char *canonicalize_file_name(const char *path);
int cat(int argc, char **argv)
{
if (argc == 1)
{
fprintf(stderr, "You have to pass at least one file path!\n");
return EXIT_SUCCESS;
}
for (int n = 1; n < argc; n++)
{
char filename[PATH_MAX];
// We have manually do resolving of . and .., as VFS does not do it
ESP32Console::console_realpath(argv[n], filename);
FILE *file = fopen(filename, "r");
if (file == nullptr)
{
fprintf(stderr, "%s %s : %s\n", argv[0], filename,
strerror(errno));
return errno;
}
int chr;
while ((chr = getc(file)) != EOF)
fprintf(stdout, "%c", chr);
fclose(file);
}
return EXIT_SUCCESS;
}
int pwd(int argc, char **argv)
{
printf("%s\n", ESP32Console::console_getpwd());
return EXIT_SUCCESS;
}
int cd(int argc, char **argv)
{
const char *path;
if (argc != 2)
{
path = getenv("HOME");
if (!path)
{
fprintf(stderr, "No HOME env variable set!\n");
return EXIT_FAILURE;
}
}
else
{
path = argv[1];
}
// Check if target path is a file
char resolved[PATH_MAX];
ESP32Console::console_realpath(path, resolved);
FILE *file = fopen(resolved, "r");
// If we can open it, then we can not chdir into it.
if (file)
{
fclose(file);
fprintf(stderr, "Can not cd into a file!\n");
return 1;
}
if (ESP32Console::console_chdir(path))
{
fprintf(stderr, "Error: %s\n", strerror(errno));
return 1;
}
const char *pwd = ESP32Console::console_getpwd();
// Check if the new PWD exists, and show a warning if not
DIR *dir = opendir(pwd);
if (dir)
{
closedir(dir);
}
else if (ENOENT == errno)
{
fprintf(stderr, "Choosen directory maybe does not exists!\n");
}
return EXIT_SUCCESS;
}
int ls(int argc, char **argv)
{
char *inpath;
if (argc == 1)
{
inpath = (char *)".";
}
else if (argc == 2)
{
inpath = argv[1];
}
else
{
printf("You can pass only one filename!\n");
return 1;
}
char path[PATH_MAX];
ESP32Console::console_realpath(inpath, path);
DIR *dir = opendir(path);
if (!dir)
{
fprintf(stderr, "Could not open filepath: %s\n", strerror(errno));
return 1;
}
struct dirent *d;
while ((d = readdir(dir)) != NULL)
{
printf("%s\n", d->d_name);
}
closedir(dir);
return EXIT_SUCCESS;
}
int mv(int argc, char **argv)
{
if (argc != 3)
{
fprintf(stderr, "Syntax is mv [ORIGIN] [TARGET]\n");
return 1;
}
char old_name[PATH_MAX], new_name[PATH_MAX];
// Resolve arguments to full path
ESP32Console::console_realpath(argv[1], old_name);
ESP32Console::console_realpath(argv[2], new_name);
// Do rename
if (rename(old_name, new_name))
{
printf("Error moving: %s\n", strerror(errno));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int cp(int argc, char **argv)
{
//TODO: Shows weird error message
if (argc != 3)
{
fprintf(stderr, "Syntax is cp [ORIGIN] [TARGET]\n");
return 1;
}
char old_name[PATH_MAX], new_name[PATH_MAX];
// Resolve arguments to full path
ESP32Console::console_realpath(argv[1], old_name);
ESP32Console::console_realpath(argv[2], new_name);
// Do copy
FILE *origin = fopen(old_name, "r");
if (!origin)
{
fprintf(stderr, "Error opening origin file: %s\n", strerror(errno));
return 1;
}
FILE *target = fopen(new_name, "w");
if (!target)
{
fclose(origin);
fprintf(stderr, "Error opening target file: %s\n", strerror(errno));
return 1;
}
int buffer;
// Clear existing errors
auto error = errno;
while ((buffer = getc(origin)) != EOF)
{
if(fputc(buffer, target) == EOF) {
fprintf(stderr, "Error writing: %s\n", strerror(errno));
fclose(origin); fclose(target);
return 1;
}
}
error = errno;
if (error && !feof(origin))
{
fprintf(stderr, "Error copying: %s\n", strerror(error));
fclose(origin);
fclose(target);
return 1;
}
fclose(origin);
fclose(target);
return EXIT_SUCCESS;
}
int rm(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "You have to pass exactly one file. Syntax rm [FIILE]\n");
return EXIT_SUCCESS;
}
char filename[PATH_MAX];
ESP32Console::console_realpath(argv[1], filename);
if(unlink(filename)) {
fprintf(stderr, "Error deleting %s: %s\n", filename, strerror(errno));
}
return EXIT_SUCCESS;
}
int rmdir(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "You have to pass exactly one file. Syntax rmdir [FIILE]\n");
return EXIT_SUCCESS;
}
char filename[PATH_MAX];
ESP32Console::console_realpath(argv[1], filename);
if(rmdir(filename)) {
fprintf(stderr, "Error deleting %s: %s\n", filename, strerror(errno));
}
return EXIT_SUCCESS;
}
namespace ESP32Console::Commands
{
const ConsoleCommand getCatCommand()
{
return ConsoleCommand("cat", &cat, "Show the content of one or more files.");
}
const ConsoleCommand getPWDCommand()
{
return ConsoleCommand("pwd", &pwd, "Show the current working dir");
}
const ConsoleCommand getCDCommand()
{
return ConsoleCommand("cd", &cd, "Change the working directory");
}
const ConsoleCommand getLsCommand()
{
return ConsoleCommand("ls", &ls, "List the contents of the given path");
}
const ConsoleCommand getMvCommand()
{
return ConsoleCommand("mv", &mv, "Move the given file to another place or name");
}
const ConsoleCommand getCPCommand()
{
return ConsoleCommand("cp", &cp, "Copy the given file to another place or name");
}
const ConsoleCommand getRMCommand()
{
return ConsoleCommand("rm", &rm, "Permanenty deletes the given file.");
}
const ConsoleCommand getRMDirCommand()
{
return ConsoleCommand("rmdir", &rmdir, "Permanenty deletes the given folder. Folder must be empty!");
}
const ConsoleCommand getEditCommand()
{
return ConsoleCommand("edit", &ESP32Console::Kilo::kilo, "Edit files");
}
}
================================================
FILE: src/ESP32Console/Commands/VFSCommands.h
================================================
#pragma once
#include "ESP32Console/ConsoleCommand.h"
namespace ESP32Console::Commands
{
const ConsoleCommand getCatCommand();
const ConsoleCommand getPWDCommand();
const ConsoleCommand getCDCommand();
const ConsoleCommand getLsCommand();
const ConsoleCommand getMvCommand();
const ConsoleCommand getCPCommand();
const ConsoleCommand getRMCommand();
const ConsoleCommand getRMDirCommand();
const ConsoleCommand getEditCommand();
}
================================================
FILE: src/ESP32Console/Console.cpp
================================================
#include "./Console.h"
#include "soc/soc_caps.h"
#include "esp_err.h"
#include "esp_idf_version.h"
#include "ESP32Console/Commands/CoreCommands.h"
#include "ESP32Console/Commands/SystemCommands.h"
#include "ESP32Console/Commands/NetworkCommands.h"
#include "ESP32Console/Commands/VFSCommands.h"
#include "ESP32Console/Commands/GPIOCommands.h"
#include "driver/uart.h"
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
#include "driver/uart_vfs.h"
#else
#include "esp_vfs_dev.h"
#endif
#include "linenoise/linenoise.h"
#include "ESP32Console/Helpers/PWDHelpers.h"
#include "ESP32Console/Helpers/InputParser.h"
static const char *TAG = "ESP32Console";
using namespace ESP32Console::Commands;
namespace ESP32Console
{
void Console::registerCoreCommands()
{
registerCommand(getClearCommand());
registerCommand(getHistoryCommand());
registerCommand(getEchoCommand());
registerCommand(getSetMultilineCommand());
registerCommand(getEnvCommand());
registerCommand(getDeclareCommand());
}
void Console::registerSystemCommands()
{
registerCommand(getSysInfoCommand());
registerCommand(getRestartCommand());
registerCommand(getMemInfoCommand());
registerCommand(getDateCommand());
}
void ESP32Console::Console::registerNetworkCommands()
{
registerCommand(getPingCommand());
registerCommand(getIpconfigCommand());
}
void Console::registerVFSCommands()
{
registerCommand(getCatCommand());
registerCommand(getCDCommand());
registerCommand(getPWDCommand());
registerCommand(getLsCommand());
registerCommand(getMvCommand());
registerCommand(getCPCommand());
registerCommand(getRMCommand());
registerCommand(getRMDirCommand());
registerCommand(getEditCommand());
}
void Console::registerGPIOCommands()
{
registerCommand(getPinModeCommand());
registerCommand(getDigitalReadCommand());
registerCommand(getDigitalWriteCommand());
registerCommand(getAnalogReadCommand());
}
void Console::beginCommon()
{
/* Tell linenoise where to get command completions and hints */
linenoiseSetCompletionCallback(&esp_console_get_completion);
linenoiseSetHintsCallback((linenoiseHintsCallback *)&esp_console_get_hint);
/* Set command history size */
linenoiseHistorySetMaxLen(max_history_len_);
/* Set command maximum length */
linenoiseSetMaxLineLen(max_cmdline_len_);
// Load history if defined
if (history_save_path_)
{
linenoiseHistoryLoad(history_save_path_);
}
// Register core commands like echo
esp_console_register_help_command();
registerCoreCommands();
}
void Console::begin(int baud, int rxPin, int txPin, uart_port_t channel)
{
log_d("Initialize console");
if (channel >= SOC_UART_NUM)
{
log_e("Serial number is invalid, please use numers from 0 to %u", SOC_UART_NUM - 1);
return;
}
this->uart_channel_ = channel;
//Reinit the UART driver if the channel was already in use
if (uart_is_driver_installed(channel)) {
uart_driver_delete(channel);
}
/* Drain stdout before reconfiguring it */
fflush(stdout);
fsync(fileno(stdout));
/* Disable buffering on stdin */
setvbuf(stdin, NULL, _IONBF, 0);
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
uart_vfs_dev_port_set_rx_line_endings(channel, ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
uart_vfs_dev_port_set_tx_line_endings(channel, ESP_LINE_ENDINGS_CRLF);
#else
esp_vfs_dev_uart_port_set_rx_line_endings(channel, ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_uart_port_set_tx_line_endings(channel, ESP_LINE_ENDINGS_CRLF);
#endif
/* Configure UART. Note that REF_TICK is used so that the baud rate remains
* correct while APB frequency is changing in light sleep mode.
*/
const uart_config_t uart_config = {
.baud_rate = baud,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
#if SOC_UART_SUPPORT_REF_TICK
.source_clk = UART_SCLK_REF_TICK,
#elif SOC_UART_SUPPORT_XTAL_CLK
.source_clk = UART_SCLK_XTAL,
#endif
};
ESP_ERROR_CHECK(uart_param_config(channel, &uart_config));
// Set the correct pins for the UART of needed
if (rxPin > 0 || txPin > 0) {
if (rxPin < 0 || txPin < 0) {
log_e("Both rxPin and txPin has to be passed!");
}
uart_set_pin(channel, txPin, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
}
/* Install UART driver for interrupt-driven reads and writes */
ESP_ERROR_CHECK(uart_driver_install(channel, 256, 0, 0, NULL, 0));
/* Tell VFS to use UART driver */
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
uart_vfs_dev_use_driver(channel);
#else
esp_vfs_dev_uart_use_driver(channel);
#endif
esp_console_config_t console_config = {
.max_cmdline_length = max_cmdline_len_,
.max_cmdline_args = max_cmdline_args_,
.hint_color = 333333};
ESP_ERROR_CHECK(esp_console_init(&console_config));
beginCommon();
// Start REPL task
if (xTaskCreate(&Console::repl_task, "console_repl", 4096, this, 2, &task_) != pdTRUE)
{
log_e("Could not start REPL task!");
}
}
static void resetAfterCommands()
{
//Reset all global states a command could change
//Reset getopt parameters
optind = 0;
}
void Console::repl_task(void *args)
{
Console const &console = *(static_cast<Console *>(args));
/* Change standard input and output of the task if the requested UART is
* NOT the default one. This block will replace stdin, stdout and stderr.
* We have to do this in the repl task (not in the begin, as these settings are only valid for the current task)
*/
if (console.uart_channel_ != CONFIG_ESP_CONSOLE_UART_NUM)
{
char path[13] = {0};
snprintf(path, 13, "/dev/uart/%d", console.uart_channel_);
stdin = fopen(path, "r");
stdout = fopen(path, "w");
stderr = stdout;
}
setvbuf(stdin, NULL, _IONBF, 0);
/* This message shall be printed here and not earlier as the stdout
* has just been set above. */
printf("\r\n"
"Type 'help' to get the list of commands.\r\n"
"Use UP/DOWN arrows to navigate through command history.\r\n"
"Press TAB when typing command name to auto-complete.\r\n");
// Probe terminal status
int probe_status = linenoiseProbe();
if (probe_status)
{
linenoiseSetDumbMode(1);
}
if (linenoiseIsDumbMode())
{
printf("\r\n"
"Your terminal application does not support escape sequences.\n\n"
"Line editing and history features are disabled.\n\n"
"On Windows, try using Putty instead.\r\n");
}
linenoiseSetMaxLineLen(console.max_cmdline_len_);
while (1)
{
String prompt = console.prompt_;
// Insert current PWD into prompt if needed
prompt.replace("%pwd%", console_getpwd());
char *line = linenoise(prompt.c_str());
if (line == NULL)
{
ESP_LOGD(TAG, "empty line");
/* Ignore empty lines */
continue;
}
log_v("Line received from linenoise: %s\n", line);
/* Add the command to the history */
linenoiseHistoryAdd(line);
/* Save command history to filesystem */
if (console.history_save_path_)
{
linenoiseHistorySave(console.history_save_path_);
}
//Interpolate the input line
String interpolated_line = interpolateLine(line);
log_v("Interpolated line: %s\n", interpolated_line.c_str());
/* Try to run the command */
int ret;
esp_err_t err = esp_console_run(interpolated_line.c_str(), &ret);
//Reset global state
resetAfterCommands();
if (err == ESP_ERR_NOT_FOUND)
{
printf("Unrecognized command\n");
}
else if (err == ESP_ERR_INVALID_ARG)
{
// command was empty
}
else if (err == ESP_OK && ret != ESP_OK)
{
printf("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(ret));
}
else if (err != ESP_OK)
{
printf("Internal error: %s\n", esp_err_to_name(err));
}
/* linenoise allocates line buffer on the heap, so need to free it */
linenoiseFree(line);
}
ESP_LOGD(TAG, "REPL task ended");
vTaskDelete(NULL);
}
void Console::end()
{
}
};
================================================
FILE: src/ESP32Console/Console.h
================================================
#pragma once
#if !defined(ESP32)
#error This library depends on ESP-IDF and only works on ESP32!
#endif
#include "esp_console.h"
#include "Arduino.h"
#include "./ConsoleCommandBase.h"
#include "freertos/task.h"
#include "linenoise/linenoise.h"
#include "driver/uart.h"
namespace ESP32Console
{
class Console
{
private:
const char *prompt_ = "ESP32> ";
const uint32_t task_priority_;
const BaseType_t task_stack_size_;
uint16_t max_history_len_ = 40;
const char* history_save_path_ = nullptr;
const size_t max_cmdline_len_;
const size_t max_cmdline_args_;
uart_port_t uart_channel_;
TaskHandle_t task_;
static void repl_task(void *args);
void beginCommon();
public:
/**
* @brief Create a new ESP32Console with the default parameters
*/
Console(const uint32_t task_stack_size = 4096, const BaseType_t task_priority = 2, int max_cmdline_len = 256, int max_cmdline_args = 32) : task_priority_(task_priority), task_stack_size_(task_stack_size), max_cmdline_len_(max_cmdline_len), max_cmdline_args_(max_cmdline_args){};
~Console()
{
vTaskDelete(task_);
end();
}
/**
* @brief Register the given command, using the raw ESP-IDF structure.
*
* @param cmd The command that should be registered
* @return Return true, if the registration was successfull, false if not.
*/
bool registerCommand(const esp_console_cmd_t *cmd)
{
log_v("Registering new command %s", cmd->command);
auto code = esp_console_cmd_register(cmd);
if (code != ESP_OK)
{
log_e("Error registering command (Reason %s)", esp_err_to_name(code));
return false;
}
return true;
}
/**
* @brief Register the given command
*
* @param cmd The command that should be registered
* @return true If the command was registered successful.
* @return false If the command was not registered because of an error.
*/
bool registerCommand(const ConsoleCommandBase &cmd)
{
auto c = cmd.toCommandStruct();
return registerCommand(&c);
}
/**
* @brief Registers the given command
*
* @param command The name under which the command can be called (e.g. "ls"). Must not contain spaces.
* @param func A pointer to the function which should be run, when this command is called
* @param help A text shown in output of "help" command describing this command. When empty it is not shown in help.
* @param hint A text describing the usage of the command in help output
* @return true If the command was registered successful.
* @return false If the command was not registered because of an error.
*/
bool registerCommand(const char *command, esp_console_cmd_func_t func, const char *help, const char *hint = "")
{
const esp_console_cmd_t cmd = {
.command = command,
.help = help,
.hint = hint,
.func = func,
.argtable = nullptr
};
return registerCommand(&cmd);
};
void registerCoreCommands();
void registerSystemCommands();
void registerNetworkCommands();
void registerVFSCommands();
void registerGPIOCommands();
/**
* @brief Set the command prompt. Default is "ESP32>".
*
* @param prompt
*/
void setPrompt(const char *prompt) { prompt_ = prompt; };
/**
* @brief Set the History Max Length object
*
* @param max_length
*/
void setHistoryMaxLength(uint16_t max_length)
{
max_history_len_ = max_length;
linenoiseHistorySetMaxLen(max_length);
}
/**
* @brief Enable saving of command history, which makes history persistent over resets. SPIFF need to be enabled, or you need to pass the filename to use.
*
* @param history_save_path The file which will be used to save command history. Set to nullptr to disable persistent saving
*/
void enablePersistentHistory(const char *history_save_path = "/spiffs/.history.txt") { history_save_path_ = history_save_path; };
/**
* @brief Starts the console. Similar to the Serial.begin() function
*
* @param baud The baud rate with which the console should work. Recommended: 115200
* @param rxPin The pin to use for RX
* @param txPin The pin to use for TX
* @param channel The UART port to use
*/
void begin(int baud, int rxPin = -1, int txPin = -1, uart_port_t channel = UART_NUM_0);
/**
* @brief Starts the console. Overload for backward compatibility with uint8_t channel argument.
*
* @param baud The baud rate with which the console should work. Recommended: 115200
* @param rxPin The pin to use for RX
* @param txPin The pin to use for TX
* @param channel The number of the UART to use (cast to uart_port_t)
*/
void begin(int baud, int rxPin, int txPin, uint8_t channel)
{
begin(baud, rxPin, txPin, static_cast<uart_port_t>(channel));
}
void end();
};
};
================================================
FILE: src/ESP32Console/ConsoleCommand.h
================================================
#pragma once
#include "./ConsoleCommandBase.h"
namespace ESP32Console
{
/**
* @brief A class for registering custom console commands via a passed function pointer.
*
*/
class ConsoleCommand : public ConsoleCommandBase
{
protected:
const char *hint_;
public:
/**
* @brief Creates a new ConsoleCommand object with the given parameters.
*
* @param command The name under which the command will be called (e.g. "ls"). Must not contain spaces.
* @param func The pointer to the function which is run if this function is called. Takes two paramaters argc and argv, similar to a classical C program.
* @param help The text shown in "help" output for this command. If set to empty string, then the command is not shown in help.
* @param hint A hint explaining the parameters in help output
*/
ConsoleCommand(const char *command, esp_console_cmd_func_t func, const char* help, const char* hint = "") { command_ = command; func_ = func; help_= help; hint_ = hint;};
const esp_console_cmd_t toCommandStruct() const override
{
const esp_console_cmd_t cmd = {
.command = command_,
.help = help_,
.hint = hint_,
.func = func_,
.argtable = nullptr
};
return cmd;
}
};
};
================================================
FILE: src/ESP32Console/ConsoleCommandBase.h
================================================
#pragma once
#include "esp_console.h"
namespace ESP32Console {
class ConsoleCommandBase
{
protected:
const char *command_;
const char *help_;
esp_console_cmd_func_t func_;
public:
/**
* @brief Get the command name
*
* @return const char*
*/
const char* getCommand() { return command_; };
const char* getHelp() { return help_; };
virtual const esp_console_cmd_t toCommandStruct() const = 0;
};
};
================================================
FILE: src/ESP32Console/ConsoleCommandD.cpp
================================================
#include "./ConsoleCommandD.h"
#include "Arduino.h"
const static char *TAG = "ConsoleCommandD";
namespace ESP32Console
{
std::unordered_map<std::string, delegateFunc> ConsoleCommandD::registry_ = std::unordered_map<std::string, delegateFunc>();
int ConsoleCommandD::delegateResolver(int argc, char **argv)
{
// Retrieve ConsoleCommandD from registry
auto it = registry_.find(argv[0]);
if (it == registry_.end())
{
log_e("Could not resolve the delegated function call!");
return 1;
}
delegateFunc command = it->second;
int code = 0;
try
{
return command(argc, argv);
}
catch (const std::exception &err)
{
printf("%s", err.what());
printf("\n");
return 1;
}
}
}
================================================
FILE: src/ESP32Console/ConsoleCommandD.h
================================================
#pragma once
#include "./ConsoleCommand.h"
#include "esp_console.h"
#include <string>
#include <functional>
#include <unordered_map>
#include <type_traits>
namespace ESP32Console
{
using delegateFunc = std::function<int(int, char **)>;
/**
* @brief A class for registering custom console commands via delegate function element. The difference to ConsoleCommand is that you can pass a std::function object instead of a function pointer directly.
* This allows for use of lambda functions. The disadvantage is that we need more heap, as we have to save the delegate function objects in a map.
*
*/
class ConsoleCommandD : public ConsoleCommand
{
protected:
delegateFunc delegateFn_;
static int delegateResolver(int argc, char **argv);
public:
static std::unordered_map<std::string, delegateFunc> registry_;
ConsoleCommandD(const char *command, delegateFunc func, const char* help, const char* hint = ""): ConsoleCommand(command, &delegateResolver, help, hint), delegateFn_(func) {};
const esp_console_cmd_t toCommandStruct() const override
{
const esp_console_cmd_t cmd = {
.command = command_,
.help = help_,
.hint = hint_,
.func = func_,
.argtable = nullptr
};
// When the command gets registered add it to our map, so we can access it later to resolve the delegated function call
registry_.insert({std::string(command_), std::move(delegateFn_)});
return cmd;
}
delegateFunc &getDelegateFunction() { return delegateFn_; }
};
}
================================================
FILE: src/ESP32Console/Helpers/InputParser.cpp
================================================
#include "./InputParser.h"
#include <Arduino.h>
namespace ESP32Console
{
String interpolateLine(const char *in_)
{
String in(in_);
String out = in;
// Add a space at end of line, this does not change anything for our consoleLine and makes parsing easier
in = in + " ";
// Interpolate each $ with the env variable if existing. If $ is the first character in a line it is not interpolated
int var_index = 1;
while ((var_index = in.indexOf("$", var_index + 1)) > 0)
{
/**
* Extract the possible env variable
*/
int variable_start = var_index + 1;
// If the char after $ is a { we look for an closing }. Otherwise we just look for an space
char delimiter = ' ';
if (in.charAt(variable_start) == '{')
{
// Our variable starts then at the character after ${
variable_start++;
}
int variable_end = in.indexOf(delimiter, variable_start + 1);
// If delimiter not found look for next possible env variable
if (variable_end == -1)
{
continue;
}
String env_var = in.substring(variable_start, variable_end);
env_var.trim();
// Depending on whether this is an variable string, we have to include the next character
String replace_target = in.substring(var_index, delimiter == '}' ? variable_end + 1 : variable_end);
// Check if we have an env with this name, then replace it
const char *value = getenv(env_var.c_str());
if (value)
{
out.replace(replace_target.c_str(), value);
}
}
return out.c_str();
}
}
================================================
FILE: src/ESP32Console/Helpers/InputParser.h
================================================
#pragma once
#include <Arduino.h>
namespace ESP32Console
{
/**
* @brief Interpolate the given line using environment variables. $VAR and ${ENV} are replaced by the representive values of the environment variables.
*
* @param in
* @return String
*/
String interpolateLine(const char *in);
}
================================================
FILE: src/ESP32Console/Helpers/PWDHelpers.cpp
================================================
#include "ESP32Console/Helpers/PWDHelpers.h"
#include <stdlib.h>
#include <stdio.h>
#include <Arduino.h>
namespace ESP32Console
{
constexpr char *PWD_DEFAULT = (char*) "/";
const char *console_getpwd()
{
char *pwd = getenv("PWD");
if (pwd)
{ // If we have defined a PWD value, return it
return pwd;
}
// Otherwise set a default one
setenv("PWD", PWD_DEFAULT, 1);
return PWD_DEFAULT;
}
const char *console_realpath(const char *path, char *resolvedPath)
{
String in = String(path);
String pwd = String(console_getpwd());
String result;
// If path is not absolute we prepend our pwd
if (!in.startsWith("/"))
{
result = pwd + "/" + in;
}
else
{
result = in;
}
realpath(result.c_str(), resolvedPath);
return resolvedPath;
}
int console_chdir(const char *path)
{
char buffer[PATH_MAX + 2];
console_realpath(path, buffer);
size_t buffer_len = strlen(buffer);
//If path does not end with slash, add it.
if(buffer[buffer_len - 1] != '/')
{
buffer[buffer_len] = '/';
buffer[buffer_len + 1] = '\0';
}
setenv("PWD", buffer, 1);
return 0;
}
}
================================================
FILE: src/ESP32Console/Helpers/PWDHelpers.h
================================================
#pragma once
namespace ESP32Console
{
/**
* @brief Returns the current console process working dir
*
* @return const char*
*/
const char *console_getpwd();
/**
* @brief Resolves the given path using the console process working dir
*
* @return const char*
*/
const char *console_realpath(const char *path, char *resolvedPath);
int console_chdir(const char *path);
}
================================================
FILE: src/ESP32Console/OptionsConsoleCommand.cpp
================================================
#include "./OptionsConsoleCommand.h"
#include "Arduino.h"
const static char *TAG = "ArgParseCommand";
namespace ESP32Console
{
std::unordered_map<std::string, OptionsConsoleCommand> OptionsConsoleCommand::registry_ = std::unordered_map<std::string, OptionsConsoleCommand>();
int OptionsConsoleCommand::delegateResolver(int argc, char **argv)
{
// Retrieve ArgParserCommand from registry
auto it = registry_.find(argv[0]);
if (it == registry_.end())
{
log_e("Could not resolve the delegated function call!");
return 1;
}
auto command = it->second;
int code = 0;
try
{
auto options = command.options;
auto result = options.parse(argc, argv);
//Print help on --help argument
if (result.count("help")) {
printf(options.help().c_str());
printf("\n");
return EXIT_SUCCESS;
}
if (command.getVersion() && result.count("version")) {
printf("Version: %s\n", command.getVersion());
return EXIT_SUCCESS;
}
return command.delegateFn_(argc, argv, result, options);
}
catch (const std::exception &err)
{
printf(err.what());
printf("\n");
return EXIT_FAILURE;
}
}
}
================================================
FILE: src/ESP32Console/OptionsConsoleCommand.h
================================================
#pragma once
#include "./ConsoleCommandBase.h"
#include "esp_console.h"
//This define is important, otherwise we get very high memory usage from regex
#define CXXOPTS_NO_REGEX 1
#define CXXOPTS_NO_RTTI 1
#include "cxxopts/cxxopts.hpp"
#include <functional>
#include <unordered_map>
#include <string>
namespace ESP32Console
{
using cxxopts::Options;
using cxxopts::ParseResult;
using argParseFunc = std::function<int(int, char **, ParseResult&, Options&)>;
class OptionsConsoleCommand : public ConsoleCommandBase
{
protected:
argParseFunc delegateFn_;
const char *hint_;
const char *version_;
static int delegateResolver(int argc, char **argv);
public:
Options options;
static std::unordered_map<std::string, OptionsConsoleCommand> registry_;
OptionsConsoleCommand(const char *command, argParseFunc func, const char *help, const char* version = nullptr, const char *hint = nullptr): options(command, help)
{
command_ = command;
help_ = help;
version_ = version;
if (hint)
{
hint_ = hint;
}
else
{
hint_ = "Use --help option of command for more info";
}
//Add an option
options.add_options()
("help", "Show help", cxxopts::value<bool>()->default_value("false"))
;
if (version_)
{
options.add_options()
("version", "Show version number of this command", cxxopts::value<bool>()->default_value("false"))
;
}
delegateFn_ = func;
func_ = &delegateResolver;
}
const esp_console_cmd_t toCommandStruct() const override
{
const esp_console_cmd_t cmd = {
.command = command_,
.help = help_,
.hint = hint_,
.func = func_,
.argtable = nullptr
};
// When the command gets registered add it to our map, so we can access it later to resolve the delegated function call
registry_.insert({std::string(command_), std::move(*this)});
return cmd;
}
argParseFunc &getDelegateFunction() { return delegateFn_; }
const char* getVersion() const {return version_;};
};
}
================================================
FILE: src/ESP32Console.h
================================================
#pragma once
#if !defined(ESP32)
#error This library depends on ESP-IDF and only works on ESP32!
#endif
#define ESP32CONSOLE_VERSION "1.3.0"
#include "ESP32Console/Console.h"
#include "ESP32Console/ConsoleCommand.h"
#include "ESP32Console/ConsoleCommandD.h"
#include "ESP32Console/OptionsConsoleCommand.h"
================================================
FILE: src/cxxopts/cxxopts.hpp
================================================
/*
Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef CXXOPTS_HPP_INCLUDED
#define CXXOPTS_HPP_INCLUDED
#include <cctype>
#include <cstring>
#include <exception>
//#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include <algorithm>
#if defined(__GNUC__) && !defined(__clang__)
# if (__GNUC__ * 10 + __GNUC_MINOR__) < 49
# define CXXOPTS_NO_REGEX true
# endif
#endif
#ifndef CXXOPTS_NO_REGEX
# include <regex>
#endif // CXXOPTS_NO_REGEX
// Nonstandard before C++17, which is coincidentally what we also need for <optional>
#ifdef __has_include
# if __has_include(<optional>)
# include <optional>
# ifdef __cpp_lib_optional
# define CXXOPTS_HAS_OPTIONAL
# endif
# endif
#endif
#if __cplusplus >= 201603L
#define CXXOPTS_NODISCARD [[nodiscard]]
#else
#define CXXOPTS_NODISCARD
#endif
#ifndef CXXOPTS_VECTOR_DELIMITER
#define CXXOPTS_VECTOR_DELIMITER ','
#endif
#define CXXOPTS__VERSION_MAJOR 3
#define CXXOPTS__VERSION_MINOR 0
#define CXXOPTS__VERSION_PATCH 0
#if (__GNUC__ < 10 || (__GNUC__ == 10 && __GNUC_MINOR__ < 1)) && __GNUC__ >= 6
#define CXXOPTS_NULL_DEREF_IGNORE
#endif
namespace cxxopts
{
static constexpr struct {
uint8_t major, minor, patch;
} version = {
CXXOPTS__VERSION_MAJOR,
CXXOPTS__VERSION_MINOR,
CXXOPTS__VERSION_PATCH
};
} // namespace cxxopts
//when we ask cxxopts to use Unicode, help strings are processed using ICU,
//which results in the correct lengths being computed for strings when they
//are formatted for the help output
//it is necessary to make sure that <unicode/unistr.h> can be found by the
//compiler, and that icu-uc is linked in to the binary.
#ifdef CXXOPTS_USE_UNICODE
#include <unicode/unistr.h>
namespace cxxopts
{
using String = icu::UnicodeString;
inline
String
toLocalString(std::string s)
{
return icu::UnicodeString::fromUTF8(std::move(s));
}
#if defined(__GNUC__)
// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it:
// warning: base class 'class std::enable_shared_from_this<cxxopts::Value>' has accessible non-virtual destructor
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#pragma GCC diagnostic ignored "-Weffc++"
// This will be ignored under other compilers like LLVM clang.
#endif
class UnicodeStringIterator : public
std::iterator<std::forward_iterator_tag, int32_t>
{
public:
UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos)
: s(string)
, i(pos)
{
}
value_type
operator*() const
{
return s->char32At(i);
}
bool
operator==(const UnicodeStringIterator& rhs) const
{
return s == rhs.s && i == rhs.i;
}
bool
operator!=(const UnicodeStringIterator& rhs) const
{
return !(*this == rhs);
}
UnicodeStringIterator&
operator++()
{
++i;
return *this;
}
UnicodeStringIterator
operator+(int32_t v)
{
return UnicodeStringIterator(s, i + v);
}
private:
const icu::UnicodeString* s;
int32_t i;
};
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
inline
String&
stringAppend(String&s, String a)
{
return s.append(std::move(a));
}
inline
String&
stringAppend(String& s, size_t n, UChar32 c)
{
for (size_t i = 0; i != n; ++i)
{
s.append(c);
}
return s;
}
template <typename Iterator>
String&
stringAppend(String& s, Iterator begin, Iterator end)
{
while (begin != end)
{
s.append(*begin);
++begin;
}
return s;
}
inline
size_t
stringLength(const String& s)
{
return s.length();
}
inline
std::string
toUTF8String(const String& s)
{
std::string result;
s.toUTF8String(result);
return result;
}
inline
bool
empty(const String& s)
{
return s.isEmpty();
}
}
namespace std
{
inline
cxxopts::UnicodeStringIterator
begin(const icu::UnicodeString& s)
{
return cxxopts::UnicodeStringIterator(&s, 0);
}
inline
cxxopts::UnicodeStringIterator
end(const icu::UnicodeString& s)
{
return cxxopts::UnicodeStringIterator(&s, s.length());
}
}
//ifdef CXXOPTS_USE_UNICODE
#else
namespace cxxopts
{
using String = std::string;
template <typename T>
T
toLocalString(T&& t)
{
return std::forward<T>(t);
}
inline
size_t
stringLength(const String& s)
{
return s.length();
}
inline
String&
stringAppend(String&s, const String& a)
{
return s.append(a);
}
inline
String&
stringAppend(String& s, size_t n, char c)
{
return s.append(n, c);
}
template <typename Iterator>
String&
stringAppend(String& s, Iterator begin, Iterator end)
{
return s.append(begin, end);
}
template <typename T>
std::string
toUTF8String(T&& t)
{
return std::forward<T>(t);
}
inline
bool
empty(const std::string& s)
{
return s.empty();
}
} // namespace cxxopts
//ifdef CXXOPTS_USE_UNICODE
#endif
namespace cxxopts
{
namespace
{
#ifdef _WIN32
const std::string LQUOTE("\'");
const std::string RQUOTE("\'");
#else
const std::string LQUOTE("‘");
const std::string RQUOTE("’");
#endif
} // namespace
#if defined(__GNUC__)
// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it:
// warning: base class 'class std::enable_shared_from_this<cxxopts::Value>' has accessible non-virtual destructor
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#pragma GCC diagnostic ignored "-Weffc++"
// This will be ignored under other compilers like LLVM clang.
#endif
class Value : public std::enable_shared_from_this<Value>
{
public:
virtual ~Value() = default;
virtual
std::shared_ptr<Value>
clone() const = 0;
virtual void
parse(const std::string& text) const = 0;
virtual void
parse() const = 0;
virtual bool
has_default() const = 0;
virtual bool
is_container() const = 0;
virtual bool
has_implicit() const = 0;
virtual std::string
get_default_value() const = 0;
virtual std::string
get_implicit_value() const = 0;
virtual std::shared_ptr<Value>
default_value(const std::string& value) = 0;
virtual std::shared_ptr<Value>
implicit_value(const std::string& value) = 0;
virtual std::shared_ptr<Value>
no_implicit_value() = 0;
virtual bool
is_boolean() const = 0;
};
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
class OptionException : public std::exception
{
public:
explicit OptionException(std::string message)
: m_message(std::move(message))
{
}
CXXOPTS_NODISCARD
const char*
what() const noexcept override
{
return m_message.c_str();
}
private:
std::string m_message;
};
class OptionSpecException : public OptionException
{
public:
explicit OptionSpecException(const std::string& message)
: OptionException(message)
{
}
};
class OptionParseException : public OptionException
{
public:
explicit OptionParseException(const std::string& message)
: OptionException(message)
{
}
};
class option_exists_error : public OptionSpecException
{
public:
explicit option_exists_error(const std::string& option)
: OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists")
{
}
};
class invalid_option_format_error : public OptionSpecException
{
public:
explicit invalid_option_format_error(const std::string& format)
: OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE)
{
}
};
class option_syntax_exception : public OptionParseException {
public:
explicit option_syntax_exception(const std::string& text)
: OptionParseException("Argument " + LQUOTE + text + RQUOTE +
" starts with a - but has incorrect syntax")
{
}
};
class option_not_exists_exception : public OptionParseException
{
public:
explicit option_not_exists_exception(const std::string& option)
: OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist")
{
}
};
class missing_argument_exception : public OptionParseException
{
public:
explicit missing_argument_exception(const std::string& option)
: OptionParseException(
"Option " + LQUOTE + option + RQUOTE + " is missing an argument"
)
{
}
};
class option_requires_argument_exception : public OptionParseException
{
public:
explicit option_requires_argument_exception(const std::string& option)
: OptionParseException(
"Option " + LQUOTE + option + RQUOTE + " requires an argument"
)
{
}
};
class option_not_has_argument_exception : public OptionParseException
{
public:
option_not_has_argument_exception
(
const std::string& option,
const std::string& arg
)
: OptionParseException(
"Option " + LQUOTE + option + RQUOTE +
" does not take an argument, but argument " +
LQUOTE + arg + RQUOTE + " given"
)
{
}
};
class option_not_present_exception : public OptionParseException
{
public:
explicit option_not_present_exception(const std::string& option)
: OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present")
{
}
};
class option_has_no_value_exception : public OptionException
{
public:
explicit option_has_no_value_exception(const std::string& option)
: OptionException(
!option.empty() ?
("Option " + LQUOTE + option + RQUOTE + " has no value") :
"Option has no value")
{
}
};
class argument_incorrect_type : public OptionParseException
{
public:
explicit argument_incorrect_type
(
const std::string& arg
)
: OptionParseException(
"Argument " + LQUOTE + arg + RQUOTE + " failed to parse"
)
{
}
};
class option_required_exception : public OptionParseException
{
public:
explicit option_required_exception(const std::string& option)
: OptionParseException(
"Option " + LQUOTE + option + RQUOTE + " is required but not present"
)
{
}
};
template <typename T>
void throw_or_mimic(const std::string& text)
{
static_assert(std::is_base_of<std::exception, T>::value,
"throw_or_mimic only works on std::exception and "
"deriving classes");
#ifndef CXXOPTS_NO_EXCEPTIONS
// If CXXOPTS_NO_EXCEPTIONS is not defined, just throw
throw T{text};
#else
// Otherwise manually instantiate the exception, print what() to stderr,
// and exit
T exception{text};
std::cerr << exception.what() << std::endl;
std::exit(EXIT_FAILURE);
#endif
}
namespace values
{
namespace parser_tool
{
struct IntegerDesc
{
std::string negative = "";
std::string base = "";
std::string value = "";
};
struct ArguDesc {
std::string arg_name = "";
bool grouping = false;
bool set_value = false;
std::string value = "";
};
#ifdef CXXOPTS_NO_REGEX
inline IntegerDesc SplitInteger(const std::string &text)
{
if (text.empty())
{
throw_or_mimic<argument_incorrect_type>(text);
}
IntegerDesc desc;
const char *pdata = text.c_str();
if (*pdata == '-')
{
pdata += 1;
desc.negative = "-";
}
if (strncmp(pdata, "0x", 2) == 0)
{
pdata += 2;
desc.base = "0x";
}
if (*pdata != '\0')
{
desc.value = std::string(pdata);
}
else
{
throw_or_mimic<argument_incorrect_type>(text);
}
return desc;
}
inline bool IsTrueText(const std::string &text)
{
const char *pdata = text.c_str();
if (*pdata == 't' || *pdata == 'T')
{
pdata += 1;
if (strncmp(pdata, "rue\0", 4) == 0)
{
return true;
}
}
else if (strncmp(pdata, "1\0", 2) == 0)
{
return true;
}
return false;
}
inline bool IsFalseText(const std::string &text)
{
const char *pdata = text.c_str();
if (*pdata == 'f' || *pdata == 'F')
{
pdata += 1;
if (strncmp(pdata, "alse\0", 5) == 0)
{
return true;
}
}
else if (strncmp(pdata, "0\0", 2) == 0)
{
return true;
}
return false;
}
inline std::pair<std::string, std::string> SplitSwitchDef(const std::string &text)
{
std::string short_sw, long_sw;
const char *pdata = text.c_str();
if (isalnum(*pdata) && *(pdata + 1) == ',') {
short_sw = std::string(1, *pdata);
pdata += 2;
}
while (*pdata == ' ') { pdata += 1; }
if (isalnum(*pdata)) {
const char *store = pdata;
pdata += 1;
while (isalnum(*pdata) || *pdata == '-' || *pdata == '_') {
pdata += 1;
}
if (*pdata == '\0') {
long_sw = std::string(store, pdata - store);
} else {
throw_or_mimic<invalid_option_format_error>(text);
}
}
return std::pair<std::string, std::string>(short_sw, long_sw);
}
inline ArguDesc ParseArgument(const char *arg, bool &matched)
{
ArguDesc argu_desc;
const char *pdata = arg;
matched = false;
if (strncmp(pdata, "--", 2) == 0)
{
pdata += 2;
if (isalnum(*pdata))
{
argu_desc.arg_name.push_back(*pdata);
pdata += 1;
while (isalnum(*pdata) || *pdata == '-' || *pdata == '_')
{
argu_desc.arg_name.push_back(*pdata);
pdata += 1;
}
if (argu_desc.arg_name.length() > 1)
{
if (*pdata == '=')
{
argu_desc.set_value = true;
pdata += 1;
if (*pdata != '\0')
{
argu_desc.value = std::string(pdata);
}
matched = true;
}
else if (*pdata == '\0')
{
matched = true;
}
}
}
}
else if (strncmp(pdata, "-", 1) == 0)
{
pdata += 1;
argu_desc.grouping = true;
while (isalnum(*pdata))
{
argu_desc.arg_name.push_back(*pdata);
pdata += 1;
}
matched = !argu_desc.arg_name.empty() && *pdata == '\0';
}
return argu_desc;
}
#else // CXXOPTS_NO_REGEX
namespace
{
std::basic_regex<char> integer_pattern
("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)");
std::basic_regex<char> truthy_pattern
("(t|T)(rue)?|1");
std::basic_regex<char> falsy_pattern
("(f|F)(alse)?|0");
std::basic_regex<char> option_matcher
("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)");
std::basic_regex<char> option_specifier
("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?");
} // namespace
inline IntegerDesc SplitInteger(const std::string &text)
{
std::smatch match;
std::regex_match(text, match, integer_pattern);
if (match.length() == 0)
{
throw_or_mimic<argument_incorrect_type>(text);
}
IntegerDesc desc;
desc.negative = match[1];
desc.base = match[2];
desc.value = match[3];
if (match.length(4) > 0)
{
desc.base = match[5];
desc.value = "0";
return desc;
}
return desc;
}
inline bool IsTrueText(const std::string &text)
{
std::smatch result;
std::regex_match(text, result, truthy_pattern);
return !result.empty();
}
inline bool IsFalseText(const std::string &text)
{
std::smatch result;
std::regex_match(text, result, falsy_pattern);
return !result.empty();
}
inline std::pair<std::string, std::string> SplitSwitchDef(const std::string &text)
{
std::match_results<const char*> result;
std::regex_match(text.c_str(), result, option_specifier);
if (result.empty())
{
throw_or_mimic<invalid_option_format_error>(text);
}
const std::string& short_sw = result[2];
const std::string& long_sw = result[3];
return std::pair<std::string, std::string>(short_sw, long_sw);
}
inline ArguDesc ParseArgument(const char *arg, bool &matched)
{
std::match_results<const char*> result;
std::regex_match(arg, result, option_matcher);
matched = !result.empty();
ArguDesc argu_desc;
if (matched) {
argu_desc.arg_name = result[1].str();
argu_desc.set_value = result[2].length() > 0;
argu_desc.value = result[3].str();
if (result[4].length() > 0)
{
argu_desc.grouping = true;
argu_desc.arg_name = result[4].str();
}
}
return argu_desc;
}
#endif // CXXOPTS_NO_REGEX
#undef CXXOPTS_NO_REGEX
}
namespace detail
{
template <typename T, bool B>
struct SignedCheck;
template <typename T>
struct SignedCheck<T, true>
{
template <typename U>
void
operator()(bool negative, U u, const std::string& text)
{
if (negative)
{
if (u > static_cast<U>((std::numeric_limits<T>::min)()))
{
throw_or_mimic<argument_incorrect_type>(text);
}
}
else
{
if (u > static_cast<U>((std::numeric_limits<T>::max)()))
{
throw_or_mimic<argument_incorrect_type>(text);
}
}
}
};
template <typename T>
struct SignedCheck<T, false>
{
template <typename U>
void
operator()(bool, U, const std::string&) const {}
};
template <typename T, typename U>
void
check_signed_range(bool negative, U value, const std::string& text)
{
SignedCheck<T, std::numeric_limits<T>::is_signed>()(negative, value, text);
}
} // namespace detail
template <typename R, typename T>
void
checked_negate(R& r, T&& t, const std::string&, std::true_type)
{
// if we got to here, then `t` is a positive number that fits into
// `R`. So to avoid MSVC C4146, we first cast it to `R`.
// See https://github.com/jarro2783/cxxopts/issues/62 for more details.
r = static_cast<R>(-static_cast<R>(t-1)-1);
}
template <typename R, typename T>
void
checked_negate(R&, T&&, const std::string& text, std::false_type)
{
throw_or_mimic<argument_incorrect_type>(text);
}
template <typename T>
void
integer_parser(const std::string& text, T& value)
{
parser_tool::IntegerDesc int_desc = parser_tool::SplitInteger(text);
using US = typename std::make_unsigned<T>::type;
constexpr bool is_signed = std::numeric_limits<T>::is_signed;
const bool negative = int_desc.negative.length() > 0;
const uint8_t base = int_desc.base.length() > 0 ? 16 : 10;
const std::string & value_match = int_desc.value;
US result = 0;
for (char ch : value_match)
{
US digit = 0;
if (ch >= '0' && ch <= '9')
{
digit = static_cast<US>(ch - '0');
}
else if (base == 16 && ch >= 'a' && ch <= 'f')
{
digit = static_cast<US>(ch - 'a' + 10);
}
else if (base == 16 && ch >= 'A' && ch <= 'F')
{
digit = static_cast<US>(ch - 'A' + 10);
}
else
{
throw_or_mimic<argument_incorrect_type>(text);
}
const US next = static_cast<US>(result * base + digit);
if (result > next)
{
throw_or_mimic<argument_incorrect_type>(text);
}
result = next;
}
detail::check_signed_range<T>(negative, result, text);
if (negative)
{
checked_negate<T>(value, result, text, std::integral_constant<bool, is_signed>());
}
else
{
value = static_cast<T>(result);
}
}
template <typename T>
void stringstream_parser(const std::string& text, T& value)
{
std::stringstream in(text);
in >> value;
if (!in) {
throw_or_mimic<argument_incorrect_type>(text);
}
}
template <typename T,
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr
>
void parse_value(const std::string& text, T& value)
{
integer_parser(text, value);
}
inline
void
parse_value(const std::string& text, bool& value)
{
if (parser_tool::IsTrueText(text))
{
value = true;
return;
}
if (parser_tool::IsFalseText(text))
{
value = false;
return;
}
throw_or_mimic<argument_incorrect_type>(text);
}
inline
void
parse_value(const std::string& text, std::string& value)
{
value = text;
}
// The fallback parser. It uses the stringstream parser to parse all types
// that have not been overloaded explicitly. It has to be placed in the
// source code before all other more specialized templates.
template <typename T,
typename std::enable_if<!std::is_integral<T>::value>::type* = nullptr
>
void
parse_value(const std::string& text, T& value) {
stringstream_parser(text, value);
}
template <typename T>
void
parse_value(const std::string& text, std::vector<T>& value)
{
if (text.empty()) {
T v;
parse_value(text, v);
value.emplace_back(std::move(v));
return;
}
std::stringstream in(text);
std::string token;
while(!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) {
T v;
parse_value(token, v);
value.emplace_back(std::move(v));
}
}
#ifdef CXXOPTS_HAS_OPTIONAL
template <typename T>
void
parse_value(const std::string& text, std::optional<T>& value)
{
T result;
parse_value(text, result);
value = std::move(result);
}
#endif
inline
void parse_value(const std::string& text, char& c)
{
if (text.length() != 1)
{
throw_or_mimic<argument_incorrect_type>(text);
}
c = text[0];
}
template <typename T>
struct type_is_container
{
static constexpr bool value = false;
};
template <typename T>
struct type_is_container<std::vector<T>>
{
static constexpr bool value = true;
};
template <typename T>
class abstract_value : public Value
{
using Self = abstract_value<T>;
public:
abstract_value()
: m_result(std::make_shared<T>())
, m_store(m_result.get())
{
}
explicit abstract_value(T* t)
: m_store(t)
{
}
~abstract_value() override = default;
abstract_value& operator=(const abstract_value&) = default;
abstract_value(const abstract_value& rhs)
{
if (rhs.m_result)
{
m_result = std::make_shared<T>();
m_store = m_result.get();
}
else
{
m_store = rhs.m_store;
}
m_default = rhs.m_default;
m_implicit = rhs.m_implicit;
m_default_value = rhs.m_default_value;
m_implicit_value = rhs.m_implicit_value;
}
void
parse(const std::string& text) const override
{
parse_value(text, *m_store);
}
bool
is_container() const override
{
return type_is_container<T>::value;
}
void
parse() const override
{
parse_value(m_default_value, *m_store);
}
bool
has_default() const override
{
return m_default;
}
bool
has_implicit() const override
{
return m_implicit;
}
std::shared_ptr<Value>
default_value(const std::string& value) override
{
m_default = true;
m_default_value = value;
return shared_from_this();
}
std::shared_ptr<Value>
implicit_value(const std::string& value) override
{
m_implicit = true;
m_implicit_value = value;
return shared_from_this();
}
std::shared_ptr<Value>
no_implicit_value() override
{
m_implicit = false;
return shared_from_this();
}
std::string
get_default_value() const override
{
return m_default_value;
}
std::string
get_implicit_value() const override
{
return m_implicit_value;
}
bool
is_boolean() const override
{
return std::is_same<T, bool>::value;
}
const T&
get() const
{
if (m_store == nullptr)
{
return *m_result;
}
return *m_store;
}
protected:
std::shared_ptr<T> m_result{};
T* m_store{};
bool m_default = false;
bool m_implicit = false;
std::string m_default_value{};
std::string m_implicit_value{};
};
template <typename T>
class standard_value : public abstract_value<T>
{
public:
using abstract_value<T>::abstract_value;
CXXOPTS_NODISCARD
std::shared_ptr<Value>
clone() const override
{
return std::make_shared<standard_value<T>>(*this);
}
};
template <>
class standard_value<bool> : public abstract_value<bool>
{
public:
~standard_value() override = default;
standard_value()
{
set_default_and_implicit();
}
explicit standard_value(bool* b)
: abstract_value(b)
{
set_default_and_implicit();
}
std::shared_ptr<Value>
clone() const override
{
return std::make_shared<standard_value<bool>>(*this);
}
private:
void
set_default_and_implicit()
{
m_default = true;
m_default_value = "false";
m_implicit = true;
m_implicit_value = "true";
}
};
} // namespace values
template <typename T>
std::shared_ptr<Value>
value()
{
return std::make_shared<values::standard_value<T>>();
}
template <typename T>
std::shared_ptr<Value>
value(T& t)
{
return std::make_shared<values::standard_value<T>>(&t);
}
class OptionAdder;
class OptionDetails
{
public:
OptionDetails
(
std::string short_,
std::string long_,
String desc,
std::shared_ptr<const Value> val
)
: m_short(std::move(short_))
, m_long(std::move(long_))
, m_desc(std::move(desc))
, m_value(std::move(val))
, m_count(0)
{
m_hash = std::hash<std::string>{}(m_long + m_short);
}
OptionDetails(const OptionDetails& rhs)
: m_desc(rhs.m_desc)
, m_value(rhs.m_value->clone())
, m_count(rhs.m_count)
{
}
OptionDetails(OptionDetails&& rhs) = default;
CXXOPTS_NODISCARD
const String&
description() const
{
return m_desc;
}
CXXOPTS_NODISCARD
const Value&
value() const {
return *m_value;
}
CXXOPTS_NODISCARD
std::shared_ptr<Value>
make_storage() const
{
return m_value->clone();
}
CXXOPTS_NODISCARD
const std::string&
short_name() const
{
return m_short;
}
CXXOPTS_NODISCARD
const std::string&
long_name() const
{
return m_long;
}
CXXOPTS_NODISCARD
const std::string&
essential_name() const
{
return m_long.empty() ? m_short : m_long;
}
size_t
hash() const
{
return m_hash;
}
private:
std::string m_short{};
std::string m_long{};
String m_desc{};
std::shared_ptr<const Value> m_value{};
int m_count;
size_t m_hash{};
};
struct HelpOptionDetails
{
std::string s;
std::string l;
String desc;
bool has_default;
std::string default_value;
bool has_implicit;
std::string implicit_value;
std::string arg_help;
bool is_container;
bool is_boolean;
};
struct HelpGroupDetails
{
std::string name{};
std::string description{};
std::vector<HelpOptionDetails> options{};
};
class OptionValue
{
public:
void
parse
(
const std::shared_ptr<const OptionDetails>& details,
const std::string& text
)
{
ensure_value(details);
++m_count;
m_value->parse(text);
m_long_name = &details->long_name();
}
void
parse_default(const std::shared_ptr<const OptionDetails>& details)
{
ensure_value(details);
m_default = true;
m_long_name = &details->long_name();
m_value->parse();
}
void
parse_no_value(const std::shared_ptr<const OptionDetails>& details)
{
m_long_name = &details->long_name();
}
#if defined(CXXOPTS_NULL_DEREF_IGNORE)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnull-dereference"
#endif
CXXOPTS_NODISCARD
size_t
count() const noexcept
{
return m_count;
}
#if defined(CXXOPTS_NULL_DEREF_IGNORE)
#pragma GCC diagnostic pop
#endif
// TODO: maybe default options should count towards the number of arguments
CXXOPTS_NODISCARD
bool
has_default() const noexcept
{
return m_default;
}
template <typename T>
const T&
as() const
{
if (m_value == nullptr) {
throw_or_mimic<option_has_no_value_exception>(
m_long_name == nullptr ? "" : *m_long_name);
}
#ifdef CXXOPTS_NO_RTTI
return static_cast<const values::standard_value<T>&>(*m_value).get();
#else
return dynamic_cast<const values::standard_value<T>&>(*m_value).get();
#endif
}
private:
void
ensure_value(const std::shared_ptr<const OptionDetails>& details)
{
if (m_value == nullptr)
{
m_value = details->make_storage();
}
}
const std::string* m_long_name = nullptr;
// Holding this pointer is safe, since OptionValue's only exist in key-value pairs,
// where the key has the string we point to.
std::shared_ptr<Value> m_value{};
size_t m_count = 0;
bool m_default = false;
};
class KeyValue
{
public:
KeyValue(std::string key_, std::string value_)
: m_key(std::move(key_))
, m_value(std::move(value_))
{
}
CXXOPTS_NODISCARD
const std::string&
key() const
{
return m_key;
}
CXXOPTS_NODISCARD
const std::string&
value() const
{
return m_value;
}
template <typename T>
T
as() const
{
T result;
values::parse_value(m_value, result);
return result;
}
private:
std::string m_key;
std::string m_value;
};
using ParsedHashMap = std::unordered_map<size_t, OptionValue>;
using NameHashMap = std::unordered_map<std::string, size_t>;
class ParseResult
{
public:
class Iterator
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = KeyValue;
using difference_type = void;
using pointer = const KeyValue*;
using reference = const KeyValue&;
Iterator() = default;
Iterator(const Iterator&) = default;
Iterator(const ParseResult *pr, bool end=false)
: m_pr(pr)
, m_iter(end? pr->m_defaults.end(): pr->m_sequential.begin())
{
}
Iterator& operator++()
{
++m_iter;
if(m_iter == m_pr->m_sequential.end())
{
m_iter = m_pr->m_defaults.begin();
return *this;
}
return *this;
}
Iterator operator++(int)
{
Iterator retval = *this;
++(*this);
return retval;
}
bool operator==(const Iterator& other) const
{
return m_iter == other.m_iter;
}
bool operator!=(const Iterator& other) const
{
return !(*this == other);
}
const KeyValue& operator*()
{
return *m_iter;
}
const KeyValue* operator->()
{
return m_iter.operator->();
}
private:
const ParseResult* m_pr;
std::vector<KeyValue>::const_iterator m_iter;
};
ParseResult() = default;
ParseResult(const ParseResult&) = default;
ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<KeyValue> sequential,
std::vector<KeyValue> default_opts, std::vector<std::string>&& unmatched_args)
: m_keys(std::move(keys))
, m_values(std::move(values))
, m_sequential(std::move(sequential))
, m_defaults(std::move(default_opts))
, m_unmatched(std::move(unmatched_args))
{
}
ParseResult& operator=(ParseResult&&) = default;
ParseResult& operator=(const ParseResult&) = default;
Iterator
begin() const
{
return Iterator(this);
}
Iterator
end() const
{
return Iterator(this, true);
}
size_t
count(const std::string& o) const
{
auto iter = m_keys.find(o);
if (iter == m_keys.end())
{
return 0;
}
auto viter = m_values.find(iter->second);
if (viter == m_values.end())
{
return 0;
}
return viter->second.count();
}
const OptionValue&
operator[](const std::string& option) const
{
auto iter = m_keys.find(option);
if (iter == m_keys.end())
{
throw_or_mimic<option_not_present_exception>(option);
}
auto viter = m_values.find(iter->second);
if (viter == m_values.end())
{
throw_or_mimic<option_not_present_exception>(option);
}
return viter->second;
}
const std::vector<KeyValue>&
arguments() const
{
return m_sequential;
}
const std::vector<std::string>&
unmatched() const
{
return m_unmatched;
}
const std::vector<KeyValue>&
defaults() const
{
return m_defaults;
}
const std::string
arguments_string() const
{
std::string result;
for(const auto& kv: m_sequential)
{
result += kv.key() + " = " + kv.value() + "\n";
}
for(const auto& kv: m_defaults)
{
result += kv.key() + " = " + kv.value() + " " + "(default)" + "\n";
}
return result;
}
private:
NameHashMap m_keys{};
ParsedHashMap m_values{};
std::vector<KeyValue> m_sequential{};
std::vector<KeyValue> m_defaults{};
std::vector<std::string> m_unmatched{};
};
struct Option
{
Option
(
std::string opts,
std::string desc,
std::shared_ptr<const Value> value = ::cxxopts::value<bool>(),
std::string arg_help = ""
)
: opts_(std::move(opts))
, desc_(std::move(desc))
, value_(std::move(value))
, arg_help_(std::move(arg_help))
{
}
std::string opts_;
std::string desc_;
std::shared_ptr<const Value> value_;
std::string arg_help_;
};
using OptionMap = std::unordered_map<std::string, std::shared_ptr<OptionDetails>>;
using PositionalList = std::vector<std::string>;
using PositionalListIterator = PositionalList::const_iterator;
class OptionParser
{
public:
OptionParser(const OptionMap& options, const PositionalList& positional, bool allow_unrecognised)
: m_options(options)
, m_positional(positional)
, m_allow_unrecognised(allow_unrecognised)
{
}
ParseResult
parse(int argc, const char* const* argv);
bool
consume_positional(const std::string& a, PositionalListIterator& next);
void
checked_parse_arg
(
int argc,
const char* const* argv,
int& current,
const std::shared_ptr<OptionDetails>& value,
const std::string& name
);
void
add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg);
void
parse_option
(
const std::shared_ptr<OptionDetails>& value,
const std::string& name,
const std::string& arg = ""
);
void
parse_default(const std::shared_ptr<OptionDetails>& details);
void
parse_no_value(const std::shared_ptr<OptionDetails>& details);
private:
void finalise_aliases();
const OptionMap& m_options;
const PositionalList& m_positional;
std::vector<KeyValue> m_sequential{};
std::vector<KeyValue> m_defaults{};
bool m_allow_unrecognised;
ParsedHashMap m_parsed{};
NameHashMap m_keys{};
};
class Options
{
public:
explicit Options(std::string program, std::string help_string = "")
: m_program(std::move(program))
, m_help_string(toLocalString(std::move(help_string)))
, m_custom_help("[OPTION...]")
, m_positional_help("positional parameters")
, m_show_positional(false)
, m_allow_unrecognised(false)
, m_width(76)
, m_tab_expansion(false)
, m_options(std::make_shared<OptionMap>())
{
}
Options&
positional_help(std::string help_text)
{
m_positional_help = std::move(help_text);
return *this;
}
Options&
custom_help(std::string help_text)
{
m_custom_help = std::move(help_text);
return *this;
}
Options&
show_positional_help()
{
m_show_positional = true;
return *this;
}
Options&
allow_unrecognised_options()
{
m_allow_unrecognised = true;
return *this;
}
Options&
set_width(size_t width)
{
m_width = width;
return *this;
}
Options&
set_tab_expansion(bool expansion=true)
{
m_tab_expansion = expansion;
return *this;
}
ParseResult
parse(int argc, const char* const* argv);
OptionAdder
add_options(std::string group = "");
void
add_options
(
const std::string& group,
std::initializer_list<Option> options
);
void
add_option
(
const std::string& group,
const Option& option
);
void
add_option
(
const std::string& group,
const std::string& s,
const std::string& l,
std::string desc,
const std::shared_ptr<const Value>& value,
std::string arg_help
);
//parse positional arguments into the given option
void
parse_positional(std::string option);
void
parse_positional(std::vector<std::string> options);
void
parse_positional(std::initializer_list<std::string> options);
template <typename Iterator>
void
parse_positional(Iterator begin, Iterator end) {
parse_positional(std::vector<std::string>{begin, end});
}
std::string
help(const std::vector<std::string>& groups = {}) const;
std::vector<std::string>
groups() const;
const HelpGroupDetails&
group_help(const std::string& group) const;
const std::string& program() const
{
return m_program;
}
private:
void
add_one_option
(
const std::string& option,
const std::shared_ptr<OptionDetails>& details
);
String
help_one_group(const std::string& group) const;
void
generate_group_help
(
String& result,
const std::vector<std::string>& groups
) const;
void
generate_all_groups_help(String& result) const;
std::string m_program{};
String m_help_string{};
std::string m_custom_help{};
std::string m_positional_help{};
bool m_show_positional;
bool m_allow_unrecognised;
size_t m_width;
bool m_tab_expansion;
std::shared_ptr<OptionMap> m_options;
std::vector<std::string> m_positional{};
std::unordered_set<std::string> m_positional_set{};
//mapping from groups to help options
std::map<std::string, HelpGroupDetails> m_help{};
};
class OptionAdder
{
public:
OptionAdder(Options& options, std::string group)
: m_options(options), m_group(std::move(group))
{
}
OptionAdder&
operator()
(
const std::string& opts,
const std::string& desc,
const std::shared_ptr<const Value>& value
= ::cxxopts::value<bool>(),
std::string arg_help = ""
);
private:
Options& m_options;
std::string m_group;
};
namespace
{
constexpr size_t OPTION_LONGEST = 30;
constexpr size_t OPTION_DESC_GAP = 2;
String
format_option
(
const HelpOptionDetails& o
)
{
const auto& s = o.s;
const auto& l = o.l;
String result = " ";
if (!s.empty())
{
result += "-" + toLocalString(s);
if (!l.empty())
{
result += ",";
}
}
else
{
result += " ";
}
if (!l.empty())
{
result += " --" + toLocalString(l);
}
auto arg = !o.arg_help.empty() ? toLocalString(o.arg_help) : "arg";
if (!o.is_boolean)
{
if (o.has_implicit)
{
result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
}
else
{
result += " " + arg;
}
}
return result;
}
String
format_description
(
const HelpOptionDetails& o,
size_t start,
size_t allowed,
bool tab_expansion
)
{
auto desc = o.desc;
if (o.has_default && (!o.is_boolean || o.default_value != "false"))
{
if(!o.default_value.empty())
{
desc += toLocalString(" (default: " + o.default_value + ")");
}
else
{
desc += toLocalString(" (default: \"\")");
}
}
String result;
if (tab_expansion)
{
String desc2;
auto size = size_t{ 0 };
for (auto c = std::begin(desc); c != std::end(desc); ++c)
{
if (*c == '\n')
{
desc2 += *c;
size = 0;
}
else if (*c == '\t')
{
auto skip = 8 - size % 8;
stringAppend(desc2, skip, ' ');
size += skip;
}
else
{
desc2 += *c;
++size;
}
}
desc = desc2;
}
desc += " ";
auto current = std::begin(desc);
auto previous = current;
auto startLine = current;
auto lastSpace = current;
auto size = size_t{};
bool appendNewLine;
bool onlyWhiteSpace = true;
while (current != std::end(desc))
{
appendNewLine = false;
if (std::isblank(*previous))
{
lastSpace = current;
}
if (!std::isblank(*current))
{
onlyWhiteSpace = false;
}
while (*current == '\n')
{
previous = current;
++current;
appendNewLine = true;
}
if (!appendNewLine && size >= allowed)
{
if (lastSpace != startLine)
{
current = lastSpace;
previous = current;
}
appendNewLine = true;
}
if (appendNewLine)
{
stringAppend(result, startLine, current);
startLine = current;
lastSpace = current;
if (*previous != '\n')
{
stringAppend(result, "\n");
}
stringAppend(result, start, ' ');
if (*previous != '\n')
{
stringAppend(result, lastSpace, current);
}
onlyWhiteSpace = true;
size = 0;
}
previous = current;
++current;
++size;
}
//append whatever is left but ignore whitespace
if (!onlyWhiteSpace)
{
stringAppend(result, startLine, previous);
}
return result;
}
} // namespace
inline
void
Options::add_options
(
const std::string &group,
std::initializer_list<Option> options
)
{
OptionAdder option_adder(*this, group);
for (const auto &option: options)
{
option_adder(option.opts_, option.desc_, option.value_, option.arg_help_);
}
}
inline
OptionAdder
Options::add_options(std::string group)
{
return OptionAdder(*this, std::move(group));
}
inline
OptionAdder&
OptionAdder::operator()
(
const std::string& opts,
const std::string& desc,
const std::shared_ptr<const Value>& value,
std::string arg_help
)
{
std::string short_sw, long_sw;
std::tie(short_sw, long_sw) = values::parser_tool::SplitSwitchDef(opts);
if (!short_sw.length() && !long_sw.length())
{
throw_or_mimic<invalid_option_format_error>(opts);
}
else if (long_sw.length() == 1 && short_sw.length())
{
throw_or_mimic<invalid_option_format_error>(opts);
}
auto option_names = []
(
const std::string &short_,
const std::string &long_
)
{
if (long_.length() == 1)
{
return std::make_tuple(long_, short_);
}
return std::make_tuple(short_, long_);
}(short_sw, long_sw);
m_options.add_option
(
m_group,
std::get<0>(option_names),
std::get<1>(option_names),
desc,
value,
std::move(arg_help)
);
return *this;
}
inline
void
OptionParser::parse_default(const std::shared_ptr<OptionDetails>& details)
{
// TODO: remove the duplicate code here
auto& store = m_parsed[details->hash()];
store.parse_default(details);
m_defaults.emplace_back(details->essential_name(), details->value().get_default_value());
}
inline
void
OptionParser::parse_no_value(const std::shared_ptr<OptionDetails>& details)
{
auto& store = m_parsed[details->hash()];
store.parse_no_value(details);
}
inline
void
OptionParser::parse_option
(
const std::shared_ptr<OptionDetails>& value,
const std::string& /*name*/,
const std::string& arg
)
{
auto hash = value->hash();
auto& result = m_parsed[hash];
result.parse(value, arg);
m_sequential.emplace_back(value->essential_name(), arg);
}
inline
void
OptionParser::checked_parse_arg
(
int argc,
const char* const* argv,
int& current,
const std::shared_ptr<OptionDetails>& value,
const std::string& name
)
{
if (current + 1 >= argc)
{
if (value->value().has_implicit())
{
parse_option(value, name, value->value().get_implicit_value());
}
else
{
throw_or_mimic<missing_argument_exception>(name);
}
}
else
{
if (value->value().has_implicit())
{
parse_option(value, name, value->value().get_implicit_value());
}
else
{
parse_option(value, name, argv[current + 1]);
++current;
}
}
}
inline
void
OptionParser::add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg)
{
parse_option(iter->second, option, arg);
}
inline
bool
OptionParser::consume_positional(const std::string& a, PositionalListIterator& next)
{
while (next != m_positional.end())
{
auto iter = m_options.find(*next);
if (iter != m_options.end())
{
if (!iter->second->value().is_container())
{
auto& result = m_parsed[iter->second->hash()];
if (result.count() == 0)
{
add_to_option(iter, *next, a);
++next;
return true;
}
++next;
continue;
}
add_to_option(iter, *next, a);
return true;
}
throw_or_mimic<option_not_exists_exception>(*next);
}
return false;
}
inline
void
Options::parse_positional(std::string option)
{
parse_positional(std::vector<std::string>{std::move(option)});
}
inline
void
Options::parse_positional(std::vector<std::string> options)
{
m_positional = std::move(options);
m_positional_set.insert(m_positional.begin(), m_positional.end());
}
inline
void
Options::parse_positional(std::initializer_list<std::string> options)
{
parse_positional(std::vector<std::string>(options));
}
inline
ParseResult
Options::parse(int argc, const char* const* argv)
{
OptionParser parser(*m_options, m_positional, m_allow_unrecognised);
return parser.parse(argc, argv);
}
inline ParseResult
OptionParser::parse(int argc, const char* const* argv)
{
int current = 1;
bool consume_remaining = false;
auto next_positional = m_positional.begin();
std::vector<std::string> unmatched;
while (current != argc)
{
if (strcmp(argv[current], "--") == 0)
{
consume_remaining = true;
++current;
break;
}
bool matched = false;
values::parser_tool::ArguDesc argu_desc =
values::parser_tool::ParseArgument(argv[current], matched);
if (!matched)
{
//not a flag
// but if it starts with a `-`, then it's an error
if (argv[current][0] == '-' && argv[current][1] != '\0') {
if (!m_allow_unrecognised) {
throw_or_mimic<option_syntax_exception>(argv[current]);
}
}
//if true is returned here then it was consumed, otherwise it is
//ignored
if (consume_positional(argv[current], next_positional))
{
}
else
{
unmatched.emplace_back(argv[current]);
}
//if we return from here then it was parsed successfully, so continue
}
else
{
//short or long option?
if (argu_desc.grouping)
{
const std::string& s = argu_desc.arg_name;
for (std::size_t i = 0; i != s.size(); ++i)
{
std::string name(1, s[i]);
auto iter = m_options.find(name);
if (iter == m_options.end())
{
if (m_allow_unrecognised)
{
unmatched.push_back(std::string("-") + s[i]);
continue;
}
//error
throw_or_mimic<option_not_exists_exception>(name);
}
auto value = iter->second;
if (i + 1 == s.size())
{
//it must be the last argument
checked_parse_arg(argc, argv, current, value, name);
}
else if (value->value().has_implicit())
{
parse_option(value, name, value->value().get_implicit_value());
}
else if (i + 1 < s.size())
{
std::string arg_value = s.substr(i + 1);
parse_option(value, name, arg_value);
break;
}
else
{
//error
throw_or_mimic<option_requires_argument_exception>(name);
}
}
}
else if (argu_desc.arg_name.length() != 0)
{
const std::string& name = argu_desc.arg_name;
auto iter = m_options.find(name);
if (iter == m_options.end())
{
if (m_allow_unrecognised)
{
// keep unrecognised options in argument list, skip to next argument
unmatched.emplace_back(argv[current]);
++current;
continue;
}
//error
throw_or_mimic<option_not_exists_exception>(name);
}
auto opt = iter->second;
//equals provided for long option?
if (argu_desc.set_value)
{
//parse the option given
parse_option(opt, name, argu_desc.value);
}
else
{
//parse the next argument
checked_parse_arg(argc, argv, current, opt, name);
}
}
}
++current;
}
for (auto& opt : m_options)
{
auto& detail = opt.second;
const auto& value = detail->value();
auto& store = m_parsed[detail->hash()];
if (value.has_default()) {
if (!store.count() && !store.has_default()) {
parse_default(detail);
}
}
else {
parse_no_value(detail);
}
}
if (consume_remaining)
{
while (current < argc)
{
if (!consume_positional(argv[current], next_positional)) {
break;
}
++current;
}
//adjust argv for any that couldn't be swallowed
while (current != argc) {
unmatched.emplace_back(argv[current]);
++current;
}
}
finalise_aliases();
ParseResult parsed(std::move(m_keys), std::move(m_parsed), std::move(m_sequential), std::move(m_defaults), std::move(unmatched));
return parsed;
}
inline
void
OptionParser::finalise_aliases()
{
for (auto& option: m_options)
{
auto& detail = *option.second;
auto hash = detail.hash();
m_keys[detail.short_name()] = hash;
m_keys[detail.long_name()] = hash;
m_parsed.emplace(hash, OptionValue());
}
}
inline
void
Options::add_option
(
const std::string& group,
const Option& option
)
{
add_options(group, {option});
}
inline
void
Options::add_option
(
const std::string& group,
const std::string& s,
const std::string& l,
std::string desc,
const std::shared_ptr<const Value>& value,
std::string arg_help
)
{
auto stringDesc = toLocalString(std::move(desc));
auto option = std::make_shared<OptionDetails>(s, l, stringDesc, value);
if (!s.empty())
{
add_one_option(s, option);
}
if (!l.empty())
{
add_one_option(l, option);
}
//add the help details
auto& options = m_help[group];
options.options.emplace_back(HelpOptionDetails{s, l, stringDesc,
value->has_default(), value->get_default_value(),
value->has_implicit(), value->get_implicit_value(),
std::move(arg_help),
value->is_container(),
value->is_boolean()});
}
inline
void
Options::add_one_option
(
const std::string& option,
const std::shared_ptr<OptionDetails>& details
)
{
auto in = m_options->emplace(option, details);
if (!in.second)
{
throw_or_mimic<option_exists_error>(option);
}
}
inline
String
Options::help_one_group(const std::string& g) const
{
using OptionHelp = std::vector<std::pair<String, String>>;
auto group = m_help.find(g);
if (group == m_help.end())
{
return "";
}
OptionHelp format;
size_t longest = 0;
String result;
if (!g.empty())
{
result += toLocalString(" " + g + " options:\n");
}
for (const auto& o : group->second.options)
{
if (m_positional_set.find(o.l) != m_positional_set.end() &&
!m_show_positional)
{
continue;
}
auto s = format_option(o);
longest = (std::max)(longest, stringLength(s));
format.push_back(std::make_pair(s, String()));
}
longest = (std::min)(longest, OPTION_LONGEST);
//widest allowed description -- min 10 chars for helptext/line
size_t allowed = 10;
if (m_width > allowed + longest + OPTION_DESC_GAP)
{
allowed = m_width - longest - OPTION_DESC_GAP;
}
auto fiter = format.begin();
for (const auto& o : group->second.options)
{
if (m_positional_set.find(o.l) != m_positional_set.end() &&
!m_show_positional)
{
continue;
}
auto d = format_description(o, longest + OPTION_DESC_GAP, allowed, m_tab_expansion);
result += fiter->first;
if (stringLength(fiter->first) > longest)
{
result += '\n';
result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' '));
}
else
{
result += toLocalString(std::string(longest + OPTION_DESC_GAP -
stringLength(fiter->first),
' '));
}
result += d;
result += '\n';
++fiter;
}
return result;
}
inline
void
Options::generate_group_help
(
String& result,
const std::vector<std::string>& print_groups
) const
{
for (size_t i = 0; i != print_groups.size(); ++i)
{
const String& group_help_text = help_one_group(print_groups[i]);
if (empty(group_help_text))
{
continue;
}
result += group_help_text;
if (i < print_groups.size() - 1)
{
result += '\n';
}
}
}
inline
void
Options::generate_all_groups_help(String& result) const
{
std::vector<std::string> all_groups;
std::transform(
m_help.begin(),
m_help.end(),
std::back_inserter(all_groups),
[] (const std::map<std::string, HelpGroupDetails>::value_type& group)
{
return group.first;
}
);
generate_group_help(result, all_groups);
}
inline
std::string
Options::help(const std::vector<std::string>& help_groups) const
{
String result = m_help_string + "\nUsage:\n " +
toLocalString(m_program) + " " + toLocalString(m_custom_help);
if (!m_positional.empty() && !m_positional_help.empty()) {
result += " " + toLocalString(m_positional_help);
}
result += "\n\n";
if (help_groups.empty())
{
generate_all_groups_help(result);
}
else
{
generate_group_help(result, help_groups);
}
return toUTF8String(result);
}
inline
std::vector<std::string>
Options::groups() const
{
std::vector<std::string> g;
std::transform(
m_help.begin(),
m_help.end(),
std::back_inserter(g),
[] (const std::map<std::string, HelpGroupDetails>::value_type& pair)
{
return pair.first;
}
);
return g;
}
inline
const HelpGroupDetails&
Options::group_help(const std::string& group) const
{
return m_help.at(group);
}
} // namespace cxxopts
#endif //CXXOPTS_HPP_INCLUDED
================================================
FILE: src/kilo/CREDITS
================================================
Kilo editor from:
https://github.com/antirez/kilo
================================================
FILE: src/kilo/kilo.cpp
================================================
/* Kilo -- A very simple editor in less than 1-kilo lines of code (as counted
* by "cloc"). Does not depend on libcurses, directly emits VT100
* escapes on the terminal.
*
* -----------------------------------------------------------------------
*
* Copyright (C) 2016 Salvatore Sanfilippo <antirez at gmail dot com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Modified by Jan Boehmer 2022, to match the requirements of ESP32Console
*
*/
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wwrite-strings"
#define KILO_VERSION "0.0.1"
#ifdef __linux__
#define _POSIX_C_SOURCE 200809L
#endif
#include <kilo/kilo.h>
#include <termios.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdarg.h>
#include <fcntl.h>
#include <signal.h>
/* Syntax highlight types */
#define HL_NORMAL 0
#define HL_NONPRINT 1
#define HL_COMMENT 2 /* Single line comment. */
#define HL_MLCOMMENT 3 /* Multi-line comment. */
#define HL_KEYWORD1 4
#define HL_KEYWORD2 5
#define HL_STRING 6
#define HL_NUMBER 7
#define HL_MATCH 8 /* Search match. */
#define HL_HIGHLIGHT_STRINGS (1 << 0)
#define HL_HIGHLIGHT_NUMBERS (1 << 1)
namespace ESP32Console::Kilo
{
struct editorSyntax
{
char **filematch;
char **keywords;
char singleline_comment_start[3];
char multiline_comment_start[3];
char multiline_comment_end[3];
int flags;
};
/* This structure represents a single line of the file we are editing. */
typedef struct erow
{
int idx; /* Row index in the file, zero-based. */
int size; /* Size of the row, excluding the null term. */
int rsize; /* Size of the rendered row. */
char *chars; /* Row content. */
char *render; /* Row content "rendered" for screen (for TABs). */
unsigned char *hl; /* Syntax highlight type for each character in render.*/
int hl_oc; /* Row had open comment at end in last syntax highlight
check. */
} erow;
typedef struct hlcolor
{
int r, g, b;
} hlcolor;
struct editorConfig
{
int cx, cy; /* Cursor x and y position in characters */
int rowoff; /* Offset of row displayed. */
int coloff; /* Offset of column displayed. */
int screenrows; /* Number of rows that we can show */
int screencols; /* Number of cols that we can show */
int numrows; /* Number of rows */
int rawmode; /* Is terminal raw mode enabled? */
erow *row; /* Rows */
int dirty; /* File modified but not saved. */
char *filename; /* Currently open filename */
char statusmsg[80];
time_t statusmsg_time;
struct editorSyntax *syntax; /* Current syntax highlight, or NULL. */
};
static struct editorConfig E;
enum KEY_ACTION
{
KEY_NULL = 0, /* NULL */
CTRL_C = 3, /* Ctrl-c */
CTRL_D = 4, /* Ctrl-d */
CTRL_F = 6, /* Ctrl-f */
CTRL_H = 8, /* Ctrl-h */
TAB = 9, /* Tab */
CTRL_L = 12, /* Ctrl+l */
ENTER = 13, /* Enter */
CTRL_Q = 17, /* Ctrl-q */
CTRL_S = 19, /* Ctrl-s */
CTRL_U = 21, /* Ctrl-u */
ESC = 27, /* Escape */
BACKSPACE = 127, /* Backspace */
/* The following are just soft codes, not really reported by the
* terminal directly. */
ARROW_LEFT = 1000,
ARROW_RIGHT,
ARROW_UP,
ARROW_DOWN,
DEL_KEY,
HOME_KEY,
END_KEY,
PAGE_UP,
PAGE_DOWN
};
void editorSetStatusMessage(const char *fmt, ...);
/* =========================== Syntax highlights DB =========================
*
* In order to add a new syntax, define two arrays with a list of file name
* matches and keywords. The file name matches are used in order to match
* a given syntax with a given file name: if a match pattern starts with a
* dot, it is matched as the last past of the filename, for example ".c".
* Otherwise the pattern is just searched inside the filenme, like "Makefile").
*
* The list of keywords to highlight is just a list of words, however if they
* a trailing '|' character is added at the end, they are highlighted in
* a different color, so that you can have two different sets of keywords.
*
* Finally add a stanza in the HLDB global variable with two two arrays
* of strings, and a set of flags in order to enable highlighting of
* comments and numbers.
*
* The characters for single and multi line comments must be exactly two
* and must be provided as well (see the C language example).
*
* There is no support to highlight patterns currently. */
/* C / C++ */
char *C_HL_extensions[] = {".c", ".h", ".cpp", ".hpp", ".cc", NULL};
char *C_HL_keywords[] = {
/* C Keywords */
"auto", "break", "case", "continue", "default", "do", "else", "enum",
"extern", "for", "goto", "if", "register", "return", "sizeof", "static",
"struct", "switch", "typedef", "union", "volatile", "while", "NULL",
/* C++ Keywords */
"alignas", "alignof", "and", "and_eq", "asm", "bitand", "bitor", "class",
"compl", "constexpr", "const_cast", "deltype", "delete", "dynamic_cast",
"explicit", "export", "false", "friend", "inline", "mutable", "namespace",
"new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq",
"private", "protected", "public", "reinterpret_cast", "static_assert",
"static_cast", "template", "this", "thread_local", "throw", "true", "try",
"typeid", "typename", "virtual", "xor", "xor_eq",
/* C types */
"int|", "long|", "double|", "float|", "char|", "unsigned|", "signed|",
"void|", "short|", "auto|", "const|", "bool|", NULL};
/* Here we define an array of syntax highlights by extensions, keywords,
* comments delimiters and flags. */
struct editorSyntax HLDB[] = {
{/* C / C++ */
C_HL_extensions,
C_HL_keywords,
"//", "/*", "*/",
HL_HIGHLIGHT_STRINGS | HL_HIGHLIGHT_NUMBERS}};
#define HLDB_ENTRIES (sizeof(HLDB) / sizeof(HLDB[0]))
/* ======================= Low level terminal handling ====================== */
static struct termios orig_termios; /* In order to restore at exit.*/
void disableRawMode(int fd)
{
/* Don't even check the return value as it's too late. */
if (E.rawmode)
{
tcsetattr(fd, TCSAFLUSH, &orig_termios);
E.rawmode = 0;
}
}
/* Called at exit to avoid remaining in raw mode. */
void editorAtExit(void)
{
disableRawMode(STDIN_FILENO);
}
/* Raw mode: 1960 magic shit. */
int enableRawMode(int fd)
{
struct termios raw;
if (E.rawmode)
return 0; /* Already enabled. */
if (!isatty(STDIN_FILENO))
goto fatal;
atexit(editorAtExit);
if (tcgetattr(fd, &orig_termios) == -1)
goto fatal;
raw = orig_termios; /* modify the original mode */
/* input modes: no break, no CR to NL, no parity check, no strip char,
* no start/stop output control. */
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
/* output modes - disable post processing */
raw.c_oflag &= ~(OPOST);
/* control modes - set 8 bit chars */
raw.c_cflag |= (CS8);
/* local modes - choing off, canonical off, no extended functions,
* no signal chars (^Z,^C) */
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
/* control chars - set return condition: min number of bytes and timer. */
raw.c_cc[VMIN] = 0; /* Return each byte, or zero for timeout. */
raw.c_cc[VTIME] = 1; /* 100 ms timeout (unit is tens of second). */
/* put terminal in raw mode after flushing */
if (tcsetattr(fd, TCSAFLUSH, &raw) < 0)
goto fatal;
E.rawmode = 1;
return 0;
fatal:
errno = ENOTTY;
return -1;
}
/* Read a key from the terminal put in raw mode, trying to handle
* escape sequences. */
int editorReadKey(int fd)
{
int nread;
char c, seq[3];
while ((nread = read(fd, &c, 1)) == 0)
;
if (nread == -1)
throw KiloException(1);
while (1)
{
switch (c)
{
case ESC: /* escape sequence */
/* If this is just an ESC, we'll timeout here. */
if (read(fd, seq, 1) == 0)
return ESC;
if (read(fd, seq + 1, 1) == 0)
return ESC;
/* ESC [ sequences. */
if (seq[0] == '[')
{
if (seq[1] >= '0' && seq[1] <= '9')
{
/* Extended escape, read additional byte. */
if (read(fd, seq + 2, 1) == 0)
return ESC;
if (seq[2] == '~')
{
switch (seq[1])
{
case '3':
return DEL_KEY;
case '5':
return PAGE_UP;
case '6':
return PAGE_DOWN;
}
}
}
else
{
switch (seq[1])
{
case 'A':
return ARROW_UP;
case 'B':
return ARROW_DOWN;
case 'C':
return ARROW_RIGHT;
case 'D':
return ARROW_LEFT;
case 'H':
return HOME_KEY;
case 'F':
return END_KEY;
}
}
}
/* ESC O sequences. */
else if (seq[0] == 'O')
{
switch (seq[1])
{
case 'H':
return HOME_KEY;
case 'F':
return END_KEY;
}
}
break;
default:
return c;
}
}
}
/* Use the ESC [6n escape sequence to query the horizontal cursor position
* and return it. On error -1 is returned, on success the position of the
* cursor is stored at *rows and *cols and 0 is returned. */
int getCursorPosition(int ifd, int ofd, int *rows, int *cols)
{
char buf[32];
unsigned int i = 0;
/* Report cursor location */
if (write(ofd, "\x1b[6n", 4) != 4)
return -1;
/* Read the response: ESC [ rows ; cols R */
while (i < sizeof(buf) - 1)
{
if (read(ifd, buf + i, 1) != 1)
break;
if (buf[i] == 'R')
break;
i++;
}
buf[i] = '\0';
/* Parse it. */
if (buf[0] != ESC || buf[1] != '[')
return -1;
if (sscanf(buf + 2, "%d;%d", rows, cols) != 2)
return -1;
return 0;
}
/* Try to get the number of columns in the current terminal. If the ioctl()
* call fails the function will try to query the terminal itself.
* Returns 0 on success, -1 on error. */
int getWindowSize(int ifd, int ofd, int *rows, int *cols)
{
/* ioctl() failed. Try to query the terminal itself. */
int orig_row, orig_col, retval;
/* Get the initial position so we can restore it later. */
retval = getCursorPosition(ifd, ofd, &orig_row, &orig_col);
if (retval == -1)
goto failed;
/* Go to right/bottom margin and get position. */
if (write(ofd, "\x1b[999C\x1b[999B", 12) != 12)
goto failed;
retval = getCursorPosition(ifd, ofd, rows, cols);
if (retval == -1)
goto failed;
/* Restore position. */
char seq[32];
snprintf(seq, 32, "\x1b[%d;%dH", orig_row, orig_col);
if (write(ofd, seq, strlen(seq)) == -1)
{
/* Can't recover... */
}
return 0;
failed:
return -1;
}
/* ====================== Syntax highlight color scheme ==================== */
int is_separator(int c)
{
return c == '\0' || isspace(c) || strchr(",.()+-/*=~%[];", c) != NULL;
}
/* Return true if the specified row last char is part of a multi line comment
* that starts at this row or at one before, and does not end at the end
* of the row but spawns to the next row. */
int editorRowHasOpenComment(erow *row)
{
if (row->hl && row->rsize && row->hl[row->rsize - 1] == HL_MLCOMMENT &&
(row->rsize < 2 || (row->render[row->rsize - 2] != '*' ||
row->render[row->rsize - 1] != '/')))
return 1;
return 0;
}
/* Set every byte of row->hl (that corresponds to every character in the line)
* to the right syntax highlight type (HL_* defines). */
void editorUpdateSyntax(erow *row)
{
row->hl = (unsigned char *)realloc(row->hl, row->rsize);
memset(row->hl, HL_NORMAL, row->rsize);
if (E.syntax == NULL)
return; /* No syntax, everything is HL_NORMAL. */
int i, prev_sep, in_string, in_comment;
char *p;
char **keywords = E.syntax->keywords;
char *scs = E.syntax->singleline_comment_start;
char *mcs = E.syntax->multiline_comment_start;
char *mce = E.syntax->multiline_comment_end;
/* Point to the first non-space char. */
p = row->render;
i = 0; /* Current char offset */
while (*p && isspace(*p))
{
p++;
i++;
}
prev_sep = 1; /* Tell the parser if 'i' points to start of word. */
in_string = 0; /* Are we inside "" or '' ? */
in_comment = 0; /* Are we inside multi-line comment? */
/* If the previous line has an open comment, this line starts
* with an open comment state. */
if (row->idx > 0 && editorRowHasOpenComment(&E.row[row->idx - 1]))
in_comment = 1;
while (*p)
{
/* Handle // comments. */
if (prev_sep && *p == scs[0] && *(p + 1) == scs[1])
{
/* From here to end is a comment */
memset(row->hl + i, HL_COMMENT, row->size - i);
return;
}
/* Handle multi line comments. */
if (in_comment)
{
row->hl[i] = HL_MLCOMMENT;
if (*p == mce[0] && *(p + 1) == mce[1])
{
row->hl[i + 1] = HL_MLCOMMENT;
p += 2;
i += 2;
in_comment = 0;
prev_sep = 1;
continue;
}
else
{
prev_sep = 0;
p++;
i++;
continue;
}
}
else if (*p == mcs[0] && *(p + 1) == mcs[1])
{
row->hl[i] = HL_MLCOMMENT;
row->hl[i + 1] = HL_MLCOMMENT;
p += 2;
i += 2;
in_comment = 1;
prev_sep = 0;
continue;
}
/* Handle "" and '' */
if (in_string)
{
row->hl[i] = HL_STRING;
if (*p == '\\')
{
row->hl[i + 1] = HL_STRING;
p += 2;
i += 2;
prev_sep = 0;
continue;
}
if (*p == in_string)
in_string = 0;
p++;
i++;
continue;
}
else
{
if (*p == '"' || *p == '\'')
{
in_string = *p;
row->hl[i] = HL_STRING;
p++;
i++;
prev_sep = 0;
continue;
}
}
/* Handle non printable chars. */
if (!isprint(*p))
{
row->hl[i] = HL_NONPRINT;
p++;
i++;
prev_sep = 0;
continue;
}
/* Handle numbers */
if ((isdigit(*p) && (prev_sep || row->hl[i - 1] == HL_NUMBER)) ||
(*p == '.' && i > 0 && row->hl[i - 1] == HL_NUMBER))
{
row->hl[i] = HL_NUMBER;
p++;
i++;
prev_sep = 0;
continue;
}
/* Handle keywords and lib calls */
if (prev_sep)
{
int j;
for (j = 0; keywords[j]; j++)
{
int klen = strlen(keywords[j]);
int kw2 = keywords[j][klen - 1] == '|';
if (kw2)
klen--;
if (!memcmp(p, keywords[j], klen) &&
is_separator(*(p + klen)))
{
/* Keyword */
memset(row->hl + i, kw2 ? HL_KEYWORD2 : HL_KEYWORD1, klen);
p += klen;
i += klen;
break;
}
}
if (keywords[j] != NULL)
{
prev_sep = 0;
continue; /* We had a keyword match */
}
}
/* Not special chars */
prev_sep = is_separator(*p);
p++;
i++;
}
/* Propagate syntax change to the next row if the open commen
* state changed. This may recursively affect all the following rows
* in the file. */
int oc = editorRowHasOpenComment(row);
if (row->hl_oc != oc && row->idx + 1 < E.numrows)
editorUpdateSyntax(&E.row[row->idx + 1]);
row->hl_oc = oc;
}
/* Maps syntax highlight token types to terminal colors. */
int editorSyntaxToColor(int hl)
{
switch (hl)
{
case HL_COMMENT:
case HL_MLCOMMENT:
return 36; /* cyan */
case HL_KEYWORD1:
return 33; /* yellow */
case HL_KEYWORD2:
return 32; /* green */
case HL_STRING:
return 35; /* magenta */
case HL_NUMBER:
return 31; /* red */
case HL_MATCH:
return 34; /* blu */
default:
return 37; /* white */
}
}
/* Select the syntax highlight scheme depending on the filename,
* setting it in the global state E.syntax. */
void editorSelectSyntaxHighlight(char *filename)
{
for (unsigned int j = 0; j < HLDB_ENTRIES; j++)
{
struct editorSyntax *s = HLDB + j;
unsigned int i = 0;
while (s->filematch[i])
{
char *p;
int patlen = strlen(s->filematch[i]);
if ((p = strstr(filename, s->filematch[i])) != NULL)
{
if (s->filematch[i][0] != '.' || p[patlen] == '\0')
{
E.syntax = s;
return;
}
}
i++;
}
}
}
/* ======================= Editor rows implementation ======================= */
/* Update the rendered version and the syntax highlight of a row. */
void editorUpdateRow(erow *row)
{
unsigned int tabs = 0, nonprint = 0;
int j, idx;
/* Create a version of the row we can directly print on the screen,
* respecting tabs, substituting non printable characters with '?'. */
free(row->render);
for (j = 0; j < row->size; j++)
if (row->chars[j] == TAB)
tabs++;
unsigned long long allocsize =
(unsigned long long)row->size + tabs * 8 + nonprint * 9 + 1;
if (allocsize > UINT32_MAX)
{
printf("Some line of the edited file is too long for kilo\n");
throw KiloException(1);
}
row->render = (char *)malloc(row->size + tabs * 8 + nonprint * 9 + 1);
idx = 0;
for (j = 0; j < row->size; j++)
{
if (row->chars[j] == TAB)
{
row->render[idx++] = ' ';
while ((idx + 1) % 8 != 0)
row->render[idx++] = ' ';
}
else
{
row->render[idx++] = row->chars[j];
}
}
row->rsize = idx;
row->render[idx] = '\0';
/* Update the syntax highlighting attributes of the row. */
editorUpdateSyntax(row);
}
/* Insert a row at the specified position, shifting the other rows on the bottom
* if required. */
void editorInsertRow(int at, char *s, size_t len)
{
if (at > E.numrows)
return;
E.row = (erow *)realloc(E.row, sizeof(erow) * (E.numrows + 1));
if (at != E.numrows)
{
memmove(E.row + at + 1, E.row + at, sizeof(E.row[0]) * (E.numrows - at));
for (int j = at + 1; j <= E.numrows; j++)
E.row[j].idx++;
}
E.row[at].size = len;
E.row[at].chars = (char *)malloc(len + 1);
memcpy(E.row[at].chars, s, len + 1);
E.row[at].hl = NULL;
E.row[at].hl_oc = 0;
E.row[at].render = NULL;
E.row[at].rsize = 0;
E.row[at].idx = at;
editorUpdateRow(E.row + at);
E.numrows++;
E.dirty++;
}
/* Free row's heap allocated stuff. */
void editorFreeRow(erow *row)
{
free(row->render);
free(row->chars);
free(row->hl);
}
/* Remove the row at the specified position, shifting the remainign on the
* top. */
void editorDelRow(int at)
{
erow *row;
if (at >= E.numrows)
return;
row = E.row + at;
editorFreeRow(row);
memmove(E.row + at, E.row + at + 1, sizeof(E.row[0]) * (E.numrows - at - 1));
for (int j = at; j < E.numrows - 1; j++)
E.row[j].idx++;
E.numrows--;
E.dirty++;
}
/* Turn the editor rows into a single heap-allocated string.
* Returns the pointer to the heap-allocated string and populate the
* integer pointed by 'buflen' with the size of the string, escluding
* the final nulterm. */
char *editorRowsToString(int *buflen)
{
char *buf = NULL, *p;
int totlen = 0;
int j;
/* Compute count of bytes */
for (j = 0; j < E.numrows; j++)
totlen += E.row[j].size + 1; /* +1 is for "\n" at end of every row */
*buflen = totlen;
totlen++; /* Also make space for nulterm */
p = buf = (char *)malloc(totlen);
for (j = 0; j < E.numrows; j++)
{
memcpy(p, E.row[j].chars, E.row[j].size);
p += E.row[j].size;
*p = '\n';
p++;
}
*p = '\0';
return buf;
}
/* Insert a character at the specified position in a row, moving the remaining
* chars on the right if needed. */
void editorRowInsertChar(erow *row, int at, int c)
{
if (at > row->size)
{
/* Pad the string with spaces if the insert location is outside the
* current length by more than a single character. */
int padlen = at - row->size;
/* In the next line +2 means: new char and null term. */
row->chars = (char *)realloc(row->chars, row->size + padlen + 2);
memset(row->chars + row->size, ' ', padlen);
row->chars[row->size + padlen + 1] = '\0';
row->size += padlen + 1;
}
else
{
/* If we are in the middle of the string just make space for 1 new
* char plus the (already existing) null term. */
row->chars = (char *)realloc(row->chars, row->size + 2);
memmove(row->chars + at + 1, row->chars + at, row->size - at + 1);
row->size++;
}
row->chars[at] = c;
editorUpdateRow(row);
E.dirty++;
}
/* Append the string 's' at the end of a row */
void editorRowAppendString(erow *row, char *s, size_t len)
{
row->chars = (char *)realloc(row->chars, row->size + len + 1);
memcpy(row->chars + row->size, s, len);
row->size += len;
row->chars[row->size] = '\0';
editorUpdateRow(row);
E.dirty++;
}
/* Delete the character at offset 'at' from the specified row. */
void editorRowDelChar(erow *row, int at)
{
if (row->size <= at)
return;
memmove(row->chars + at, row->chars + at + 1, row->size - at);
editorUpdateRow(row);
row->size--;
E.dirty++;
}
/* Insert the specified char at the current prompt position. */
void editorInsertChar(int c)
{
int filerow = E.rowoff + E.cy;
int filecol = E.coloff + E.cx;
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
/* If the row where the cursor is currently located does not exist in our
* logical representaion of the file, add enough empty rows as needed. */
if (!row)
{
while (E.numrows <= filerow)
editorInsertRow(E.numrows, "", 0);
}
row = &E.row[filerow];
editorRowInsertChar(row, filecol, c);
if (E.cx == E.screencols - 1)
E.coloff++;
else
E.cx++;
E.dirty++;
}
/* Inserting a newline is slightly complex as we have to handle inserting a
* newline in the middle of a line, splitting the line as needed. */
void editorInsertNewline(void)
{
int filerow = E.rowoff + E.cy;
int filecol = E.coloff + E.cx;
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
if (!row)
{
if (filerow == E.numrows)
{
editorInsertRow(filerow, "", 0);
goto fixcursor;
}
return;
}
/* If the cursor is over the current line size, we want to conceptually
* think it's just over the last character. */
if (filecol >= row->size)
filecol = row->size;
if (filecol == 0)
{
editorInsertRow(filerow, "", 0);
}
else
{
/* We are in the middle of a line. Split it between two rows. */
editorInsertRow(filerow + 1, row->chars + filecol, row->size - filecol);
row = &E.row[filerow];
row->chars[filecol] = '\0';
row->size = filecol;
editorUpdateRow(row);
}
fixcursor:
if (E.cy == E.screenrows - 1)
{
E.rowoff++;
}
else
{
E.cy++;
}
E.cx = 0;
E.coloff = 0;
}
/* Delete the char at the current prompt position. */
void editorDelChar()
{
int filerow = E.rowoff + E.cy;
int filecol = E.coloff + E.cx;
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
if (!row || (filecol == 0 && filerow == 0))
return;
if (filecol == 0)
{
/* Handle the case of column 0, we need to move the current line
* on the right of the previous one. */
filecol = E.row[filerow - 1].size;
editorRowAppendString(&E.row[filerow - 1], row->chars, row->size);
editorDelRow(filerow);
row = NULL;
if (E.cy == 0)
E.rowoff--;
else
E.cy--;
E.cx = filecol;
if (E.cx >= E.screencols)
{
int shift = (E.screencols - E.cx) + 1;
E.cx -= shift;
E.coloff += shift;
}
}
else
{
editorRowDelChar(row, filecol - 1);
if (E.cx == 0 && E.coloff)
E.coloff--;
else
E.cx--;
}
if (row)
editorUpdateRow(row);
E.dirty++;
}
/* Load the specified program in the editor memory and returns 0 on success
* or 1 on error. */
int editorOpen(char *filename)
{
FILE *fp;
E.dirty = 0;
free(E.filename);
size_t fnlen = strlen(filename) + 1;
E.filename = (char *)malloc(fnlen);
memcpy(E.filename, filename, fnlen);
fp = fopen(filename, "r");
if (!fp)
{
if (errno != ENOENT)
{
perror("Opening file");
throw KiloException(1);
}
return 1;
}
char *line = NULL;
size_t linecap = 0;
ssize_t linelen;
while ((linelen = __getline(&line, &linecap, fp)) != -1)
{
if (linelen && (line[linelen - 1] == '\n' || line[linelen - 1] == '\r'))
line[--linelen] = '\0';
editorInsertRow(E.numrows, line, linelen);
}
free(line);
fclose(fp);
E.dirty = 0;
return 0;
}
/* Save the current file on disk. Return 0 on success, 1 on error. */
int editorSave(void)
{
int len;
char *buf = editorRowsToString(&len);
FILE* file = fopen(E.filename, "wb");
if(!file) {
goto writeerr;
}
for(int n=0; n<len; n++) {
if(fputc(buf[n], file) == EOF) {
goto writeerr;
}
}
fflush(file);
/*int fd = open(E.filename, O_RDWR | O_CREAT, 0644);
if (fd == -1)
goto writeerr;
fwrite()
/* Use truncate + a single write(2) call in order to make saving
* a bit safer, under the limits of what we can do in a small editor.
// if (ftruncate(fd, len) == -1)
// goto writeerr;
if (write(fd, buf, len) != len)
goto writeerr;
close(fd);*/
free(buf);
//Ensure that the file is really written to FS before closing it
fflush(file);
fsync(fileno(file));
fclose(file);
E.dirty = 0;
editorSetStatusMessage("%d bytes written on disk", len);
return 0;
writeerr:
free(buf);
if (file)
fclose(file);
editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno));
return 1;
}
/* ============================= Terminal update ============================ */
/* We define a very simple "append buffer" structure, that is an heap
* allocated string where we can append to. This is useful in order to
* write all the escape sequences in a buffer and flush them to the standard
* output in a single call, to avoid flickering effects. */
struct abuf
{
char *b;
int len;
};
#define ABUF_INIT \
{ \
NULL, 0 \
}
void abAppend(struct abuf *ab, const char *s, int len)
{
char *new_ = (char *)realloc(ab->b, ab->len + len);
if (new_ == NULL)
return;
memcpy(new_ + ab->len, s, len);
ab->b = new_;
ab->len += len;
}
void abFree(struct abuf *ab)
{
free(ab->b);
}
/* This function writes the whole screen using VT100 escape characters
* starting from the logical state of the editor in the global state 'E'. */
void editorRefreshScreen(void)
{
int y;
erow *r;
char buf[32];
struct abuf ab = ABUF_INIT;
abAppend(&ab, "\x1b[?25l", 6); /* Hide cursor. */
abAppend(&ab, "\x1b[H", 3); /* Go home. */
for (y = 0; y < E.screenrows; y++)
{
int filerow = E.rowoff + y;
if (filerow >= E.numrows)
{
if (E.numrows == 0 && y == E.screenrows / 3)
{
char welcome[80];
int welcomelen = snprintf(welcome, sizeof(welcome),
"Kilo editor -- verison %s\x1b[0K\r\n", KILO_VERSION);
int padding = (E.screencols - welcomelen) / 2;
if (padding)
{
abAppend(&ab, "~", 1);
padding--;
}
while (padding--)
abAppend(&ab, " ", 1);
abAppend(&ab, welcome, welcomelen);
}
else
{
abAppend(&ab, "~\x1b[0K\r\n", 7);
}
continue;
}
r = &E.row[filerow];
int len = r->rsize - E.coloff;
int current_color = -1;
if (len > 0)
{
if (len > E.screencols)
len = E.screencols;
char *c = r->render + E.coloff;
unsigned char *hl = r->hl + E.coloff;
int j;
for (j = 0; j < len; j++)
{
if (hl[j] == HL_NONPRINT)
{
char sym;
abAppend(&ab, "\x1b[7m", 4);
if (c[j] <= 26)
sym = '@' + c[j];
else
sym = '?';
abAppend(&ab, &sym, 1);
abAppend(&ab, "\x1b[0m", 4);
}
else if (hl[j] == HL_NORMAL)
{
if (current_color != -1)
{
abAppend(&ab, "\x1b[39m", 5);
current_color = -1;
}
abAppend(&ab, c + j, 1);
}
else
{
int color = editorSyntaxToColor(hl[j]);
if (color != current_color)
{
char buf[16];
int clen = snprintf(buf, sizeof(buf), "\x1b[%dm", color);
current_color = color;
abAppend(&ab, buf, clen);
}
abAppend(&ab, c + j, 1);
}
}
}
abAppend(&ab, "\x1b[39m", 5);
abAppend(&ab, "\x1b[0K", 4);
abAppend(&ab, "\r\n", 2);
}
/* Create a two rows status. First row: */
abAppend(&ab, "\x1b[0K", 4);
abAppend(&ab, "\x1b[7m", 4);
char status[80], rstatus[80];
int len = snprintf(status, sizeof(status), "%.20s - %d lines %s",
E.filename, E.numrows, E.dirty ? "(modified)" : "");
int rlen = snprintf(rstatus, sizeof(rstatus),
"%d/%d", E.rowoff + E.cy + 1, E.numrows);
if (len > E.screencols)
len = E.screencols;
abAppend(&ab, status, len);
while (len < E.screencols)
{
if (E.screencols - len == rlen)
{
abAppend(&ab, rstatus, rlen);
break;
}
else
{
abAppend(&ab, " ", 1);
len++;
}
}
abAppend(&ab, "\x1b[0m\r\n", 6);
/* Second row depends on E.statusmsg and the status message update time. */
abAppend(&ab, "\x1b[0K", 4);
int msglen = strlen(E.statusmsg);
if (msglen && time(NULL) - E.statusmsg_time < 5)
abAppend(&ab, E.statusmsg, msglen <= E.screencols ? msglen : E.screencols);
/* Put cursor at its current position. Note that the horizontal position
* at which the cursor is displayed may be different compared to 'E.cx'
* because of TABs. */
int j;
int cx = 1;
int filerow = E.rowoff + E.cy;
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
if (row)
{
for (j = E.coloff; j < (E.cx + E.coloff); j++)
{
if (j < row->size && row->chars[j] == TAB)
cx += 7 - ((cx) % 8);
cx++;
}
}
snprintf(buf, sizeof(buf), "\x1b[%d;%dH", E.cy + 1, cx);
abAppend(&ab, buf, strlen(buf));
abAppend(&ab, "\x1b[?25h", 6); /* Show cursor. */
write(STDOUT_FILENO, ab.b, ab.len);
abFree(&ab);
}
/* Set an editor status message for the second line of the status, at the
* end of the screen. */
void editorSetStatusMessage(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsnprintf(E.statusmsg, sizeof(E.statusmsg), fmt, ap);
va_end(ap);
E.statusmsg_time = time(NULL);
}
/* =============================== Find mode ================================ */
#define KILO_QUERY_LEN 256
void editorFind(int fd)
{
char query[KILO_QUERY_LEN + 1] = {0};
int qlen = 0;
int last_match = -1; /* Last line where a match was found. -1 for none. */
int find_next = 0; /* if 1 search next, if -1 search prev. */
int saved_hl_line = -1; /* No saved HL */
char *saved_hl = NULL;
#define FIND_RESTORE_HL \
do \
{ \
if (saved_hl) \
{ \
memcpy(E.row[saved_hl_line].hl, saved_hl, E.row[saved_hl_line].rsize); \
free(saved_hl); \
saved_hl = NULL; \
} \
} while (0)
/* Save the cursor position in order to restore it later. */
int saved_cx = E.cx, saved_cy = E.cy;
int saved_coloff = E.coloff, saved_rowoff = E.rowoff;
while (1)
{
editorSetStatusMessage(
"Search: %s (Use ESC/Arrows/Enter)", query);
editorRefreshScreen();
int c = editorReadKey(fd);
if (c == DEL_KEY || c == CTRL_H || c == BACKSPACE)
{
if (qlen != 0)
query[--qlen] = '\0';
last_match = -1;
}
else if (c == ESC || c == ENTER)
{
if (c == ESC)
{
E.cx = saved_cx;
E.cy = saved_cy;
E.coloff = saved_coloff;
E.rowoff = saved_rowoff;
}
FIND_RESTORE_HL;
editorSetStatusMessage("");
return;
}
else if (c == ARROW_RIGHT || c == ARROW_DOWN)
{
find_next = 1;
}
else if (c == ARROW_LEFT || c == ARROW_UP)
{
find_next = -1;
}
else if (isprint(c))
{
if (qlen < KILO_QUERY_LEN)
{
query[qlen++] = c;
query[qlen] = '\0';
last_match = -1;
}
}
/* Search occurrence. */
if (last_match == -1)
find_next = 1;
if (find_next)
{
char *match = NULL;
int match_offset = 0;
int i, current = last_match;
for (i = 0; i < E.numrows; i++)
{
current += find_next;
if (current == -1)
current = E.numrows - 1;
else if (current == E.numrows)
current = 0;
match = strstr(E.row[current].render, query);
if (match)
{
match_offset = match - E.row[current].render;
break;
}
}
find_next = 0;
/* Highlight */
FIND_RESTORE_HL;
if (match)
{
erow *row = &E.row[current];
last_match = current;
if (row->hl)
{
saved_hl_line = current;
saved_hl = (char *)malloc(row->rsize);
memcpy(saved_hl, row->hl, row->rsize);
memset(row->hl + match_offset, HL_MATCH, qlen);
}
E.cy = 0;
E.cx = match_offset;
E.rowoff = current;
E.coloff = 0;
/* Scroll horizontally as needed. */
if (E.cx > E.screencols)
{
int diff = E.cx - E.screencols;
E.cx -= diff;
E.coloff += diff;
}
}
}
}
}
/* ========================= Editor events handling ======================== */
/* Handle cursor position change because arrow keys were pressed. */
void editorMoveCursor(int key)
{
int filerow = E.rowoff + E.cy;
int filecol = E.coloff + E.cx;
int rowlen;
erow *row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
switch (key)
{
case ARROW_LEFT:
if (E.cx == 0)
{
if (E.coloff)
{
E.coloff--;
}
else
{
if (filerow > 0)
{
E.cy--;
E.cx = E.row[filerow - 1].size;
if (E.cx > E.screencols - 1)
{
E.coloff = E.cx - E.screencols + 1;
E.cx = E.screencols - 1;
}
}
}
}
else
{
E.cx -= 1;
}
break;
case ARROW_RIGHT:
if (row && filecol < row->size)
{
if (E.cx == E.screencols - 1)
{
E.coloff++;
}
else
{
E.cx += 1;
}
}
else if (row && filecol == row->size)
{
E.cx = 0;
E.coloff = 0;
if (E.cy == E.screenrows - 1)
{
E.rowoff++;
}
else
{
E.cy += 1;
}
}
break;
case ARROW_UP:
if (E.cy == 0)
{
if (E.rowoff)
E.rowoff--;
}
else
{
E.cy -= 1;
}
break;
case ARROW_DOWN:
if (filerow < E.numrows)
{
if (E.cy == E.screenrows - 1)
{
E.rowoff++;
}
else
{
E.cy += 1;
}
}
break;
}
/* Fix cx if the current line has not enough chars. */
filerow = E.rowoff + E.cy;
filecol = E.coloff + E.cx;
row = (filerow >= E.numrows) ? NULL : &E.row[filerow];
rowlen = row ? row->size : 0;
if (filecol > rowlen)
{
E.cx -= filecol - rowlen;
if (E.cx < 0)
{
E.coloff += E.cx;
E.cx = 0;
}
}
}
/* Process events arriving from the standard input, which is, the user
* is typing stuff on the terminal. */
#define KILO_QUIT_TIMES 3
void editorProcessKeypress(int fd)
{
/* When the file is modified, requires Ctrl-q to be pressed N times
* before actually quitting. */
static int quit_times = KILO_QUIT_TIMES;
int c = editorReadKey(fd);
switch (c)
{
case ENTER: /* Enter */
editorInsertNewline();
break;
case CTRL_C: /* Ctrl-c */
/* We ignore ctrl-c, it can't be so simple to lose the changes
* to the edited file. */
break;
case CTRL_Q: /* Ctrl-q */
/* Quit if the file was already saved. */
if (E.dirty && quit_times)
{
editorSetStatusMessage("WARNING!!! File has unsaved changes. "
"Press Ctrl-Q %d more times to quit.",
quit_times);
quit_times--;
return;
}
throw KiloException(0);
break;
case CTRL_S: /* Ctrl-s */
editorSave();
break;
case CTRL_F:
editorFind(fd);
break;
case BACKSPACE: /* Backspace */
case CTRL_H: /* Ctrl-h */
case DEL_KEY:
editorDelChar();
break;
case PAGE_UP:
case PAGE_DOWN:
if (c == PAGE_UP && E.cy != 0)
E.cy = 0;
else if (c == PAGE_DOWN && E.cy != E.screenrows - 1)
E.cy = E.screenrows - 1;
{
int times = E.screenrows;
while (times--)
editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
}
break;
case ARROW_UP:
case ARROW_DOWN:
case ARROW_LEFT:
case ARROW_RIGHT:
editorMoveCursor(c);
break;
case CTRL_L: /* ctrl+l, clear screen */
/* Just refresht the line as side effect. */
break;
case ESC:
/* Nothing to do for ESC in this mode. */
break;
default:
editorInsertChar(c);
break;
}
quit_times = KILO_QUIT_TIMES; /* Reset it to the original value. */
}
int editorFileWasModified(void)
{
return E.dirty;
}
void updateWindowSize(void)
{
if (getWindowSize(STDIN_FILENO, STDOUT_FILENO,
&E.screenrows, &E.screencols) == -1)
{
perror("Unable to query the screen for size (columns / rows)");
throw KiloException(1);
}
E.screenrows -= 2; /* Get room for status bar. */
}
void handleSigWinCh(int unused __attribute__((unused)))
{
updateWindowSize();
if (E.cy > E.screenrows)
E.cy = E.screenrows - 1;
if (E.cx > E.screencols)
E.cx = E.screencols - 1;
editorRefreshScreen();
}
void initEditor(void)
{
E.cx = 0;
E.cy = 0;
E.rowoff = 0;
E.coloff = 0;
E.numrows = 0;
E.row = NULL;
E.dirty = 0;
E.filename = NULL;
E.syntax = NULL;
updateWindowSize();
// signal(SIGWINCH, handleSigWinCh);
}
int kilo(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage: edit <filename>\n");
return 1;
}
char filename[512];
ESP32Console::console_realpath(argv[1], filename);
try
{
initEditor();
editorSelectSyntaxHighlight(filename);
editorOpen(filename);
enableRawMode(fileno(stdin));
editorSetStatusMessage(
"HELP: Ctrl-S = save | Ctrl-Q = quit | Ctrl-F = find");
while (1)
{
editorRefreshScreen();
editorProcessKeypress(fileno(stdin));
}
}
catch (KiloException ex)
{
// Ignore exception
}
editorAtExit();
//Free some heap
for (int n = 0; n<E.numrows; n++)
{
Kilo::editorFreeRow(&E.row[n]);
}
free(E.row);
linenoiseClearScreen();
return 0;
}
}
#pragma GCC diagnostic pop
================================================
FILE: src/kilo/kilo.h
================================================
#pragma once
#include "ESP32Console/Helpers/PWDHelpers.h"
#include <exception>
#include "linenoise/linenoise.h"
namespace ESP32Console::Kilo
{
int kilo(int argc, char **argv);
struct KiloException : public std::exception
{
private:
int code_;
public:
KiloException(int code) : code_(code){};
const char *what() const throw()
{
return "Kilo exited";
}
};
}
gitextract_h38c8r86/
├── .github/
│ └── workflows/
│ ├── arduino-ci.yaml
│ └── arduino-lint.yaml
├── LICENSE
├── README.md
├── commands.md
├── examples/
│ ├── argparser/
│ │ └── argparser.ino
│ ├── basic/
│ │ └── basic.ino
│ ├── gpio/
│ │ └── gpio.ino
│ ├── network/
│ │ └── network.ino
│ ├── other_uart_channel/
│ │ └── other_uart_channel.ino
│ └── vfs/
│ └── vfs.ino
├── library.json
├── library.properties
└── src/
├── ESP32Console/
│ ├── Commands/
│ │ ├── CoreCommands.cpp
│ │ ├── CoreCommands.h
│ │ ├── GPIOCommands.cpp
│ │ ├── GPIOCommands.h
│ │ ├── NetworkCommands.cpp
│ │ ├── NetworkCommands.h
│ │ ├── SystemCommands.cpp
│ │ ├── SystemCommands.h
│ │ ├── VFSCommands.cpp
│ │ └── VFSCommands.h
│ ├── Console.cpp
│ ├── Console.h
│ ├── ConsoleCommand.h
│ ├── ConsoleCommandBase.h
│ ├── ConsoleCommandD.cpp
│ ├── ConsoleCommandD.h
│ ├── Helpers/
│ │ ├── InputParser.cpp
│ │ ├── InputParser.h
│ │ ├── PWDHelpers.cpp
│ │ └── PWDHelpers.h
│ ├── OptionsConsoleCommand.cpp
│ └── OptionsConsoleCommand.h
├── ESP32Console.h
├── cxxopts/
│ └── cxxopts.hpp
└── kilo/
├── CREDITS
├── kilo.cpp
└── kilo.h
SYMBOL INDEX (311 symbols across 25 files)
FILE: src/ESP32Console/Commands/CoreCommands.cpp
function clear (line 7) | static int clear(int argc, char **argv)
function echo (line 20) | static int echo(int argc, char **argv)
function set_multiline_mode (line 31) | static int set_multiline_mode(int argc, char **argv)
function history (line 65) | static int history(int argc, char **argv)
function env (line 100) | static int env(int argc, char **argv)
function declare (line 111) | static int declare(int argc, char **argv)
type ESP32Console::Commands (line 123) | namespace ESP32Console::Commands
function ConsoleCommand (line 125) | const ConsoleCommand getClearCommand()
function ConsoleCommand (line 130) | const ConsoleCommand getEchoCommand()
function ConsoleCommand (line 135) | const ConsoleCommand getSetMultilineCommand()
function ConsoleCommand (line 140) | const ConsoleCommand getHistoryCommand(int uart_channel)
function ConsoleCommand (line 146) | const ConsoleCommand getEnvCommand()
function ConsoleCommand (line 151) | const ConsoleCommand getDeclareCommand()
FILE: src/ESP32Console/Commands/CoreCommands.h
function namespace (line 5) | namespace ESP32Console::Commands
FILE: src/ESP32Console/Commands/GPIOCommands.cpp
function _pinmode (line 6) | static int _pinmode(int argc, char **argv)
function _digitalWrite (line 67) | static int _digitalWrite(int argc, char** argv)
function _digitalRead (line 115) | static int _digitalRead(int argc, char** argv)
function _analogRead (line 156) | static int _analogRead(int argc, char** argv)
type ESP32Console::Commands (line 192) | namespace ESP32Console::Commands
function ConsoleCommand (line 194) | const ConsoleCommand getPinModeCommand()
function ConsoleCommand (line 199) | const ConsoleCommand getDigitalWriteCommand()
function ConsoleCommand (line 204) | const ConsoleCommand getDigitalReadCommand()
function ConsoleCommand (line 209) | const ConsoleCommand getAnalogReadCommand()
FILE: src/ESP32Console/Commands/GPIOCommands.h
function namespace (line 5) | namespace ESP32Console::Commands
FILE: src/ESP32Console/Commands/NetworkCommands.cpp
function on_ping_success (line 56) | static void on_ping_success(esp_ping_handle_t hdl, void *args)
function on_ping_timeout (line 71) | static void on_ping_timeout(esp_ping_handle_t hdl, void *args)
function on_ping_end (line 80) | static void on_ping_end(esp_ping_handle_t hdl, void *args)
function ping (line 84) | static int ping(int argc, char **argv)
function ipconfig_wlan (line 192) | static void ipconfig_wlan()
function ipconfig (line 222) | static int ipconfig(int argc, char **argv)
type ESP32Console::Commands (line 228) | namespace ESP32Console::Commands
function ConsoleCommand (line 230) | const ConsoleCommand getPingCommand()
function ConsoleCommand (line 235) | const ConsoleCommand getIpconfigCommand()
FILE: src/ESP32Console/Commands/NetworkCommands.h
function namespace (line 5) | namespace ESP32Console::Commands
FILE: src/ESP32Console/Commands/SystemCommands.cpp
function String (line 26) | static String mac2String(uint64_t mac)
function sysInfo (line 94) | static int sysInfo(int argc, char **argv)
function restart (line 138) | static int restart(int argc, char **argv)
function meminfo (line 145) | static int meminfo(int argc, char **argv)
function date (line 157) | static int date(int argc, char **argv)
type ESP32Console::Commands (line 249) | namespace ESP32Console::Commands
function ConsoleCommand (line 251) | const ConsoleCommand getRestartCommand()
function ConsoleCommand (line 256) | const ConsoleCommand getSysInfoCommand()
function ConsoleCommand (line 261) | const ConsoleCommand getMemInfoCommand()
function ConsoleCommand (line 266) | const ConsoleCommand getDateCommand()
FILE: src/ESP32Console/Commands/SystemCommands.h
function namespace (line 5) | namespace ESP32Console::Commands
FILE: src/ESP32Console/Commands/VFSCommands.cpp
function cat (line 15) | int cat(int argc, char **argv)
function pwd (line 46) | int pwd(int argc, char **argv)
function cd (line 52) | int cd(int argc, char **argv)
function ls (line 105) | int ls(int argc, char **argv)
function mv (line 142) | int mv(int argc, char **argv)
function cp (line 166) | int cp(int argc, char **argv)
function rm (line 226) | int rm(int argc, char **argv)
function rmdir (line 244) | int rmdir(int argc, char **argv)
type ESP32Console::Commands (line 262) | namespace ESP32Console::Commands
function ConsoleCommand (line 264) | const ConsoleCommand getCatCommand()
function ConsoleCommand (line 269) | const ConsoleCommand getPWDCommand()
function ConsoleCommand (line 274) | const ConsoleCommand getCDCommand()
function ConsoleCommand (line 279) | const ConsoleCommand getLsCommand()
function ConsoleCommand (line 284) | const ConsoleCommand getMvCommand()
function ConsoleCommand (line 289) | const ConsoleCommand getCPCommand()
function ConsoleCommand (line 294) | const ConsoleCommand getRMCommand()
function ConsoleCommand (line 299) | const ConsoleCommand getRMDirCommand()
function ConsoleCommand (line 304) | const ConsoleCommand getEditCommand()
FILE: src/ESP32Console/Commands/VFSCommands.h
function namespace (line 5) | namespace ESP32Console::Commands
FILE: src/ESP32Console/Console.cpp
type ESP32Console (line 24) | namespace ESP32Console
function resetAfterCommands (line 181) | static void resetAfterCommands()
FILE: src/ESP32Console/Console.h
function namespace (line 14) | namespace ESP32Console
function begin (line 158) | void begin(int baud, int rxPin, int txPin, uint8_t channel)
FILE: src/ESP32Console/ConsoleCommand.h
function namespace (line 5) | namespace ESP32Console
FILE: src/ESP32Console/ConsoleCommandBase.h
function namespace (line 5) | namespace ESP32Console {
FILE: src/ESP32Console/ConsoleCommandD.cpp
type ESP32Console (line 6) | namespace ESP32Console
FILE: src/ESP32Console/ConsoleCommandD.h
function namespace (line 11) | namespace ESP32Console
FILE: src/ESP32Console/Helpers/InputParser.cpp
type ESP32Console (line 5) | namespace ESP32Console
function String (line 7) | String interpolateLine(const char *in_)
FILE: src/ESP32Console/Helpers/InputParser.h
function namespace (line 4) | namespace ESP32Console
FILE: src/ESP32Console/Helpers/PWDHelpers.cpp
type ESP32Console (line 7) | namespace ESP32Console
function console_chdir (line 43) | int console_chdir(const char *path)
FILE: src/ESP32Console/Helpers/PWDHelpers.h
function namespace (line 3) | namespace ESP32Console
FILE: src/ESP32Console/OptionsConsoleCommand.cpp
type ESP32Console (line 6) | namespace ESP32Console
FILE: src/ESP32Console/OptionsConsoleCommand.h
function namespace (line 15) | namespace ESP32Console
FILE: src/cxxopts/cxxopts.hpp
type cxxopts (line 82) | namespace cxxopts
function String (line 106) | inline
class UnicodeStringIterator (line 121) | class UnicodeStringIterator : public
method UnicodeStringIterator (line 126) | UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos)
method value_type (line 132) | value_type
method UnicodeStringIterator (line 150) | UnicodeStringIterator&
method UnicodeStringIterator (line 157) | UnicodeStringIterator
function String (line 171) | inline
function String (line 178) | inline
function String (line 191) | String&
function stringLength (line 203) | inline
function toUTF8String (line 210) | inline
function empty (line 220) | inline
function T (line 253) | T
function stringLength (line 259) | inline
function String (line 266) | inline
function String (line 273) | inline
function String (line 281) | String&
function toUTF8String (line 288) | std::string
function empty (line 294) | inline
class Value (line 326) | class Value : public std::enable_shared_from_this<Value>
class OptionException (line 372) | class OptionException : public std::exception
method OptionException (line 375) | explicit OptionException(std::string message)
method CXXOPTS_NODISCARD (line 380) | CXXOPTS_NODISCARD
class OptionSpecException (line 391) | class OptionSpecException : public OptionException
method OptionSpecException (line 395) | explicit OptionSpecException(const std::string& message)
class OptionParseException (line 401) | class OptionParseException : public OptionException
method OptionParseException (line 404) | explicit OptionParseException(const std::string& message)
class option_exists_error (line 410) | class option_exists_error : public OptionSpecException
method option_exists_error (line 413) | explicit option_exists_error(const std::string& option)
class invalid_option_format_error (line 419) | class invalid_option_format_error : public OptionSpecException
method invalid_option_format_error (line 422) | explicit invalid_option_format_error(const std::string& format)
class option_syntax_exception (line 428) | class option_syntax_exception : public OptionParseException {
method option_syntax_exception (line 430) | explicit option_syntax_exception(const std::string& text)
class option_not_exists_exception (line 437) | class option_not_exists_exception : public OptionParseException
method option_not_exists_exception (line 440) | explicit option_not_exists_exception(const std::string& option)
class missing_argument_exception (line 446) | class missing_argument_exception : public OptionParseException
method missing_argument_exception (line 449) | explicit missing_argument_exception(const std::string& option)
class option_requires_argument_exception (line 457) | class option_requires_argument_exception : public OptionParseException
method option_requires_argument_exception (line 460) | explicit option_requires_argument_exception(const std::string& option)
class option_not_has_argument_exception (line 468) | class option_not_has_argument_exception : public OptionParseException
method option_not_has_argument_exception (line 471) | option_not_has_argument_exception
class option_not_present_exception (line 485) | class option_not_present_exception : public OptionParseException
method option_not_present_exception (line 488) | explicit option_not_present_exception(const std::string& option)
class option_has_no_value_exception (line 494) | class option_has_no_value_exception : public OptionException
method option_has_no_value_exception (line 497) | explicit option_has_no_value_exception(const std::string& option)
class argument_incorrect_type (line 506) | class argument_incorrect_type : public OptionParseException
method argument_incorrect_type (line 509) | explicit argument_incorrect_type
class option_required_exception (line 520) | class option_required_exception : public OptionParseException
method option_required_exception (line 523) | explicit option_required_exception(const std::string& option)
function throw_or_mimic (line 532) | void throw_or_mimic(const std::string& text)
type values (line 550) | namespace values
type parser_tool (line 552) | namespace parser_tool
type IntegerDesc (line 554) | struct IntegerDesc
type ArguDesc (line 560) | struct ArguDesc {
function IntegerDesc (line 567) | inline IntegerDesc SplitInteger(const std::string &text)
function IsTrueText (line 596) | inline bool IsTrueText(const std::string &text)
function IsFalseText (line 614) | inline bool IsFalseText(const std::string &text)
function SplitSwitchDef (line 632) | inline std::pair<std::string, std::string> SplitSwitchDef(const st...
function ArguDesc (line 656) | inline ArguDesc ParseArgument(const char *arg, bool &matched)
function IntegerDesc (line 725) | inline IntegerDesc SplitInteger(const std::string &text)
function IsTrueText (line 750) | inline bool IsTrueText(const std::string &text)
function IsFalseText (line 757) | inline bool IsFalseText(const std::string &text)
function SplitSwitchDef (line 764) | inline std::pair<std::string, std::string> SplitSwitchDef(const st...
function ArguDesc (line 779) | inline ArguDesc ParseArgument(const char *arg, bool &matched)
type detail (line 804) | namespace detail
type SignedCheck (line 807) | struct SignedCheck
type SignedCheck<T, true> (line 810) | struct SignedCheck<T, true>
type SignedCheck<T, false> (line 834) | struct SignedCheck<T, false>
function check_signed_range (line 842) | void
function checked_negate (line 850) | void
function checked_negate (line 860) | void
function integer_parser (line 867) | void
function stringstream_parser (line 924) | void stringstream_parser(const std::string& text, T& value)
function parse_value (line 936) | void parse_value(const std::string& text, T& value)
function parse_value (line 941) | inline
function parse_value (line 960) | inline
function parse_value (line 973) | void
function parse_value (line 979) | void
function parse_value (line 999) | void
function parse_value (line 1008) | inline
type type_is_container (line 1020) | struct type_is_container
type type_is_container<std::vector<T>> (line 1026) | struct type_is_container<std::vector<T>>
class abstract_value (line 1032) | class abstract_value : public Value
method abstract_value (line 1037) | abstract_value()
method abstract_value (line 1043) | explicit abstract_value(T* t)
method abstract_value (line 1050) | abstract_value& operator=(const abstract_value&) = default;
method abstract_value (line 1052) | abstract_value(const abstract_value& rhs)
method parse (line 1070) | void
method is_container (line 1076) | bool
method parse (line 1082) | void
method has_default (line 1088) | bool
method has_implicit (line 1094) | bool
method default_value (line 1100) | std::shared_ptr<Value>
method implicit_value (line 1108) | std::shared_ptr<Value>
method no_implicit_value (line 1116) | std::shared_ptr<Value>
method get_default_value (line 1123) | std::string
method get_implicit_value (line 1129) | std::string
method is_boolean (line 1135) | bool
method T (line 1141) | const T&
class standard_value (line 1163) | class standard_value : public abstract_value<T>
method override (line 1170) | const override
class standard_value<bool> (line 1177) | class standard_value<bool> : public abstract_value<bool>
method standard_value (line 1182) | standard_value()
method standard_value (line 1187) | explicit standard_value(bool* b)
method clone (line 1193) | std::shared_ptr<Value>
method set_default_and_implicit (line 1201) | void
function value (line 1213) | std::shared_ptr<Value>
function value (line 1220) | std::shared_ptr<Value>
class OptionAdder (line 1226) | class OptionAdder
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
class OptionDetails (line 1228) | class OptionDetails
method OptionDetails (line 1231) | OptionDetails
method OptionDetails (line 1247) | OptionDetails(const OptionDetails& rhs)
method OptionDetails (line 1254) | OptionDetails(OptionDetails&& rhs) = default;
method CXXOPTS_NODISCARD (line 1256) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1263) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1269) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1276) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1283) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1290) | CXXOPTS_NODISCARD
method hash (line 1297) | size_t
type HelpOptionDetails (line 1313) | struct HelpOptionDetails
type HelpGroupDetails (line 1327) | struct HelpGroupDetails
class OptionValue (line 1334) | class OptionValue
method parse (line 1337) | void
method parse_default (line 1350) | void
method parse_no_value (line 1359) | void
method CXXOPTS_NODISCARD (line 1370) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1382) | CXXOPTS_NODISCARD
method T (line 1390) | const T&
method ensure_value (line 1406) | void
class KeyValue (line 1424) | class KeyValue
method KeyValue (line 1427) | KeyValue(std::string key_, std::string value_)
method CXXOPTS_NODISCARD (line 1433) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1440) | CXXOPTS_NODISCARD
method T (line 1448) | T
class ParseResult (line 1464) | class ParseResult
class Iterator (line 1467) | class Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method ParseResult (line 1528) | ParseResult() = default;
method ParseResult (line 1529) | ParseResult(const ParseResult&) = default;
method ParseResult (line 1531) | ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<...
method ParseResult (line 1541) | ParseResult& operator=(ParseResult&&) = default;
method ParseResult (line 1542) | ParseResult& operator=(const ParseResult&) = default;
method Iterator (line 1544) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method Iterator (line 1550) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method count (line 1556) | size_t
method OptionValue (line 1575) | const OptionValue&
method arguments_string (line 1613) | const std::string
type Option (line 1636) | struct Option
method Option (line 1638) | Option
class OptionParser (line 1662) | class OptionParser
method OptionParser (line 1665) | OptionParser(const OptionMap& options, const PositionalList& positio...
class Options (line 1720) | class Options
method Options (line 1724) | explicit Options(std::string program, std::string help_string = "")
method Options (line 1737) | Options&
method Options (line 1744) | Options&
method Options (line 1751) | Options&
method Options (line 1758) | Options&
method Options (line 1765) | Options&
method Options (line 1772) | Options&
method parse_positional (line 1821) | void
class OptionAdder (line 1879) | class OptionAdder
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
function String (line 1908) | String
function String (line 1954) | String
function OptionAdder (line 2100) | inline
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
function OptionAdder (line 2107) | inline
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
function ParseResult (line 2285) | inline
class Iterator (line 1467) | class Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method ParseResult (line 1528) | ParseResult() = default;
method ParseResult (line 1529) | ParseResult(const ParseResult&) = default;
method ParseResult (line 1531) | ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<...
method ParseResult (line 1541) | ParseResult& operator=(ParseResult&&) = default;
method ParseResult (line 1542) | ParseResult& operator=(const ParseResult&) = default;
method Iterator (line 1544) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method Iterator (line 1550) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method count (line 1556) | size_t
method OptionValue (line 1575) | const OptionValue&
method arguments_string (line 1613) | const std::string
function ParseResult (line 2294) | inline ParseResult
class Iterator (line 1467) | class Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method ParseResult (line 1528) | ParseResult() = default;
method ParseResult (line 1529) | ParseResult(const ParseResult&) = default;
method ParseResult (line 1531) | ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<...
method ParseResult (line 1541) | ParseResult& operator=(ParseResult&&) = default;
method ParseResult (line 1542) | ParseResult& operator=(const ParseResult&) = default;
method Iterator (line 1544) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method Iterator (line 1550) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method count (line 1556) | size_t
method OptionValue (line 1575) | const OptionValue&
method arguments_string (line 1613) | const std::string
function String (line 2542) | inline
function HelpGroupDetails (line 2704) | inline
type cxxopts (line 102) | namespace cxxopts
function String (line 106) | inline
class UnicodeStringIterator (line 121) | class UnicodeStringIterator : public
method UnicodeStringIterator (line 126) | UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos)
method value_type (line 132) | value_type
method UnicodeStringIterator (line 150) | UnicodeStringIterator&
method UnicodeStringIterator (line 157) | UnicodeStringIterator
function String (line 171) | inline
function String (line 178) | inline
function String (line 191) | String&
function stringLength (line 203) | inline
function toUTF8String (line 210) | inline
function empty (line 220) | inline
function T (line 253) | T
function stringLength (line 259) | inline
function String (line 266) | inline
function String (line 273) | inline
function String (line 281) | String&
function toUTF8String (line 288) | std::string
function empty (line 294) | inline
class Value (line 326) | class Value : public std::enable_shared_from_this<Value>
class OptionException (line 372) | class OptionException : public std::exception
method OptionException (line 375) | explicit OptionException(std::string message)
method CXXOPTS_NODISCARD (line 380) | CXXOPTS_NODISCARD
class OptionSpecException (line 391) | class OptionSpecException : public OptionException
method OptionSpecException (line 395) | explicit OptionSpecException(const std::string& message)
class OptionParseException (line 401) | class OptionParseException : public OptionException
method OptionParseException (line 404) | explicit OptionParseException(const std::string& message)
class option_exists_error (line 410) | class option_exists_error : public OptionSpecException
method option_exists_error (line 413) | explicit option_exists_error(const std::string& option)
class invalid_option_format_error (line 419) | class invalid_option_format_error : public OptionSpecException
method invalid_option_format_error (line 422) | explicit invalid_option_format_error(const std::string& format)
class option_syntax_exception (line 428) | class option_syntax_exception : public OptionParseException {
method option_syntax_exception (line 430) | explicit option_syntax_exception(const std::string& text)
class option_not_exists_exception (line 437) | class option_not_exists_exception : public OptionParseException
method option_not_exists_exception (line 440) | explicit option_not_exists_exception(const std::string& option)
class missing_argument_exception (line 446) | class missing_argument_exception : public OptionParseException
method missing_argument_exception (line 449) | explicit missing_argument_exception(const std::string& option)
class option_requires_argument_exception (line 457) | class option_requires_argument_exception : public OptionParseException
method option_requires_argument_exception (line 460) | explicit option_requires_argument_exception(const std::string& option)
class option_not_has_argument_exception (line 468) | class option_not_has_argument_exception : public OptionParseException
method option_not_has_argument_exception (line 471) | option_not_has_argument_exception
class option_not_present_exception (line 485) | class option_not_present_exception : public OptionParseException
method option_not_present_exception (line 488) | explicit option_not_present_exception(const std::string& option)
class option_has_no_value_exception (line 494) | class option_has_no_value_exception : public OptionException
method option_has_no_value_exception (line 497) | explicit option_has_no_value_exception(const std::string& option)
class argument_incorrect_type (line 506) | class argument_incorrect_type : public OptionParseException
method argument_incorrect_type (line 509) | explicit argument_incorrect_type
class option_required_exception (line 520) | class option_required_exception : public OptionParseException
method option_required_exception (line 523) | explicit option_required_exception(const std::string& option)
function throw_or_mimic (line 532) | void throw_or_mimic(const std::string& text)
type values (line 550) | namespace values
type parser_tool (line 552) | namespace parser_tool
type IntegerDesc (line 554) | struct IntegerDesc
type ArguDesc (line 560) | struct ArguDesc {
function IntegerDesc (line 567) | inline IntegerDesc SplitInteger(const std::string &text)
function IsTrueText (line 596) | inline bool IsTrueText(const std::string &text)
function IsFalseText (line 614) | inline bool IsFalseText(const std::string &text)
function SplitSwitchDef (line 632) | inline std::pair<std::string, std::string> SplitSwitchDef(const st...
function ArguDesc (line 656) | inline ArguDesc ParseArgument(const char *arg, bool &matched)
function IntegerDesc (line 725) | inline IntegerDesc SplitInteger(const std::string &text)
function IsTrueText (line 750) | inline bool IsTrueText(const std::string &text)
function IsFalseText (line 757) | inline bool IsFalseText(const std::string &text)
function SplitSwitchDef (line 764) | inline std::pair<std::string, std::string> SplitSwitchDef(const st...
function ArguDesc (line 779) | inline ArguDesc ParseArgument(const char *arg, bool &matched)
type detail (line 804) | namespace detail
type SignedCheck (line 807) | struct SignedCheck
type SignedCheck<T, true> (line 810) | struct SignedCheck<T, true>
type SignedCheck<T, false> (line 834) | struct SignedCheck<T, false>
function check_signed_range (line 842) | void
function checked_negate (line 850) | void
function checked_negate (line 860) | void
function integer_parser (line 867) | void
function stringstream_parser (line 924) | void stringstream_parser(const std::string& text, T& value)
function parse_value (line 936) | void parse_value(const std::string& text, T& value)
function parse_value (line 941) | inline
function parse_value (line 960) | inline
function parse_value (line 973) | void
function parse_value (line 979) | void
function parse_value (line 999) | void
function parse_value (line 1008) | inline
type type_is_container (line 1020) | struct type_is_container
type type_is_container<std::vector<T>> (line 1026) | struct type_is_container<std::vector<T>>
class abstract_value (line 1032) | class abstract_value : public Value
method abstract_value (line 1037) | abstract_value()
method abstract_value (line 1043) | explicit abstract_value(T* t)
method abstract_value (line 1050) | abstract_value& operator=(const abstract_value&) = default;
method abstract_value (line 1052) | abstract_value(const abstract_value& rhs)
method parse (line 1070) | void
method is_container (line 1076) | bool
method parse (line 1082) | void
method has_default (line 1088) | bool
method has_implicit (line 1094) | bool
method default_value (line 1100) | std::shared_ptr<Value>
method implicit_value (line 1108) | std::shared_ptr<Value>
method no_implicit_value (line 1116) | std::shared_ptr<Value>
method get_default_value (line 1123) | std::string
method get_implicit_value (line 1129) | std::string
method is_boolean (line 1135) | bool
method T (line 1141) | const T&
class standard_value (line 1163) | class standard_value : public abstract_value<T>
method override (line 1170) | const override
class standard_value<bool> (line 1177) | class standard_value<bool> : public abstract_value<bool>
method standard_value (line 1182) | standard_value()
method standard_value (line 1187) | explicit standard_value(bool* b)
method clone (line 1193) | std::shared_ptr<Value>
method set_default_and_implicit (line 1201) | void
function value (line 1213) | std::shared_ptr<Value>
function value (line 1220) | std::shared_ptr<Value>
class OptionAdder (line 1226) | class OptionAdder
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
class OptionDetails (line 1228) | class OptionDetails
method OptionDetails (line 1231) | OptionDetails
method OptionDetails (line 1247) | OptionDetails(const OptionDetails& rhs)
method OptionDetails (line 1254) | OptionDetails(OptionDetails&& rhs) = default;
method CXXOPTS_NODISCARD (line 1256) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1263) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1269) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1276) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1283) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1290) | CXXOPTS_NODISCARD
method hash (line 1297) | size_t
type HelpOptionDetails (line 1313) | struct HelpOptionDetails
type HelpGroupDetails (line 1327) | struct HelpGroupDetails
class OptionValue (line 1334) | class OptionValue
method parse (line 1337) | void
method parse_default (line 1350) | void
method parse_no_value (line 1359) | void
method CXXOPTS_NODISCARD (line 1370) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1382) | CXXOPTS_NODISCARD
method T (line 1390) | const T&
method ensure_value (line 1406) | void
class KeyValue (line 1424) | class KeyValue
method KeyValue (line 1427) | KeyValue(std::string key_, std::string value_)
method CXXOPTS_NODISCARD (line 1433) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1440) | CXXOPTS_NODISCARD
method T (line 1448) | T
class ParseResult (line 1464) | class ParseResult
class Iterator (line 1467) | class Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method ParseResult (line 1528) | ParseResult() = default;
method ParseResult (line 1529) | ParseResult(const ParseResult&) = default;
method ParseResult (line 1531) | ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<...
method ParseResult (line 1541) | ParseResult& operator=(ParseResult&&) = default;
method ParseResult (line 1542) | ParseResult& operator=(const ParseResult&) = default;
method Iterator (line 1544) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method Iterator (line 1550) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method count (line 1556) | size_t
method OptionValue (line 1575) | const OptionValue&
method arguments_string (line 1613) | const std::string
type Option (line 1636) | struct Option
method Option (line 1638) | Option
class OptionParser (line 1662) | class OptionParser
method OptionParser (line 1665) | OptionParser(const OptionMap& options, const PositionalList& positio...
class Options (line 1720) | class Options
method Options (line 1724) | explicit Options(std::string program, std::string help_string = "")
method Options (line 1737) | Options&
method Options (line 1744) | Options&
method Options (line 1751) | Options&
method Options (line 1758) | Options&
method Options (line 1765) | Options&
method Options (line 1772) | Options&
method parse_positional (line 1821) | void
class OptionAdder (line 1879) | class OptionAdder
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
function String (line 1908) | String
function String (line 1954) | String
function OptionAdder (line 2100) | inline
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
function OptionAdder (line 2107) | inline
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
function ParseResult (line 2285) | inline
class Iterator (line 1467) | class Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method ParseResult (line 1528) | ParseResult() = default;
method ParseResult (line 1529) | ParseResult(const ParseResult&) = default;
method ParseResult (line 1531) | ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<...
method ParseResult (line 1541) | ParseResult& operator=(ParseResult&&) = default;
method ParseResult (line 1542) | ParseResult& operator=(const ParseResult&) = default;
method Iterator (line 1544) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method Iterator (line 1550) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method count (line 1556) | size_t
method OptionValue (line 1575) | const OptionValue&
method arguments_string (line 1613) | const std::string
function ParseResult (line 2294) | inline ParseResult
class Iterator (line 1467) | class Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method ParseResult (line 1528) | ParseResult() = default;
method ParseResult (line 1529) | ParseResult(const ParseResult&) = default;
method ParseResult (line 1531) | ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<...
method ParseResult (line 1541) | ParseResult& operator=(ParseResult&&) = default;
method ParseResult (line 1542) | ParseResult& operator=(const ParseResult&) = default;
method Iterator (line 1544) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method Iterator (line 1550) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method count (line 1556) | size_t
method OptionValue (line 1575) | const OptionValue&
method arguments_string (line 1613) | const std::string
function String (line 2542) | inline
function HelpGroupDetails (line 2704) | inline
type std (line 228) | namespace std
function begin (line 230) | inline
function end (line 237) | inline
type cxxopts (line 248) | namespace cxxopts
function String (line 106) | inline
class UnicodeStringIterator (line 121) | class UnicodeStringIterator : public
method UnicodeStringIterator (line 126) | UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos)
method value_type (line 132) | value_type
method UnicodeStringIterator (line 150) | UnicodeStringIterator&
method UnicodeStringIterator (line 157) | UnicodeStringIterator
function String (line 171) | inline
function String (line 178) | inline
function String (line 191) | String&
function stringLength (line 203) | inline
function toUTF8String (line 210) | inline
function empty (line 220) | inline
function T (line 253) | T
function stringLength (line 259) | inline
function String (line 266) | inline
function String (line 273) | inline
function String (line 281) | String&
function toUTF8String (line 288) | std::string
function empty (line 294) | inline
class Value (line 326) | class Value : public std::enable_shared_from_this<Value>
class OptionException (line 372) | class OptionException : public std::exception
method OptionException (line 375) | explicit OptionException(std::string message)
method CXXOPTS_NODISCARD (line 380) | CXXOPTS_NODISCARD
class OptionSpecException (line 391) | class OptionSpecException : public OptionException
method OptionSpecException (line 395) | explicit OptionSpecException(const std::string& message)
class OptionParseException (line 401) | class OptionParseException : public OptionException
method OptionParseException (line 404) | explicit OptionParseException(const std::string& message)
class option_exists_error (line 410) | class option_exists_error : public OptionSpecException
method option_exists_error (line 413) | explicit option_exists_error(const std::string& option)
class invalid_option_format_error (line 419) | class invalid_option_format_error : public OptionSpecException
method invalid_option_format_error (line 422) | explicit invalid_option_format_error(const std::string& format)
class option_syntax_exception (line 428) | class option_syntax_exception : public OptionParseException {
method option_syntax_exception (line 430) | explicit option_syntax_exception(const std::string& text)
class option_not_exists_exception (line 437) | class option_not_exists_exception : public OptionParseException
method option_not_exists_exception (line 440) | explicit option_not_exists_exception(const std::string& option)
class missing_argument_exception (line 446) | class missing_argument_exception : public OptionParseException
method missing_argument_exception (line 449) | explicit missing_argument_exception(const std::string& option)
class option_requires_argument_exception (line 457) | class option_requires_argument_exception : public OptionParseException
method option_requires_argument_exception (line 460) | explicit option_requires_argument_exception(const std::string& option)
class option_not_has_argument_exception (line 468) | class option_not_has_argument_exception : public OptionParseException
method option_not_has_argument_exception (line 471) | option_not_has_argument_exception
class option_not_present_exception (line 485) | class option_not_present_exception : public OptionParseException
method option_not_present_exception (line 488) | explicit option_not_present_exception(const std::string& option)
class option_has_no_value_exception (line 494) | class option_has_no_value_exception : public OptionException
method option_has_no_value_exception (line 497) | explicit option_has_no_value_exception(const std::string& option)
class argument_incorrect_type (line 506) | class argument_incorrect_type : public OptionParseException
method argument_incorrect_type (line 509) | explicit argument_incorrect_type
class option_required_exception (line 520) | class option_required_exception : public OptionParseException
method option_required_exception (line 523) | explicit option_required_exception(const std::string& option)
function throw_or_mimic (line 532) | void throw_or_mimic(const std::string& text)
type values (line 550) | namespace values
type parser_tool (line 552) | namespace parser_tool
type IntegerDesc (line 554) | struct IntegerDesc
type ArguDesc (line 560) | struct ArguDesc {
function IntegerDesc (line 567) | inline IntegerDesc SplitInteger(const std::string &text)
function IsTrueText (line 596) | inline bool IsTrueText(const std::string &text)
function IsFalseText (line 614) | inline bool IsFalseText(const std::string &text)
function SplitSwitchDef (line 632) | inline std::pair<std::string, std::string> SplitSwitchDef(const st...
function ArguDesc (line 656) | inline ArguDesc ParseArgument(const char *arg, bool &matched)
function IntegerDesc (line 725) | inline IntegerDesc SplitInteger(const std::string &text)
function IsTrueText (line 750) | inline bool IsTrueText(const std::string &text)
function IsFalseText (line 757) | inline bool IsFalseText(const std::string &text)
function SplitSwitchDef (line 764) | inline std::pair<std::string, std::string> SplitSwitchDef(const st...
function ArguDesc (line 779) | inline ArguDesc ParseArgument(const char *arg, bool &matched)
type detail (line 804) | namespace detail
type SignedCheck (line 807) | struct SignedCheck
type SignedCheck<T, true> (line 810) | struct SignedCheck<T, true>
type SignedCheck<T, false> (line 834) | struct SignedCheck<T, false>
function check_signed_range (line 842) | void
function checked_negate (line 850) | void
function checked_negate (line 860) | void
function integer_parser (line 867) | void
function stringstream_parser (line 924) | void stringstream_parser(const std::string& text, T& value)
function parse_value (line 936) | void parse_value(const std::string& text, T& value)
function parse_value (line 941) | inline
function parse_value (line 960) | inline
function parse_value (line 973) | void
function parse_value (line 979) | void
function parse_value (line 999) | void
function parse_value (line 1008) | inline
type type_is_container (line 1020) | struct type_is_container
type type_is_container<std::vector<T>> (line 1026) | struct type_is_container<std::vector<T>>
class abstract_value (line 1032) | class abstract_value : public Value
method abstract_value (line 1037) | abstract_value()
method abstract_value (line 1043) | explicit abstract_value(T* t)
method abstract_value (line 1050) | abstract_value& operator=(const abstract_value&) = default;
method abstract_value (line 1052) | abstract_value(const abstract_value& rhs)
method parse (line 1070) | void
method is_container (line 1076) | bool
method parse (line 1082) | void
method has_default (line 1088) | bool
method has_implicit (line 1094) | bool
method default_value (line 1100) | std::shared_ptr<Value>
method implicit_value (line 1108) | std::shared_ptr<Value>
method no_implicit_value (line 1116) | std::shared_ptr<Value>
method get_default_value (line 1123) | std::string
method get_implicit_value (line 1129) | std::string
method is_boolean (line 1135) | bool
method T (line 1141) | const T&
class standard_value (line 1163) | class standard_value : public abstract_value<T>
method override (line 1170) | const override
class standard_value<bool> (line 1177) | class standard_value<bool> : public abstract_value<bool>
method standard_value (line 1182) | standard_value()
method standard_value (line 1187) | explicit standard_value(bool* b)
method clone (line 1193) | std::shared_ptr<Value>
method set_default_and_implicit (line 1201) | void
function value (line 1213) | std::shared_ptr<Value>
function value (line 1220) | std::shared_ptr<Value>
class OptionAdder (line 1226) | class OptionAdder
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
class OptionDetails (line 1228) | class OptionDetails
method OptionDetails (line 1231) | OptionDetails
method OptionDetails (line 1247) | OptionDetails(const OptionDetails& rhs)
method OptionDetails (line 1254) | OptionDetails(OptionDetails&& rhs) = default;
method CXXOPTS_NODISCARD (line 1256) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1263) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1269) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1276) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1283) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1290) | CXXOPTS_NODISCARD
method hash (line 1297) | size_t
type HelpOptionDetails (line 1313) | struct HelpOptionDetails
type HelpGroupDetails (line 1327) | struct HelpGroupDetails
class OptionValue (line 1334) | class OptionValue
method parse (line 1337) | void
method parse_default (line 1350) | void
method parse_no_value (line 1359) | void
method CXXOPTS_NODISCARD (line 1370) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1382) | CXXOPTS_NODISCARD
method T (line 1390) | const T&
method ensure_value (line 1406) | void
class KeyValue (line 1424) | class KeyValue
method KeyValue (line 1427) | KeyValue(std::string key_, std::string value_)
method CXXOPTS_NODISCARD (line 1433) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1440) | CXXOPTS_NODISCARD
method T (line 1448) | T
class ParseResult (line 1464) | class ParseResult
class Iterator (line 1467) | class Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method ParseResult (line 1528) | ParseResult() = default;
method ParseResult (line 1529) | ParseResult(const ParseResult&) = default;
method ParseResult (line 1531) | ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<...
method ParseResult (line 1541) | ParseResult& operator=(ParseResult&&) = default;
method ParseResult (line 1542) | ParseResult& operator=(const ParseResult&) = default;
method Iterator (line 1544) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method Iterator (line 1550) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method count (line 1556) | size_t
method OptionValue (line 1575) | const OptionValue&
method arguments_string (line 1613) | const std::string
type Option (line 1636) | struct Option
method Option (line 1638) | Option
class OptionParser (line 1662) | class OptionParser
method OptionParser (line 1665) | OptionParser(const OptionMap& options, const PositionalList& positio...
class Options (line 1720) | class Options
method Options (line 1724) | explicit Options(std::string program, std::string help_string = "")
method Options (line 1737) | Options&
method Options (line 1744) | Options&
method Options (line 1751) | Options&
method Options (line 1758) | Options&
method Options (line 1765) | Options&
method Options (line 1772) | Options&
method parse_positional (line 1821) | void
class OptionAdder (line 1879) | class OptionAdder
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
function String (line 1908) | String
function String (line 1954) | String
function OptionAdder (line 2100) | inline
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
function OptionAdder (line 2107) | inline
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
function ParseResult (line 2285) | inline
class Iterator (line 1467) | class Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method ParseResult (line 1528) | ParseResult() = default;
method ParseResult (line 1529) | ParseResult(const ParseResult&) = default;
method ParseResult (line 1531) | ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<...
method ParseResult (line 1541) | ParseResult& operator=(ParseResult&&) = default;
method ParseResult (line 1542) | ParseResult& operator=(const ParseResult&) = default;
method Iterator (line 1544) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method Iterator (line 1550) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method count (line 1556) | size_t
method OptionValue (line 1575) | const OptionValue&
method arguments_string (line 1613) | const std::string
function ParseResult (line 2294) | inline ParseResult
class Iterator (line 1467) | class Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method ParseResult (line 1528) | ParseResult() = default;
method ParseResult (line 1529) | ParseResult(const ParseResult&) = default;
method ParseResult (line 1531) | ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<...
method ParseResult (line 1541) | ParseResult& operator=(ParseResult&&) = default;
method ParseResult (line 1542) | ParseResult& operator=(const ParseResult&) = default;
method Iterator (line 1544) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method Iterator (line 1550) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method count (line 1556) | size_t
method OptionValue (line 1575) | const OptionValue&
method arguments_string (line 1613) | const std::string
function String (line 2542) | inline
function HelpGroupDetails (line 2704) | inline
type cxxopts (line 305) | namespace cxxopts
function String (line 106) | inline
class UnicodeStringIterator (line 121) | class UnicodeStringIterator : public
method UnicodeStringIterator (line 126) | UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos)
method value_type (line 132) | value_type
method UnicodeStringIterator (line 150) | UnicodeStringIterator&
method UnicodeStringIterator (line 157) | UnicodeStringIterator
function String (line 171) | inline
function String (line 178) | inline
function String (line 191) | String&
function stringLength (line 203) | inline
function toUTF8String (line 210) | inline
function empty (line 220) | inline
function T (line 253) | T
function stringLength (line 259) | inline
function String (line 266) | inline
function String (line 273) | inline
function String (line 281) | String&
function toUTF8String (line 288) | std::string
function empty (line 294) | inline
class Value (line 326) | class Value : public std::enable_shared_from_this<Value>
class OptionException (line 372) | class OptionException : public std::exception
method OptionException (line 375) | explicit OptionException(std::string message)
method CXXOPTS_NODISCARD (line 380) | CXXOPTS_NODISCARD
class OptionSpecException (line 391) | class OptionSpecException : public OptionException
method OptionSpecException (line 395) | explicit OptionSpecException(const std::string& message)
class OptionParseException (line 401) | class OptionParseException : public OptionException
method OptionParseException (line 404) | explicit OptionParseException(const std::string& message)
class option_exists_error (line 410) | class option_exists_error : public OptionSpecException
method option_exists_error (line 413) | explicit option_exists_error(const std::string& option)
class invalid_option_format_error (line 419) | class invalid_option_format_error : public OptionSpecException
method invalid_option_format_error (line 422) | explicit invalid_option_format_error(const std::string& format)
class option_syntax_exception (line 428) | class option_syntax_exception : public OptionParseException {
method option_syntax_exception (line 430) | explicit option_syntax_exception(const std::string& text)
class option_not_exists_exception (line 437) | class option_not_exists_exception : public OptionParseException
method option_not_exists_exception (line 440) | explicit option_not_exists_exception(const std::string& option)
class missing_argument_exception (line 446) | class missing_argument_exception : public OptionParseException
method missing_argument_exception (line 449) | explicit missing_argument_exception(const std::string& option)
class option_requires_argument_exception (line 457) | class option_requires_argument_exception : public OptionParseException
method option_requires_argument_exception (line 460) | explicit option_requires_argument_exception(const std::string& option)
class option_not_has_argument_exception (line 468) | class option_not_has_argument_exception : public OptionParseException
method option_not_has_argument_exception (line 471) | option_not_has_argument_exception
class option_not_present_exception (line 485) | class option_not_present_exception : public OptionParseException
method option_not_present_exception (line 488) | explicit option_not_present_exception(const std::string& option)
class option_has_no_value_exception (line 494) | class option_has_no_value_exception : public OptionException
method option_has_no_value_exception (line 497) | explicit option_has_no_value_exception(const std::string& option)
class argument_incorrect_type (line 506) | class argument_incorrect_type : public OptionParseException
method argument_incorrect_type (line 509) | explicit argument_incorrect_type
class option_required_exception (line 520) | class option_required_exception : public OptionParseException
method option_required_exception (line 523) | explicit option_required_exception(const std::string& option)
function throw_or_mimic (line 532) | void throw_or_mimic(const std::string& text)
type values (line 550) | namespace values
type parser_tool (line 552) | namespace parser_tool
type IntegerDesc (line 554) | struct IntegerDesc
type ArguDesc (line 560) | struct ArguDesc {
function IntegerDesc (line 567) | inline IntegerDesc SplitInteger(const std::string &text)
function IsTrueText (line 596) | inline bool IsTrueText(const std::string &text)
function IsFalseText (line 614) | inline bool IsFalseText(const std::string &text)
function SplitSwitchDef (line 632) | inline std::pair<std::string, std::string> SplitSwitchDef(const st...
function ArguDesc (line 656) | inline ArguDesc ParseArgument(const char *arg, bool &matched)
function IntegerDesc (line 725) | inline IntegerDesc SplitInteger(const std::string &text)
function IsTrueText (line 750) | inline bool IsTrueText(const std::string &text)
function IsFalseText (line 757) | inline bool IsFalseText(const std::string &text)
function SplitSwitchDef (line 764) | inline std::pair<std::string, std::string> SplitSwitchDef(const st...
function ArguDesc (line 779) | inline ArguDesc ParseArgument(const char *arg, bool &matched)
type detail (line 804) | namespace detail
type SignedCheck (line 807) | struct SignedCheck
type SignedCheck<T, true> (line 810) | struct SignedCheck<T, true>
type SignedCheck<T, false> (line 834) | struct SignedCheck<T, false>
function check_signed_range (line 842) | void
function checked_negate (line 850) | void
function checked_negate (line 860) | void
function integer_parser (line 867) | void
function stringstream_parser (line 924) | void stringstream_parser(const std::string& text, T& value)
function parse_value (line 936) | void parse_value(const std::string& text, T& value)
function parse_value (line 941) | inline
function parse_value (line 960) | inline
function parse_value (line 973) | void
function parse_value (line 979) | void
function parse_value (line 999) | void
function parse_value (line 1008) | inline
type type_is_container (line 1020) | struct type_is_container
type type_is_container<std::vector<T>> (line 1026) | struct type_is_container<std::vector<T>>
class abstract_value (line 1032) | class abstract_value : public Value
method abstract_value (line 1037) | abstract_value()
method abstract_value (line 1043) | explicit abstract_value(T* t)
method abstract_value (line 1050) | abstract_value& operator=(const abstract_value&) = default;
method abstract_value (line 1052) | abstract_value(const abstract_value& rhs)
method parse (line 1070) | void
method is_container (line 1076) | bool
method parse (line 1082) | void
method has_default (line 1088) | bool
method has_implicit (line 1094) | bool
method default_value (line 1100) | std::shared_ptr<Value>
method implicit_value (line 1108) | std::shared_ptr<Value>
method no_implicit_value (line 1116) | std::shared_ptr<Value>
method get_default_value (line 1123) | std::string
method get_implicit_value (line 1129) | std::string
method is_boolean (line 1135) | bool
method T (line 1141) | const T&
class standard_value (line 1163) | class standard_value : public abstract_value<T>
method override (line 1170) | const override
class standard_value<bool> (line 1177) | class standard_value<bool> : public abstract_value<bool>
method standard_value (line 1182) | standard_value()
method standard_value (line 1187) | explicit standard_value(bool* b)
method clone (line 1193) | std::shared_ptr<Value>
method set_default_and_implicit (line 1201) | void
function value (line 1213) | std::shared_ptr<Value>
function value (line 1220) | std::shared_ptr<Value>
class OptionAdder (line 1226) | class OptionAdder
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
class OptionDetails (line 1228) | class OptionDetails
method OptionDetails (line 1231) | OptionDetails
method OptionDetails (line 1247) | OptionDetails(const OptionDetails& rhs)
method OptionDetails (line 1254) | OptionDetails(OptionDetails&& rhs) = default;
method CXXOPTS_NODISCARD (line 1256) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1263) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1269) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1276) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1283) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1290) | CXXOPTS_NODISCARD
method hash (line 1297) | size_t
type HelpOptionDetails (line 1313) | struct HelpOptionDetails
type HelpGroupDetails (line 1327) | struct HelpGroupDetails
class OptionValue (line 1334) | class OptionValue
method parse (line 1337) | void
method parse_default (line 1350) | void
method parse_no_value (line 1359) | void
method CXXOPTS_NODISCARD (line 1370) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1382) | CXXOPTS_NODISCARD
method T (line 1390) | const T&
method ensure_value (line 1406) | void
class KeyValue (line 1424) | class KeyValue
method KeyValue (line 1427) | KeyValue(std::string key_, std::string value_)
method CXXOPTS_NODISCARD (line 1433) | CXXOPTS_NODISCARD
method CXXOPTS_NODISCARD (line 1440) | CXXOPTS_NODISCARD
method T (line 1448) | T
class ParseResult (line 1464) | class ParseResult
class Iterator (line 1467) | class Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method ParseResult (line 1528) | ParseResult() = default;
method ParseResult (line 1529) | ParseResult(const ParseResult&) = default;
method ParseResult (line 1531) | ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<...
method ParseResult (line 1541) | ParseResult& operator=(ParseResult&&) = default;
method ParseResult (line 1542) | ParseResult& operator=(const ParseResult&) = default;
method Iterator (line 1544) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method Iterator (line 1550) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method count (line 1556) | size_t
method OptionValue (line 1575) | const OptionValue&
method arguments_string (line 1613) | const std::string
type Option (line 1636) | struct Option
method Option (line 1638) | Option
class OptionParser (line 1662) | class OptionParser
method OptionParser (line 1665) | OptionParser(const OptionMap& options, const PositionalList& positio...
class Options (line 1720) | class Options
method Options (line 1724) | explicit Options(std::string program, std::string help_string = "")
method Options (line 1737) | Options&
method Options (line 1744) | Options&
method Options (line 1751) | Options&
method Options (line 1758) | Options&
method Options (line 1765) | Options&
method Options (line 1772) | Options&
method parse_positional (line 1821) | void
class OptionAdder (line 1879) | class OptionAdder
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
function String (line 1908) | String
function String (line 1954) | String
function OptionAdder (line 2100) | inline
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
function OptionAdder (line 2107) | inline
method OptionAdder (line 1883) | OptionAdder(Options& options, std::string group)
function ParseResult (line 2285) | inline
class Iterator (line 1467) | class Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method ParseResult (line 1528) | ParseResult() = default;
method ParseResult (line 1529) | ParseResult(const ParseResult&) = default;
method ParseResult (line 1531) | ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<...
method ParseResult (line 1541) | ParseResult& operator=(ParseResult&&) = default;
method ParseResult (line 1542) | ParseResult& operator=(const ParseResult&) = default;
method Iterator (line 1544) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method Iterator (line 1550) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method count (line 1556) | size_t
method OptionValue (line 1575) | const OptionValue&
method arguments_string (line 1613) | const std::string
function ParseResult (line 2294) | inline ParseResult
class Iterator (line 1467) | class Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method ParseResult (line 1528) | ParseResult() = default;
method ParseResult (line 1529) | ParseResult(const ParseResult&) = default;
method ParseResult (line 1531) | ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<...
method ParseResult (line 1541) | ParseResult& operator=(ParseResult&&) = default;
method ParseResult (line 1542) | ParseResult& operator=(const ParseResult&) = default;
method Iterator (line 1544) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method Iterator (line 1550) | Iterator
method Iterator (line 1476) | Iterator() = default;
method Iterator (line 1477) | Iterator(const Iterator&) = default;
method Iterator (line 1479) | Iterator(const ParseResult *pr, bool end=false)
method Iterator (line 1485) | Iterator& operator++()
method Iterator (line 1496) | Iterator operator++(int)
method KeyValue (line 1513) | const KeyValue& operator*()
method KeyValue (line 1518) | const KeyValue* operator->()
method count (line 1556) | size_t
method OptionValue (line 1575) | const OptionValue&
method arguments_string (line 1613) | const std::string
function String (line 2542) | inline
function HelpGroupDetails (line 2704) | inline
FILE: src/kilo/kilo.cpp
type ESP32Console::Kilo (line 81) | namespace ESP32Console::Kilo
type editorSyntax (line 83) | struct editorSyntax
type erow (line 94) | struct erow
type hlcolor (line 106) | struct hlcolor
type editorConfig (line 111) | struct editorConfig
type editorSyntax (line 125) | struct editorSyntax
type editorConfig (line 128) | struct editorConfig
type editorSyntax (line 125) | struct editorSyntax
type KEY_ACTION (line 130) | enum KEY_ACTION
type editorSyntax (line 204) | struct editorSyntax
type termios (line 215) | struct termios
function disableRawMode (line 217) | void disableRawMode(int fd)
function editorAtExit (line 228) | void editorAtExit(void)
function enableRawMode (line 234) | int enableRawMode(int fd)
function editorReadKey (line 274) | int editorReadKey(int fd)
function getCursorPosition (line 356) | int getCursorPosition(int ifd, int ofd, int *rows, int *cols)
function getWindowSize (line 387) | int getWindowSize(int ifd, int ofd, int *rows, int *cols)
function is_separator (line 419) | int is_separator(int c)
function editorRowHasOpenComment (line 427) | int editorRowHasOpenComment(erow *row)
function editorUpdateSyntax (line 438) | void editorUpdateSyntax(erow *row)
function editorSyntaxToColor (line 608) | int editorSyntaxToColor(int hl)
function editorSelectSyntaxHighlight (line 632) | void editorSelectSyntaxHighlight(char *filename)
function editorUpdateRow (line 658) | void editorUpdateRow(erow *row)
function editorInsertRow (line 702) | void editorInsertRow(int at, char *s, size_t len)
function editorFreeRow (line 727) | void editorFreeRow(erow *row)
function editorDelRow (line 736) | void editorDelRow(int at)
function editorRowInsertChar (line 781) | void editorRowInsertChar(erow *row, int at, int c)
function editorRowAppendString (line 808) | void editorRowAppendString(erow *row, char *s, size_t len)
function editorRowDelChar (line 819) | void editorRowDelChar(erow *row, int at)
function editorInsertChar (line 830) | void editorInsertChar(int c)
function editorInsertNewline (line 854) | void editorInsertNewline(void)
function editorDelChar (line 900) | void editorDelChar()
function editorOpen (line 943) | int editorOpen(char *filename)
function editorSave (line 980) | int editorSave(void)
type abuf (line 1037) | struct abuf
function abAppend (line 1048) | void abAppend(struct abuf *ab, const char *s, int len)
function abFree (line 1059) | void abFree(struct abuf *ab)
function editorRefreshScreen (line 1066) | void editorRefreshScreen(void)
function editorSetStatusMessage (line 1212) | void editorSetStatusMessage(const char *fmt, ...)
function editorFind (line 1225) | void editorFind(int fd)
function editorMoveCursor (line 1351) | void editorMoveCursor(int key)
function editorProcessKeypress (line 1456) | void editorProcessKeypress(int fd)
function editorFileWasModified (line 1528) | int editorFileWasModified(void)
function updateWindowSize (line 1533) | void updateWindowSize(void)
function handleSigWinCh (line 1544) | void handleSigWinCh(int unused __attribute__((unused)))
function initEditor (line 1554) | void initEditor(void)
function kilo (line 1569) | int kilo(int argc, char **argv)
FILE: src/kilo/kilo.h
function namespace (line 7) | namespace ESP32Console::Kilo
Condensed preview — 40 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (203K chars).
[
{
"path": ".github/workflows/arduino-ci.yaml",
"chars": 747,
"preview": "name: Arduino Library CI\n\non: [pull_request, push, repository_dispatch]\n\njobs:\n build:\n runs-on: ubuntu-latest\n\n "
},
{
"path": ".github/workflows/arduino-lint.yaml",
"chars": 232,
"preview": "on: [push, pull_request]\njobs:\n lint:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - u"
},
{
"path": "LICENSE",
"chars": 1066,
"preview": "MIT License\n\nCopyright (c) 2022 Jan Böhmer\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
},
{
"path": "README.md",
"chars": 8186,
"preview": "# ESP32Console\n\n[ is called)\n\n* `help`: Show a list of "
},
{
"path": "examples/argparser/argparser.ino",
"chars": 1654,
"preview": "/**\n * This example demonstrates the usage of OptionsConsoleCommand, which allows you to easily build commands with comp"
},
{
"path": "examples/basic/basic.ino",
"chars": 2313,
"preview": "#include <Arduino.h>\n\n#include \"ESP32Console.h\"\n\nusing namespace ESP32Console;\n\nConsole console;\n\nconstexpr int LED = 2;"
},
{
"path": "examples/gpio/gpio.ino",
"chars": 920,
"preview": "/**\n * This example demonstrates the usage of the internal GPIO functions and the env variables interpolation\n */\n\n#incl"
},
{
"path": "examples/network/network.ino",
"chars": 547,
"preview": "/**\n * This example demonstrates the usage of the builtin network functions\n */\n\n#include <Arduino.h>\n#include \"ESP32Con"
},
{
"path": "examples/other_uart_channel/other_uart_channel.ino",
"chars": 727,
"preview": "/**\n * This example demonstrates the usage of ESP32Console on a seperate UART channel, using its own Pins, which allows "
},
{
"path": "examples/vfs/vfs.ino",
"chars": 1003,
"preview": "/**\n * This example demonstrates the usage of the builtin VFS commands and persistent history\n */\n\n#include <Arduino.h>\n"
},
{
"path": "library.json",
"chars": 853,
"preview": "{\n \"name\": \"ESP32Console\",\n \"version\": \"1.3.0\",\n \"description\": \"Extensible UART console for ESP32 with useful "
},
{
"path": "library.properties",
"chars": 398,
"preview": "name=ESP32Console\nversion=1.3.0\nauthor=Jan Böhmer <mail@jan-boehmer.de>\nmaintainer=Jan Böhmer <mail@jan-boehmer.de>\nsent"
},
{
"path": "src/ESP32Console/Commands/CoreCommands.cpp",
"chars": 3679,
"preview": "#include \"./CoreCommands.h\"\n#include \"linenoise/linenoise.h\"\n#include \"Arduino.h\"\n#include \"soc/soc_caps.h\"\n//#include \""
},
{
"path": "src/ESP32Console/Commands/CoreCommands.h",
"chars": 387,
"preview": "#pragma once\n\n#include \"ESP32Console/ConsoleCommand.h\"\n\nnamespace ESP32Console::Commands\n{\n const ConsoleCommand getC"
},
{
"path": "src/ESP32Console/Commands/GPIOCommands.cpp",
"chars": 4684,
"preview": "#include \"./GPIOCommands.h\"\n#include \"Arduino.h\"\n#include <string>\n#include <stdexcept>\n\nstatic int _pinmode(int argc, c"
},
{
"path": "src/ESP32Console/Commands/GPIOCommands.h",
"chars": 291,
"preview": "#pragma once\n\n#include \"ESP32Console/ConsoleCommand.h\"\n\nnamespace ESP32Console::Commands\n{\n const ConsoleCommand getP"
},
{
"path": "src/ESP32Console/Commands/NetworkCommands.cpp",
"chars": 7329,
"preview": "#include \"./NetworkCommands.h\"\n#include <Arduino.h>\n\n#include <esp_ping.h>\n#include <ping/ping.h>\n#include <ping/ping_so"
},
{
"path": "src/ESP32Console/Commands/NetworkCommands.h",
"chars": 184,
"preview": "#pragma once\n\n#include \"ESP32Console/ConsoleCommand.h\"\n\nnamespace ESP32Console::Commands\n{\n const ConsoleCommand getP"
},
{
"path": "src/ESP32Console/Commands/SystemCommands.cpp",
"chars": 7352,
"preview": "#include \"./SystemCommands.h\"\n#include \"ESP32Console.h\"\n#include <Arduino.h>\n#include <esp_partition.h>\n#include <esp_ot"
},
{
"path": "src/ESP32Console/Commands/SystemCommands.h",
"chars": 277,
"preview": "#pragma once\n\n#include \"ESP32Console/ConsoleCommand.h\"\n\nnamespace ESP32Console::Commands\n{\n const ConsoleCommand getS"
},
{
"path": "src/ESP32Console/Commands/VFSCommands.cpp",
"chars": 6846,
"preview": "#include \"./VFSCommands.h\"\n#include <Arduino.h>\n#include <string>\n#include <stdio.h>\n#include <stdlib.h>\n#include <diren"
},
{
"path": "src/ESP32Console/Commands/VFSCommands.h",
"chars": 476,
"preview": "#pragma once\n\n#include \"ESP32Console/ConsoleCommand.h\"\n\nnamespace ESP32Console::Commands\n{\n const ConsoleCommand getC"
},
{
"path": "src/ESP32Console/Console.cpp",
"chars": 9628,
"preview": "#include \"./Console.h\"\n#include \"soc/soc_caps.h\"\n#include \"esp_err.h\"\n#include \"esp_idf_version.h\"\n#include \"ESP32Consol"
},
{
"path": "src/ESP32Console/Console.h",
"chars": 5590,
"preview": "#pragma once\n\n#if !defined(ESP32)\n#error This library depends on ESP-IDF and only works on ESP32!\n#endif\n\n#include \"esp_"
},
{
"path": "src/ESP32Console/ConsoleCommand.h",
"chars": 1428,
"preview": "#pragma once\n\n#include \"./ConsoleCommandBase.h\"\n\nnamespace ESP32Console\n{\n\n /**\n * @brief A class for registering"
},
{
"path": "src/ESP32Console/ConsoleCommandBase.h",
"chars": 564,
"preview": "#pragma once\n\n#include \"esp_console.h\"\n\nnamespace ESP32Console {\n class ConsoleCommandBase\n {\n protected:\n "
},
{
"path": "src/ESP32Console/ConsoleCommandD.cpp",
"chars": 857,
"preview": "#include \"./ConsoleCommandD.h\"\n#include \"Arduino.h\"\n\nconst static char *TAG = \"ConsoleCommandD\";\n\nnamespace ESP32Console"
},
{
"path": "src/ESP32Console/ConsoleCommandD.h",
"chars": 1703,
"preview": "#pragma once\n\n#include \"./ConsoleCommand.h\"\n#include \"esp_console.h\"\n#include <string>\n#include <functional>\n#include <u"
},
{
"path": "src/ESP32Console/Helpers/InputParser.cpp",
"chars": 1832,
"preview": "#include \"./InputParser.h\"\n\n#include <Arduino.h>\n\nnamespace ESP32Console\n{\n String interpolateLine(const char *in_)\n "
},
{
"path": "src/ESP32Console/Helpers/InputParser.h",
"chars": 325,
"preview": "#pragma once\n#include <Arduino.h>\n\nnamespace ESP32Console\n{\n /**\n * @brief Interpolate the given line using envir"
},
{
"path": "src/ESP32Console/Helpers/PWDHelpers.cpp",
"chars": 1372,
"preview": "#include \"ESP32Console/Helpers/PWDHelpers.h\"\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <Arduino.h>\n\nnamespace ESP"
},
{
"path": "src/ESP32Console/Helpers/PWDHelpers.h",
"chars": 429,
"preview": "#pragma once\n\nnamespace ESP32Console\n{\n\n /**\n * @brief Returns the current console process working dir\n *\n "
},
{
"path": "src/ESP32Console/OptionsConsoleCommand.cpp",
"chars": 1415,
"preview": "#include \"./OptionsConsoleCommand.h\"\n#include \"Arduino.h\"\n\nconst static char *TAG = \"ArgParseCommand\";\n\nnamespace ESP32C"
},
{
"path": "src/ESP32Console/OptionsConsoleCommand.h",
"chars": 2458,
"preview": "#pragma once\n\n#include \"./ConsoleCommandBase.h\"\n\n#include \"esp_console.h\"\n\n//This define is important, otherwise we get "
},
{
"path": "src/ESP32Console.h",
"chars": 309,
"preview": "#pragma once\n\n#if !defined(ESP32)\n#error This library depends on ESP-IDF and only works on ESP32!\n#endif\n\n#define ESP32C"
},
{
"path": "src/cxxopts/cxxopts.hpp",
"chars": 59006,
"preview": "/*\n\nCopyright (c) 2014, 2015, 2016, 2017 Jarryd Beck\n\nPermission is hereby granted, free of charge, to any person obtain"
},
{
"path": "src/kilo/CREDITS",
"chars": 49,
"preview": "Kilo editor from:\nhttps://github.com/antirez/kilo"
},
{
"path": "src/kilo/kilo.cpp",
"chars": 51340,
"preview": "/* Kilo -- A very simple editor in less than 1-kilo lines of code (as counted\n * by \"cloc\"). Does not depend on "
},
{
"path": "src/kilo/kilo.h",
"chars": 436,
"preview": "#pragma once\n\n#include \"ESP32Console/Helpers/PWDHelpers.h\"\n#include <exception>\n#include \"linenoise/linenoise.h\"\n\nnamesp"
}
]
About this extraction
This page contains the full source code of the jbtronics/ESP32Console GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 40 files (187.1 KB), approximately 47.6k tokens, and a symbol index with 311 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.