https://github.com/jibstack64/field
A subcommand-based argument parsing library.
https://github.com/jibstack64/field
args argument-parsing cpp
Last synced: about 1 month ago
JSON representation
A subcommand-based argument parsing library.
- Host: GitHub
- URL: https://github.com/jibstack64/field
- Owner: jibstack64
- License: mit
- Created: 2022-12-11T02:02:27.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2022-12-12T16:09:35.000Z (over 3 years ago)
- Last Synced: 2025-04-08T16:31:19.410Z (12 months ago)
- Topics: args, argument-parsing, cpp
- Language: C++
- Homepage:
- Size: 34.2 KB
- Stars: 4
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# field



*A subcommand-based argument parsing library for C++.*
### Information
`field` is *not* a replacement for [argh!](https://github.com/adishavit/argh) and similar libraries, it is for use in specific types of programs, as described below.
**It is not for multi-argument parsing**. `field` is for programs where, instead of having traditional GNU-style `--arg` arguments, you have so-called 'command arguments', that act as individual parts of the program.
> If you insist on using `field` for multi-argument parsing, you may set `parser.disableLock` to true. This will allow multiple subcommands to be used, instead of locking to one.
For example, say you are developing a package manager that is solely controlled using command-line arguments. When installing a package, you want the command-line syntax to look something like this:
`package-manager install `
Well? Perfect! This is exactly what `field` is for, segmenting your program into individual chunks that play their own part in the application.
*How does it work?*
The basic idea is that when an argument is passed, it has a matching function that is called alongside it - a `field::context` object and an `std::vector` are passed to the function, allowing the function to access the flags passed, and the values passed to it through the arguments.
*What about flags?*
They are completely supported. As long as they are passed before the subcommand, or after all of the subcommand's positional arguments.
### Basic syntax
The syntax in `field` is relatively basic, and is designed to be as sleek as possible.
A basic application would look something like this:
```cpp
#include
#include
#include ".../field.hpp"
void say(field::context& ctx, std::vector values) {
// as we did not specify a limit to the number of positional arguments,
// values will include all positional argument values after 'say'
for (const auto& c : values) {
std::cout << c << std::endl;
}
}
int main(int argc, char ** argv) {
// create the argument parser
field::parser parser;
// add our argument
// we pass our 'say' function
// this will be ran when the argument is passed
field::arg sayArg = parser.add("say", say);
// now we parse
parser.parse(argc, argv);
// or alternatively drop the argc
// parser.parse(argv);
return 0;
}
```
Lets run it:
`./out.o say "hello world!" "and FOSS developers!!!"`
Output:
```
hello world!
and FOSS developers!!!
```
---
### Context
Context (`field::context`) is passed to every function bound to an subcommand/flag if it is passed. It contains a list of flags passed, and any values passed outside of the range of positional arguments.
---
### Subcommands
Subcommands can be added with the `parser.add(...)` function. You pass a name, and optionally a function and `takes` (the number of positional arguments the subcommand receives).
For instance, if I wanted a basic text-mirroring program:
```cpp
#include
#include
#include ".../field.hpp"
// this is ran when "mirror" is passed
void mirror(field::context& _, std::vector text) {
for (const auto& c : text) {
std::cout << c << std::endl;
}
}
int main(int argc, char ** argv) {
field::parser parser;
// we now add the subcommand with its matching function
// number of pos. arguments
parser.add("mirror", mirror, 3);
parser.parse();
return 0;
}
```
Now, when we run the program, it takes a maximum of 3 positional arguments:
`./out.o mirror hey! im very cool`
Output:
```
hey!
im
very
```
As you can see, `cool` was cut off due to the `takes` (number of taken values) being `3`.
---
### Flags
Flags can be named in any way you would prefer, however I recommend using the GNU-style `-` and `--` prefixes to distinguish them from subcommands.
Flags are very similar to arguments, lets try making a simple hello world program:
```cpp
#include
#include ".../field.hpp"
void helloWorld(field::context& _) {
std::cout << "hello world!" << std::endl;
}
int main(int argc, char ** argv) {
field::parser parser;
parser.addFlag("--hello-world", helloWorld);
parser.parse();
return 0;
}
```
And when we run it:
`./a.out --hello-world`
Output:
```
hello world!
```
---
### Hate using functions?
If you would rather not pass functions around, and instead have a series of if statements, you can do that too.
Instead of passing a function, only pass a name (and optionally `takes`).
```cpp
#include ".../field.hpp"
int main(int argc, char ** argv) {
field::parser parser;
// no function passed
field::arg* ar = parser.add("no-func", 2);
parser.parse();
if (ar->passed) {
std::cout << "passed values:" << std::endl;
for (const auto& v : ar->values()) {
std::cout << v << std::endl;
}
std::cout << "passed flags:" << std::endl;
for (auto& fl : parser.ctx.passedFlags) {
std::cout << fl->name << std::endl;
}
std::cout << "overflowing values:" << std::endl;
for (auto& of : parser.ctx.overflowValues) {
std::cout << of << std::endl;
}
}
}
```
As you can see, this allows you to access the `passed` boolean of the argument, and manage code based on if statements.
Not only this, you can access the context outside of a function by accessing the `ctx` variable of your `parser`.
It is the equivalent of using the context variable passed to a function.