# argh **Repository Path**: jojo12332/argh ## Basic Information - **Project Name**: argh - **Description**: No description available - **Primary Language**: Unknown - **License**: BSD-3-Clause - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-06-22 - **Last Updated**: 2024-04-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ![logo](assets/argh_logo_small.png) > *Frustration-free command line processing* [![Language](https://img.shields.io/badge/language-C++-blue.svg)](https://isocpp.org/) [![Standard](https://img.shields.io/badge/C%2B%2B-11-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) [![License](https://img.shields.io/badge/license-BSD-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) [![Try it online](https://img.shields.io/badge/try%20it-online-orange.svg)](http://melpon.org/wandbox/permlink/ralxPN49F7cUY2yw) [![Build Status](https://travis-ci.org/adishavit/argh.svg?branch=master)](https://travis-ci.org/adishavit/argh) So many different command line processing libraries out there and none of them just work! Some bring their whole extended family of related and unrelated external dependencies (*yes, I'm looking at you Boost*). Some require quirky syntax and/or very verbose setups that sacrifice simplicity for the generation of a cute usage message and validation. Many come to dominate your `main()` file and yet others do not build on multiple plaforms - for some even their own tests and trivial usage cause crashes on some systems. *Argh!* If you're writing a highly-sophisticated command line tool, then `Boost.Program_options` and its kind might give you many advanced options. However, if you need to get up and running quickly, effectively and with minimal fuss, give the single header-file `argh` a try. ## TL;DR It doesn't get much simpler than this: ```cpp #include #include "argh.h" int main(int, char* argv[]) { argh::parser cmdl(argv); if (cmdl[{ "-v", "--verbose" }]) std::cout << "Verbose, I am.\n"; return EXIT_SUCCESS; } ``` ## Philosophy Contrary to many alternatives, `argh` takes a minimalist *laissez-faire* approach, very suitable for fuss-less prototyping with the following rules: The API is: - Minimalistic but expressive: - No getters nor binders - Just the `[]` and `()` operators - Easy iteration (range-`for` too) - You don't pay for what you don't use - Conversion to typed variables happens (via `std::istream >>`) on the user side *after* the parsing phase - No exceptions thrown for failures - Liberal BSD license - Single header file - No non-`std` dependencies `argh` does **not** care about: - How many '`-`' preceded your option - Which flags and options you support - that is your responsibility - Syntax validation: *any* command line is a valid (*not necessarily unique*) combination of positional *parameters*, *flags* and *options* - Automatically producing a usage message ## Tutorial Create parser: ```cpp auto cmdl = argh::parser(argc, argv); ``` In fact, you can even drop `argc`. This will also work: ```cpp argh::parser cmdl(argv); ``` Positional argument access by (integer) index with `[]`: ```cpp cout << "Exe name is: " << cmdl[0] << '\n'; ^^^ assert(cmdl[10000].empty()); // out-of-bound index returns empty string ^^^^^ ``` Boolean flag argument access by (string) name with `[]`: ```cpp cout << "Verbose mode is " << ( cmdl["verbose"] ? "ON" : "OFF" ) << '\n'; ^^^^^^^^^^^ ``` Any dashes are trimmed so are not required. Your flag can have several alternatives, just list them with `[{ "", "", ... }]`: ```cpp cout << "Verbose mode is " << ( cmdl[{ "-v", "--verbose" }] ? "ON" : "OFF" ) << '\n'; ^^^^^^^^^^^^^^^^^^^^^^^ ``` Beyond `bool` and `std::string` access with `[]`, as shown above, we can also access the argument values as an `std::istream`. This is very useful for type conversions. `std::istream` positional argument access by (integer) index with `()`: ```cpp std::string my_app_name; cmdl(0) >> my_app_name; // streaming into a string ^^^ cout << "Exe name is: " << my_app_name << '\n'; ``` We can also check if a particular positional arg was given or not (this is like using `[]` above): ```cpp if (!cmdl(10)) cerr << "Must provide at least 10 arguments!" << '\n'; else if (cmdl(11)) cout << "11th argument is: " << cmdl[11] << '\n'; ``` But we can also set default values for positional arguments. These are passed as the second argument: ```cpp float scale_factor; cmdl(2, 1.0f) >> scale_factor; ^^^^^^^ ``` If the position argument was not given or the streaming conversion failed, the default value will be used. Similarly, parameters can be accessed by name(s) (i.e. by string or list of string literals) with: `( [, ])` or `({ "", "", ... } [, ])`: ```cpp float scale_factor; cmdl("scale", 1.0f) >> scale_factor; // Use 1.0f as default value ^^^^^^^^^^^^^ float threshold; if (!(cmdl({ "-t", "--threshold"}) >> threshold)) // Check for missing param and/or bad (inconvertible) param value cerr << "Must provide a valid threshold value! Got '" << cmdl("threshold").str() << "'" << endl; else ^^^^^^ cout << "Threshold set to: " << threshold << '\n'; ``` As shown above, use `std::istream::str()` to get the param value as a `std:string` or just stream the value into a variable of a suitable type. Standard stream state indicates failure, including when the argument was not given. When using multiple names, the first value found will be returned. Positional arguments can be iterated upon directly using *range-for*: ```cpp cout << "Positional args:\n"; for (auto& pos_arg : cmdl) cout << '\t' << pos_arg << '\n'; ``` Similarly, `cmdl.size()` will return the count of *positional* arguments. Positional arguments, flags *and* parameters are accessible as "ranges": ```cpp cout << "Positional args:\n"; for (auto& pos_arg : cmdl.pos_args()) cout << '\t' << pos_arg << '\n'; cout << "\nFlags:\n"; for (auto& flag : cmdl.flags()) cout << '\t' << flag << '\n'; cout << "\nParameters:\n"; for (auto& param : cmdl.params()) cout << '\t' << param.first << " : " << param.second << '\n'; ``` By default, options are assumed to be boolean flags. When this is not what you want, there are several ways to specify when an option is a parameter with an associated value. Specify **`PREFER_PARAM_FOR_UNREG_OPTION`** mode to interpret *any* `