├── .gitignore ├── .github └── workflows │ └── test.yml ├── Makefile ├── LICENSE ├── README.md ├── test.sh ├── t └── testprog ├── testprog.cpp ├── OptionParser.h └── OptionParser.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | /testprog 3 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | push: 4 | schedule: 5 | - cron: '0 0 1 * *' # monthly 6 | jobs: 7 | linux: 8 | runs-on: ubuntu-latest 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | compiler: [gcc, clang] 13 | cpp11: [0, 1] 14 | steps: 15 | - uses: actions/checkout@v3 16 | - run: make test WARN=1 17 | env: 18 | CC: ${{ matrix.compiler }} 19 | CPP11: ${{ matrix.cpp11 }} 20 | macos: 21 | runs-on: macos-latest 22 | steps: 23 | - uses: actions/checkout@v3 24 | - run: make test WARN=1 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(WARN),1) 2 | ifeq ($(CXX),g++) 3 | WARN_FLAGS = -O3 -g -Wall -Wextra -Werror # -Weffc++ 4 | else ifeq ($(CXX),clang++) 5 | WARN_FLAGS = -O3 -g -Wall -Wextra -Werror 6 | else ifeq ($(CXX),icpc) 7 | WARN_FLAGS = -O3 -ipo -g -Wall -wd981 -wd383 -wd2259 -Werror # -Weffc++ 8 | endif 9 | endif 10 | 11 | ifeq ($(CPP11),1) 12 | STD_FLAGS = -std=c++0x 13 | endif 14 | 15 | BIN = testprog 16 | OBJECTS = OptionParser.o testprog.o 17 | 18 | $(BIN): $(OBJECTS) 19 | $(CXX) -o $@ $(OBJECTS) $(WARN_FLAGS) $(STD_FLAGS) $(LINKFLAGS) 20 | 21 | %.o: %.cpp OptionParser.h 22 | $(CXX) $(WARN_FLAGS) $(STD_FLAGS) $(CXXFLAGS) -c $< -o $@ 23 | 24 | .PHONY: clean test 25 | 26 | test: testprog 27 | ./test.sh 28 | 29 | clean: 30 | rm -f *.o $(BIN) 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2010 Johannes Weißl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cpp-optparse 2 | 3 | This is yet another option parser for C++. It is modelled after the excellent 4 | Python optparse API. Although incomplete, anyone familiar to 5 | [optparse](http://docs.python.org/library/optparse.html) should feel at home. 6 | 7 | - Copyright (c) 2010 Johannes Weißl 8 | - License: MIT License 9 | 10 | ## Design decisions 11 | 12 | - Elegant and easy usage more important than speed / flexibility 13 | - Small size more important than feature completeness, e.g.: 14 | * No unicode 15 | * No checking for user programming errors 16 | * No conflict handlers 17 | * No adding of new actions 18 | 19 | ## FAQ 20 | 21 | - Why not use getopt/getopt_long? 22 | * Not C++ / not completely POSIX 23 | * Too cumbersome to use, would need lot of additional code 24 | - Why not use Boost.Program_options? 25 | * Boost not installed on all target platforms (esp. cluster, HPC, ...) 26 | * Too big to include just for option handling for many projects: 27 | 322 *.h (44750 lines) + 7 *.cpp (2078 lines) 28 | - Why not use tclap/Opag/Options/CmdLine/Anyoption/Argument_helper/...? 29 | * Similarity to Python desired for faster learning curve 30 | 31 | ## Future work 32 | 33 | - Support nargs > 1? 34 | 35 | ## Example 36 | 37 | ```cpp 38 | using optparse::OptionParser; 39 | 40 | OptionParser parser = OptionParser() .description("just an example"); 41 | 42 | parser.add_option("-f", "--file") .dest("filename") 43 | .help("write report to FILE") .metavar("FILE"); 44 | parser.add_option("-q", "--quiet") 45 | .action("store_false") .dest("verbose") .set_default("1") 46 | .help("don't print status messages to stdout"); 47 | 48 | optparse::Values options = parser.parse_args(argc, argv); 49 | vector args = parser.args(); 50 | 51 | if (options.get("verbose")) 52 | cout << options["filename"] << endl; 53 | ``` 54 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- mode: sh; coding: utf-8; indent-tabs-mode: nil -*- 3 | # vim: set filetype=sh fileencoding=utf-8 expandtab sw=4 sts=4: 4 | 5 | export COLUMNS=80 6 | 7 | c () { 8 | echo "$(printf "%q " ./testprog "$@")" 9 | local t_stdout_cpp=$(mktemp -t cpp-stdout-optparse.XXXXXXXXXX) 10 | local t_stderr_cpp=$(mktemp -t cpp-stderr-optparse.XXXXXXXXXX) 11 | local t_stdout_pyt=$(mktemp -t pyt-stdout-optparse.XXXXXXXXXX) 12 | local t_stderr_pyt=$(mktemp -t pyt-stderr-optparse.XXXXXXXXXX) 13 | ./testprog "$@" >"$t_stdout_cpp" 2>"$t_stderr_cpp" 14 | status_cpp=$? 15 | ./t/testprog "$@" >"$t_stdout_pyt" 2>"$t_stderr_pyt" 16 | status_pyt=$? 17 | if ! cmp -s "$t_stderr_cpp" "$t_stderr_pyt" ; then 18 | diff -au "$t_stderr_cpp" "$t_stderr_pyt" 19 | exit 1 20 | fi 21 | rm -f "$t_stderr_cpp" "$t_stderr_pyt" 22 | if ! cmp -s "$t_stdout_cpp" "$t_stdout_pyt" ; then 23 | diff -au "$t_stdout_cpp" "$t_stdout_pyt" 24 | exit 1 25 | fi 26 | rm -f "$t_stdout_cpp" "$t_stdout_pyt" 27 | if [[ $status_cpp -ne $status_pyt ]] ; then 28 | echo >&2 "status $status_pyt expected, got $status_cpp" 29 | exit 1 30 | fi 31 | } 32 | 33 | c 34 | c --str # ambiguous option 35 | c -Z # unknown argument 36 | c --argument-does-not-exist 37 | c --version 38 | c -h 39 | c --help 40 | c "foo bar" baz "" 41 | c --clear 42 | c --no-clear 43 | c --clear --no-clear 44 | c --clear --no-clear --clear 45 | c --string "foo bar" 46 | c -n # requires argument 47 | c --string # requires argument 48 | c -x foo 49 | c --clause foo 50 | c --sentence foo 51 | c -k -k -k -k -k 52 | c --verbose 53 | c -s 54 | c --silent 55 | c -v -s 56 | c -n-10 57 | c -n 300 58 | c --number=0 59 | c -H 60 | c -V 61 | c -i-10 62 | c -i 300 63 | c --int=0 64 | # c -i 2.3 # TODO: ignores suffix 65 | c -i no-number 66 | c -f-2.3 67 | c -f 300 68 | c --float=0 69 | c -f no-number 70 | c -c-2.3 71 | c -c 300 72 | c --complex=0 73 | c -c no-number 74 | c -C foo 75 | c --choices baz 76 | c -C wrong-choice 77 | c --choices-list item2 78 | c --choices-list wrong-item 79 | c -m a -m b 80 | c -m a --more b -m c 81 | c --more-milk --more-milk 82 | c --hidden foo 83 | c -K -K -K 84 | c --string-callback x 85 | c --no-clear foo bar -k -k z -v -n3 "x y" -i 8 -f 3.2 -c 2 86 | DISABLE_INTERSPERSED_ARGS=1 c -k a -k b 87 | DISABLE_USAGE=1 c --argument-does-not-exist 88 | DISABLE_USAGE=1 c --help 89 | -------------------------------------------------------------------------------- /t/testprog: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- mode: python; coding: utf-8; indent-tabs-mode: nil -*- 3 | # vim: set filetype=python fileencoding=utf-8 expandtab sw=4 sts=4: 4 | 5 | import os 6 | from optparse import OptionParser, OptionGroup, SUPPRESS_HELP, SUPPRESS_USAGE 7 | 8 | class MyCallback: 9 | def __init__(self): 10 | self.counter = 0 11 | def __call__(self, option, opt, val, parser): 12 | self.counter += 1 13 | print("--- MyCallback --- " + str(self.counter) + ". time called") 14 | print("--- MyCallback --- option.action(): " + option.action) 15 | print("--- MyCallback --- option.type(): " + (option.type if option.type else "")) 16 | print("--- MyCallback --- opt: " + opt) 17 | print("--- MyCallback --- val: " + (val if val else "")) 18 | print("--- MyCallback --- parser.usage(): " + parser.usage) 19 | print() 20 | 21 | def main(): 22 | usage = \ 23 | "usage: %prog [OPTION]... DIR [FILE]..." \ 24 | if "DISABLE_USAGE" not in os.environ else \ 25 | SUPPRESS_USAGE 26 | version = ( 27 | "%prog 1.0\nCopyright (C) 2010 Johannes Weißl\n" 28 | "License GPLv3+: GNU GPL version 3 or later " 29 | ".\n" 30 | "This is free software: you are free to change and redistribute it.\n" 31 | "There is NO WARRANTY, to the extent permitted by law." 32 | ) 33 | desc = ( 34 | "Lorem ipsum dolor sit amet, consectetur adipisicing" 35 | " elit, sed do eiusmod tempor incididunt ut labore et dolore magna" 36 | " aliqua.\nUt enim ad minim veniam, quis nostrud exercitation ullamco" 37 | " laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor" 38 | " in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla" 39 | " pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa" 40 | " qui officia deserunt mollit anim id est laborum." 41 | ) 42 | epilog = ( 43 | "Sed ut perspiciatis unde omnis iste natus error sit" 44 | " voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque" 45 | " ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae" 46 | " dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit" 47 | " aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos" 48 | " qui ratione voluptatem sequi nesciunt.\nNeque porro quisquam est, qui" 49 | " dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia" 50 | " non numquam eius modi tempora incidunt ut labore et dolore magnam" 51 | " aliquam quaerat voluptatem." 52 | ) 53 | 54 | parser = OptionParser( 55 | usage=usage, 56 | version=version, 57 | description=desc, 58 | epilog=epilog 59 | ) 60 | if "DISABLE_INTERSPERSED_ARGS" in os.environ: 61 | parser.disable_interspersed_args() 62 | 63 | parser.set_defaults(verbosity="50") 64 | parser.set_defaults(no_clear=False) 65 | 66 | parser.add_option("--clear", action="store_false", dest="no_clear", help="clear (default)") 67 | parser.add_option("--no-clear", action="store_true", help="not clear") 68 | parser.add_option("--string", 69 | help="This is a really long text... very long indeed! It must be wrapped on normal terminals.") 70 | parser.add_option("-x", "--clause", "--sentence", metavar="SENTENCE", default="I'm a sentence", 71 | help="This is a really long text... very long indeed! It must be wrapped on normal terminals. " 72 | "Also it should appear not on the same line as the option.") 73 | parser.add_option("-k", action="count", help="how many times?") 74 | parser.add_option("--verbose", action="store_const", const="100", dest="verbosity", help="be verbose!") 75 | parser.add_option("-s", "--silent", action="store_const", const="0", dest="verbosity", help="be silent!") 76 | parser.add_option("-n", "--number", type="int", default=1, metavar="NUM", help="number of files (default: %default)") 77 | parser.add_option("-H", action="help", help="alternative help") 78 | parser.add_option("-V", action="version", help="alternative version") 79 | parser.add_option("-i", "--int", action="store", type="int", default=3, help="default: %default") 80 | parser.add_option("-f", "--float", action="store", type="float", default=5.3, help="default: %default") 81 | parser.add_option("-c", "--complex", action="store", type="complex") 82 | choices = ["foo", "bar", "baz"] 83 | parser.add_option("-C", "--choices", choices=choices) 84 | choices_list = ["item1", "item2", "item3"] 85 | parser.add_option("--choices-list", choices=choices_list) 86 | parser.add_option("-m", "--more", action="append") 87 | parser.add_option("--more-milk", action="append_const", const="milk") 88 | parser.add_option("--hidden", help=SUPPRESS_HELP) 89 | 90 | # test for 325cb47 91 | parser.add_option("--option1", action="store", type="int", default=1) 92 | parser.add_option("--option2", action="store", type="int", default="1") 93 | parser.set_defaults(option1="640") 94 | parser.set_defaults(option2=640) # now works 95 | 96 | mc = MyCallback() 97 | parser.add_option("-K", "--callback", action="callback", callback=mc, help="callback test") 98 | parser.add_option("--string-callback", action="callback", callback=mc, type="string", help="callback test") 99 | 100 | group1 = OptionGroup(parser, "Dangerous Options", 101 | "Caution: use these options at your own risk. " 102 | "It is believed that some of them\nbite.") 103 | group1.add_option("-g", action="store_true", help="Group option.", default=False) 104 | parser.add_option_group(group1) 105 | 106 | group2 = OptionGroup(parser, "Size Options", "Image Size Options.") 107 | group2.add_option("-w", "--width", action="store", type="int", default=640, help="default: %default") 108 | group2.add_option("--height", action="store", type="int", help="default: %default") 109 | parser.set_defaults(height=480) 110 | parser.add_option_group(group2) 111 | 112 | options, args = parser.parse_args() 113 | 114 | print("clear:", ("false" if options.no_clear else "true")) 115 | print("string:", options.string if options.string else "") 116 | print("clause:", options.clause) 117 | print("k:", options.k if options.k else "") 118 | print("verbosity:", options.verbosity) 119 | print("number:", options.number) 120 | print("int:", options.int) 121 | print("float: %g" % (options.float,)) 122 | c = complex(0) 123 | if options.complex is not None: 124 | c = options.complex 125 | print("complex: (%g,%g)" % (c.real, c.imag)) 126 | print("choices:", options.choices if options.choices else "") 127 | print("choices-list:", options.choices_list if options.choices_list else "") 128 | print("more: ", end="") 129 | print(", ".join(options.more if options.more else [])) 130 | 131 | print("more_milk:") 132 | for opt in (options.more_milk if options.more_milk else []): 133 | print("-", opt) 134 | 135 | print("hidden:", options.hidden if options.hidden else "") 136 | print("group:", ("true" if options.g else "false")) 137 | 138 | print("option1:", options.option1) 139 | print("option2:", options.option2) 140 | 141 | print("width:", options.width) 142 | print("height:", options.height) 143 | 144 | print() 145 | print("leftover arguments: ") 146 | for arg in args: 147 | print("arg: " + arg) 148 | 149 | return 0 150 | 151 | if __name__ == "__main__": 152 | main() 153 | -------------------------------------------------------------------------------- /testprog.cpp: -------------------------------------------------------------------------------- 1 | #include "OptionParser.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | using namespace optparse; 13 | 14 | class Output { 15 | public: 16 | Output(stringstream& ss, const string& d) : stream(ss), delim(d), first(true) {} 17 | void operator() (const string& s) { 18 | if (first) 19 | first = false; 20 | else 21 | stream << delim; 22 | stream << s; 23 | } 24 | stringstream& stream; 25 | const string& delim; 26 | bool first; 27 | }; 28 | 29 | class MyCallback : public optparse::Callback { 30 | public: 31 | MyCallback() : counter(0) {} 32 | void operator() (const Option& option, const string& opt, const string& val, const OptionParser& parser) { 33 | counter++; 34 | cout << "--- MyCallback --- " << counter << ". time called" << endl; 35 | cout << "--- MyCallback --- option.action(): " << option.action() << endl; 36 | cout << "--- MyCallback --- option.type(): " << option.type() << endl; 37 | cout << "--- MyCallback --- opt: " << opt << endl; 38 | cout << "--- MyCallback --- val: " << val << endl; 39 | cout << "--- MyCallback --- parser.usage(): " << parser.usage() << endl; 40 | cout << endl; 41 | } 42 | int counter; 43 | }; 44 | 45 | int main(int argc, char *argv[]) 46 | { 47 | const string usage = 48 | (!getenv("DISABLE_USAGE")) ? 49 | "usage: %prog [OPTION]... DIR [FILE]..." : SUPPRESS_USAGE; 50 | const string version = "%prog 1.0\nCopyright (C) 2010 Johannes Weißl\n" 51 | "License GPLv3+: GNU GPL version 3 or later " 52 | ".\n" 53 | "This is free software: you are free to change and redistribute it.\n" 54 | "There is NO WARRANTY, to the extent permitted by law."; 55 | const string desc = "Lorem ipsum dolor sit amet, consectetur adipisicing" 56 | " elit, sed do eiusmod tempor incididunt ut labore et dolore magna" 57 | " aliqua.\nUt enim ad minim veniam, quis nostrud exercitation ullamco" 58 | " laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor" 59 | " in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla" 60 | " pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa" 61 | " qui officia deserunt mollit anim id est laborum."; 62 | const string epilog = "Sed ut perspiciatis unde omnis iste natus error sit" 63 | " voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque" 64 | " ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae" 65 | " dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit" 66 | " aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos" 67 | " qui ratione voluptatem sequi nesciunt.\nNeque porro quisquam est, qui" 68 | " dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia" 69 | " non numquam eius modi tempora incidunt ut labore et dolore magnam" 70 | " aliquam quaerat voluptatem."; 71 | 72 | OptionParser parser = OptionParser() 73 | .usage(usage) 74 | .version(version) 75 | .description(desc) 76 | .epilog(epilog) 77 | ; 78 | if (getenv("DISABLE_INTERSPERSED_ARGS")) 79 | parser.disable_interspersed_args(); 80 | 81 | parser.set_defaults("verbosity", "50"); 82 | parser.set_defaults("no_clear", "0"); 83 | 84 | // test all actions 85 | parser.add_option("--clear") .action("store_false") .dest("no_clear") .help("clear (default)"); 86 | parser.add_option("--no-clear") .action("store_true") .help("not clear"); 87 | parser.add_option("--string") 88 | .help("This is a really long text... very long indeed! It must be wrapped on normal terminals."); 89 | parser.add_option("-x", "--clause", "--sentence") .metavar("SENTENCE") .set_default("I'm a sentence") 90 | .help("This is a really long text... very long indeed! It must be wrapped on normal terminals. " 91 | "Also it should appear not on the same line as the option."); 92 | parser.add_option("-k") .action("count") .help("how many times?"); 93 | parser.add_option("--verbose") .action("store_const") .set_const("100") .dest("verbosity") .help("be verbose!"); 94 | parser.add_option("-s", "--silent") .action("store_const") .set_const("0") .dest("verbosity") .help("be silent!"); 95 | parser.add_option("-n", "--number") .type("int") .set_default("1") .metavar("NUM") .help("number of files (default: %default)"); 96 | parser.add_option("-H") .action("help") .help("alternative help"); 97 | parser.add_option("-V") .action("version") .help("alternative version"); 98 | parser.add_option("-i", "--int") .action("store") .type("int") .set_default(3) .help("default: %default"); 99 | parser.add_option("-f", "--float") .action("store") .type("float") .set_default(5.3) .help("default: %default"); 100 | parser.add_option("-c", "--complex") .action("store") .type("complex"); 101 | char const* const choices[] = { "foo", "bar", "baz" }; 102 | parser.add_option("-C", "--choices") .choices(&choices[0], &choices[3]); 103 | #if __cplusplus >= 201103L 104 | parser.add_option("--choices-list") .choices({"item1", "item2", "item3"}); 105 | #else 106 | char const* const choices_list[] = { "item1", "item2", "item3" }; 107 | parser.add_option("--choices-list") .choices(&choices_list[0], &choices_list[3]); 108 | #endif 109 | parser.add_option("-m", "--more") .action("append"); 110 | parser.add_option("--more-milk") .action("append_const") .set_const("milk"); 111 | parser.add_option("--hidden") .help(SUPPRESS_HELP); 112 | 113 | // test for 325cb47 114 | parser.add_option("--option1") .action("store") .type("int") .set_default(1); 115 | parser.add_option("--option2") .action("store") .type("int") .set_default("1"); 116 | parser.set_defaults("option1", "640"); 117 | parser.set_defaults("option2", 640); // now works 118 | 119 | MyCallback mc; 120 | parser.add_option("-K", "--callback") .action("callback") .callback(mc) .help("callback test"); 121 | parser.add_option("--string-callback") .action("callback") .callback(mc) .type("string") .help("callback test"); 122 | 123 | OptionGroup group1 = OptionGroup(parser, "Dangerous Options", 124 | "Caution: use these options at your own risk. " 125 | "It is believed that some of them\nbite."); 126 | group1.add_option("-g") .action("store_true") .help("Group option.") .set_default("0"); 127 | parser.add_option_group(group1); 128 | 129 | OptionGroup group2 = OptionGroup(parser, "Size Options", "Image Size Options."); 130 | group2.add_option("-w", "--width") .action("store") .type("int") .set_default(640) .help("default: %default"); 131 | group2.add_option("--height") .action("store") .type("int") .help("default: %default"); 132 | parser.set_defaults("height", 480); 133 | parser.add_option_group(group2); 134 | 135 | try { 136 | Values& options = parser.parse_args(argc, argv); 137 | vector args = parser.args(); 138 | 139 | cout << "clear: " << (options.get("no_clear") ? "false" : "true") << endl; 140 | cout << "string: " << options["string"] << endl; 141 | cout << "clause: " << options["clause"] << endl; 142 | cout << "k: " << options["k"] << endl; 143 | cout << "verbosity: " << options["verbosity"] << endl; 144 | cout << "number: " << (int) options.get("number") << endl; 145 | cout << "int: " << (int) options.get("int") << endl; 146 | cout << "float: " << (float) options.get("float") << endl; 147 | complex c = 0; 148 | if (options.is_set("complex")) { 149 | stringstream ss; 150 | ss << options["complex"]; 151 | ss >> c; 152 | } 153 | cout << "complex: " << c << endl; 154 | cout << "choices: " << (const char*) options.get("choices") << endl; 155 | cout << "choices-list: " << (const char*) options.get("choices_list") << endl; 156 | { 157 | stringstream ss; 158 | for_each(options.all("more").begin(), options.all("more").end(), Output(ss, ", ")); 159 | cout << "more: " << ss.str() << endl; 160 | } 161 | cout << "more_milk:" << endl; 162 | for (Values::iterator it = options.all("more_milk").begin(); it != options.all("more_milk").end(); ++it) 163 | cout << "- " << *it << endl; 164 | cout << "hidden: " << options["hidden"] << endl; 165 | cout << "group: " << (options.get("g") ? "true" : "false") << endl; 166 | 167 | cout << "option1: " << (int) options.get("option1") << std::endl; 168 | cout << "option2: " << (int) options.get("option2") << std::endl; 169 | 170 | cout << "width: " << (int) options.get("width") << std::endl; 171 | cout << "height: " << (int) options.get("height") << std::endl; 172 | 173 | cout << endl << "leftover arguments: " << endl; 174 | for (vector::const_iterator it = args.begin(); it != args.end(); ++it) { 175 | cout << "arg: " << *it << endl; 176 | } 177 | } 178 | catch(int ex) { 179 | return ex; 180 | } 181 | 182 | return 0; 183 | } 184 | -------------------------------------------------------------------------------- /OptionParser.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2010 Johannes Weißl 3 | * License: MIT License 4 | * URL: https://github.com/weisslj/cpp-optparse 5 | */ 6 | 7 | #ifndef OPTIONPARSER_H_ 8 | #define OPTIONPARSER_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace optparse { 19 | 20 | class OptionParser; 21 | class OptionGroup; 22 | class Option; 23 | class Values; 24 | class Value; 25 | class Callback; 26 | 27 | typedef std::map strMap; 28 | typedef std::map > lstMap; 29 | typedef std::map optMap; 30 | 31 | const char* const SUPPRESS_HELP = "SUPPRESS" "HELP"; 32 | const char* const SUPPRESS_USAGE = "SUPPRESS" "USAGE"; 33 | 34 | //! Class for automatic conversion from string -> anytype 35 | class Value { 36 | public: 37 | Value() : str(), valid(false) {} 38 | Value(const std::string& v) : str(v), valid(true) {} 39 | operator const char*() { return str.c_str(); } 40 | operator bool() { bool t; return (valid && (std::istringstream(str) >> t)) ? t : false; } 41 | operator short() { short t; return (valid && (std::istringstream(str) >> t)) ? t : 0; } 42 | operator unsigned short() { unsigned short t; return (valid && (std::istringstream(str) >> t)) ? t : 0; } 43 | operator int() { int t; return (valid && (std::istringstream(str) >> t)) ? t : 0; } 44 | operator unsigned int() { unsigned int t; return (valid && (std::istringstream(str) >> t)) ? t : 0; } 45 | operator long() { long t; return (valid && (std::istringstream(str) >> t)) ? t : 0; } 46 | operator unsigned long() { unsigned long t; return (valid && (std::istringstream(str) >> t)) ? t : 0; } 47 | operator float() { float t; return (valid && (std::istringstream(str) >> t)) ? t : 0; } 48 | operator double() { double t; return (valid && (std::istringstream(str) >> t)) ? t : 0; } 49 | operator long double() { long double t; return (valid && (std::istringstream(str) >> t)) ? t : 0; } 50 | private: 51 | const std::string str; 52 | bool valid; 53 | }; 54 | 55 | class Values { 56 | public: 57 | Values() : _map() {} 58 | const std::string& operator[] (const std::string& d) const; 59 | std::string& operator[] (const std::string& d) { return _map[d]; } 60 | bool is_set(const std::string& d) const { return _map.find(d) != _map.end(); } 61 | bool is_set_by_user(const std::string& d) const { return _userSet.find(d) != _userSet.end(); } 62 | void is_set_by_user(const std::string& d, bool yes); 63 | Value get(const std::string& d) const { return (is_set(d)) ? Value((*this)[d]) : Value(); } 64 | 65 | typedef std::list::iterator iterator; 66 | typedef std::list::const_iterator const_iterator; 67 | std::list& all(const std::string& d) { return _appendMap[d]; } 68 | const std::list& all(const std::string& d) const { return _appendMap.find(d)->second; } 69 | 70 | private: 71 | strMap _map; 72 | lstMap _appendMap; 73 | std::set _userSet; 74 | }; 75 | 76 | class Option { 77 | public: 78 | Option(const OptionParser& p) : 79 | _parser(p), _action("store"), _type("string"), _nargs(1), _callback(0) {} 80 | virtual ~Option() {} 81 | 82 | Option& action(const std::string& a); 83 | Option& type(const std::string& t); 84 | Option& dest(const std::string& d) { _dest = d; return *this; } 85 | Option& set_default(const std::string& d) { _default = d; return *this; } 86 | template 87 | Option& set_default(T t) { std::ostringstream ss; ss << t; _default = ss.str(); return *this; } 88 | Option& nargs(size_t n) { _nargs = n; return *this; } 89 | Option& set_const(const std::string& c) { _const = c; return *this; } 90 | template 91 | Option& choices(InputIterator begin, InputIterator end) { 92 | _choices.assign(begin, end); type("choice"); return *this; 93 | } 94 | #if __cplusplus >= 201103L 95 | Option& choices(std::initializer_list ilist) { 96 | _choices.assign(ilist); type("choice"); return *this; 97 | } 98 | #endif 99 | Option& help(const std::string& h) { _help = h; return *this; } 100 | Option& metavar(const std::string& m) { _metavar = m; return *this; } 101 | Option& callback(Callback& c) { _callback = &c; return *this; } 102 | 103 | const std::string& action() const { return _action; } 104 | const std::string& type() const { return _type; } 105 | const std::string& dest() const { return _dest; } 106 | const std::string& get_default() const; 107 | size_t nargs() const { return _nargs; } 108 | const std::string& get_const() const { return _const; } 109 | const std::list& choices() const { return _choices; } 110 | const std::string& help() const { return _help; } 111 | const std::string& metavar() const { return _metavar; } 112 | Callback* callback() const { return _callback; } 113 | 114 | private: 115 | std::string check_type(const std::string& opt, const std::string& val) const; 116 | std::string format_option_help(unsigned int indent = 2) const; 117 | std::string format_help(unsigned int indent = 2) const; 118 | 119 | const OptionParser& _parser; 120 | 121 | std::set _short_opts; 122 | std::set _long_opts; 123 | 124 | std::string _action; 125 | std::string _type; 126 | std::string _dest; 127 | std::string _default; 128 | size_t _nargs; 129 | std::string _const; 130 | std::list _choices; 131 | std::string _help; 132 | std::string _metavar; 133 | Callback* _callback; 134 | 135 | friend class OptionContainer; 136 | friend class OptionParser; 137 | }; 138 | 139 | class OptionContainer { 140 | public: 141 | OptionContainer(const std::string& d = "") : _description(d) {} 142 | virtual ~OptionContainer() {} 143 | 144 | virtual OptionContainer& description(const std::string& d) { _description = d; return *this; } 145 | virtual const std::string& description() const { return _description; } 146 | 147 | Option& add_option(const std::string& opt); 148 | Option& add_option(const std::string& opt1, const std::string& opt2); 149 | Option& add_option(const std::string& opt1, const std::string& opt2, const std::string& opt3); 150 | Option& add_option(const std::vector& opt); 151 | 152 | std::string format_option_help(unsigned int indent = 2) const; 153 | 154 | protected: 155 | std::string _description; 156 | 157 | std::list