{"id":13418970,"url":"https://github.com/muellan/clipp","last_synced_at":"2025-05-16T04:02:34.608Z","repository":{"id":37334676,"uuid":"110020935","full_name":"muellan/clipp","owner":"muellan","description":"easy to use, powerful \u0026 expressive command line argument parsing for modern C++ / single header / usage \u0026 doc generation","archived":false,"fork":false,"pushed_at":"2024-05-30T08:13:54.000Z","size":256,"stargazers_count":1240,"open_issues_count":53,"forks_count":154,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-04-08T14:04:00.119Z","etag":null,"topics":["args","argument-parser","argument-parsing","argv","argv-parser","cli","cmdline-parser","command-line","commandline","cpp","cpp11","header-only","man-page","nested-alternatives","option","option-parser","options","options-parsing"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/muellan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-11-08T19:29:29.000Z","updated_at":"2025-04-01T09:21:42.000Z","dependencies_parsed_at":"2023-01-19T10:59:18.514Z","dependency_job_id":"71ddfd9c-65cd-4975-9b48-28a617e779e4","html_url":"https://github.com/muellan/clipp","commit_stats":{"total_commits":119,"total_committers":3,"mean_commits":"39.666666666666664","dds":"0.050420168067226934","last_synced_commit":"2c32b2f1f7cc530b1ec1f62c92f698643bb368db"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muellan%2Fclipp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muellan%2Fclipp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muellan%2Fclipp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muellan%2Fclipp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/muellan","download_url":"https://codeload.github.com/muellan/clipp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254464891,"owners_count":22075570,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["args","argument-parser","argument-parsing","argv","argv-parser","cli","cmdline-parser","command-line","commandline","cpp","cpp11","header-only","man-page","nested-alternatives","option","option-parser","options","options-parsing"],"created_at":"2024-07-30T22:01:09.550Z","updated_at":"2025-05-16T04:02:34.012Z","avatar_url":"https://github.com/muellan.png","language":"C++","funding_links":[],"categories":["TODO scan for Android support in followings","CLI","C++","Argument Parsers","cli"],"sub_categories":[],"readme":"clipp - command line interfaces for modern C++\n===========================================================\n\n[![Linux build status](https://travis-ci.org/muellan/clipp.svg?branch=master)](https://travis-ci.org/muellan/clipp) [![MSVC build status](https://ci.appveyor.com/api/projects/status/ci29ngpfks980i7g?svg=true)](https://ci.appveyor.com/project/muellan/clipp)\n\nEasy to use, powerful and expressive command line argument handling for C++11/14/17 contained in a **single header file**. \n\n- options, options+value(s), positional values, positional commands, nested alternatives, decision trees, joinable flags, custom value filters, ...\n- documentation generation (usage lines, man pages); error handling \n- lots of examples; large set of tests\n\n- ### [Quick Reference Table](#quick-reference)\n- ### [Overview (short examples)](#overview)\n- ### [Detailed Examples](#examples)\n- #### [Why yet another library for parsing command line arguments?](#motivation) / [Design goals](#design-goals)\n- #### [Requirements / Compilers](#requirements)\n\n\n\n## Quick Intro\n\n### Simple Use Case — Simple Setup!\nConsider this command line interface:\n```man\nSYNOPSIS\n    convert \u003cinput file\u003e [-r] [-o \u003coutput format\u003e] [-utf16]\n\nOPTIONS\n    -r, --recursive  convert files recursively\n    -utf16           use UTF-16 encoding\n```\nHere is the code that defines the positional value ```input file``` and the three options ```-r```, ```-o``` and ```-utf16```. If parsing fails, the above default man page-like snippet will be printed to stdout.\n```cpp\n#include \u003ciostream\u003e\n#include \"clipp.h\"\nusing namespace clipp; using std::cout; using std::string;\n\nint main(int argc, char* argv[]) { \n    bool rec = false, utf16 = false;\n    string infile = \"\", fmt = \"csv\";\n\n    auto cli = (\n        value(\"input file\", infile),\n        option(\"-r\", \"--recursive\").set(rec).doc(\"convert files recursively\"),\n        option(\"-o\") \u0026 value(\"output format\", fmt),\n        option(\"-utf16\").set(utf16).doc(\"use UTF-16 encoding\")\n    );\n\n    if(!parse(argc, argv, cli)) cout \u003c\u003c make_man_page(cli, argv[0]);\n    // ...\n}\n```\n\n\n\n### A More Complex Example:\n```man\nSYNOPSIS\n    finder make \u003cwordfile\u003e -dict \u003cdictionary\u003e [--progress] [-v]\n    finder find \u003cinfile\u003e... -dict \u003cdictionary\u003e [-o \u003coutfile\u003e] [-split|-nosplit] [-v] \n    finder help [-v]\n\nOPTIONS\n    --progress, -p           show progress                       \n    -o, --output \u003coutfile\u003e   write to file instead of stdout\n    -split, -nosplit         (do not) split output\n    -v, --version            show version\n```\nThis CLI has three alternative commands (```make```, ```find```, ```help```), some positional value-arguments (```\u003cwordfile\u003e```, ```\u003cinfile\u003e```) of which one is repeatable, a required flag with value-argument (```-dict \u003cdictionary\u003e```), an option with value-argument (```-o \u003coutfile\u003e```), one option with two alternatives (```-split```, ```-nosplit```) and two conventional options (```-v```, ```--progress```).\n\nHere is the code that defines the interface, generates the man page snippet above *and* handles the parsing result:\n```cpp\nusing namespace clipp; using std::cout; using std::string;\n\n//variables storing the parsing result; initialized with their default values\nenum class mode {make, find, help};\nmode selected = mode::help;\nstd::vector\u003cstring\u003e input;\nstring dict, out;\nbool split = false, progr = false;\n\nauto dictionary = required(\"-dict\") \u0026 value(\"dictionary\", dict);\n\nauto makeMode = (\n    command(\"make\").set(selected,mode::make),\n    values(\"wordfile\", input),\n    dictionary,\n    option(\"--progress\", \"-p\").set(progr) % \"show progress\" );\n\nauto findMode = (\n    command(\"find\").set(selected,mode::find),\n    values(\"infile\", input),\n    dictionary,\n    (option(\"-o\", \"--output\") \u0026 value(\"outfile\", out)) % \"write to file instead of stdout\",\n    ( option(\"-split\"  ).set(split,true) |\n      option(\"-nosplit\").set(split,false) ) % \"(do not) split output\" );\n\nauto cli = (\n    (makeMode | findMode | command(\"help\").set(selected,mode::help) ),\n    option(\"-v\", \"--version\").call([]{cout \u003c\u003c \"version 1.0\\n\\n\";}).doc(\"show version\")  );\n\nif(parse(argc, argv, cli)) {\n    switch(selected) {\n        case mode::make: /* ... */ break;\n        case mode::find: /* ... */ break;\n        case mode::help: cout \u003c\u003c make_man_page(cli, \"finder\"); break;\n    }\n} else {\n     cout \u003c\u003c usage_lines(cli, \"finder\") \u003c\u003c '\\n';\n}\n```\n\n\n\n\n## Quick Reference\n\nBelow are a few examples that should give you an idea for how clipp works.\nConsider this basic setup with a few variables that we want to set using\ncommand line arguments:\n```cpp\nint main(int argc, char* argv[]) { \n    using namespace clipp;\n\n    // define some variables\n    bool a = false, b = false;\n    int n = 0, k = 0;\n    double x = 0.0, y = 0.0;\n    std::vector\u003cint\u003e ids;\n\n    auto cli = ( /* CODE DEFINING COMMAND LINE INTERFACE GOES HERE */ );\n\n    parse(argc, argv, cli);    //excludes argv[0]\n\n    std::cout \u003c\u003c usage_lines(cli, \"exe\") \u003c\u003c '\\n';\n}\n```\n\n| Interface (`usage_lines`)  | Code (content of `cli` parentheses )\n| -------------------------- | ------------------------------------\n| ` exe [-a] `               | ` option(\"-a\", \"--all\").set(a)`\n| ` exe [--all] `            | ` option(\"--all\", \"-a\", \"--ALL\").set(a)`\n| ` exe [-a] [-b] `          | ` option(\"-a\").set(a), option(\"-b\").set(b)`\n| ` exe -a `                 | ` required(\"-a\").set(a)`\n| ` exe [-a] -b `            | ` option(\"-a\").set(a), required(\"-b\").set(b)`\n| ` exe [-n \u003ctimes\u003e] `       | ` option(\"-n\", \"--iter\") \u0026 value(\"times\", n) `\n| ` exe [-n [\u003ctimes\u003e]] `     | ` option(\"-n\", \"--iter\") \u0026 opt_value(\"times\", n) `\n| ` exe -n \u003ctimes\u003e  `        | ` required(\"-n\", \"--iter\") \u0026 value(\"times\", n) `\n| ` exe -n [\u003ctimes\u003e] `       | ` required(\"-n\", \"--iter\") \u0026 opt_value(\"times\", n) `\n| ` exe [-c \u003cx\u003e \u003cy\u003e]`        | ` option(\"-c\") \u0026 value(\"x\", x) \u0026 value(\"y\", y)`\n| ` exe -c \u003cx\u003e \u003cy\u003e `         | ` required(\"-c\") \u0026 value(\"x\", x) \u0026 value(\"y\", y)`\n| ` exe -c \u003cx\u003e [\u003cy\u003e] `       | ` required(\"-c\") \u0026 value(\"x\", x) \u0026 opt_value(\"y\", y)`\n| ` exe [-l \u003clines\u003e...] `    | ` option(\"-l\") \u0026 values(\"lines\", ids) `\n| ` exe [-l [\u003clines\u003e...]] `  | ` option(\"-l\") \u0026 opt_values(\"lines\", ids) `\n| ` exe [-l \u003clines\u003e]... `    | ` repeatable( option(\"-l\") \u0026 value(\"lines\", ids) ) `\n| ` exe -l \u003clines\u003e... `      | ` required(\"-l\") \u0026 values(\"lines\", ids) `\n| ` exe -l [\u003clines\u003e...] `    | ` required(\"-l\") \u0026 opt_values(\"lines\", ids) `\n| ` exe (-l \u003clines\u003e)... `    | ` repeatable( required(\"-l\") \u0026 value(\"lines\", ids) ) `\n| ` exe fetch [-a] `         | ` command(\"fetch\").set(k,1), option(\"-a\").set(a) `\n| ` exe init \\| fetch [-a] ` | ` command(\"init\").set(k,0) \\| (command(\"fetch\").set(k,1), option(\"-a\").set(a)) `\n| ` exe [-a\\|-b]  `          | ` option(\"-a\").set(a) \\| option(\"-b\").set(b) `\n| ` exe [-m a\\|b] `          | ` option(\"-m\") \u0026 (required(\"a\").set(a) \\| required(\"b\").set(b)) `\n\n\n\n\n## Overview\n\nSee the [examples](#examples) section for detailed explanations of each topic.\n\nNamespace qualifiers are omitted from all examples for better readability. All entities are defined in ```namespace clipp```.\n\n\n#### Basic Setup\n```cpp\nint main(int argc, char* argv[]) { \n    using namespace clipp;\n\n    auto cli = ( /* CODE DEFINING COMMAND LINE INTERFACE GOES HERE */ );\n    parse(argc, argv, cli);    //excludes argv[0]\n\n    //if you want to include argv[0]\n    //parse(argv, argv+argc, cli);\n}\n```\n\nThere are two kinds of building blocks for command line interfaces: parameters and groups. Convieniently named factory functions produce parameters or groups with the desired settings applied.\n#### Parameters ([flag strings](#flag-strings), [commands](#commands), [positional values](#required-positional-values), [required flags](#required-flags), [repeatable parameters](#repeatable-parameters))\n```cpp\nbool a = false, f = false;\nstring s; vector\u003cstring\u003e vs;\nauto cli = (                             // matches  required  positional  repeatable\n    command(\"push\"),                     // exactly      yes       yes         no\n    required(\"-f\", \"--file\").set(f),     // exactly      yes       no          no\n    required(\"-a\", \"--all\", \"-A\").set(a),  // exactly      no        no          no\n                                                  \n    value(\"file\", s),                    // any arg      yes       yes         no\n    values(\"file\", vs),                  // any arg      yes       yes         yes\n    opt_value(\"file\", s),                // any arg      no        yes         no\n    opt_values(\"file\", vs),              // any arg      no        yes         yes\n    \n    //\"catch all\" parameter - useful for error handling\n    any_other(vs),                       // any arg      no        no          yes\n    //catches arguments that fulfill a predicate and aren't matched by other parameters\n    any(predicate, vs)                   // predicate    no        no          yes\n);\n```\nThe functions above are convenience factories:\n```cpp\nbool f = true; string s;\nauto v1 = values(\"file\", s);\n// is equivalent to:\nauto v2 = parameter{match::nonempty}.label(\"file\").blocking(true).repeatable(true).set(s);\n\nauto r1 = required(\"-f\", \"--file\").set(f);\n// is equivalent to:\nauto r2 = parameter{\"-f\", \"--file\"}.required(true).set(f);\n```\n - a required parameter has to match at least one command line argument \n - a repeatable parameter can match any number of arguments\n - non-positional (=non-blocking) parameters can match arguments in any order\n - a positional (blocking) parameter defines a \"stop point\", i.e., until it matches all parameters following it are not allowed to match; once it matched, all parameters preceding it (wihtin the current group) will become unreachable \n\n##### [Flags + Values](#options-with-values)\nIf you want parameters to be matched in sequence, you can tie them together using either ```operator \u0026``` or the grouping function ```in_sequence```:\n\n```cpp\nint n = 1; string s; vector\u003cint\u003e ls;\nauto cli = (\n    //option with required value\n    option(\"-n\", \"--repeat\") \u0026 value(\"times\", n),\n\n    //required flag with optional value\n    required(\"--file\") \u0026 opt_value(\"name\", s),\n    \n    //option with exactly two values\n    option(\"-p\", \"--pos\") \u0026 value(\"x\") \u0026 value(\"y\"),\n\n    //same as before                   v            v\n    in_sequence( option(\"-p\", \"--pos\") , value(\"x\") , value(\"y\") ),\n    \n    //option with at least one value (and optionally more)\n    option(\"-l\") \u0026 values(\"lines\", ls)\n);\n```\n\n##### [Filtering Value Parameters](#value-filters)\nValue parameters use a filter function to test if they are allowed to match an argument string. The default filter ```match::nonempty``` that is used by ```value```, ```values```, ```opt_value``` and ```opt_values``` will match any non-empty argument string. \nYou can either supply other filter functions/function objects as first argument of ```value```, ```values```, etc. or use one of these built-in shorthand factory functions covering the most common cases:\n```cpp\nstring name; double r = 0.0; int n = 0;\nauto cli = (\n    value(\"user\", name),   // matches any non-empty string\n    word(\"user\", name),    // matches any non-empty alphanumeric string\n    number(\"ratio\", r),    // matches string representations of numbers\n    integer(\"times\", n)    // matches string representations of integers\n);\n```\nAnalogous to ```value```, ```opt_value```, etc. there are also functions for ```words```, ```opt_word```, etc.\n\n##### Value Parameters With [Custom Filters](#custom-value-filters)\n```cpp\nauto is_char = [](const string\u0026 arg) { return arg.size() == 1 \u0026\u0026 std::isalpha(arg[0]); };\n\nchar c = ' ';\n                             // matches       required  positional  repeatable\nvalue(is_char, \"c\", c);      // one character  yes       yes         no\n```\n\n\n#### Groups\n - [group](#grouping) mutually compatible parameters with parentheses and commas:\n   ```cpp\n   auto cli = ( option(\"-a\"), option(\"-b\"), option(\"-c\") );\n   ```\n\n - group mutually exclusive parameters as [alternatives](#alternatives) using ```operator |``` or ```one_of```:\n   ```cpp\n   auto cli1 = ( value(\"input_file\") | command(\"list\") | command(\"flush\") );\n\n   auto cli2 = one_of( value(\"input_file\") , command(\"list\") , command(\"flush\") );\n   ```\n\n - group parameters so that they must be matched in sequence using ```operator \u0026``` or ```in_sequence```:\n   ```cpp\n   double x = 0, y = 0, z = 0;\n   auto cli1 = ( option(\"-pos\") \u0026 value(\"X\",x) \u0026 value(\"Y\",y) \u0026 value(\"Z\",z) );\n   \n   auto cli2 = in_sequence( option(\"-pos\") , value(\"X\",x) , value(\"Y\",y) , value(\"Z\",z) );\n   ```\n   Note that surrounding groups are not affected by this, so that ```-a``` and ```-b``` can be matched in any order while ```-b``` and the value ```X``` must match in sequence:\n   ```cpp\n   bool a = false, b = false; int x = 0;\n   auto cli = (  option(\"-a\").set(a),  option(\"-b\").set(b) \u0026 value(\"X\",x)  );\n   ```\n\n - groups can be nested and combined to form arbitrarily complex interfaces (see [here](#nested-alternatives) and [here](#complex-nestings)):\n   ```cpp\n   auto cli = ( command(\"push\") | ( command(\"pull\"), option(\"-f\", \"--force\") )  );\n   ```\n\n - groups can be repeatable as well:\n   ```cpp\n   auto cli1 = repeatable( command(\"flip\") | command(\"flop\") );\n   ```\n\n - force common prefixes on a group of flags:\n   ```cpp\n   int x = 0;\n   auto cli1 = with_prefix(\"-\", option(\"a\"), option(\"b\") \u0026 value(\"x\",x), ... );\n                             // =\u003e     -a           -b     ^unaffected^\n\n   auto cli2 = with_prefix_short_long(\"-\", \"--\", option(\"a\", \"all\"), option(\"b\"), ... );\n                                                  // =\u003e -a  --all           -b\n   ```\n\n - force common suffixes on a group of flags:\n   ```cpp\n   int x = 0;\n   auto cli1 = with_suffix(\"=\", option(\"a\") \u0026 value(\"x\",x), ... );\n                             // =\u003e      a=    ^unaffected^\n\n   auto cli2 = with_suffix_short_long(\":\", \":=\", option(\"a\", \"all\"), option(\"b\"), ... );\n                                                  // =\u003e  a:   all:=          b:\n   ```\n\n - make a group of flags [joinable](#joinable-flags):\n   ```cpp\n   auto cli1 = joinable( option(\"-a\"), option(\"-b\"));  //will match \"-a\", \"-b\", \"-ab\", \"-ba\"\n\n   //works also with arbitrary common prefixes:\n   auto cli2 = joinable( option(\"--xA0\"), option(\"--xB1\"));  //will also match \"--xA0B1\" or \"--xB1A0\"\n   ```\n\n\n#### Interfacing With Your Code\nThe easiest way to connect the command line interface to the rest of your code is to bind object values or function (object) calls to parameters (see also [here](#actions)):  \n```cpp\nbool b = false; int i = 5; int m = 0; string x; ifstream fs;\nauto cli = ( \n    option(\"-b\").set(b),                      // \"-b\" detected -\u003e set b to true\n    option(\"-m\").set(m,2),                    // \"-m\" detected -\u003e set m to 2\n    option(\"-x\") \u0026 value(\"X\", x),             // set x's value from arg string \n    option(\"-i\") \u0026 opt_value(\"i\", i),         // set i's value from arg string  \n    option(\"-v\").call( []{ cout \u003c\u003c \"v\"; } ),  // call function (object) / lambda\n    option(\"-v\")( []{ cout \u003c\u003c \"v\"; } ),       // same as previous line\n    option(\"-f\") \u0026 value(\"file\").call([\u0026](string f){ fs.open(f); })\n);\n```\n\nIn production code one would probably use a settings class:\n```cpp\nstruct settings { bool x = false; /* ... */ };\n\nsettings cmdline_settings(int argc, char* argv[]) {\n    settings s;\n    auto cli = ( option(\"-x\").set(s.x), /* ... */ );\n    parse(argc, argv, cli);\n    return s;\n}\n```\nNote that the target must either be:\n - a fundamental type (```int, long int, float, double, ...```)\n - a type that is convertible from ```const char*```\n - a callable entity: function, function object / lambda\n   that either has an empty parameter list or exactly one parameter that is\n   convertible from ```const char*```\n\n\n#### Generating Documentation ([see also here](#documentation-generation))\nDocstrings for groups and for parameters can either be set with the member function ```doc``` or with ```operator %```:\n```cpp\nauto cli = (\n    (   option(\"x\").set(x).doc(\"sets X\"),\n        option(\"y\").set(y) % \"sets Y\"         \n    ),\n    \"documented group 1:\" % (  \n        option(\"-g\").set(g).doc(\"activates G\"),   \n        option(\"-h\").set(h) % \"activates H\"   \n    ),\n    (   option(\"-i\").set(i) % \"activates I\",   \n        option(\"-j\").set(j) % \"activates J\" \n    ).doc(\"documented group 2:\")\n);\n```\n\nUsage Lines:\n```cpp\ncout \u003c\u003c usage_lines(cli, \"progname\") \u003c\u003c '\\n';\n\n//with formatting options\nauto fmt = doc_formatting{}\n           .first_column(3)\n           .last_column(79);\ncout \u003c\u003c usage_lines(cli, \"progname\", fmt) \u003c\u003c '\\n';\n```\n\nDetailed Documentation:\n```cpp\ncout \u003c\u003c documentation(cli) \u003c\u003c '\\n';\n\n//with formatting options\nauto fmt = doc_formatting{}\n           .first_column(7)\n           .doc_column(15)\n           .last_column(99);\ncout \u003c\u003c documentation(cli, fmt) \u003c\u003c '\\n';\n```\n\nMan Pages:\n```cpp\nauto cli = ( /*CODE DEFINING COMMAND LINE INTERFACE GOES HERE*/ );\ncout \u003c\u003c make_man_page(cli, \"progname\") \u003c\u003c '\\n';\n\n//with formatting options\nauto fmt = doc_formatting{}\n           .first_column(7)\n           .doc_column(15)\n           .last_column(99);\ncout \u003c\u003c make_man_page(cli, \"progname\", fmt) \u003c\u003c '\\n'; \n```\n\n\n#### (Error) Event Handlers ([see here](#error-handling), [and here](#per-parameter-parsing-report))\nEach parameter can have event handler functions attached to it. These are invoked once for each argument that is mapped to the parameter (or once per missing event):\n```cpp\nstring file = \"default.txt\";\nauto param = required(\"-nof\").set(file,\"\") | \n             required(\"-f\") \u0026 value(\"file\", file) \n                              // on 2nd, 3rd, 4th,... match (would be an error in this case)\n                              .if_repeated( [] { /* ... */ } )    \n                              // if required value-param was missing\n                              .if_missing( [] { /* ... */ } )    \n                              // if unreachable, e.g. no flag \"-f\" before filename\n                              .if_blocked( [] { /* ... */ } )    \n                              // if match is in conflict with other alternative \"-nof\"\n                              .if_conflicted( [] { /* ... */ } );   \n```\nThe handler functions can also take an int, which is set to the argument index at which the event occurred first:\n```cpp\nstring file = \"default.txt\";\nauto param = required(\"-nof\").set(file,\"\") | \n             required(\"-f\") \u0026 value(\"file\", file) \n                              .if_repeated  ( [] (int argIdx) { /* ... */ } )\n                              .if_missing   ( [] (int argIdx) { /* ... */ } )\n                              .if_blocked   ( [] (int argIdx) { /* ... */ } )\n                              .if_conflicted( [] (int argIdx) { /* ... */ } );\n```\n\n\n#### Special Cases\nIf we give ```-f -b``` or ```-b -f -a``` as command line arguments for the following CLI, an error will be reported, since the value after ```-f``` is not optional: \n```cpp\nauto cli = (  option(\"-a\"),  option(\"-f\") \u0026 value(\"filename\"),  option(\"-b\")  );\n```\nThis behavior is fine for most use cases. \nBut what if we want our program to take any string as a filename, because our filenames might also collide with flag names? We can make the value parameter [greedy](#greedy-parameters) with ```operator !```. This way, the next string after ```-f``` will always be matched with highest priority as soon as ```-f``` was given:\n```cpp\nauto cli = (  option(\"-a\"),  option(\"-f\") \u0026 !value(\"filename\"),   option(\"-b\")  );\n                                        //  ^~~~~~ \n```\nBe **very careful** with greedy parameters! \n\n\n\n#### Parsing Result Analysis\n```cpp\nauto cli = ( /* your interface here */ );\nauto res = parse(argc, argv, cli);\n\nif(res.any_error()) { /* ... */ }\n\n//aggregated errors\nif(res.unmapped_args_count()) { /* ... */ }\nif(res.any_bad_repeat()) { /* ... */ }\nif(res.any_blocked())    { /* ... */ }\nif(res.any_conflict())   { /* ... */ }\n\nfor(const auto\u0026 m : res.missing()) { \n    cout \u003c\u003c \"missing \" \u003c\u003c m.param() \u003c\u003c \" after index \" \u003c\u003c m.after_index() \u003c\u003c '\\n';\n}\n\n//per-argument mapping\nfor(const auto\u0026 m : res) {\n    cout \u003c\u003c m.index() \u003c\u003c \": \" \u003c\u003c m.arg() \u003c\u003c \" -\u003e \" \u003c\u003c m.param();\n    cout \u003c\u003c \" repeat #\" \u003c\u003c m.repeat();\n    if(m.blocked()) cout \u003c\u003c \" blocked\";\n    if(m.conflict()) cout \u003c\u003c \" conflict\";\n    cout \u003c\u003c '\\n';\n}\n```\n\n#### Writing Your Own Convenience Factories\nSometimes it can make your CLI code more expressive and increase maintainability, if you create your own factory functions for making parameters:\n```cpp\n//value that can only connect to one object with automatic default value documentation\ntemplate\u003cclass Target\u003e\nclipp::parameter\ndocumented_value(const std::string\u0026 name, Target\u0026 tgt, const std::string\u0026 docstr) {\n    using std::to_string;\n    return clipp::value(name,tgt).doc(docstr + \"(default: \" + to_string(tgt) + \")\");\n}\n```\n```cpp\n//value that only matches strings without prefix '-'\ntemplate\u003cclass Target, class... Targets\u003e\nclipp::parameter\nnodash_value(std::string label, Target\u0026\u0026 tgt, Targets\u0026\u0026... tgts) {\n    return clipp::value(clipp::match::prefix_not{\"-\"}, std::move(label), \n               std::forward\u003cTarget\u003e(tgt), std::forward\u003cTargets\u003e(tgts)...);\n}\n```\n\n\n\n\n## Examples\n\nNote that namespace qualifiers are omitted from all examples for better readability. \nThe repository folder \"examples\" contains code for most of the following examples.\n\n- [options](#options)\n- [coding styles](#coding-styles)\n- [flag strings](#flag-strings)\n- [groups](#grouping)\n- [positional values](#required-positional-values)\n- [options with values](#options-with-values)\n- [options with multiple values](#options-with-multiple-values)\n- [required flags](#required-flags)\n- [repeatable parameters](#repeatable-parameters)\n- [actions](#actions)\n- [joinable flags](#joinable-flags)\n- [alternatives](#alternatives)\n- [commands](#commands)\n- [nested alternatives](#nested-alternatives)\n- [complex nestings](#complex-nestings)\n- [example from docopt](#an-example-from-docopt)\n- [value filters](#value-filters)\n- [greedy parameters](#greedy-parameters)\n- [generalized joinable parameters](#generalized-joinable-parameters)\n- [custom value filters](#custom-value-filters)\n- [sanity checks](#sanity-checks)\n- [basic error handling](#basic-error-handling)\n- [parsing](#parsing)\n- [documentation generation](#documentation-generation)\n- [documentation filtering](#documentation-filtering)\n\n\n\n### Options\n```man\nSYNOPSIS\n       switch [-a] [-b] [-c] [--hi]\n\nOPTIONS\n       -a          activates a\n       -b          activates b\n       -c, --noc   deactivates c\n       --hi        says hi\n```\n\n```cpp\nbool a = false, b = false, c = true; //target variables\n\nauto cli = ( \n    option(\"-a\").set(a)                  % \"activates a\",\n    option(\"-b\").set(b)                  % \"activates b\",\n    option(\"-c\", \"--noc\").set(c,false)   % \"deactivates c\",\n    option(\"--hi\")([]{cout \u003c\u003c \"hi!\\n\";}) % \"says hi\");\n\nif(parse(argc, argv, cli)) \n    cout \u003c\u003c \"a=\" \u003c\u003c a \u003c\u003c \"\\nb=\" \u003c\u003c b \u003c\u003c \"\\nc=\" \u003c\u003c c \u003c\u003c '\\n';\nelse \n    cout \u003c\u003c make_man_page(cli, \"switch\");\n```\nThis will set ```a``` to true, if ```-a``` is found, ```b``` to true, if ```-b``` is found, ```c``` to false, if ```-c``` or ```--noc``` are found and prints \"hi\" if ```--hi``` is found in ```argv```. In case of parsing errors a man page will be printed.\n\n\n\n### Coding Styles\nIf you like it more verbose use ```set``` to set variables, ```call``` to call functions and ```doc``` for docstrings. The sequence of member function calls doesn't matter. \n```cpp\nauto cli = ( \n    option(\"-b\").set(b).doc(\"activates b\"),\n    option(\"-c\", \"--noc\").set(c,false).doc(\"deactivates c\"),\n    option(\"--hi\").call([]{cout \u003c\u003c \"hi!\\n\";}).doc(\"says hi\") );\n```\n\n#### You can also use ```operator \u003e\u003e``` and ```operator \u003c\u003c``` to define actions\n```cpp\nauto cli = ( \n    option(\"-b\")          % \"activates b\"   \u003e\u003e b,             \n    option(\"-c\", \"--noc\") % \"deactivates c\" \u003e\u003e set(c,false),\n    option(\"--hi\")        % \"says hi\"       \u003e\u003e []{cout \u003c\u003c \"hi!\\n\";} );\n```\n\n```cpp\nauto cli = ( \n    option(\"-b\")          % \"activates b\"   \u003e\u003e b,             \n    option(\"-c\", \"--noc\") % \"deactivates c\" \u003e\u003e set(c,false),\n    option(\"--hi\")        % \"says hi\"       \u003e\u003e []{cout \u003c\u003c \"hi!\\n\";} );\n```\n```cpp\nauto cli = ( \n    b                    \u003c\u003c option(\"-b\")          % \"activates b\",\n    set(c,false)         \u003c\u003c option(\"-c\", \"--noc\") % \"deactivates c\",\n    []{cout \u003c\u003c \"hi!\\n\";} \u003c\u003c option(\"--hi\")        % \"says hi\" );\n\n```\n```cpp\nauto cli = ( \n    \"activates b\"   % option(\"-b\")          \u003e\u003e b,\n    \"deactivates c\" % option(\"-c\", \"--noc\") \u003e\u003e set(c,false),\n    \"says hi\"       % option(\"--hi\")        \u003e\u003e []{cout \u003c\u003c \"hi!\\n\";} );\n```\nNote that ```%``` has a higher precedence than ```\u003c\u003c``` and ```\u003e\u003e``` which means that you either have to keep the docstrings closer to the command line parameters than the actions or use parentheses.\n\nYou should also have a look at [actions](#actions) for more details.\n\n\n#### Step-by-step configuration of parameters:\n```cpp\nint n = 1;\n\nauto optN = parameter{\"-n\", \"-N\", \"--iterations\", \"--repeats\"}.required(true);\n\nauto valN = parameter{match::any}\n    .label(\"times\")\n    .set(n)\n    .call([](string s) { if(!str::represents_number(s)) throw runtime_error{\"invalid value for 'times'\"}; })\n    .if_missing([]{ cout \u003c\u003c \"value 'times' not found!\\n\"; })\n    .doc(\"number of iterations (default = \" + std::to_string(n) + \")\");\n\nauto cli = group{};\ncli.push_back(std::move(optN));\ncli.push_back(std::move(valN));\n\n// or:\nauto cli = group{std::move(optN), std::move(valN)};\n```\n\n\n\n### Flag Strings\nThere are no limitations regarding formatting and you can have an arbitrary number of flags per command line parameter.\n```cpp\nbool onetwo = false;\nauto myopt = option(\"-1\", \"-2\", \"1\", \"2\", \":1\", \":2\", \"--no1\", \"--no2\").set(onetwo);\n             //     ^----- will match any one of these strings ------^\n``` \n\n#### Same prefix for all flags\n```cpp\nbool a = false, b = false;\n\nauto cli = with_prefix(\"-\", \n    option(\"a\").set(a),     // -a\n    option(\"b\").set(b)      // -b\n);\n```\n\n#### Same prefix for all flags: single vs. multiple character(s)\nSingle-letter flags will get the first prefix, flags with more than one letter will get the second one.\n```cpp\nbool a = false, b = false;\n\nauto cli = with_prefixes_short_long(\"-\", \"--\",\n    option(\"a\", \"all\").set(a),      // -a, --all\n    option(\"b\", \"bottom\").set(b)    // -b, --bottom\n);\n```\n\n#### Same suffix for all flags\n```cpp\nbool a = false, b = false;\n\nauto cli = with_suffix(\":\", \n    option(\"a\").set(a),     // a:\n    option(\"b\").set(b)      // b:\n);\n```\n\n#### Same suffix for all flags: single vs. multiple character(s)\nSingle-letter flags will get the first suffix (empty in this example), flags with more than one letter will get the second one.\n```cpp\nint a = 0, b = 0;\n\nauto cli = with_suffixes_short_long(\"\", \"=\",\n    option(\"a\", \"all\") \u0026 value(\"A\", a),      // -a, --all=\n    option(\"b\", \"bottom\") \u0026 value(\"B\", b)    // -b, --bottom=\n);\n```\n\n#### Make Sure No Flag Occurs As Prefix Of Another Flag\n```cpp\nauto cli = ( /* your command line interface here */ );\nassert(cli.flags_are_prefix_free());\n```\nNote that identical flags will not trigger an error.\n\n\n### Grouping\nGroups can be nested (see [here](#nested-alternatives)) and have their own documentation string. \nThe statement ```auto cli = ( ... );``` creates a group, if there are more than two parameters/groups declared inside the parentheses.\n\n```man\nSYNOPSIS\n        myprogram [x] [y] [a] [b] [-c] [-d] [-e] [-f]\n\nOPTIONS\n        x      sets X\n        y      sets Y\n\n        documented group 1:\n        a      activates A\n        b      activates B\n\n        documented group 2:\n        -c     activates C\n        -d     activates D\n\n        -e, -f activates E or F\n```\n\n```cpp\nbool x = false, y = false, a = false, b = false;\nbool g = false, h = false, e = false, f = false;\n\nauto cli = (\n    (   option(\"x\").set(x) % \"sets X\",  //simple group \n        option(\"y\").set(y) % \"sets Y\"\n    ),\n    (   option(\"a\").set(a) % \"activates A\",   \n        option(\"b\").set(b) % \"activates B\" \n    ) % \"documented group 1:\"           //docstring after group\n    ,\n    \"documented group 2:\" % (           //docstring before group\n        option(\"-g\").set(g) % \"activates G\",   \n        option(\"-h\").set(h) % \"activates H\" \n    ),\n    \"activates E or F\" % (              \n        option(\"-e\").set(e),        //no docstrings inside group\n        option(\"-f\").set(f)\n    )\n);\n\ncout \u003c\u003c make_man_page(cli, \"myprogram\");\n```\n\nThe above example is in fact shorthand for this:\n```cpp\ngroup cli{\n    group{   \n        parameter{\"x\"}.set(x).doc(\"sets X\"),\n        parameter{\"y\"}.set(y).doc(\"sets Y\")\n    },\n    group{\n        parameter{\"a\"}.set(a).doc(\"activates A\"),   \n        parameter{\"b\"}.set(b).doc(\"activates B\")\n    }.doc(\"documented group 1:\")\n    ,\n    group{\n        parameter{\"-g\"}.set(g).doc(\"activates G\"),   \n        parameter{\"-h\"}.set(h).doc(\"activates H\")\n    }.doc(\"documented group 2:\")\n    ,\n    group{\n        parameter{\"-e\"}.set(e), \n        parameter{\"-f\"}.set(f)\n    }.doc(\"activates E or F\")\n};\n\ncout \u003c\u003c make_man_page(cli, \"myprogram\");\n```\n\nYou can of course also fill groups one-by-one:\n```cpp\ngroup cli;\ncli.push_back(option(\"x\").sets(x).doc(\"sets X\"));\n//...\n```\n\n\n\n### Required Positional Values\n```man\nSYNOPSIS\n        myprogram \u003cinfile\u003e \u003coutfile\u003e [-s]\n   \nOPTIONS\n        infile        input filename\n        outfile       output filename\n        -s, --split   split files\n```\n\n```cpp\nstring ifile, ofile;\nbool split = false; \nauto cli = (\n    value(\"infile\", ifile)             % \"input filename\",\n    value(\"outfile\", ofile)            % \"output filename\",\n    option(\"-s\", \"--split\").set(split) % \"split files\" );\n```\n\n#### Alternative Value Mapping Style\n```cpp\nauto cli = (\n     value(\"infile\")         % \"input filename\"  \u003e\u003e ifile,\n     value(\"outfile\")        % \"output filename\" \u003e\u003e ofile,\n     option(\"-s\", \"--split\") % \"split files\"     \u003e\u003e split  );\n```\nSee [here](#coding-styles) for more on possible mapping styles.\n\n\n\n### Options With Values \nParameters can be sequenced using operator ```\u0026``` or the function ```in_sequence```. Sequenced parameters can only be matched one after the other. This mechanism can be used to attach a value parameter to an option. \n\n```man\nSYNOPSIS\n       simplify [-n \u003ccount\u003e] [-r \u003cratio\u003e] [-m [\u003clines=5\u003e]] \n\nOPTIONS\n       -n, --count \u003ccount\u003e     number of iterations\n       -r, --ratio \u003cratio\u003e     compression ratio\n       -m \u003clines=5\u003e            merge lines (default: 5)\n```\n\n```cpp\nint n = 0;\nbool domerge = false;\nlong m = 5;\nauto print_ratio = [](const char* r) { cout \u003c\u003c \"using ratio of \" \u003c\u003c r \u003c\u003c '\\n'; };\n\nauto cli = ( \n    (option(\"-n\", \"--count\") \u0026 value(\"count\", n))           % \"number of iterations\",\n    (option(\"-r\", \"--ratio\") \u0026 value(\"ratio\", print_ratio)) % \"compression ratio\",\n    (option(\"-m\").set(domerge) \u0026 opt_value(\"lines=5\", m))   % \"merge lines (default: 5)\"\n);\n```\n\n\n#### Alternative Value Mapping Styles\n```cpp\nauto cli = ( \n    (option(\"-n\", \"--count\") \u0026 value(\"count\") \u003e\u003e n                 ) % \"number of iterations\",\n    (option(\"-r\", \"--ratio\") \u0026 value(\"ratio\") \u003e\u003e print_ratio       ) % \"compression ratio\",\n    (option(\"-m\"           ) \u0026 opt_value(\"lines=5\") \u003e\u003e m \u003e\u003e domerge) % \"merge lines (default: 5)\" \n);\n```\n```cpp\nauto cli = ( \n    (option(\"-n\", \"--count\") \u0026 value(\"count\").set(n))         % \"number of iterations\",\n    (option(\"-r\", \"--ratio\") \u0026 value(\"ratio\")(print_ratio))   % \"compression ratio\",\n    (option(\"-m\").set(domerge) \u0026 opt_value(\"lines=5\").set(m)) % \"merge lines (default: 5)\"\n);\n```\nSee [here](#coding-styles) for more on coding styles.\n\n\n\n### Options With Multiple Values \nParameters can be sequenced using operator ```\u0026``` or the function ```in_sequence```. Sequenced parameters can only be matched one after the other. This mechanism can be used to attach multiple values to an option.\n\n```man\nSYNOPSIS\n       transform \u003cgeometry file\u003e [-translate \u003cx\u003e \u003cy\u003e \u003cz\u003e] [-rotate \u003cazimuth\u003e \u003cpolar\u003e]\n```\n\n```cpp\nstring infile;\nbool tr = false, rot = false;\ndouble x = 0, y = 0, z = 0;\ndouble phi = 0, theta = 0;\n\nauto cli = (\n    value(\"geometry file\", infile),\n    option(\"-translate\").set(tr) \u0026 value(\"x\", x) \u0026 value(\"y\", y) \u0026 value(\"z\", z),\n    option(\"-rotate\").set(rot) \u0026 value(\"azimuth\", phi) \u0026 value(\"polar\", theta)\n);\n```\n\nNote that the following interface definition is equivalent to the above. Since ```value``` is positional we can list it with ```,```, but we have to make sure that the groups of values will only be matched after the options, hence the ```\u0026```.\n```cpp\nauto cli = (\n    value(\"geometry file\", infile),\n    option(\"-translate\").set(tr) \u0026 ( value(\"x\", x), value(\"y\", y), value(\"z\", z) ),\n    option(\"-rotate\").set(rot)   \u0026 ( value(\"azimuth\", phi) , value(\"polar\", theta) )\n);\n```\n\n\n\n### Required Flags\nRequired flags are usually used together with non-optional values. Note that ```-i``` and ```-o``` are not positional in the following example, i.e., the relative order in which command line arguments for ```-i```, ```-o``` and ```-r``` are provided is irrelevant.\n\n```man\nSYNOPSIS\n        myprogram [-r] -i \u003cinput dir\u003e -o \u003coutput dir\u003e\n\nOPTIONS\n        -r, --recursive\n                search in subdirectories\n        -i, --in \u003cinput dir\u003e\n                path to input directory\n        -o, --out \u003coutput dir\u003e\n                path to output directory\n```\n\n```cpp\nbool recurse = false;\nstring inpath, outpath;\n\nauto cli = (\n    option(\"-r\", \"--recursive\").set(recurse)                 % \"search in subdirectories\",\n    (required(\"-i\", \"--in\" ) \u0026 value(\"input dir\", inpath))   % \"path to input directory\",\n    (required(\"-o\", \"--out\") \u0026 value(\"output dir\", outpath)) % \"path to output directory\"\n);\n```\n\n\n\n### Repeatable Parameters\n```man\nSYNOPSIS\n        simplify \u003cfile\u003e... [-c] [-i \u003cline\u003e...]\n   \nOPTIONS\n        \u003cfile\u003e...               input files\n        -c, --compress          compress results             \n        -i, --ignore \u003cline\u003e...  lines to be ignored\n```\n\n```cpp\nvector\u003cstring\u003e files;\nvector\u003cint\u003e lines;\nbool zip = false;\nauto cli = (\n    values(\"file\", files)                                % \"input files\",\n    option(\"-c\", \"--compress\").set(zip)                  % \"compress results\",\n    (option(\"-i\", \"--ignore\") \u0026 integers(\"line\", lines)) % \"lines to be ignored\"\n);\n```\n\nThe call ```values(\"v\")``` is shorthand for ```value(\"v\").repeatable(true)```.\n\nNote, that the  value parameter ```line``` is repeatable, but the flag ```--ignore``` is not. So \nsomething like\n```\n    simplify file1 file2 --ignore 1 2 --ignore 3 4 -c\n```\nis taken to be an error.\nHowever, it is possible if you make the group of ```--ignore``` and ```line``` itself repeatable:\n\n#### Repeatable Groups of Options with Repeatable Values\n```man\nSYNOPSIS\n        simplify \u003cfile\u003e... [-c] [-i \u003cline\u003e...]...\n   \nOPTIONS\n        \u003cfile\u003e...               input files\n        -c, --compress          compress results             \n        -i, --ignore \u003cline\u003e...  lines to be ignored\n```\n\n```cpp\nvector\u003cstring\u003e files;\nvector\u003cint\u003e lines;\nbool zip = false;\nauto cli = (\n    values(\"file\", files)                            % \"input files\",\n    option(\"-c\", \"--compress\").set(zip)              % \"compress results\",\n    repeatable(  // \u003c-----\n        option(\"-i\", \"--ignore\") \u0026 integers(\"line\", lines)\n    )                                                % \"lines to be ignored\"\n);\n```\nNow both the option ```--ignore``` *and* the value parameter ```value``` are repeatable. In all of the following examples ```lines``` will be set to ```{1,2,3,4}``` and ```c``` will be set to ```true```:\n```\n    simplify file1 file2 -c --ignore 1 2 3 4 \n    simplify file1 file2 --ignore 1 2 3 4 -c\n    simplify file1 file2 --ignore 1 -c --ignore 2 3 4\n    simplify file1 file2 --ignore 1 2 --ignore 3 4 -c\n    simplify file1 file2 --ignore 1 --ignore 2 -c --ignore 3 --ignore 4\n    simplify file1 file2 -c --ignore1 --ignore2 --ignore3 --ignore4\n```\n\n\n\n### Actions\nActions are executed if a parameter matched an argument string in the command line arguments list. Actions are defined using the following member functions or operators:\n\n- ```parameter::call(f)``` or ```parameter::operator () (f)```: call a callable entity ```f``` (function, lambda, custom function object) for each one of the matched argument strings. If ```f``` accepts exactly one parameter that is convertible from ```const char*```, the command line argument is passed to it. If the parameter list is empty, it is simply called without argument.\n\n- ```parameter::set(target, value)```: assign a fixed value to a target object; note that the assignment ```target = value;``` must be a valid statement\n\n- ```parameter::set(target)```:\n    - A ```bool``` target is set to true if the flag/value is present and **left unchanged otherwise**.\n    - A target object of fundamental type ```T``` (```int```, ```long```, ```float```, ```double```, ...) will be assigned the result of converting the argument string to type ```T```.\n    - Targets of type ```std::vector\u003cT\u003e``` are appended with a value for each matched argument string. Note that ```T``` must either be (explicitly) convertible from ```const char*``` or a fundamental type.\n\n- ```operator \u003c\u003c``` or ```operator \u003e\u003e``` assign arg strings to lvalues or call callable entities. Which kind of action will be performed is automatically determined through overload resolution.\n\n\n#### Predefined Functions \n```cpp\nint x = 0;                   // equivalent to:     \noption(\"-x\")(set(x))         // option(\"-x\").set(x) \noption(\"-x\")(set(x,2))       // option(\"-x\").set(x,2) \noption(\"-x\")(increment(x))   // option(\"-x\")([\u0026]{++x;})\noption(\"-x\")(decrement(x))   // option(\"-x\")([\u0026]{--x;})\n\nbool b = false;              // equivalent to:\noption(\"-b\")(flip(b))        // option(\"-x\")([\u0026]{b = !b;})\n```\n\n\n#### Some Examples\n```cpp\nbool a = false, b = false;\nint i = 1, n = 0, m = 0;\nfloat x = 0.0f;\n\nauto cli = (                           //INFORMAL description\n    option(\"-a\").set(a),               //if(found(\"-a\")) a = true;\n    option(\"-b\") \u003e\u003e b,                 //if(found(\"-b\")) b = true;\n    option(\"--toggle\").call(flip(b)),  //if(found(\"--toggle\")) flip(b);\n\n    value(\"n\").set(n),                 //n = std::atoi(arg);\n    option(\"-i\") \u0026 value(\"#\",i),       //if(found(\"-i arg\")) i = std::atoi(arg);\n    option(\"-1\").set(m,1),             //if(found(\"-1\")) m = 1;\n    option(\"-2\").set(m,2),             //if(found(\"-2\")) m = 2;\n\n    //if(found(\"-z\")) call_lambda_with_arg(\"-z\");\n    option(\"-z\").call([](const char* s) { cout \u003c\u003c s; }),\n\n    //using 'operator()' instead of 'call'\n    //if(found(\"bob\")) call_lambda_with_arg(\"bob\");\n    option(\"bob\")([](const std::string\u0026 s) { cout \u003c\u003c s; }),\n\n    //for_each_occurence(\"-x arg\", call_lambda_with_arg(arg));\n    repeatable( option(\"-x\") \u0026 value(\"X\")([\u0026](const char* s) { x = std::atof(s); }) ),\n\n    option(\"--all\") \u003e\u003e []()              { cout \u003c\u003c \"found --all\\n\"; }\n                    \u003e\u003e [](const char* s) { cout \u003c\u003c \"found flag \" \u003c\u003c s \u003c\u003c '\\n'; };\n);\n```\n\n\n\n### Joinable Flags\n```man\nSYNOPSIS\n        edit \u003cfile\u003e [-rbs] ([:vim] [:st3] [:atom] [:emacs])\n\nOPTIONS\n        -r      open read-only\n        -b      use backup file\n        -s      use swap file\n\n        :vim, :st3, :atom, :emacs\n                editor(s) to use; multiple possible        \n```\n\n```cpp\nstd::string file;\nbool readonly = false, usebackup = false, useswap = false;\nenum class editor {vim, sublime3, atom, emacs};\nstd::vector\u003ceditor\u003e editors;\nauto add = [\u0026](editor e){ return [\u0026]{ editors.push_back(e); }; };\n\nauto cli = (\n    value(\"file\", file),\n    joinable(\n        option(\"-r\").set(readonly)  % \"open read-only\",\n        option(\"-b\").set(usebackup) % \"use backup file\",\n        option(\"-s\").set(useswap)   % \"use swap file\"\n    ),\n    joinable(\n        option(\":vim\")    \u003e\u003e add(editor::vim),\n        option(\":st3\")    \u003e\u003e add(editor::sublime3),\n        option(\":atom\")   \u003e\u003e add(editor::atom),\n        option(\":emacs\")  \u003e\u003e add(editor::emacs)\n    ) % \"editor(s) to use; multiple possible\"\n);\n```\n- Flags can be joined regardless of their length (second group in the example). \n- If the flags have a common prefix (```-``` or ```:``` in the example) it must be given at least\n  once as leading prefix in the command line argument.\n- Allowed args for the first group are:\n  ```-r```, ```-b```, ```-s```, ```-rb```, ```-br```, ```-rs```, ```-sr```, \n  ```-sb```, ```-bs```, ```-rbs```, ```-rsb```, ...\n- Allowed args for the second group are:\n  ```:vim```, ```:vim:atom```, ```:emacs:st3```, ```:vimatom```, ...\n\n#### More Examples\n\n| joinable flags           | valid args                                                                         |\n| ------------------------ | ---------------------                                                              |\n| ```a```, ```b```         | ```ab```, ```ba```, ```a```, ```b```                                               |\n| ```-a```, ```-b```       | ```-ab```, ```-ba```, ```-a```, ```-b```, ```-a-b```, ```-b-a```                   |\n| ```--a```, ```--b```     | ```--ab```, ```--ba```, ```--a```, ```--b```, ```--a--b```, ```--b--a```           |\n| ```,a```, ```,b```       | ```,ab```, ```,ba```, ```,a```, ```,b```, ```,a,b```, ```,b,a```                   |\n| ```Xab```, ```Xcd```     | ```Xabcd```, ```Xcdab```, ```XabXcd```, ```XcdXab```, ```Xab```, ```Xcd```         |\n| ```x:ab```, ```x:cd```   | ```x:abcd```, ```x:cdab```, ```x:abx:cd```, ```x:cdx:ab```, ```x:ab```, ```x:cd``` |\n\n\n\n### Alternatives\n```man\nSYNOPSIS\n        find \u003cfile\u003e... -s \u003cexpr\u003e [any|all]\n\nOPTIONS\n        \u003cfile\u003e...  input filenames\n        -s \u003cexpr\u003e  string to look for\n        any        report as soon as any matches\n        all        report only if all match\n```\n\n```cpp\nvector\u003cstring\u003e files;\nstring expr;\nbool ifany = false, ifall = false;\n\nauto cli = (\n    values(\"file\", files)                  % \"input filenames\",\n    (required(\"-s\") \u0026 value(\"expr\", expr)) % \"string to look for\",\n    option(\"any\").set(ifany)               % \"report as soon as any matches\" |\n    option(\"all\").set(ifall)               % \"report only if all match\"\n);\n```\n\nIf you like it more verbose you can use the function ```one_of``` instead of ```operator |```:\n```cpp\nauto cli = (\n    values(\"file\", files)                  % \"input filenames\",\n    (required(\"-s\") \u0026 value(\"expr\", expr)) % \"string to look for\",\n    one_of( option(\"any\").set(ifany)       % \"report as soon as any matches\",\n            option(\"all\").set(ifall)       % \"report only if all match\" )\n);\n```\n\n\n#### gcc-style switches\n```man\nSYNOPSIS\n        format [-o \u003coutput file\u003e] [-falign|-fnoalign)]\n\nOPTIONS\n        -o, --out \u003cfile\u003e\n                output filename\n\n        -falign, -fnoalign \n                control alignment\n```\n\n```cpp\nstring outfile = \"a.out\";\nbool align = false;\n     \nauto cli = (\n    (option(\"-o\", \"--out\") \u0026 value(\"output file\", outfile)) % \"output filename\",\n    ( option(\"-falign\"  ).set(align,true) |\n      option(\"-fnoalign\").set(align,false) )                % \"control alignment\"\n);\n```\n    \nNote, that the documentation string is attached to the group of parameters for better readability.\n\n\n#### non-redundant prefix specification\n```cpp\n//has the same meaning as the code above\nstring outfile = \"a.out\";\nbool align = false;\n\nauto cli = (\n    (option(\"-o\", \"--out\") \u0026 value(\"output file\", outfile)) % \"output filename\",\n    with_prefix(\"-f\", option(\"align\"  ).set(align,true) |\n                      option(\"noalign\").set(align,false) )  % \"control alignment\"\n);\n```\n\n\n#### merge alternatives with common prefixes in documentation\n```man\nUsage:   format [-o \u003coutput file\u003e] [-f(align|noalign)]\n```\n```cpp\nauto fmt = doc_formatting{}.merge_alternative_flags_with_common_prefix(true);\ncout \u003c\u003c usage_lines(cli, \"format\", fmt) \u003c\u003c '\\n';\n```\n\n\n\n### Commands \n**= positional, required flags**\n```man\nSYNOPSIS\n        make_doc new \u003cfilename\u003e [-e \u003cenc\u003e]\n\nOPTIONS\n        -e, --encoding  'utf8' or 'cp1252', default is UTF-8\n    \n```\n\n```cpp\nstd::string fname;\nstd::string enc = \"utf8\";\n\nauto cli = (\n    command(\"new\"),\n    value(\"filename\", fname),\n    option(\"-e\", \"--encoding\") \u0026 value(\"enc\", enc).doc(\"'utf8' or 'cp1252', default is \" + enc)\n);\n```\n\n\n\n### Nested Alternatives\n```man\nSYNOPSIS\n        image-find help\n        image-find build (new|add) \u003cfile\u003e... [-v] [-b [\u003csize=1024\u003e]] [--init|--no-init]\n        image-find query \u003cinfile\u003e -o \u003coutfile\u003e [-f \u003cformat\u003e]\n\nOPTIONS\n        -v, --verbose\n                print detailed report\n\n        -b, --buffer [\u003csize=1024\u003e]\n                sets buffer size in KiByte\n\n        --init, --no-init \n                do or don't initialize\n\n        -f, --out-format \u003cformat\u003e\n                determine output format\n```\n\nValue handling actions are omitted; see examples/nested_alternatives.cpp for a fully functional demo.\n```cpp\nauto cli = (\n    command(\"help\") \n    | ( command(\"build\"),\n        ( command(\"new\") | command(\"add\")),                  \n        values(\"file\"),\n        option(\"-v\", \"--verbose\")                           % \"print detailed report\",\n        (option(\"-b\", \"--buffer\") \u0026 opt_value(\"size=1024\")) % \"sets buffer size in KiByte\",\n        ( option(\"--init\") | option(\"--no-init\") )          % \"do or don't initialize\"\n    ) \n    | ( command(\"query\"),\n        value(\"infile\"),\n        required(\"-o\", \"--out\") \u0026 value(\"outfile\"),\n        (option(\"-f\", \"--out-format\") \u0026 value(\"format\"))  % \"determine output format\"\n    )\n);\n```\n\nNote: \n```\ndoc_formatting::split_alternatives(bool)             //default: true\ndoc_formatting::alternatives_min_split_size(int)     //default: 3\n```\ncontrol if the usage is split up into several lines if any group inside an alternative exceeds a given minimum size.\n\n\n\n### Complex Nestings\nThe combination of blocking parameters, alternatives and grouping makes it possible to define interfaces with decision trees/DAGs of arbitrary complexity.\n```man\nSYNOPSIS\n    complex_nesting [-v] [-i] (copy|move) [--all] [--replace] [-f] \u003cfiles\u003e... [-r] [-h]\n    complex_nesting [-v] [-i] compare (date|content) [-b] [-q] \u003cfiles\u003e... [-r] [-h]\n    complex_nesting [-v] [-i] merge (diff|patch) -o \u003coutdir\u003e [--show-conflicts] \u003cfiles\u003e... [-r] [-h]\n    complex_nesting [-v] [-i] merge content [--git-style] [-m \u003cmarker\u003e] -o \u003coutdir\u003e [--show-conflicts] \u003cfiles\u003e... [-r] [-h]\n    complex_nesting [-v] [-i] list \u003cfiles\u003e... [-r] [-h]\n\nOPTIONS\n    user interface options:\n        -v, --verbose      show detailed output\n        -i, --interactive  use interactive mode\n\n    copy mode:\n        --all              copy all\n        --replace          replace existing files\n        -f, --force        don't ask for confirmation\n\n    compare mode:\n        -b, --binary       compare files byte by byte\n        -q, --quick        use heuristics for faster comparison\n\n    merge mode:\n        diff               merge using diff\n        patch              merge using patch\n        content            merge based on content\n\n        content based merge options:\n            --git-style    emulate git's merge behavior\n            \u003cmarker\u003e       merge marker symbol\n\n        \u003coutdir\u003e           target directory for merge result\n        --show-conflicts   show merge conflicts during run\n\n    mode-independent options:\n        \u003cfiles\u003e...         input files\n        -r, --recursive    descend into subdirectories\n        -h, --help         show help\n```\n\nActions and target variables are omitted in the code. \n```cpp\nauto copyMode = \"copy mode:\" % (\n    command(\"copy\") | command(\"move\"),\n    option(\"--all\")         % \"copy all\",\n    option(\"--replace\")     % \"replace existing files\",\n    option(\"-f\", \"--force\") % \"don't ask for confirmation\"\n);\n\nauto compareMode = \"compare mode:\" % (\n    command(\"compare\"),\n    (command(\"date\") | command(\"content\")),\n    option(\"-b\", \"--binary\") % \"compare files byte by byte\",\n    option(\"-q\", \"--quick\")  % \"use heuristics for faster comparison\"\n);\n\nauto mergeAlgo = (\n    command(\"diff\")  % \"merge using diff\"  |\n    command(\"patch\") % \"merge using patch\" |\n    (   command(\"content\") % \"merge based on content\",\n        \"content based merge options:\" % (\n          option(\"--git-style\") % \"emulate git's merge behavior\",\n          option(\"-m\", \"--marker\") \u0026 value(\"marker\") % \"merge marker symbol\"\n        )\n    )\n);\n\nauto mergeMode = \"merge mode:\" % (\n    command(\"merge\"),\n    mergeAlgo,\n    required(\"-o\") \u0026 value(\"outdir\") % \"target directory for merge result\",\n    option(\"--show-conflicts\")       % \"show merge conflicts during run\"\n);\n\nauto firstOpt = \"user interface options:\" % (\n    option(\"-v\", \"--verbose\")     % \"show detailed output\",\n    option(\"-i\", \"--interactive\") % \"use interactive mode\"\n);\nauto lastOpt = \"mode-independent options:\" % (\n    values(\"files\")             % \"input files\",\n    option(\"-r\", \"--recursive\") % \"descend into subdirectories\",\n    option(\"-h\", \"--help\")      % \"show help\"\n);\n\nauto cli = (\n    firstOpt,\n    copyMode | compareMode | mergeMode | command(\"list\"),\n    lastOpt\n);\n\nif(parse(argc, argv, cli)) {\n     // program logic...\n} else {\n    auto fmt = doc_formatting{}.doc_column(31);\n    cout \u003c\u003c make_man_page(cli, argv[0], fmt) \u003c\u003c '\\n';\n}\n```\n\nYou could of course write down everything as one big expression (docstrings are omitted)...:\n```cpp\nauto cli = (\n    option(\"-v\", \"--verbose\"),\n    option(\"-i\", \"--interactive\"),\n    (\n        (   (command(\"copy\") | command(\"move\")),\n            option(\"--all\"), option(\"--replace\"),\n            option(\"-f\", \"--force\") \n        )\n        | ( command(\"compare\"),\n            (command(\"date\") | command(\"content\")),\n            option(\"-b\", \"--binary\"), option(\"-q\", \"--quick\") \n        ) \n        | ( command(\"merge\"),\n            (\n                ( command(\"content\"),\n                  option(\"--git-style\"),\n                  option(\"-m\", \"--marker\") \u0026 value(\"marker\")\n                )\n                | command(\"diff\")\n                | command(\"patch\")\n            ),\n            required(\"-o\") \u0026 value(\"outdir\"),\n            option(\"--show-conflicts\")\n        ) \n        | command(\"list\")\n    ),\n    values(\"files\"),\n    option(\"-r\", \"--recursive\"),\n    option(\"-h\", \"--help\")\n);\n ```\n...but it is probably more readable and maintainable if you break up the CLI definition into logical parts.\n\nNote: \n```\ndoc_formatting::split_alternatives(bool)             //default: true\ndoc_formatting::alternatives_min_split_size(int)     //default: 3\n```\ncontrol whether the usage is split up into several lines if any group inside an alternative  exceeds a given minimum size.\n\n\n\n### An Example From [docopt]\n```man\nNaval Fate.\n\nUsage:\n  naval_fate ship new \u003cname\u003e...\n  naval_fate ship \u003cname\u003e move \u003cx\u003e \u003cy\u003e [--speed= \u003ckn\u003e]\n  naval_fate ship shoot \u003cx\u003e \u003cy\u003e\n  naval_fate mine (set|remove) \u003cx\u003e \u003cy\u003e [--moored|--drifting]\n  naval_fate -h | --help\n  naval_fate --version\n\nOptions:\n  --speed= \u003ckn\u003e  Speed in knots [default: 10].\n  --moored       Moored (anchored) mine.\n  --drifting     Drifting mine.\n  -h, --help     Show this screen.\n  --version      Show version.\n```\n\nThis code defines the command line interface, handles the parsing result and\ngenerates the above man page snippet.\n```cpp\nint x = 0, y = 0;\nfloat speed = 0.0f;\nbool drift = true;\nvector\u003cstring\u003e names;\nenum class mode { none, help, shipnew, shipmove, shipshoot, mineset, minerem};\nmode selected = mode::none;\n\n//define command line interface\nauto coordinates = ( value(\"x\", x), value(\"y\", y) );\n\nauto shipnew  = ( command(\"new\").set(selected,mode::shipnew),\n                  values(\"name\", names) );\n\nauto shipmove = (\n    value(\"name\", names),\n    command(\"move\").set(selected,mode::shipmove), coordinates,\n    option(\"--speed=\") \u0026 value(\"kn\",speed) % \"Speed in knots [default: 10]\");\n\nauto shipshoot = ( command(\"shoot\").set(selected,mode::shipshoot),\n                   coordinates );\n\nauto mines = ( \n    command(\"mine\"),\n    (command(\"set\"   ).set(selected,mode::mineset) | \n     command(\"remove\").set(selected,mode::minerem) ),\n    coordinates,\n    (option(\"--moored\"  ).set(drift,false) % \"Moored (anchored) mine.\" | \n     option(\"--drifting\").set(drift,true)  % \"Drifting mine.\"          )\n);\n\nauto navalcli = (\n    ( command(\"ship\"), ( shipnew | shipmove | shipshoot ) )\n    | mines,\n    | command(\"-h\", \"--help\").set(selected,mode::help)     % \"Show this screen.\"\n    | command(\"--version\")([]{ cout \u003c\u003c \"version 1.0\\n\"; }) % \"Show version.\"\n);\n\nparse(argc, argv, navalcli);\n\n//handle results\nswitch(m) {\n    case mode::none: \n        break;\n    case mode::help: {\n        auto fmt = doc_formatting{}\n            .first_column(2).doc_column(16)\n            .max_flags_per_param_in_usage(4);\n\n        cout \u003c\u003c \"Naval Fate.\\n\\nUsage:\\n\"\n             \u003c\u003c usage_lines(navalcli, \"naval_fate\", fmt)\n             \u003c\u003c \"\\n\\nOptions:\\n\"\n             \u003c\u003c documentation(navalcli, fmt) \u003c\u003c '\\n';\n        }\n        break;\n    }\n    //... \n}\n```\n\n\n\n\n### Value Filters\nIf a parameter doesn't have flags, i.e. it is a value-parameter, a filter function will be used to test if it matches an argument string. The default filter is ```clipp::match::nonempty``` which will match any non-empty argument string. \nIf you want more control over what is matched, you can use some other predefined filters or you can write your own ones (see [here](#custom-value-filters)).\n\n```man\nUsage:   exec [-n \u003ctimes\u003e] [-l \u003cline\u003e...] [-b \u003cratio\u003e] [-f \u003cterm\u003e]\n```\n\n```cpp\nint n = 1;\nstd::vector\u003cint\u003e lines;\ndouble r = 1.0;\nstring term, name;\nauto cli = (\n    option(\"-n\", \"--repeat\") \u0026 integer(\"times\", n),\n    option(\"-l\", \"--line\")   \u0026 integers(\"#\", lines),\n    option(\"-r\", \"--ratio)   \u0026 number(\"ratio\", r),\n    option(\"-f\", \"--find\")   \u0026 word(\"term\", term)\n);\n```\n\n#### Predefined Filtering Value-Parameters\n```cpp\nauto cli = (\n    value(\"x\"),    //non-empty string\n    word(\"x\"),     //alphanumeric string\n    number(\"x\"),   //string representing integer or floating point number\n    integer(\"x\")   //string representing integral number\n);\n```\nNote that there are additional functions for\n - optional parameters: ```opt_value```, ```opt_word```, ...\n - repeatable parameters: ```values```, ```words```, ...\n - repeatable, optional parameters: ```opt_values```, ```opt_words```, ...\n\n\n#### Using Filters Explicitly\nTwo kinds of filters are supported right now that can be passed as first argument of ```value```, ```values```, ```opt_value``` or ```opt_values``` as well as argument of the constructor ```parameter::parameter(Filter\u0026\u0026)```\n - Predicates ```(const string\u0026) -\u003e bool``` \n   which should return true if and only if an argument is an exact match.\n\n - Substring matchers ```(const string\u0026) -\u003e subrange```\n   which in case of a match also indicate the position and length of the matched substring within a command line argument.\n\n```cpp\nstring s;\nvalue( match::length{1,5}, \"str\", s);\n\n//or using the parameter class directly\nauto p = parameter{ match::length{1,5} }\n         .positional(true).required(true)\n         .label(\"str\").set(s);\n```\nThere are a couple of predefined filters in ```namespace clipp::match```, but you can of course write your own ones (see [here](#custom-value-filters)).\n\nHere is another example that makes sure we don't catch any value starting with \"-\" as a filename:\n```cpp\nauto cli = (  \n    option(\"-a\")  \n    option(\"-f\") \u0026 value(match::prefix_not(\"-\"), \"filename\"),\n    option(\"-b\")  \n);\n```\n\n```cpp\nnamespace clipp {\nnamespace match {\n\n  //simple predicates\n  bool none (const string\u0026);\n  bool any (const string\u0026);\n  bool nonempty (const string\u0026);\n  bool alphabetic (const string\u0026);\n  bool alphanumeric (const string\u0026);\n\n  //filters with settings and substring matching\n  class numbers {\n      explicit numbers(char decimalPoint = '.', char digitSeparator = ',', char exponentSeparator = 'e');\n      subrange operator () (const string\u0026 arg);\n  };\n\n  class integers {\n      explicit integers(char digitSeparator = ',');\n      subrange operator () (const string\u0026 arg);\n  };\n\n  class substring {\n      explicit substring(const string\u0026 str);\n      subrange operator () (const string\u0026 arg);\n  };\n\n  class prefix {\n      explicit prefix(const string\u0026 prefix);\n      subrange operator () (const string\u0026 arg);\n  };\n\n  class prefix_not {\n      explicit prefix_not(const string\u0026 prefix);\n      subrange operator () (const string\u0026 arg);\n  };\n\n  class length {\n      explicit length(size_t exact);\n      explicit length(size_t min, size_t max);\n      subrange operator () (const string\u0026 arg);\n  };\n\n} }\n```\n\n\n\n### Greedy Parameters\n\nBy default, the parser tries to identify a command line argument (in that order) as\n - a single flag\n - a concatenation of multiple, _joinable_ flags (in any order)\n - a concatenation of a _joinable_ flag sequence in the order defined in the CLI code\n - a single value parameter\n - a concatenation of a _joinable_ flag/value sequence in the order defined in the CLI code\n - a concatenation of _joinable_ flags \u0026 values in no particular order\n\nIf no match was found, the parser tries the same list again without any restrictions imposed by blocking (positional) parameters, conflicting alternatives, etc. If this leads to any match, an error will be reported. This way, _potential_, but illegal matches can be found and, e.g., conflicting alternatives can be reported.\n\nConsider this CLI:\n```cpp\nauto cli = (  option(\"-a\"),  option(\"-f\") \u0026 value(\"filename\"),  option(\"-b\")  );\n```\nIf we give ```-f -b``` or ```-b -f -a``` as command line arguments, an error will be reported, since the value after ```-f``` is not optional. \n\nThis behavior is fine for most use cases. \nBut what if we want our program to take any string as a filename, because our filenames might also collide with flag names? We can make the ```filename``` value parameter greedy, so that the next string after ```-f``` will always be matched with highest priority as soon as ```-f``` was given:\n```cpp\nauto cli = (  option(\"-a\"),  option(\"-f\") \u0026 greedy(value(\"filename\")),  option(\"-b\")  );\n```\nor using ```operator !```:\n```cpp\nauto cli = (  option(\"-a\"),  option(\"-f\") \u0026 !value(\"filename\"),   option(\"-b\")  );\n```\n\nNow, every string coming after an ```-f``` will be used as filename. \n\nIf we don't want just *any* kind of match accepted, but still retain a higher priority for a value parameter, we could use a [value filter](#value-filters):\n```cpp\nauto cli = (  \n    (   command(\"A\"),\n        option(\"-f\") \u0026 !value(match::prefix_not(\"-\"), \"filename\"),\n        option(\"-b\")  \n    ) |\n    (   command(\"B\"),\n        option(\"-x\")  \n    )\n);\n```\nThis way, the command line arguments ```A -f B``` will set the filename to \"B\" and produce no conflict error between the alternative commands ```A``` and ```B``` but ```A -f -b``` will still give an error.\n\nNote, that there is an inherent decision problem: either we want the ```filename``` value to match no matter what, or we won't get proper error handling if someone forgets to specify a filename and gives ```A -f -b``` Also, there might be interfaces where we really want to catch something like ```A -f B``` as a command conflict.\n\n\n\n\n### Generalized Joinable Parameters\n\nNot only flags, but arbitrary combinations of flags and values can be made joinable. This feature is especially powerful if combined with repeatable groups. \nImportant: in order for an argument to be matched by such expressions, no parameter requirements must be violated during the matching. Also, no partial argument matches are allowed.\n\n#### Example 1: Counting Letters\n```man\nUsage:   counter [a|b]...\n```\n\n```cpp\nint as = 0, bs = 0;\n\nauto cli = joinable( repeatable(\n        option(\"a\").call([\u0026]{++as;}) |\n        option(\"b\").call([\u0026]{++bs;})\n    ) );\n\nif(parse(argc, argv, cli))     \n    cout \u003c\u003c \"as: \" \u003c\u003c as \u003c\u003c \"\\nbs: \" \u003c\u003c bs \u003c\u003c '\\n';\nelse \n    cout \u003c\u003c \"Usage:\\n\" \u003c\u003c usage_lines(cli, argv[0]) \u003c\u003c '\\n';\n```\n\nValid input includes:\n```\n$ ./counter a                               \n$ ./counter b\n$ ./counter ab\n$ ./counter abba\n$ ./counter a b baba\n$ ./counter a babba abab abbbbba b a ba a\n    ...\n```\n\n#### Example 2: Listing Numbers\n```man\nUsage:   numbers ([,] [\u003cnumber\u003e])...\n```\n\n```cpp\nstd::vector\u003cdouble\u003e nums;\n\nauto cli = joinable(repeatable( option(\",\") , opt_number(\"number\", nums) ));\n\nif(parse(argc, argv, cli)) {\n    cout \u003c\u003c \"numbers:\\n\";\n    for(auto n : nums) cout \u003c\u003c n \u003c\u003c '\\n';\n} else {\n    cout \u003c\u003c \"Usage:\\n\" \u003c\u003c usage_lines(cli, argv[0]) \u003c\u003c '\\n';\n}\n```\n\nValid input includes:\n```\n$ ./numbers 1\n$ ./numbers 1 2 3\n$ ./numbers 1 , 2\n$ ./numbers 1 , 2 , 3\n$ ./numbers 1, 2, 3\n$ ./numbers 1 ,2 ,3\n$ ./numbers 1,2\n$ ./numbers 1,2,3\n$ ./numbers 1.1 , 2\n$ ./numbers 1,2.3,4.5\n$ ./numbers 1,2,3 4.2 5,6 2 7.1,8.23,9 \n```\n\n**Warning:** Be careful with joinable and repeatable parameters! The resulting command line interface might be a lot less intuitive to use than you think. It can also be hard to get the \"grammar\" of complex parsing expressions right.\nThe following definition for example, contains a subtle pitfall:\n```cpp\nauto cli = joinable(repeatable( option(\",\") , number(\"number\", nums) ));\n//                                            ^^^ non-optional\n```\nThis will not match arguments like ```\"1,\"```. This is, because, if the repeat group is 'hit' by any of its child parameters, all non-optional parameters must also match within the current 'repeat cycle'. So, if the parser hits the ```\",\"``` it expects to find a number arg as well, because it is blocking (positional) and required. Only after seeing this number can it enter the next repeat cycle. Thus, the argument will not be matched, since joined matches are only valid if no error occured. Making the number optional solves the problem.\n\n\n### Custom Value Filters\nTwo kinds of filters are supported right now that can be passed as first argument of ```value```, ```values```, ```opt_value``` or ```opt_values``` as well as argument of the constructor ```parameter::parameter(Filter\u0026\u0026)```:\n\n - Predicates ```(const string\u0026) -\u003e bool``` \n   which should return true if and only if an argument is an exact match.\n\n - Substring matchers ```(const string\u0026) -\u003e subrange```\n   which in case of a match also indicate the position and length of the matched substring within a command line argument.\n\n\n#### Simple Predicate Example\n ```man\nUsage:   annotate auto | (label \u003ccharacter\u003e)\n```\n\n```cpp\nauto is_char = [](const string\u0026 arg) { return arg.size() == 1 \u0026\u0026 std::isalpha(arg[0]); };\n\nchar lbl = ' ';\nauto cli = (  command(\"auto\") | ( command(\"label\"), value(is_char, \"character\", lbl) )  );\n```\n\n\n#### Substring Matcher Example\n\nLet's write a program that takes strings and lists all tag names (```\u003ctag\u003e```) contained in them:\n```man\nUsage:   tagnames \u003cstring\u003e...\n```\n\n```cpp\n//custom filter\nauto tag_name = [] (const string\u0026 arg) {\n    if(arg.size() \u003c 3) return subrange{}; //too short\n    auto i = arg.find(\"\u003c\");\n    if(i == string::npos) return subrange{}; //no tag start found\n    auto j = arg.find(\"\u003e\", i+1);\n    if(j == string::npos) return subrange{}; //didn't find end of tag\n    return subrange{i,j-i+1}; //partial match {start, length}\n};\n\nstd::set\u003cstring\u003e tags;\nauto cli = joinable(\n    values(tag_name, \"string\", \n           [\u0026](const string\u0026 arg){ if(arg[1] != '/') tags.insert(arg);})\n);\n\nif(parse(argc, argv, cli)) {\n    cout \u003c\u003c \"tag names:\\n\";\n    for(const auto\u0026 t : tags) cout \u003c\u003c t \u003c\u003c '\\n';\n} else {\n    cout \u003c\u003c \"Usage:\\n\" \u003c\u003c usage_lines(cli, \"tagnames\") \u003c\u003c '\\n';\n}\n```\n\n```\n$ ./tagnames \"\u003ccee\u003e\u003cd\u003e\u003ce\u003e\u003c/e\u003e\u003c/d\u003e\u003c/cee\u003e\" \"\u003ca\u003e\u003cbo\u003e\u003c/bo\u003e\u003c/a\u003e\"\ntag names:\n\u003ca\u003e\n\u003cbo\u003e\n\u003ccee\u003e\n\u003cd\u003e\n\u003ce\u003e\n```\n\n\n\n### Sanity Checks\n\nCheck, if no flag occurs as prefix of any other flag (identical flags will be ignored):\n```cpp\nauto cli = ( /* command line interface definition */);\n\nassert( cli.flags_are_prefix_free() );\n```\n\nCheck common prefix of all flags, like for example \"-\" (or \"/\" on Windows):\n```cpp\nauto cli = ( /* command line interface definition */);\n\nassert( cli.common_flag_prefix() == \"-\" );\n```\n\n\n\n### Basic Error Handling\n\nEach parameter can have error handler functions/lambdas/function objects for different fail cases attached to it:\n - ```if_repeated``` is raised each time an argument is mapped to a parameter regardless of that parameter's repeatability setting\n - ```if_missing``` is raised if a required parameter has no argument associated with it\n - ```if_conflicted``` is raised if two or more arguments are mapped to more than one parameter of a group of alternatives\n - ```if_blocked``` is raised if an argument can only be mapped to a parameter that was not reachable at the time (e.g. because a positional value was expected before that parameter or the parameter was in a non-active alternative branch)\n\n#### Example:\n```man\nUsage:   send \u003cfile\u003e -t \u003ctarget\u003e... [--http|--ftp]\n```\n\n```cpp\nstring filename;\nvector\u003cstring\u003e targets;\nvector\u003cstring\u003e wrong;\nbool http = true;\n\nauto istarget = match::prefix_not(\"-\");\n\nauto cli = (\n    value(\"file\", filename)\n        .if_missing([]{ cout \u003c\u003c \"You need to provide a source filename!\\n\"; } )\n        .if_repeated([](int idx){ cout \u003c\u003c \"Only one source file allowed! (index \" \u003c\u003c idx \u003c\u003c \")\\n\"; } )\n    ,\n    required(\"-t\") \u0026 values(istarget, \"target\", targets)\n        .if_missing([]{ cout \u003c\u003c \"You need to provide at least one target filename!\\n\"; } )\n        .if_blocked([]{ cout \u003c\u003c \"Target names must not be given before the source file name!\\n\"; })\n    ,\n    option(\"--http\").set(http,true) | \n    option(\"--ftp\").set(http,false) % \"protocol, default is http\"\n        .if_conflicted([]{ cout \u003c\u003c \"You can only use one protocol at a time!\\n\"; } )\n    ,\n    any_other(wrong)\n);\n\nif(parse(argc, argv, cli) \u0026\u0026 wrong.empty()) {\n    cout \u003c\u003c \"OK\\n\";\n    /* ... */\n} else {\n    for(const auto\u0026 arg : wrong) cout \u003c\u003c \"'\" \u003c\u003c arg \u003c\u003c \"' is not a valid argument\\n\";\n    cout \u003c\u003c \"Usage:\" \u003c\u003c usage_lines(cli,argv[0]) \u003c\u003c '\\n';\n}\n```\nAn error handler can either have an empty parameter list or take an ```int``` which is set to the command line argument index where the error occured first.\n\nThe catch-all parameter made by ```any_other``` is used to catch command line arguments that are not supported.\n\nThe value parameter ```target``` will only match command line arguments that do not begin with ```\"-\"```, so that wrongly spelled options cannot be parsed as ```target``` value.\n\n\n### Parsing\n```cpp\nauto cli = ( \n    command(\"make\"),\n    value(\"file\")           % \"name of file to make\",\n    option(\"-f\", \"--force\") % \"overwrite existing file\"\n);\n\n//excludes argv[0]\nparse(argc, argv, cli);\n\n//if you want to include argv[0]\nparse(argv, argv+argc, cli);\n\nparse({\"make\", \"out.txt\"}, cli);\n\nauto args = std::vector\u003cstd::string\u003e {\"make\", \"out.txt\", \"-f\"};\nparse(args, cli);\n```\n\nThe parse functions return an object of ```parsing_result``` which can be used for detailed analysis and will (explicitly) convert to false if any error occured during parsing. \n```cpp\nauto result = parse(argc, argv, cli);\n\nauto doc_label = [](const parameter\u0026 p) {\n    if(!p.flags().empty()) return p.flags().front();\n    if(!p.label().empty()) return p.label();\n    return doc_string{\"\u003c?\u003e\"};\n};\n\ncout \u003c\u003c \"args -\u003e parameter mapping:\\n\";\nfor(const auto\u0026 m : result) {\n    os \u003c\u003c \"#\" \u003c\u003c m.index() \u003c\u003c \" \" \u003c\u003c m.arg() \u003c\u003c \" -\u003e \";\n    auto p = m.param();\n    if(p) {\n        os \u003c\u003c doc_label(*p) \u003c\u003c \" \\t\";\n        if(m.repeat() \u003e 0) {\n            os \u003c\u003c (m.bad_repeat() ? \"[bad repeat \" : \"[repeat \")\n               \u003c\u003c  m.repeat() \u003c\u003c \"]\";\n        }\n        if(m.blocked())  os \u003c\u003c \" [blocked]\";\n        if(m.conflict()) os \u003c\u003c \" [conflict]\";\n        os \u003c\u003c '\\n';\n    }\n    else {\n        os \u003c\u003c \" [unmapped]\\n\";\n    }\n}\n\ncout \u003c\u003c \"missing parameters:\\n\";\nfor(const auto\u0026 m : result.missing()) {\n    auto p = m.param();\n    if(p) {\n        os \u003c\u003c doc_label(*p) \u003c\u003c \" \\t\";\n        os \u003c\u003c \" [missing after \" \u003c\u003c m.after_index() \u003c\u003c \"]\\n\";\n    }\n}\n\n```\n\n\n\n### Documentation Generation\nGenerate usage lines and documentation from parameters:\n```cpp\nauto cli = ( /* command line interface definition */ );\n\n//used default formatting\ncout \u003c\u003c \"Usage:\\n\" \u003c\u003c usage_lines(cli, \"progname\")\n     \u003c\u003c \"\\nOptions:\\n\" \u003c\u003c documentation(cli) \u003c\u003c '\\n';\n```\n... or generate an entire man page in one go:\n```cpp\nauto cli = ( /* command line interface definition */ );\n\ncout \u003c\u003c make_man_page(cli, \"progname\")\n        .prepend_section(\"DESCRIPTION\", \"    The best thing since sliced bread.\")\n        .append_section(\"LICENSE\", \"    GPL3\");\n```\n\n#### Example\n```man\nDESCRIPTION\n    Builds a database of words from text files.\n\nSYNOPSIS\n    worddb help\n    worddb build (new|add) \u003cfile\u003e\n    worddb query -i \u003cinfile\u003e [-p]\n    worddb info space\n    worddb info statistics (words|chars)\n    worddb remove (any|all) \u003cregex\u003e\n    worddb modify [-c] [-u] [-m \u003csize\u003e]\n\nOPTIONS\n    build commands\n        new                  make new database\n        add                  append to existing database\n\n    query settings\n        \u003cinfile\u003e             input file\n        -p, --pretty-print   human friendly output\n\n    database info modes\n        space                detailed memory occupation analysis\n\n        statistics analysis\n            words            word frequency table\n            chars            character frequency table\n\n    remove mode\n        \u003cregex\u003e              regular expression filter\n\n    modification operations\n        -c, --compress       compress database in-memory\n        -u, --unique         keep only unique entries\n        -m, --memlimit       max. size in RAM\n\nLICENSE\n    GPL3\n ```\n\nThe full code:\n```cpp\nauto cli = (\n    command(\"help\") | \n    ( command(\"build\"),\n        \"build commands\" %\n        (   command(\"new\")  % \"make new database\"\n          | command(\"add\")  % \"append to existing database\"\n        ),\n        value(\"file\")\n    ) | \n    ( command(\"query\"),\n        \"query settings\" %\n        (   required(\"-i\", \"--input\") \u0026 value(\"infile\") % \"input file\",\n            option(\"-p\", \"--pretty-print\") % \"human friendly output\")\n    ) | \n    ( command(\"info\"),\n        \"database info modes\" % (\n            command(\"space\") % \"detailed memory occupation analysis\" |\n            (\n                command(\"statistics\"),\n                \"statistics analysis\" % (\n                    command(\"words\") % \"word frequency table\" |\n                    command(\"chars\") % \"character frequency table\"\n                )\n            )\n        )\n    ) | \n    \"remove mode\" % (\n        command(\"remove\"),\n        \"modify\" % ( command(\"any\") | command(\"all\") ),\n        value(\"regex\") % \"regular expression filter\"\n    ) | \n    ( command(\"modify\"),\n        \"modification operations\" % (\n            option(\"-c\", \"--compress\") % \"compress database in-memory\",\n            option(\"-u\", \"--unique\")   % \"keep only unique entries\",\n            option(\"-m\", \"--memlimit\") % \"max. size in RAM\" \u0026 value(\"size\")\n        )\n    )\n);\n\nauto fmt = doc_formatting{} .first_column(4) .doc_column(28) .last_column(80);\n\ncout \u003c\u003c make_man_page(cli, \"worddb\", fmt)\n    .prepend_section(\"DESCRIPTION\", \"    Builds a database of words from text files.\")\n    .append_section(\"LICENSE\", \"    GPL3\") \u003c\u003c '\\n';\n```\n\n\n#### Formatting Options\n```cpp\n//all formatting options (with their default values)\nauto fmt = doc_formatting{}\n    .first_column(8)                           //left border column for text body\n    .doc_column(20)                            //column where parameter docstring starts\n    .last_column(100)                          //right border column for text body\n    .indent_size(4)                            //indent of documentation lines for children of a documented group\n    .line_spacing(0)                           //number of empty lines after single documentation lines\n    .paragraph_spacing(1)                      //number of empty lines before and after paragraphs\n    .flag_separator(\", \")                      //between flags of the same parameter\n    .param_separator(\" \")                      //between parameters \n    .group_separator(\" \")                      //between groups (in usage)\n    .alternative_param_separator(\"|\")          //between alternative flags \n    .alternative_group_separator(\" | \")        //between alternative groups \n    .surround_group(\"(\", \")\")                  //surround groups with these \n    .surround_alternatives(\"(\", \")\")           //surround group of alternatives with these\n    .surround_alternative_flags(\"\", \"\")        //surround alternative flags with these\n    .surround_joinable(\"(\", \")\")               //surround group of joinable flags with these\n    .surround_optional(\"[\", \"]\")               //surround optional parameters with these\n    .surround_repeat(\"\", \"...\")                //surround repeatable parameters with these\n    .surround_value(\"\u003c\", \"\u003e\")                  //surround values with these\n    .empty_label(\"\")                           //used if parameter has no flags and no label\n    .max_flags_per_param_in_usage(1)           //max. # of flags per parameter in usage\n    .max_flags_per_param_in_doc(32)            //max. # of flags per parameter in detailed documentation\n    .split_alternatives(true)                  //split usage into several lines for large alternatives\n    .alternatives_min_split_size(3)            //min. # of parameters for separate usage line\n    .merge_alternative_flags_with_common_prefix(false)  //-ab(cdxy|xy) instead of -abcdxy|-abxy\n    .merge_joinable_flags_with_common_prefix(true)     //-abc instead of -a -b -c\n    .ignore_newline_chars(false)               //ignore '\\n' in docstrings\n    ;\n\ncout \u003c\u003c \"Usage:\\n\" \u003c\u003c usage_lines(cli, \"progname\", fmt)\n     \u003c\u003c \"\\nOptions:\\n\" \u003c\u003c documentation(cli, fmt) \u003c\u003c '\\n';\n\n//or generate entire man page in one go\ncout \u003c\u003c make_man_page(cli, \"progname\", fmt)\n        .prepend_section(\"DESCRIPTION\", \"This program lets you format text.\")\n        .append_section(\"LICENSE\", \"GPLv3\");\n```\n\n\n\n### Documentation Filtering\n\nThe documentation generator class ```documentation``` can also take an additional third constructor argument that allows to filter parameters according to their properties.\n\n```cpp\nint main(int argc, char* argv[]) {\n    auto cli = (\n        value(\"input file\"),\n        option(\"-r\", \"--recursive\").set(rec).doc(\"convert files recursively\"),\n        option(\"-o\") \u0026 value(\"output format\", fmt),\n        option(\"-utf16\").set(utf16).doc(\"use UTF-16 encoding\")\n    );\n\n    auto fmt = doc_formatting{}.doc_column(28);\n\n    auto filter = param_filter{}.prefix(\"--\");\n\n    cout \u003c\u003c \"Usage:\\n\" \u003c\u003c usage_lines(cli, argv[0]) \u003c\u003c \"\\n\\n\"\n         \u003c\u003c \"Parameters:\\n\" \u003c\u003c documentation(cli, fmt, filter) \u003c\u003c '\\n';}\n```\n\nWhich results in:\n```man\nUsage:\n        convert \u003cinput file\u003e [-r] [-o \u003coutput format\u003e] [-utf16]\n\nParameters:\n        -r, --recursive    convert files recursively\n```\n\n#### Parameter Filters\n\nAny function/lambda that maps a parameter to a bool can be used as filter \npredicate. CLIPP also comes with a default parameter filter class:\n```cpp\n//all param_filter options (with their default values)\nauto filter = param_filter{}\n    .prefix(\"\")               //only parameters with given prefix\n    .required(tri::either)    //required parameters \n    .blocking(tri::either)    //blocking/positional parameters\n    .repeatable(tri::either)  //repeatable parameters\n    .has_doc(tri::yes)        //parameters with/without docstrings\n    ;\n```\nwhich uses a dedicated tristate type:\n```cpp\nnamespace clipp {\n   enum class tri { no, yes, either };\n}\n```\n\n\n## Motivation\nWell, I didn't find a library that makes building simple command line interfaces simple, yet can also be used to build complex CLIs. I really don't want to write 20 lines of boilerplate just to have 3 simple command line options. I also don't want to drag along monstrosities like boost or Qt for that. Over time, *clipp* evolved into a domain specific language (in pure C++) that I hope can at least somewhat approach the readability of [docopt] but can leverage the benefits (toolability, etc.) of C++'s type system.\n\n\n#### Other libraries (Boost, POCO, Qt, adishavit/Argh, Taywee/args ... or 'getopt')\n - often involve a lot of boilerplate (also for very simple use cases) \n - Some libs might be okay in terms of usability, but don't let you build complex interfaces\n   with nested alternatives, mixed commands \u0026 options, positional values, more than 2 flags per option, etc.\n - I really like ad-hoc parsers like [Argh](https://github.com/adishavit/argh) for their simplicity, but they don't generate usage / man pages and don't allow complex interfaces with error checking.\n - Most libs make it really hard to figure out the resulting command line interface by looking at the code (OK, you be the judge if I did a better job at this...).\n - Some libs come with a ton of dependencies (Qt, Boost). I want a single header file!\n - Some libs require the separation of code related to one command/option. I find this harder to maintain than having everything related to one option in one place.\n - Sometimes flag strings of commands/options have to be repeated several times over.\n - Many libs come with restrictions regarding flag names, formatting, joinability, etc.\n\n\n#### What about [docopt]?\nI like the basic idea, but I don't like redundancy in code, especially if it involves repeating string literals. Docopt generates a command line argument parser from a \"man page docstring\". After parsing, you have to query a dictionary to get values or check for option presence. That means you either have to mention the same flag names twice (in the docstring *and* in the query) or you have to use string variables which makes the docstring hard to read and kind of defeats the purpose of docopt. Furthermore, the code tends to be littered with string-to-whatever conversions.\n\nI also wanted the ability to keep *everything* related to one option/command/value together in the code which I found very useful for programs with lots of command line options. Docopt doesn't let you do that since the interface definition and the code performing any actions is always separated (unless you give up on the \"beautiful doc page\" idea at the heart of docopt and build your input string to the parser generator piece-by-piece).\n\n\n\n\n## Design Goals\n - minimize boilerplate \n - simple code for simple use cases\n - good code readability (as far as C++ allows for it)\n - avoid ambiguities \n - eliminate repetitions\n - ability to keep code related to one option/command/value together \n - support many different command line interface conventions\n - support different coding styles, conventions \u0026 tastes\n - value semantics wherever possible\n - do not break clipp's general interface and conventions in the future\n\n\n\n\n## Requirements\n  - requires a mostly C++11 conforming compiler\n\n### Compilers, clipp compiles with\n  - g++ 5.3.0, g++ 5.4.1, g++ 6, g++ 7\n  - clang++ 3.8, clang++ 3.9, clang++ 4.0, clang++ 5.0\n  - MSVC 14.11.25503 (compiler 19.11.25547)\n\n\n\n\n## Feedback\nI would be delighted to hear from anyone who uses *clipp* in their project(s). If you find bugs or design flaws or want to suggest improvements please open an issue or submit a pull request.\n\n\n\n\n## Development\n*clipp* is still very young, so I probably won't add new features any time soon and rather:\n - fix bugs \n - improve test cases and coverage\n - add more code documentation \n - clean up the code / make it more understandable\n - add the ability to use other string classes \n\n\n[docopt]: http://docopt.org\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmuellan%2Fclipp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmuellan%2Fclipp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmuellan%2Fclipp/lists"}