pax_global_header00006660000000000000000000000064141500011440014500gustar00rootroot0000000000000052 comment=ee74d1b53bd680748af14e737378de57e2a0a954 libavif-0.0~git20211125.ee74d1b/000077500000000000000000000000001415000114400156255ustar00rootroot00000000000000libavif-0.0~git20211125.ee74d1b/.gitignore000066400000000000000000000000061415000114400176110ustar00rootroot00000000000000build libavif-0.0~git20211125.ee74d1b/.travis.yml000066400000000000000000000010631415000114400177360ustar00rootroot00000000000000language: cpp dist: trusty #Ubuntu 14.04 by default sudo: false #Use container based infrastructure matrix: include: #Extensive testing for base compiler - env: MATRIX_EVAL="CC=gcc-5 CXX=g++-5" addons: { apt: { packages: ["cmake", "g++-5"], sources: ["ubuntu-toolchain-r-test"] } } before_install: - eval "${MATRIX_EVAL}" #Set compiler versions - echo $CC - echo $CXX script: #Build - mkdir -p build - pushd build - cmake .. - make -j2 #Test - ./argparse_example -h - ./argparse_test libavif-0.0~git20211125.ee74d1b/CMakeLists.txt000066400000000000000000000032441415000114400203700ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.9) project("libargparse") if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) #Only set compiler settings if we are not a sub-project set(WARN_FLAGS "-Wall -Wextra -Wpedantic -Wcast-qual -Wcast-align -Wshadow -Wformat=2 -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wredundant-decls -Wswitch-default -Wundef -Wunused-variable -Wdisabled-optimization -Wnoexcept -Woverloaded-virtual -Wctor-dtor-privacy -Wnon-virtual-dtor") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++14 ${WARN_FLAGS}") #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize=leak -fsanitize=undefined") set(FLEX_BISON_WARN_SUPPRESS_FLAGS "-Wno-switch-default -Wno-unused-parameter -Wno-missing-declarations") endif() set(LIB_INCLUDE_DIRS src) file(GLOB_RECURSE LIB_SOURCES src/*.cpp) file(GLOB_RECURSE LIB_HEADERS src/*.hpp src/*.tpp) #Create the library add_library(libargparse STATIC ${LIB_HEADERS} ${LIB_SOURCES}) set_target_properties(libargparse PROPERTIES PREFIX "") #Avoid extra 'lib' prefix set_target_properties(libargparse PROPERTIES PUBLIC_HEADER "${LIB_HEADERS}") target_include_directories(libargparse PUBLIC ${LIB_INCLUDE_DIRS}) install(TARGETS libargparse) if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) #Create the test executable add_executable(argparse_test argparse_test.cpp) target_link_libraries(argparse_test libargparse) add_test(NAME argparse_test COMMAND argparse_test) enable_testing() #Create the example executable add_executable(argparse_example argparse_example.cpp) target_link_libraries(argparse_example libargparse) endif() libavif-0.0~git20211125.ee74d1b/LICENSE.md000066400000000000000000000020601415000114400172270ustar00rootroot00000000000000The MIT License (MIT) Copyright 2017 K. Murray Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. libavif-0.0~git20211125.ee74d1b/README.md000066400000000000000000000132361415000114400171110ustar00rootroot00000000000000libargparse =========== This is (yet another) simple command-line parser for C++ applications, inspired by Python's agparse module. It requires only a C++11 compiler, and has no external dependancies. One of the advantages of libargparse is that all conversions from command-line strings to program types (bool, int etc.) are performed when the command line is parsed (and not when the options are accessed). This avoids command-line related errors from showing up deep in the program execution, which can be problematic for long-running programs. Basic Usage =========== ```cpp #include "argparse.hpp" struct Args { argparse::ArgValue do_foo; argparse::ArgValue enable_bar; argparse::ArgValue filename; argparse::ArgValue verbosity; }; int main(int argc, const char** argv) { Args args; auto parser = argparse::ArgumentParser(argv[0], "My application description"); parser.add_argument(args.filename, "filename") .help("File to process"); parser.add_argument(args.do_foo, "--foo") .help("Causes foo") .default_value("false") .action(argparse::Action::STORE_TRUE); parser.add_argument(args.enable_bar, "--bar") .help("Control bar") .default_value("false"); parser.add_argument(args.verbosity, "--verbosity", "-v") .help("Sets the verbosity") .default_value("1") .choices({"0", "1", "2"}); parser.parse_args(argc, argv); //Show the arguments std::cout << "args.filename: " << args.filename << "\n"; std::cout << "args.do_foo: " << args.do_foo << "\n"; std::cout << "args.verbosity: " << args.verbosity << "\n"; std::cout << "\n"; //Do work if (args.do_foo) { if (args.verbosity > 0) { std::cout << "Doing foo with " << args.filename << "\n"; } if (args.verbosity > 1) { std::cout << "Doing foo step 1" << "\n"; std::cout << "Doing foo step 2" << "\n"; std::cout << "Doing foo step 3" << "\n"; } } if (args.enable_bar) { if (args.verbosity > 0) { std::cout << "Bar is enabled" << "\n"; } } else { if (args.verbosity > 0) { std::cout << "Bar is disabled" << "\n"; } } return 0; } ``` and the resulting help: ``` $ ./argparse_example -h usage: argparse_example filename [--foo] [--bar {true, false}] [-v {0, 1, 2}] [-h] My application description arguments: filename File to process --foo Causes foo (Default: false) --bar {true, false} Control whether bar is enabled (Default: false) -v {0, 1, 2}, --verbosity {0, 1, 2} Sets the verbosity (Default: 1) -h, --help Shows this help message ``` By default the usage and help messages are line-wrapped to 80 characters. Custom Conversions ================== By default libargparse performs string to program type conversions using ````, meaning any type supporting ``operator<<()`` and ``operator>>()`` should be automatically supported. However this does not always provide sufficient flexibility. As a result libargparse also supports custom conversions, allowing user-defined mappings between command-line strings to program types. If we wanted to modify the above example so the '--bar' argument accepted the strings 'on' and 'off' (instead of the default 'true' and 'false') we would define a custom class as follows: ```cpp struct OnOff { ConvertedValue from_str(std::string str) { ConvertedValue converted_value; if (str == "on") converted_value.set_value(true); else if (str == "off") converted_value.set_value(false); else converted_value.set_error("Invalid argument value"); return converted_value; } ConvertedValue to_str(bool val) { ConvertedValue converted_value; if (val) converted_value.set_value("on"); else converted_value.set_value("off"); return converted_value; } std::vector default_choices() { return {"on", "off"}; } }; ``` Where the `from_str()` and `to_str()` define the conversions to and from a string, and `default_choices()` returns the set of valid choices. Note that default_choices() can return an empty vector to indicate there is no specified default set of choices. We then modify the ``add_argument()`` call to use our conversion object: ```cpp parser.add_argument(args.enable_bar, "--bar") .help("Control whether bar is enabled") .default_value("off"); ``` with the resulting help: ``` usage: argparse_example filename [--foo] [--bar {on, off}] [-v {0, 1, 2}] [-h] My application description arguments: filename File to process --foo Causes foo (Default: false) --bar {on, off} Control whether bar is enabled (Default: off) -v {0, 1, 2}, --verbosity {0, 1, 2} Sets the verbosity (Default: 1) -h, --help Shows this help message ``` Advanced Usage ============== For more advanced usage such as argument groups see [argparse_test.cpp](argparse_test.cpp) and [argparse.hpp](src/argparse.hpp). Future Work =========== libargparse is missing a variety of more advanced features found in Python's argparse, including (but not limited to): * action: append, count * subcommands * mutually exclusive options * parsing only known args * concatenated short options (e.g. `-xvf`, for options `-x`, `-v`, `-f`) * equal concatenated option values (e.g. `--foo=VALUE`) Acknowledgements ================ Python's [argparse module](https://docs.python.org/2.7/library/argparse.html) libavif-0.0~git20211125.ee74d1b/argparse_example.cpp000066400000000000000000000101201415000114400216420ustar00rootroot00000000000000#include "argparse.hpp" using argparse::ArgValue; using argparse::ConvertedValue; struct Args { ArgValue do_foo; ArgValue enable_bar; ArgValue filename; ArgValue verbosity; ArgValue show_version; ArgValue utilization; ArgValue> zulus; ArgValue> alphas; }; struct OnOff { ConvertedValue from_str(std::string str) { ConvertedValue converted_value; if (str == "on") converted_value.set_value(true); else if (str == "off") converted_value.set_value(false); else converted_value.set_error("Invalid argument value"); return converted_value; } ConvertedValue to_str(bool val) { ConvertedValue converted_value; if (val) converted_value.set_value("on"); else converted_value.set_value("off"); return converted_value; } std::vector default_choices() { return {"on", "off"}; } }; struct ZeroOneRange { ConvertedValue from_str(std::string str) { float value; std::stringstream ss(str); ss >> value; ConvertedValue converted_value; if (value < 0. || value > 1.) { std::stringstream msg; msg << "Value '" << value << "' out of expected range [0.0, 1.0]"; converted_value.set_error(msg.str()); } else { converted_value.set_value(value); } return converted_value; } std::string to_str(float value) { return std::to_string(value); } std::vector default_choices() { return {}; } }; int main(int argc, const char** argv) { Args args; auto parser = argparse::ArgumentParser(argv[0], "My application description"); parser.version("Version: 0.0.1"); parser.add_argument(args.filename, "filename") .help("File to process"); parser.add_argument(args.do_foo, "--foo") .help("Causes foo") .default_value("false") .action(argparse::Action::STORE_TRUE); parser.add_argument(args.enable_bar, "--bar") .help("Control whether bar is enabled") .default_value("off"); parser.add_argument(args.verbosity, "--verbosity", "-v") .help("Sets the verbosity") .default_value("1") .choices({"0", "1", "2"}); parser.add_argument(args.show_version, "--version", "-V") .help("Show version information") .action(argparse::Action::VERSION); parser.add_argument(args.utilization, "--util") .help("Sets target utilization") .default_value("1.0"); parser.add_argument(args.zulus, "--zulu") .help("One or more float values") .nargs('+') .default_value({"1.0", "0.2"}); parser.add_argument(args.alphas, "--alphas") .help("Zero or more float values") .nargs('*') .default_value({}); parser.parse_args(argc, argv); //Show the arguments std::cout << "args.filename: " << args.filename << "\n"; std::cout << "args.do_foo: " << args.do_foo << "\n"; std::cout << "args.verbosity: " << args.verbosity << "\n"; std::cout << "args.utilization: " << args.utilization << "\n"; std::cout << "args.zulu: " << argparse::join(args.zulus.value(), ", ") << "\n"; std::cout << "args.alphas: " << argparse::join(args.alphas.value(), ", ") << "\n"; std::cout << "\n"; //Do work if (args.do_foo) { if (args.verbosity > 0) { std::cout << "Doing foo with " << args.filename << "\n"; } if (args.verbosity > 1) { std::cout << "Doing foo step 1" << "\n"; std::cout << "Doing foo step 2" << "\n"; std::cout << "Doing foo step 3" << "\n"; } } if (args.enable_bar) { if (args.verbosity > 0) { std::cout << "Bar is enabled" << "\n"; } } else { if (args.verbosity > 0) { std::cout << "Bar is disabled" << "\n"; } } return 0; } libavif-0.0~git20211125.ee74d1b/argparse_test.cpp000066400000000000000000000731051415000114400212020ustar00rootroot00000000000000#include "argparse.hpp" #include "argparse_util.hpp" using argparse::ArgValue; using argparse::ConvertedValue; #define TEST struct Args { ArgValue architecture_file; ArgValue circuit; ArgValue disp; ArgValue auto_value; ArgValue pack; ArgValue place; ArgValue route; ArgValue show_help; ArgValue timing_analysis; ArgValue slack_definition; ArgValue echo_files; ArgValue verify_file_digests; ArgValue num_workers; ArgValue blif_file; ArgValue net_file; ArgValue place_file; ArgValue route_file; ArgValue sdc_file; ArgValue outfile_prefix; ArgValue absorb_buffer_luts; ArgValue sweep_dangling_primary_ios; ArgValue sweep_dangling_nets; ArgValue sweep_dangling_blocks; ArgValue sweep_constant_primary_outputs; ArgValue connection_driven_clustering; ArgValue allow_unrelated_clustering; ArgValue alpha_clustering; ArgValue beta_clustering; ArgValue timing_driven_clustering; ArgValue cluster_seed_type; ArgValue seed; ArgValue enable_timing_computations; ArgValue inner_num; ArgValue init_t; ArgValue exit_t; ArgValue alpha_t; ArgValue fix_pins; ArgValue place_algorithm; ArgValue place_chan_width; ArgValue timing_tradeoff; ArgValue recompute_crit_iter; ArgValue inner_loop_recompute_divider; ArgValue td_place_exp_first; ArgValue td_place_exp_last; ArgValue max_router_iterations; ArgValue first_iter_pres_fac; ArgValue initial_pres_fac; ArgValue pres_fac_mult; ArgValue acc_fac; ArgValue bb_factor; ArgValue base_cost_type; ArgValue bend_cost; ArgValue route_type; ArgValue route_chan_width; ArgValue min_route_chan_width_hint; ArgValue verify_binary_search; ArgValue router_algorithm; ArgValue min_incremental_reroute_fanout; ArgValue astar_fac; ArgValue max_criticality; ArgValue criticality_exp; ArgValue routing_failure_predictor; ArgValue power; ArgValue tech_properties_file; ArgValue activity_file; ArgValue full_stats; ArgValue gen_post_synthesis_netlist; ArgValue> one_or_more; ArgValue> zero_or_more; }; bool expect_pass(argparse::ArgumentParser& parser, std::vector cmd_line); bool expect_fail(argparse::ArgumentParser& parser, std::vector cmd_line); struct OnOff { ConvertedValue from_str(std::string str) { ConvertedValue converted_value; if (str == "on") converted_value.set_value(true); else if (str == "off") converted_value.set_value(false); else converted_value.set_error("Invalid argument value"); return converted_value; } ConvertedValue to_str(bool val) { ConvertedValue converted_value; if (val) converted_value.set_value("on"); else converted_value.set_value("off"); return converted_value; } std::vector default_choices() { return {"on", "off"}; } }; int main( int #ifndef TEST argc #endif , const char** argv) { Args args; auto parser = argparse::ArgumentParser(argv[0], "Test parser for libargparse"); parser.epilog("This is the epilog"); auto& pos_grp = parser.add_argument_group("positional arguments"); pos_grp.add_argument(args.architecture_file, "architecture") .help("FPGA Architecture description file (XML)"); pos_grp.add_argument(args.circuit, "circuit") .help("Circuit file (or circuit name if --blif_file specified)"); auto& stage_grp = parser.add_argument_group("stage options"); stage_grp.add_argument(args.pack, "--pack") .help("Run packing") .action(argparse::Action::STORE_TRUE) .default_value("off"); stage_grp.add_argument(args.place, "--place") .help("Run placement") .action(argparse::Action::STORE_TRUE) .default_value("off"); stage_grp.add_argument(args.route, "--route") .help("Run routing") .action(argparse::Action::STORE_TRUE) .default_value("off"); stage_grp.add_argument(args.route, "--analysis") .help("Run analysis") .action(argparse::Action::STORE_TRUE) .required(true) .default_value("off"); stage_grp.epilog("If none of the stage options are specified, all stages are run.\n" "Analysis is always run after routing."); auto& gfx_grp = parser.add_argument_group("graphics options"); gfx_grp.add_argument(args.disp, "--disp") .help("Enable or disable interactive graphics") .default_value("off"); gfx_grp.add_argument(args.auto_value, "--auto") .help("Controls how often VPR pauses for interactive" " graphics (requiring Proceed to be clicked)." " Higher values pause less frequently") .default_value("1") .choices({"0", "1", "2"}) .show_in(argparse::ShowIn::HELP_ONLY); auto& gen_grp = parser.add_argument_group("general options"); gen_grp.add_argument(args.show_help, "--help", "-h") .help("Show this help message then exit") .action(argparse::Action::HELP); gen_grp.add_argument(args.timing_analysis, "--timing_analysis") .help("Controls whether timing analysis (and timing driven optimizations) are enabled.") .default_value("on") ; gen_grp.add_argument(args.slack_definition, "--slack_definition") .help("Sets the slack definition used by the classic timing analyyzer") .default_value("R") .choices({"R", "I", "S", "G", "C", "N"}) .show_in(argparse::ShowIn::HELP_ONLY); gen_grp.add_argument(args.echo_files, "--echo_file") .help("Generate echo files of key internal data structures." " Useful for debugging VPR, and typically end in .echo") .default_value("off") .show_in(argparse::ShowIn::HELP_ONLY); gen_grp.add_argument(args.verify_file_digests, "--verify_file_digests") .help("Verify that files loaded by VPR (e.g. architecture, netlist," " previous packing/placement/routing) are consistent") .default_value("on") .show_in(argparse::ShowIn::HELP_ONLY); gen_grp.add_argument(args.num_workers, "--num_workers", "-j") .help("Number of parallel workers") .default_value("1") .show_in(argparse::ShowIn::HELP_ONLY); auto& file_grp = parser.add_argument_group("filename options"); file_grp.add_argument(args.blif_file, "--blif_file") .help("Path to technology mapped circuit in BLIF format") .show_in(argparse::ShowIn::HELP_ONLY); file_grp.add_argument(args.net_file, "--net_file") .help("Path to packed netlist file") .show_in(argparse::ShowIn::HELP_ONLY); file_grp.add_argument(args.place_file, "--place_file") .help("Path to placement file") .show_in(argparse::ShowIn::HELP_ONLY); file_grp.add_argument(args.route_file, "--route_file") .help("Path to routing file") .show_in(argparse::ShowIn::HELP_ONLY); file_grp.add_argument(args.sdc_file, "--sdc_file") .help("Path to timing constraints file in SDC format") .show_in(argparse::ShowIn::HELP_ONLY); file_grp.add_argument(args.outfile_prefix, "--outfile_prefix") .help("Prefix for output files") .show_in(argparse::ShowIn::HELP_ONLY); auto& netlist_grp = parser.add_argument_group("netlist options"); netlist_grp.add_argument(args.absorb_buffer_luts, "--absorb_buffer_luts") .help("Controls whether LUTS programmed as buffers are absorbed by downstream logic") .default_value("on") .show_in(argparse::ShowIn::HELP_ONLY); netlist_grp.add_argument(args.sweep_dangling_primary_ios, "--sweep_dangling_primary_ios") .help("Controls whether dangling primary inputs and outputs are removed from the netlist") .default_value("on") .show_in(argparse::ShowIn::HELP_ONLY); netlist_grp.add_argument(args.sweep_dangling_nets, "--sweep_dangling_nets") .help("Controls whether dangling nets are removed from the netlist") .default_value("on") .show_in(argparse::ShowIn::HELP_ONLY); netlist_grp.add_argument(args.sweep_dangling_blocks, "--sweep_dangling_blocks") .help("Controls whether dangling blocks are removed from the netlist") .default_value("on") .show_in(argparse::ShowIn::HELP_ONLY); netlist_grp.add_argument(args.sweep_constant_primary_outputs, "--sweep_constant_primary_outputs") .help("Controls whether primary outputs driven by constant values are removed from the netlist") .default_value("off") .show_in(argparse::ShowIn::HELP_ONLY); auto& pack_grp = parser.add_argument_group("packing options"); pack_grp.add_argument(args.connection_driven_clustering, "--connection_driven_clustering") .help("Controls whether or not packing prioritizes the absorption of nets with fewer" " connections into a complex logic block over nets with more connections") .default_value("on") .show_in(argparse::ShowIn::HELP_ONLY); pack_grp.add_argument(args.allow_unrelated_clustering, "--allow_unrelated_clustering") .help("Controls whether or not primitives with no attraction to the current cluster" " can be packed into it") .default_value("on") .show_in(argparse::ShowIn::HELP_ONLY); pack_grp.add_argument(args.alpha_clustering, "--alpha_clustering") .help("Parameter that weights the optimization of timing vs area. 0.0 focuses solely on" " area, 1.0 solely on timing.") .default_value("0.75") .show_in(argparse::ShowIn::HELP_ONLY); pack_grp.add_argument(args.beta_clustering, "--beta_clustering") .help("Parameter that weights the absorption of small nets vs signal sharing." " 0.0 focuses solely on sharing, 1.0 solely on small net absoprtion." " Only meaningful if --connection_driven_clustering=on") .default_value("0.9") .show_in(argparse::ShowIn::HELP_ONLY); pack_grp.add_argument(args.timing_driven_clustering, "--timing_driven_clustering") .help("Controls whether custering optimizes for timing") .default_value("on") .show_in(argparse::ShowIn::HELP_ONLY); pack_grp.add_argument(args.cluster_seed_type, "--cluster_seed_type") .help("Controls how primitives are chosen as seeds." " (Default: blend if timing driven, max_inputs otherwise)") .choices({"blend", "timing", "max_inputs"}) .show_in(argparse::ShowIn::HELP_ONLY); auto& place_grp = parser.add_argument_group("placement options"); place_grp.add_argument(args.seed, "--seed") .help("Placement random number generator seed") .default_value("1") .show_in(argparse::ShowIn::HELP_ONLY); place_grp.add_argument(args.enable_timing_computations, "--enable_timing_computations") .help("Displays delay statistics even if placement is not timing driven") .default_value("on") .show_in(argparse::ShowIn::HELP_ONLY); place_grp.add_argument(args.inner_num, "--inner_num") .help("Controls number of moves per temperature: inner_num * num_blocks ^ (4/3)") .default_value("10.0") .show_in(argparse::ShowIn::HELP_ONLY); place_grp.add_argument(args.init_t, "--init_t") .help("Initial temperature for manual annealing schedule") .default_value("100.0") .show_in(argparse::ShowIn::HELP_ONLY); place_grp.add_argument(args.exit_t, "--exit_t") .help("Temperature at which annealing which terminate for manual annealing schedule") .default_value("0.01") .show_in(argparse::ShowIn::HELP_ONLY); place_grp.add_argument(args.alpha_t, "--alpha_t") .help("Temperature scaling factor for manual annealing schedule." " Old temperature is multiplied by alpha_t") .default_value("0.01") .show_in(argparse::ShowIn::HELP_ONLY); place_grp.add_argument(args.fix_pins, "--fix_pins") .help("Fixes I/O pad locations during placement." " Can be 'random' for a random initial assignment," " 'off' to allow the place to optimize pad locations," " or a file specifying the pad locations.") .default_value("off") .show_in(argparse::ShowIn::HELP_ONLY); place_grp.add_argument(args.place_algorithm, "--place_algorithm") .help("Controls which placement algorithm is used") .default_value("path_timing_driven") .choices({"bounding_box", "path_timing_driven"}) .show_in(argparse::ShowIn::HELP_ONLY); place_grp.add_argument(args.place_chan_width, "--place_chan_width") .help("Sets the assumed channel width during placement") .default_value("100") .show_in(argparse::ShowIn::HELP_ONLY); auto& place_timing_grp = parser.add_argument_group("timing-driven placement options"); place_timing_grp.add_argument(args.timing_tradeoff, "--timing_tradeoff") .help("Trade-off control between delay and wirelength during placement." " 0.0 focuses completely on wirelength, 1.0 completely on timing") .default_value("0.5") .show_in(argparse::ShowIn::HELP_ONLY); place_timing_grp.add_argument(args.recompute_crit_iter, "--recompute_crit_iter") .help("Controls how many temperature updates occur between timing analysis during placement") .default_value("1") .show_in(argparse::ShowIn::HELP_ONLY); place_timing_grp.add_argument(args.inner_loop_recompute_divider, "--inner_loop_recompute_divider") .help("Controls how many timing analysies are perform per temperature during placement") .default_value("0") .show_in(argparse::ShowIn::HELP_ONLY); place_timing_grp.add_argument(args.td_place_exp_first, "--td_place_exp_first") .help("Controls how critical a connection is as a function of slack at the start of placement." " A value of zero treats all connections as equally critical (regardless of slack)." " Values larger than 1.0 cause low slack connections to be treated more critically." " The value increases to --td_place_exp_last during placement.") .default_value("1.0") .show_in(argparse::ShowIn::HELP_ONLY); place_timing_grp.add_argument(args.td_place_exp_last, "--td_place_exp_last") .help("Controls how critical a connection is as a function of slack at the end of placement.") .default_value("8.0") .show_in(argparse::ShowIn::HELP_ONLY); auto& route_grp = parser.add_argument_group("routing options"); route_grp.add_argument(args.max_router_iterations, "--max_route_iterations") .help("Maximum number of Pathfinder-based routing iterations before the circuit is" " declared unroutable at a given channel width") .default_value("50") .show_in(argparse::ShowIn::HELP_ONLY); route_grp.add_argument(args.initial_pres_fac, "--first_iter_pres_fac") .help("Sets the present overuse factor for the first routing iteration") .default_value("0.0") .show_in(argparse::ShowIn::HELP_ONLY); route_grp.add_argument(args.initial_pres_fac, "--initial_pres_fac") .help("Sets the present overuse factor for the second routing iteration") .default_value("0.5") .show_in(argparse::ShowIn::HELP_ONLY); route_grp.add_argument(args.pres_fac_mult, "--pres_fac_mult") .help("Sets the growth factor by which the present overuse penalty factor is" " multiplied after each routing iteration") .default_value("1.3") .show_in(argparse::ShowIn::HELP_ONLY); route_grp.add_argument(args.acc_fac, "--acc_fac") .help("Specifies the accumulated overuse factor (historical congestion cost factor)") .default_value("1.0") .show_in(argparse::ShowIn::HELP_ONLY); route_grp.add_argument(args.bb_factor, "--bb_factor") .help("Sets the distance (in channels) outside a connection's bounding box which can be explored") .default_value("3") .show_in(argparse::ShowIn::HELP_ONLY); route_grp.add_argument(args.base_cost_type, "--base_cost_type") .help("Sets the basic cost of routing resource nodes:\n" " * demand_only: based on expected demand of node type\n" " * delay_normalized: like demand_only but normalized to magnitude of typical routing resource delay\n" "(Default: demand_only for bread-first router, delay_normalized for timing-driven router)") .choices({"demand_only", "delay_normalized"}) .show_in(argparse::ShowIn::HELP_ONLY); route_grp.add_argument(args.bend_cost, "--bend_cost") .help("The cost of a bend. (Default: 1.0 for global routing, 0.0 for detailed routing)") .show_in(argparse::ShowIn::HELP_ONLY); route_grp.add_argument(args.route_type, "--route_type") .help("Specifies whether global, or combined global and detailed routing is performed.") .choices({"global", "detailed"}) .show_in(argparse::ShowIn::HELP_ONLY); route_grp.add_argument(args.route_chan_width, "--route_chan_width") .help("Specifies a fixed channel width to route at.") .metavar("CHANNEL_WIDTH"); route_grp.add_argument(args.min_route_chan_width_hint, "--min_route_chan_width_hint") .help("Hint to the router what the minimum routable channel width is." " Good hints can speed-up determining the minimum channel width.") .show_in(argparse::ShowIn::HELP_ONLY); route_grp.add_argument(args.verify_binary_search, "--verify_binary_search") .help("Force the router to verify the minimum channel width by routing at" " consecutively lower channel widths until two consecutive failures are observed.") .default_value("off") .show_in(argparse::ShowIn::HELP_ONLY); route_grp.add_argument(args.router_algorithm, "--router_algorithm") .help("Specifies the router algorithm to use.\n" " * breadth_first: focuses solely on routability\n" " * timing driven: focuses on routability and circuit speed\n") .default_value("timing_driven") .choices({"breadth_first", "timing_driven"}) .show_in(argparse::ShowIn::HELP_ONLY); route_grp.add_argument(args.min_incremental_reroute_fanout, "--min_incremental_reroute_fanout") .help("The net fanout thershold above which nets will be re-routed incrementally.") .default_value("64") .show_in(argparse::ShowIn::HELP_ONLY); auto& route_timing_grp = parser.add_argument_group("timing-driven routing options"); route_timing_grp.add_argument(args.astar_fac, "--astar_fac") .help("How aggressive the directed search used by the timing-driven router is." " Values between 1 and 2 are resonable; higher values trade some quality for reduced run-time") .default_value("1.2") .show_in(argparse::ShowIn::HELP_ONLY); route_timing_grp.add_argument(args.max_criticality, "--max_criticality") .help("Sets the maximum fraction of routing cost derived from delay (vs routability) for any net." " 0.0 means no attention is paid to delay, 1.0 means nets on the critical path ignore congestion") .default_value("0.99") .show_in(argparse::ShowIn::HELP_ONLY); route_timing_grp.add_argument(args.criticality_exp, "--criticality_exp") .help("Controls the delay-routability trade-off for nets as a function of slack." " 0.0 implies all nets treated equally regardless of slack." " At large values (>> 1) only nets on the critical path will consider delay.") .default_value("1.0") .show_in(argparse::ShowIn::HELP_ONLY); route_timing_grp.add_argument(args.routing_failure_predictor, "--routing_failure_predictor") .help("Controls how aggressively the router will predict a routing as unsuccessful" " and give up early. This can significantly reducing the run-time required" " to find the minimum channel width).\n" " * safe: Only abort when it is extremely unlikely a routing will succeed\n" " * aggressive: Further reduce run-time by giving up earlier. This may increase the reported minimum channel width\n" " * off: Only abort when the maximum number of iterations is reached\n") .default_value("safe") .choices({"safe", "aggressive", "off"}) .show_in(argparse::ShowIn::HELP_ONLY); auto& analysis_grp = parser.add_argument_group("analysis options"); analysis_grp.add_argument(args.full_stats, "--full_stats") .help("Print extra statistics about the circuit and it's routing (useful for wireability analysis)") .default_value("off") .show_in(argparse::ShowIn::HELP_ONLY); analysis_grp.add_argument(args.gen_post_synthesis_netlist, "--gen_post_synthesis_netlist") .help("Generates the post-synthesis netlist (in BLIF and Verilog) along with delay information (in SDF)." " Used for post-implementation simulation and verification") .default_value("off") .show_in(argparse::ShowIn::HELP_ONLY); auto& power_grp = parser.add_argument_group("power analysis options"); power_grp.add_argument(args.power, "--power") .help("Enable power estimation") .action(argparse::Action::STORE_TRUE) .default_value("off") .show_in(argparse::ShowIn::HELP_ONLY); power_grp.add_argument(args.tech_properties_file, "--tech_properties_file") .help("XML file containing CMOS technology properties (see documentation).") .show_in(argparse::ShowIn::HELP_ONLY); power_grp.add_argument(args.activity_file, "--activity_file") .help("Signal activities file for all nets (see documentation).") .show_in(argparse::ShowIn::HELP_ONLY); auto& test_grp = parser.add_argument_group("test options"); test_grp.add_argument(args.one_or_more, "--one_or_more") .nargs('+'); test_grp.add_argument(args.zero_or_more, "--zero_or_more") .nargs('*'); #ifndef TEST auto specified_args = parser.parse_args(argc, argv); for(auto& arg : specified_args) { std::cout << "Group: " << arg->group_name() << " Specified argument: " << arg->long_option(); auto short_opt = arg->short_option(); if (!short_opt.empty()) { std::cout << "/" << short_opt; } std::cout << "\n"; } return 0; #else parser.print_help(); std::cout << "\n"; std::vector> pass_cases = { {"my_arch1.xml", "my_circuit1.blif", "--analysis"}, {"my_arch2.xml", "my_circuit2.blif", "--analysis", "--pack"}, {"my_arch3.xml", "my_circuit3.blif", "--analysis", "--timing_analysis", "on"}, {"my_arch4.xml", "my_circuit4.blif", "--analysis", "--route_chan_width", "300"}, {"my_arch5.xml", "my_circuit5.blif", "--analysis", "--criticality_exp", "2"}, //Float from integer {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--criticality_exp", "2.0"}, //Float {"my_arch6.xml", "my_circuit6.blif", "--analysis", "-j", "3"}, {"my_arch6.xml", "my_circuit6.blif", "--analysis", "-j3"}, //No-space for single letter arg {"my_arch6.xml", "my_circuit6.blif", "--analysis", "-j 3"}, //Space in short arg (but one string) {"my_arch6.xml", "my_circuit6.blif", "--analysis", "-j3", "--analysis"}, //Space in short arg (but one string) {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--one_or_more", "3.24"}, //Single value argument {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--one_or_more", "3.24", "10", "29"}, //Multiple values {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--zero_or_more"}, //No values {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--zero_or_more", "234"}, //One values {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--zero_or_more", "234", "254", "1.23"}, //Multiple values {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--zero_or_more", "234", "254", "1.23", "--one_or_more", "284"}, //* followed by + {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--zero_or_more", "--one_or_more", "284"}, //* followed by + {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--one_or_more", "284", "--zero_or_more", }, //+ followed by * {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--one_or_more", "284", "--zero_or_more", "798"}, //+ followed by * {"my_arch6.xml", "--analysis", "--one_or_more", "3.24", "10", "29", "my_circuit6.blif"}, //positional after nargs='+' {"my_arch6.xml", "--analysis", "--one_or_more", "3.24", "10", "29", "my_circuit6.blif"}, //positional after nargs='+' {"my_arch6.xml", "--analysis", "--zero_or_more", "3.24", "10", "29", "my_circuit6.blif"}, //positional after nargs='*' }; int num_failed = 0; for(const auto& cmd_line : pass_cases) { bool pass = expect_pass(parser, cmd_line); if(!pass) { std::cout << " Failed to parse: '" << argparse::join(cmd_line, " ") << "'" << std::endl; ++num_failed; } } std::vector> fail_cases = { {"--analysis"}, //Missing positional {"my_arch7.xml", "--analysis"}, //Missing positional {"my_arch8.xml", "my_circuit8.blif", "--analysis", "extra"}, //Extra positional {"my_arch9.xml", "my_circuit9.blif", "--analysis", "--route_chan_width"}, //Missing value to option {"my_arch10.xml", "my_circuit10.blif", "--analysis", "--route_chan_width", "off"}, //Wrong option value type {"my_arch11.xml", "my_circuit11.blif", "--analysis", "--disp", "132"}, //Wrong option value {"my_arch12.xml", "my_circuit12.blif", "--analysis", "--route_chan_width", "300", "5"}, //Extra option value {"my_arch13.xml", "my_circuit13.blif", "--analysis", "--pack", "on"}, //Extra option value to toggle option {"my_arch14.xml", "my_circuit14.blif", "--analysis", "--route_chan_width", "300.5"}, //Type mismatch: float->int {"my_arch15.xml", "my_circuit15.blif", "--analysis", "--criticality_exp", "on"}, //Wrong value type for float {"my_arch16.xml", "my_circuit16.blif", "--analysis", "--slack_definition", "Z"}, //Valid type, but wrong choice {"my_arch17.xml", "my_circuit17.blif"}, //Missing required {"my_arch6.xml", "my_circuit6.blif", "--analysis", "-j", "3.4"}, //Float when expected unsigned {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--one_or_more"}, //Expected at least one argument }; for(const auto& cmd_line : fail_cases) { bool pass = expect_fail(parser, cmd_line); if(!pass) { std::cout << " Parsed successfully when expected failure: '" << argparse::join(cmd_line, " ") << "'" << std::endl; ++num_failed; } } if (num_failed != 0) { std::cout << "\n"; std::cout << "FAILED: " << num_failed << " test(s)!" << "\n"; } return num_failed; #endif } bool expect_pass(argparse::ArgumentParser& parser, std::vector cmd_line) { try { parser.parse_args_throw(cmd_line); } catch(const argparse::ArgParseHelp&) { parser.reset_destinations(); std::cout << "[PASS] Parsed help OK" << std::endl; return true; } catch(const argparse::ArgParseError& err) { std::cout << "[FAIL] " << err.what() << std::endl; parser.reset_destinations(); return false; } std::cout << "[PASS] Parsed OK" << std::endl; parser.reset_destinations(); return true; } bool expect_fail(argparse::ArgumentParser& parser, std::vector cmd_line) { try { parser.parse_args_throw(cmd_line); } catch(const argparse::ArgParseError& err) { std::cout << "[PASS] " << err.what() << std::endl; parser.reset_destinations(); return true; } std::cout << "[FAIL] Parsed OK when expected fail" << std::endl; parser.reset_destinations(); return false; } libavif-0.0~git20211125.ee74d1b/src/000077500000000000000000000000001415000114400164145ustar00rootroot00000000000000libavif-0.0~git20211125.ee74d1b/src/argparse.cpp000066400000000000000000000524221415000114400207310ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "argparse.hpp" #include "argparse_util.hpp" namespace argparse { /* * ArgumentParser */ ArgumentParser::ArgumentParser(std::string prog_name, std::string description_str, std::ostream& os) : description_(description_str) , formatter_(new DefaultFormatter()) , os_(os) { prog(prog_name); argument_groups_.push_back(ArgumentGroup("arguments")); } ArgumentParser& ArgumentParser::prog(std::string prog_name, bool basename_only) { if (basename_only) { prog_ = basename(prog_name); } else { prog_ = prog_name; } return *this; } ArgumentParser& ArgumentParser::version(std::string version_str) { version_ = version_str; return *this; } ArgumentParser& ArgumentParser::epilog(std::string epilog_str) { epilog_ = epilog_str; return *this; } ArgumentGroup& ArgumentParser::add_argument_group(std::string description_str) { argument_groups_.push_back(ArgumentGroup(description_str)); return argument_groups_[argument_groups_.size() - 1]; } void ArgumentParser::parse_args(int argc, const char* const* argv, int error_exit_code, int help_exit_code, int version_exit_code) { try { parse_args_throw(argc, argv); } catch (const argparse::ArgParseHelp&) { //Help requested print_help(); std::exit(help_exit_code); } catch (const argparse::ArgParseVersion&) { print_version(); std::exit(version_exit_code); } catch (const argparse::ArgParseError& e) { //Failed to parse std::cout << e.what() << "\n"; std::cout << "\n"; print_usage(); std::exit(error_exit_code); } } void ArgumentParser::parse_args_throw(int argc, const char* const* argv) { std::vector arg_strs; for (int i = 1; i < argc; ++i) { arg_strs.push_back(argv[i]); } parse_args_throw(arg_strs); } void ArgumentParser::parse_args_throw(std::vector arg_strs) { add_help_option_if_unspecified(); //Reset all the defaults for (const auto& group : argument_groups()) { for (const auto& arg : group.arguments()) { if (arg->default_set()) { arg->set_dest_to_default(); } } } //Create a look-up of expected argument strings and positional arguments std::map> str_to_option_arg; std::list> positional_args; for (const auto& group : argument_groups()) { for (const auto& arg : group.arguments()) { if (arg->positional()) { positional_args.push_back(arg); } else { for (const auto& opt : {arg->long_option(), arg->short_option()}) { if (opt.empty()) continue; auto ret = str_to_option_arg.insert(std::make_pair(opt, arg)); if (!ret.second) { //Option string already specified std::stringstream ss; ss << "Option string '" << opt << "' maps to multiple options"; throw ArgParseError(ss.str()); } } } } } std::set> specified_arguments; //Process the arguments for (size_t i = 0; i < arg_strs.size(); i++) { ShortArgInfo short_arg_info = no_space_short_arg(arg_strs[i], str_to_option_arg); std::shared_ptr arg; if (short_arg_info.is_no_space_short_arg) { //Short argument with no space between value arg = short_arg_info.arg; } else { //Full argument auto iter = str_to_option_arg.find(arg_strs[i]); if (iter != str_to_option_arg.end()) { arg = iter->second; } } if (arg) { //Start of an argument specified_arguments.insert(arg); if (arg->action() == Action::STORE_TRUE) { arg->set_dest_to_true(); } else if (arg->action() == Action::STORE_FALSE) { arg->set_dest_to_false(); } else if (arg->action() == Action::HELP) { arg->set_dest_to_true(); throw ArgParseHelp(); } else if (arg->action() == Action::VERSION) { arg->set_dest_to_true(); throw ArgParseVersion(); } else { assert(arg->action() == Action::STORE); size_t max_values_to_read = 0; size_t min_values_to_read = 0; if (arg->nargs() == '1') { max_values_to_read = 1; min_values_to_read = 1; } else if (arg->nargs() == '?') { max_values_to_read = 1; min_values_to_read = 0; } else if (arg->nargs() == '*') { max_values_to_read = std::numeric_limits::max(); min_values_to_read = 0; } else { assert (arg->nargs() == '+'); max_values_to_read = std::numeric_limits::max(); min_values_to_read = 1; } std::vector values; size_t nargs_read = 0; if (short_arg_info.is_no_space_short_arg) { //It is a short argument, we already have the first value if (!short_arg_info.value.empty()) { values.push_back(short_arg_info.value); ++nargs_read; } } for (; nargs_read < max_values_to_read; ++nargs_read) { size_t next_idx = i + 1 + nargs_read; if (next_idx >= arg_strs.size()) { break; } std::string str = arg_strs[next_idx]; if (is_argument(str, str_to_option_arg)) break; if (!arg->is_valid_value(str)) break; values.push_back(str); } if (nargs_read < min_values_to_read) { if (arg->nargs() == '1') { std::stringstream msg; msg << "Missing expected argument for " << arg_strs[i] << ""; throw ArgParseError(msg.str()); } else { std::stringstream msg; msg << "Expected at least " << min_values_to_read << " value"; if (min_values_to_read > 1) { msg << "s"; } msg << " for argument '" << arg_strs[i] << "'"; msg << " (found " << values.size() << ")"; throw ArgParseError(msg.str()); } } assert (nargs_read <= max_values_to_read); for (const auto& val : values) { if (!is_valid_choice(val, arg->choices())) { std::stringstream msg; msg << "Unexpected option value '" << values[0] << "' (expected one of: " << join(arg->choices(), ", "); msg << ") for " << arg->name(); throw ArgParseError(msg.str()); } } //Set the option values appropriately if (arg->nargs() == '1') { assert(nargs_read == 1); assert(values.size() == 1); try { arg->set_dest_to_value(values[0]); } catch (const ArgParseConversionError& e) { std::stringstream msg; msg << e.what() << " for " << arg->long_option(); auto short_opt = arg->short_option(); if (!short_opt.empty()) { msg << "/" << short_opt; } throw ArgParseConversionError(msg.str()); } } else if (arg->nargs() == '+' || arg->nargs() == '*') { if (arg->nargs() == '+') { assert(nargs_read >= 1); assert(values.size() >= 1); } for (const auto& value : values) { try { arg->add_value_to_dest(value); } catch (const ArgParseConversionError& e) { std::stringstream msg; msg << e.what() << " for " << arg->long_option(); auto short_opt = arg->short_option(); if (!short_opt.empty()) { msg << "/" << short_opt; } throw ArgParseConversionError(msg.str()); } } } else { std::stringstream msg; msg << "Unsupport nargs value '" << arg->nargs() << "'"; throw ArgParseError(msg.str()); } if (!short_arg_info.is_no_space_short_arg) { i += nargs_read; //Skip over the values (don't need to for short args) } } } else { if (positional_args.empty()) { //Unrecognized std::stringstream ss; ss << "Unexpected command-line argument '" << arg_strs[i] << "'"; throw ArgParseError(ss.str()); } else { //Positional argument auto pos_arg = positional_args.front(); positional_args.pop_front(); try { pos_arg->set_dest_to_value(arg_strs[i]); } catch (const ArgParseConversionError& e) { std::stringstream msg; msg << e.what() << " for positional argument " << pos_arg->long_option(); throw ArgParseConversionError(msg.str()); } auto value = arg_strs[i]; specified_arguments.insert(pos_arg); } } } //Missing positionals? for(const auto& remaining_positional : positional_args) { std::stringstream ss; ss << "Missing required positional argument: " << remaining_positional->long_option(); throw ArgParseError(ss.str()); } //Missing required? for (const auto& group : argument_groups()) { for (const auto& arg : group.arguments()) { if (arg->required()) { //potentially slow... if (!specified_arguments.count(arg)) { std::stringstream msg; msg << "Missing required argument: " << arg->long_option(); auto short_opt = arg->short_option(); if (!short_opt.empty()) { msg << "/" << short_opt; } throw ArgParseError(msg.str()); } } } } } void ArgumentParser::reset_destinations() { for (const auto& group : argument_groups()) { for (const auto& arg : group.arguments()) { arg->reset_dest(); } } } void ArgumentParser::print_usage() { formatter_->set_parser(this); os_ << formatter_->format_usage(); } void ArgumentParser::print_help() { formatter_->set_parser(this); os_ << formatter_->format_usage(); os_ << formatter_->format_description(); os_ << formatter_->format_arguments(); os_ << formatter_->format_epilog(); } void ArgumentParser::print_version() { formatter_->set_parser(this); os_ << formatter_->format_version(); } std::string ArgumentParser::prog() const { return prog_; } std::string ArgumentParser::version() const { return version_; } std::string ArgumentParser::description() const { return description_; } std::string ArgumentParser::epilog() const { return epilog_; } std::vector ArgumentParser::argument_groups() const { return argument_groups_; } void ArgumentParser::add_help_option_if_unspecified() { //Has a help already been specified bool found_help = false; for(auto& grp : argument_groups_) { for(auto& arg : grp.arguments()) { if(arg->action() == Action::HELP) { found_help = true; break; } } } if (!found_help) { auto& grp = argument_groups_[0]; grp.add_argument(show_help_dummy_, "--help", "-h") .help("Shows this help message") .action(Action::HELP); } } ArgumentParser::ShortArgInfo ArgumentParser::no_space_short_arg(std::string str, const std::map>& str_to_option_arg) const { ShortArgInfo short_arg_info; for(const auto& kv : str_to_option_arg) { if (kv.first.size() == 2) { //Is a short arg //String starts with short arg bool match = true; for (size_t i = 0; i < kv.first.size(); ++i) { if (kv.first[i] != str[i]) { match = false; break; } } bool no_space_between_short_arg_and_value = str.size() > kv.first.size(); if (match && no_space_between_short_arg_and_value) { //Only handles cases where there is no space between short arg and value short_arg_info.is_no_space_short_arg = true; short_arg_info.arg = kv.second; short_arg_info.value = std::string(str.begin() + kv.first.size(), str.end()); return short_arg_info; } } } assert(!short_arg_info.is_no_space_short_arg); return short_arg_info; } /* * ArgumentGroup */ ArgumentGroup::ArgumentGroup(std::string name_str) : name_(name_str) {} ArgumentGroup& ArgumentGroup::epilog(std::string str) { epilog_ = str; return *this; } std::string ArgumentGroup::name() const { return name_; } std::string ArgumentGroup::epilog() const { return epilog_; } const std::vector>& ArgumentGroup::arguments() const { return arguments_; } /* * Argument */ Argument::Argument(std::string long_opt, std::string short_opt) : long_opt_(long_opt) , short_opt_(short_opt) { if (long_opt_.size() < 1) { throw ArgParseError("Argument must be at least one character long"); } auto dashes_name = split_leading_dashes(long_opt_); if (dashes_name[0].size() == 1 && !short_opt_.empty()) { throw ArgParseError("Long option must be specified before short option"); } else if (dashes_name[0].size() > 2) { throw ArgParseError("More than two dashes in argument name"); } //Set defaults metavar_ = toupper(dashes_name[1]); } Argument& Argument::help(std::string help_str) { help_ = help_str; return *this; } Argument& Argument::nargs(char nargs_type) { //TODO: nargs > 1 support: '?', '*', '+' auto valid_nargs = {'0', '1', '+', '*'}; auto iter = std::find(valid_nargs.begin(), valid_nargs.end(), nargs_type); if (iter == valid_nargs.end()) { throw ArgParseError("Invalid argument to nargs (must be one of: " + join(valid_nargs, ", ") + ")"); } //Ensure nargs is consistent with the action if (action() == Action::STORE_FALSE && nargs_type != '0') { throw ArgParseError("STORE_FALSE action requires nargs to be '0'"); } else if (action() == Action::STORE_TRUE && nargs_type != '0') { throw ArgParseError("STORE_TRUE action requires nargs to be '0'"); } else if (action() == Action::HELP && nargs_type != '0') { throw ArgParseError("HELP action requires nargs to be '0'"); } else if (action() == Action::STORE && (nargs_type != '1' && nargs_type != '+' && nargs_type != '*')) { throw ArgParseError("STORE action requires nargs to be '1', '+' or '*'"); } nargs_ = nargs_type; valid_action(); return *this; } Argument& Argument::metavar(std::string metavar_str) { metavar_ = metavar_str; return *this; } Argument& Argument::choices(std::vector choice_values) { choices_ = choice_values; return *this; } Argument& Argument::action(Action action_type) { action_ = action_type; if ( action_ == Action::STORE_FALSE || action_ == Action::STORE_TRUE || action_ == Action::HELP || action_ == Action::VERSION) { this->nargs('0'); } else if (action_ == Action::STORE) { this->nargs('1'); } else { throw ArgParseError("Unrecognized argparse action"); } return *this; } Argument& Argument::required(bool is_required) { required_ = is_required; return *this; } Argument& Argument::default_value(const std::string& value) { if (nargs() != '0' && nargs() != '1' && nargs() != '?') { std::stringstream msg; msg << "Scalar default value not allowed for nargs='" << nargs() << "'"; throw ArgParseError(msg.str()); } default_value_.clear(); default_value_.push_back(value); default_set_ = true; return *this; } Argument& Argument::default_value(const std::vector& values) { if (nargs() != '+' && nargs() != '*') { std::stringstream msg; msg << "Multiple default value not allowed for nargs='" << nargs() << "'"; throw ArgParseError(msg.str()); } default_value_ = values; default_set_ = true; return *this; } Argument& Argument::default_value(const std::initializer_list& values) { //Convert to vector and process as usual return default_value(std::vector(values.begin(), values.end())); } Argument& Argument::group_name(std::string grp) { group_name_ = grp; return *this; } Argument& Argument::show_in(ShowIn show) { show_in_ = show; return *this; } std::string Argument::name() const { std::string name_str = long_option(); if (!short_option().empty()) { name_str += "/" + short_option(); } return name_str; } std::string Argument::long_option() const { return long_opt_; } std::string Argument::short_option() const { return short_opt_; } std::string Argument::help() const { return help_; } char Argument::nargs() const { return nargs_; } std::string Argument::metavar() const { return metavar_; } std::vector Argument::choices() const { return choices_; } Action Argument::action() const { return action_; } std::string Argument::default_value() const { if (default_value_.size() > 1) { std::stringstream msg; msg << "{" << join(default_value_, ", ") << "}"; return msg.str(); } else if (default_value_.size() == 1) { return default_value_[0]; } else { return ""; } } std::string Argument::group_name() const { return group_name_; } ShowIn Argument::show_in() const { return show_in_; } bool Argument::default_set() const { return default_set_; } bool Argument::required() const { if(positional()) { //Positional arguments are always required return true; } return required_; } bool Argument::positional() const { assert(long_option().size() > 1); return long_option()[0] != '-'; } } //namespace libavif-0.0~git20211125.ee74d1b/src/argparse.hpp000066400000000000000000000465201415000114400207400ustar00rootroot00000000000000#ifndef ARGPARSE_H #define ARGPARSE_H #include #include #include #include #include #include #include #include "argparse_formatter.hpp" #include "argparse_default_converter.hpp" #include "argparse_error.hpp" #include "argparse_value.hpp" namespace argparse { class Argument; class ArgumentGroup; enum class Action { STORE, STORE_TRUE, STORE_FALSE, HELP, VERSION }; enum class ShowIn { USAGE_AND_HELP, HELP_ONLY }; class ArgumentParser { public: //Initializes an argument parser ArgumentParser(std::string prog_name, std::string description_str=std::string(), std::ostream& os=std::cout); //Overrides the program name ArgumentParser& prog(std::string prog, bool basename_only=true); //Sets the program version ArgumentParser& version(std::string version); //Specifies the epilog text at the bottom of the help description ArgumentParser& epilog(std::string prog); //Adds an argument or option with a single name (single value) template> Argument& add_argument(ArgValue& dest, std::string option); //Adds an option with a long and short option name (single value) template> Argument& add_argument(ArgValue& dest, std::string long_opt, std::string short_opt); //Adds an argument or option with a single name (multi value) template> Argument& add_argument(ArgValue>& dest, std::string option); //Adds an option with a long and short option name (multi value) template> Argument& add_argument(ArgValue>& dest, std::string long_opt, std::string short_opt); //Adds a group to collect related arguments ArgumentGroup& add_argument_group(std::string description_str); //Like parse_arg_throw(), but catches exceptions and exits the program void parse_args(int argc, const char* const* argv, int error_exit_code=1, int help_exit_code=0, int version_exit_code=0); //Parses the specified command-line arguments and sets the appropriat argument values // Returns a vector of Arguments which were specified. //If an error occurs throws ArgParseError //If an help is requested occurs throws ArgParseHelp void parse_args_throw(int argc, const char* const* argv); void parse_args_throw(std::vector args); //Reset the target values to their initial state void reset_destinations(); //Prints the basic usage void print_usage(); //Prints the usage and full help description for each option void print_help(); //Prints the version information void print_version(); public: //Returns the program name std::string prog() const; std::string version() const; //Returns the program description (after usage, but before option descriptions) std::string description() const; //Returns the epilog (end of help) std::string epilog() const; //Returns all the argument groups in this parser std::vector argument_groups() const; private: void add_help_option_if_unspecified(); struct ShortArgInfo { bool is_no_space_short_arg = false; std::shared_ptr arg; std::string value; }; ShortArgInfo no_space_short_arg(std::string str, const std::map>& str_to_option_arg) const; private: std::string prog_; std::string description_; std::string epilog_; std::string version_; std::vector argument_groups_; std::unique_ptr formatter_; std::ostream& os_; ArgValue show_help_dummy_; //Dummy variable used as destination for automatically generated help option }; class ArgumentGroup { public: //Adds an argument or option with a single name (single value) template> Argument& add_argument(ArgValue& dest, std::string option); //Adds an option with a long and short option name (single value) template> Argument& add_argument(ArgValue& dest, std::string long_opt, std::string short_opt); //Adds an argument or option with a multi name (multi value) template> Argument& add_argument(ArgValue>& dest, std::string option); //Adds an option with a long and short option name (multi value) template> Argument& add_argument(ArgValue>& dest, std::string long_opt, std::string short_opt); //Adds an epilog to the group ArgumentGroup& epilog(std::string str); public: //Returns the name of the group std::string name() const; //Returns the epilog std::string epilog() const; //Returns the arguments within the group const std::vector>& arguments() const; public: ArgumentGroup(const ArgumentGroup&) = default; ArgumentGroup(ArgumentGroup&&) = default; ArgumentGroup& operator=(const ArgumentGroup&) = delete; ArgumentGroup& operator=(const ArgumentGroup&&) = delete; private: friend class ArgumentParser; ArgumentGroup(std::string name_str=std::string()); private: std::string name_; std::string epilog_; std::vector> arguments_; }; class Argument { public: Argument(std::string long_opt, std::string short_opt); public: //Configuration Mutators //Sets the hlep text Argument& help(std::string help_str); //Sets the defuault value Argument& default_value(const std::string& default_val); Argument& default_value(const std::vector& default_val); Argument& default_value(const std::initializer_list& default_val); //Sets the action Argument& action(Action action); //Sets whether this argument is required Argument& required(bool is_required); //Sets the associated metavar (if not specified, inferred from argument name, or choices) Argument& metavar(std::string metavar_sr); //Sets the expected number of arguments Argument& nargs(char nargs_type); //Sets the valid choices for this option's value Argument& choices(std::vector choice_values); //Sets the group name this argument is associated with Argument& group_name(std::string grp); //Sets where this option appears in the help Argument& show_in(ShowIn show); public: //Option setting mutators //Sets the target value to the specified default virtual void set_dest_to_default() = 0; //Sets the target value to the specified value virtual void set_dest_to_value(std::string value) = 0; //Adds the specified value to the taget values virtual void add_value_to_dest(std::string value) = 0; //Set the target value to true virtual void set_dest_to_true() = 0; //Set the target value to false virtual void set_dest_to_false() = 0; virtual void reset_dest() = 0; public: //Accessors //Returns a discriptive name build from the long/short option std::string name() const; //Returns the long option name (or positional name) for this argument. //Note that this may be a single-letter option if only a short option name was specified std::string long_option() const; //Returns the short option name for this argument, note that this returns //the empty string if no short option is specified, or if only the short option //is specified. std::string short_option() const; //Returns the help description for this option std::string help() const; //Returns the number of arguments this option expects char nargs() const; //Returns the specified metavar for this option std::string metavar() const; //Returns the list of valid choices for this option std::vector choices() const; //Returns the action associated with this option Action action() const; //Returns whether this option is required bool required() const; //Returns the specified default value std::string default_value() const; //Returns the group name associated with this argument std::string group_name() const; //Indicates where this option should appear in the help ShowIn show_in() const; //Returns true if this is a positional argument bool positional() const; //Returns true if the default_value() was set bool default_set() const; //Returns true if the proposed value is legal virtual bool is_valid_value(std::string value) = 0; public: //Lifetime virtual ~Argument() {} Argument(const Argument&) = default; Argument(Argument&&) = default; Argument& operator=(const Argument&) = delete; Argument& operator=(const Argument&&) = delete; protected: virtual bool valid_action() = 0; std::vector default_value_; private: //Data std::string long_opt_; std::string short_opt_; std::string help_; std::string metavar_; char nargs_ = '1'; std::vector choices_; Action action_ = Action::STORE; bool required_ = false; std::string group_name_; ShowIn show_in_ = ShowIn::USAGE_AND_HELP; bool default_set_ = false; }; template class SingleValueArgument : public Argument { public: //Constructors SingleValueArgument(ArgValue& dest, std::string long_opt, std::string short_opt) : Argument(long_opt, short_opt) , dest_(dest) {} public: //Mutators void set_dest_to_default() override { dest_.set(Converter().from_str(default_value()), Provenance::DEFAULT); dest_.set_argument_name(name()); dest_.set_argument_group(group_name()); } void set_dest_to_value(std::string value) override { if (dest_.provenance() == Provenance::SPECIFIED && dest_.argument_name() == name()) { throw ArgParseError("Argument " + name() + " specified multiple times"); } dest_.set(Converter().from_str(value), Provenance::SPECIFIED); dest_.set_argument_name(name()); dest_.set_argument_group(group_name()); } void add_value_to_dest(std::string /*value*/) override { throw ArgParseError("Single value option can not have multiple values set"); } void set_dest_to_true() override { throw ArgParseError("Non-boolean destination can not be set true"); } void set_dest_to_false() override { throw ArgParseError("Non-boolean destination can not be set false"); } bool valid_action() override { //Sanity check that we aren't processing a boolean action with a non-boolean destination if (action() == Action::STORE_TRUE) { std::stringstream msg; msg << "Non-boolean destination can not have STORE_TRUE action (" << long_option() << ")"; throw ArgParseError(msg.str()); } else if (action() == Action::STORE_FALSE) { std::stringstream msg; msg << "Non-boolean destination can not have STORE_FALSE action (" << long_option() << ")"; throw ArgParseError(msg.str()); } else if (action() != Action::STORE) { throw ArgParseError("Unexpected action (expected STORE)"); } return true; } void reset_dest() override { dest_ = ArgValue(); } bool is_valid_value(std::string value) override { auto converted_value = Converter().from_str(value); if (!converted_value) { return false; } return is_valid_choice(value, choices()); } private: //Data ArgValue& dest_; }; //bool specialization for STORE_TRUE/STORE_FALSE template class SingleValueArgument : public Argument { public: //Constructors SingleValueArgument(ArgValue& dest, std::string long_opt, std::string short_opt) : Argument(long_opt, short_opt) , dest_(dest) {} public: //Mutators void set_dest_to_default() override { dest_.set(Converter().from_str(default_value()), Provenance::DEFAULT); dest_.set_argument_name(name()); dest_.set_argument_group(group_name()); } void add_value_to_dest(std::string /*value*/) override { throw ArgParseError("Single value option can not have multiple values set"); } void set_dest_to_value(std::string value) override { if (dest_.provenance() == Provenance::SPECIFIED && dest_.argument_name() == name()) { throw ArgParseError("Argument " + name() + " specified multiple times"); } dest_.set(Converter().from_str(value), Provenance::SPECIFIED); dest_.set_argument_name(name()); dest_.set_argument_group(group_name()); } void set_dest_to_true() override { ConvertedValue val; val.set_value(true); dest_.set(val, Provenance::SPECIFIED); dest_.set_argument_name(name()); dest_.set_argument_group(group_name()); } void set_dest_to_false() override { ConvertedValue val; val.set_value(false); dest_.set(val, Provenance::SPECIFIED); dest_.set_argument_name(name()); dest_.set_argument_group(group_name()); } bool valid_action() override { //Any supported action is valid on a boolean destination return true; } void reset_dest() override { dest_ = ArgValue(); } bool is_valid_value(std::string value) override { auto converted_value = Converter().from_str(value); if (!converted_value) { return false; } return is_valid_choice(value, choices()); } private: //Data ArgValue& dest_; }; template class MultiValueArgument : public Argument { public: //Constructors MultiValueArgument(ArgValue& dest, std::string long_opt, std::string short_opt) : Argument(long_opt, short_opt) , dest_(dest) {} public: //Mutators void set_dest_to_default() override { auto& target = dest_.mutable_value(Provenance::DEFAULT); for (auto default_str : default_value_) { auto val = Converter().from_str(default_str); target.insert(std::end(target), val.value()); } dest_.set_argument_name(name()); dest_.set_argument_group(group_name()); } void set_dest_to_value(std::string /*value*/) override { throw ArgParseError("Multi-value option can not be set to a single value"); } void add_value_to_dest(std::string value) override { if (dest_.provenance() == Provenance::SPECIFIED && dest_.argument_name() != name()) { throw ArgParseError("Argument destination already set by " + dest_.argument_name() + " (trying to set from " + name() + ")"); } auto previous_provenance = dest_.provenance(); auto& target = dest_.mutable_value(Provenance::SPECIFIED); if (previous_provenance == Provenance::DEFAULT) { target.clear(); } //Insert is more general than push_back auto converted_value = Converter().from_str(value); if (!converted_value) { throw ArgParseConversionError(converted_value.error()); } target.insert(std::end(target), converted_value.value()); dest_.set_argument_name(name()); dest_.set_argument_group(group_name()); } void set_dest_to_true() override { throw ArgParseError("Non-boolean destination can not be set true"); } void set_dest_to_false() override { throw ArgParseError("Non-boolean destination can not be set false"); } bool valid_action() override { //Sanity check that we aren't processing a boolean action with a non-boolean destination if (action() != Action::STORE) { throw ArgParseError("Unexpected action (expected STORE)"); } return true; } void reset_dest() override { dest_ = ArgValue(); } bool is_valid_value(std::string value) override { auto converted_value = Converter().from_str(value); if (!converted_value) { return false; } return is_valid_choice(value, choices()); } private: //Data ArgValue& dest_; }; } //namespace #include "argparse.tpp" #endif libavif-0.0~git20211125.ee74d1b/src/argparse.tpp000066400000000000000000000065721415000114400207570ustar00rootroot00000000000000#include #include "argparse_util.hpp" namespace argparse { template std::shared_ptr make_singlevalue_argument(ArgValue& dest, std::string long_opt, std::string short_opt) { auto ptr = std::make_shared>(dest, long_opt, short_opt); //If the conversion object specifies a non-empty set of choices //use those by default auto default_choices = Converter().default_choices(); if (!default_choices.empty()) { ptr->choices(default_choices); } return ptr; } template std::shared_ptr make_multivalue_argument(ArgValue& dest, std::string long_opt, std::string short_opt) { auto ptr = std::make_shared>(dest, long_opt, short_opt); //If the conversion object specifies a non-empty set of choices //use those by default auto default_choices = Converter().default_choices(); if (!default_choices.empty()) { ptr->choices(default_choices); } return ptr; } /* * ArgumentParser */ template Argument& ArgumentParser::add_argument(ArgValue& dest, std::string option) { return add_argument(dest, option, std::string()); } template Argument& ArgumentParser::add_argument(ArgValue& dest, std::string long_opt, std::string short_opt) { return argument_groups_[0].add_argument(dest, long_opt, short_opt); } template Argument& ArgumentParser::add_argument(ArgValue>& dest, std::string option) { return add_argument(dest, option, std::string()); } template Argument& ArgumentParser::add_argument(ArgValue>& dest, std::string long_opt, std::string short_opt) { return argument_groups_[0].add_argument(dest, long_opt, short_opt); } /* * ArgumentGroup */ template Argument& ArgumentGroup::add_argument(ArgValue& dest, std::string option) { return add_argument(dest, option, std::string()); } template Argument& ArgumentGroup::add_argument(ArgValue& dest, std::string long_opt, std::string short_opt) { arguments_.push_back(make_singlevalue_argument(dest, long_opt, short_opt)); auto& arg = arguments_[arguments_.size() - 1]; arg->group_name(name()); //Tag the option with the group return *arg; } template Argument& ArgumentGroup::add_argument(ArgValue>& dest, std::string option) { return add_argument(dest, option, std::string()); } template Argument& ArgumentGroup::add_argument(ArgValue>& dest, std::string long_opt, std::string short_opt) { arguments_.push_back(make_multivalue_argument,Converter>(dest, long_opt, short_opt)); auto& arg = arguments_[arguments_.size() - 1]; arg->group_name(name()); //Tag the option with the group return *arg; } } //namespace libavif-0.0~git20211125.ee74d1b/src/argparse_default_converter.hpp000066400000000000000000000130151415000114400245240ustar00rootroot00000000000000#ifndef ARGPARSE_DEFAULT_CONVERTER_HPP #define ARGPARSE_DEFAULT_CONVERTER_HPP #include #include #include #include "argparse_error.hpp" #include "argparse_util.hpp" #include "argparse_value.hpp" namespace argparse { /* * Get a useful description of the argument type */ //Signed Integer template typename std::enable_if::value && std::is_signed::value, std::string>::type arg_type() { return "integer"; } //Unsigned Integer template typename std::enable_if::value && std::is_unsigned::value, std::string>::type arg_type() { return "non-negative integer"; } //Float template typename std::enable_if::value, std::string>::type arg_type() { return "float"; } //Unkown template typename std::enable_if::value && !std::is_integral::value, std::string>::type arg_type() { return ""; } //Empty /* * Default Conversions to/from strings */ template class DefaultConverter { public: ConvertedValue from_str(std::string str) { std::stringstream ss(str); T val = T(); ss >> val; bool eof = ss.eof(); bool fail = ss.fail(); bool converted_ok = eof && !fail; ConvertedValue converted_value; if (!converted_ok) { std::stringstream msg; msg << "Invalid conversion from '" << str << "'"; std::string arg_type_str = arg_type(); if (!arg_type_str.empty()) { msg << " to " << arg_type_str; } converted_value.set_error(msg.str()); } else { converted_value.set_value(val); } return converted_value; } ConvertedValue to_str(T val) { std::stringstream ss; ss << val; bool converted_ok = ss.eof() && !ss.fail(); ConvertedValue converted_value; if (!converted_ok) { std::stringstream msg; msg << "Invalid conversion from '" << val << "' to string"; converted_value.set_error(msg.str()); } else { converted_value.set_value(ss.str()); } return converted_value; } std::vector default_choices() { return {}; } }; //DefaultConverter specializations for bool // By default std::stringstream doesn't accept "true" or "false" // as boolean values. template<> class DefaultConverter { public: ConvertedValue from_str(std::string str) { ConvertedValue converted_value; str = tolower(str); if (str == "0" || str == "false") { converted_value.set_value(false); } else if (str == "1" || str == "true") { converted_value.set_value(true); } else { converted_value.set_error("Unexpected value '" + str + "' (expected one of: " + join(default_choices(), ", ") + ")"); } return converted_value; } ConvertedValue to_str(bool val) { ConvertedValue converted_value; if (val) converted_value.set_value("true"); else converted_value.set_value("false"); return converted_value; } std::vector default_choices() { return {"true", "false"}; } }; //DefaultConverter specializations for std::string // The default conversion checks for eof() which is not set for empty strings, // nessesitating the specialization template<> class DefaultConverter { public: ConvertedValue from_str(std::string str) { ConvertedValue converted_value; converted_value.set_value(str); return converted_value; } ConvertedValue to_str(std::string val) { ConvertedValue converted_value; converted_value.set_value(val); return converted_value; } std::vector default_choices() { return {}; } }; //DefaultConverter specializations for const char* // This allocates memory that the user is responsible for freeing template<> class DefaultConverter { public: ConvertedValue from_str(std::string str) { ConvertedValue val; val.set_value(strdup(str.c_str())); return val; } ConvertedValue to_str(const char* val) { ConvertedValue converted_value; converted_value.set_value(val); return converted_value; } std::vector default_choices() { return {}; } }; //DefaultConverter specializations for char* // This allocates memory that the user is responsible for freeing template<> class DefaultConverter { public: ConvertedValue from_str(std::string str) { ConvertedValue val; val.set_value(strdup(str.c_str())); return val; } ConvertedValue to_str(const char* val) { ConvertedValue converted_value; converted_value.set_value(val); return converted_value; } std::vector default_choices() { return {}; } }; } //namespace #endif libavif-0.0~git20211125.ee74d1b/src/argparse_error.hpp000066400000000000000000000006361415000114400221470ustar00rootroot00000000000000#ifndef ARGPARSE_ERROR_HPP #define ARGPARSE_ERROR_HPP #include namespace argparse { class ArgParseError : public std::runtime_error { using std::runtime_error::runtime_error; //Constructors }; class ArgParseConversionError : public ArgParseError { using ArgParseError::ArgParseError; }; class ArgParseHelp { }; class ArgParseVersion { }; } #endif libavif-0.0~git20211125.ee74d1b/src/argparse_formatter.cpp000066400000000000000000000175041415000114400230160ustar00rootroot00000000000000#include #include "argparse_formatter.hpp" #include "argparse_util.hpp" #include "argparse.hpp" namespace argparse { constexpr size_t OPTION_HELP_SLACK = 2; std::string INDENT = " "; std::string USAGE_PREFIX = "usage: "; std::string long_option_str(const Argument& argument); std::string short_option_str(const Argument& argument); std::string determine_metavar(const Argument& argument); /* * DefaultFormatter */ DefaultFormatter::DefaultFormatter(size_t option_name_width, size_t total_width) : option_name_width_(option_name_width) , total_width_(total_width) , parser_(nullptr) {} void DefaultFormatter::set_parser(ArgumentParser* parser) { parser_ = parser; } std::string DefaultFormatter::format_usage() const { if (!parser_) throw ArgParseError("parser not initialized in help formatter"); std::stringstream ss; ss << USAGE_PREFIX << parser_->prog(); int num_unshown_options = 0; for (const auto& group : parser_->argument_groups()) { auto args = group.arguments(); for(const auto& arg : args) { if(arg->show_in() != ShowIn::USAGE_AND_HELP) { num_unshown_options++; continue; } ss << " "; if (!arg->required()) { ss << "["; } auto short_opt = short_option_str(*arg); if (!short_opt.empty()) { ss << short_opt; } else { ss << long_option_str(*arg); } if (!arg->required()) { ss << "]"; } } } if (num_unshown_options > 0) { ss << " [OTHER_OPTIONS ...]"; } size_t prefix_len = USAGE_PREFIX.size(); std::stringstream wrapped_ss; bool first = true; for(const auto& line : wrap_width(ss.str(), total_width_ - prefix_len, {" [", " -"})) { if(!first) { //pass wrapped_ss << std::string(prefix_len, ' '); } wrapped_ss << line; first = false; } wrapped_ss << "\n"; return wrapped_ss.str(); } std::string DefaultFormatter::format_description() const { if (!parser_) throw ArgParseError("parser not initialized in help formatter"); std::stringstream ss; ss << "\n"; for(auto& line : wrap_width(parser_->description(), total_width_)) { ss << line; } ss << "\n"; return ss.str(); } std::string DefaultFormatter::format_arguments() const { if (!parser_) throw ArgParseError("parser not initialized in help formatter"); std::stringstream ss; for (const auto& group : parser_->argument_groups()) { auto args = group.arguments(); if (args.size() > 0) { ss << "\n"; ss << group.name() << ":" << "\n"; for (const auto& arg : args) { std::stringstream arg_ss; arg_ss << std::boolalpha; auto long_opt_descr = long_option_str(*arg); auto short_opt_descr = short_option_str(*arg); //name/option arg_ss << INDENT; if (!short_opt_descr.empty()) { arg_ss << short_opt_descr; } if (!long_opt_descr.empty()) { if (!short_opt_descr.empty()) { arg_ss << ", "; } arg_ss << long_opt_descr; } size_t pos = arg_ss.str().size(); if (pos + OPTION_HELP_SLACK > option_name_width_) { //If the option name is too long, wrap the help //around to a new line arg_ss << "\n"; pos = 0; } //Argument help auto help_lines = wrap_width(arg->help(), total_width_ - option_name_width_); for (auto& line : help_lines) { //Pad out the help assert(pos <= option_name_width_); arg_ss << std::string(option_name_width_ - pos, ' '); //Print a wrapped line arg_ss << line; pos = 0; } //Default if (!arg->default_value().empty()) { if(!arg->help().empty()) { arg_ss << " "; } arg_ss << "(Default: " << arg->default_value() << ")"; } arg_ss << "\n"; ss << arg_ss.str(); } if (!group.epilog().empty()) { ss << "\n"; auto epilog_lines = wrap_width(group.epilog(), total_width_ - INDENT.size()); for (auto& line : epilog_lines) { ss << INDENT << line; } ss << "\n"; } } } return ss.str(); } std::string DefaultFormatter::format_epilog() const { if (!parser_) throw ArgParseError("parser not initialized in help formatter"); std::stringstream ss; ss << "\n"; for(auto& line : wrap_width(parser_->epilog(), total_width_)) { ss << line; } ss << "\n"; return ss.str(); } std::string DefaultFormatter::format_version() const { if (!parser_) throw ArgParseError("parser not initialized in help formatter"); return parser_->version() + "\n"; } /* * Utilities */ std::string long_option_str(const Argument& argument) { auto long_opt = argument.long_option(); if(argument.nargs() != '0' && !argument.positional()) { long_opt += + " " + determine_metavar(argument); } return long_opt; } std::string short_option_str(const Argument& argument) { auto short_opt = argument.short_option(); if(!short_opt.empty()) { if(argument.nargs() != '0' && !argument.positional()) { short_opt += " " + determine_metavar(argument); } return short_opt; } else { return ""; } } std::string determine_metavar(const Argument& arg) { std::string base_metavar = arg.metavar(); if (!arg.choices().empty()) { //We allow choices to override the default metavar std::stringstream choices_ss; choices_ss << "{"; bool first = true; for(const auto& choice : arg.choices()) { if (!first) { choices_ss << ", "; } choices_ss << choice; first = false; } choices_ss << "}"; base_metavar = choices_ss.str(); } std::string metavar; if (arg.nargs() == '0' || arg.positional()) { //empty metavar = ""; } else if (arg.nargs() == '1') { metavar = base_metavar; } else if (arg.nargs() == '?') { metavar = "[" + base_metavar + "]"; } else if (arg.nargs() == '+') { metavar = base_metavar + " [" + base_metavar + " ...]"; } else if (arg.nargs() == '*') { metavar = "[" + base_metavar + " [" + base_metavar + " ...]]"; } else { assert(false); } return metavar; } } //namespace libavif-0.0~git20211125.ee74d1b/src/argparse_formatter.hpp000066400000000000000000000023161415000114400230160ustar00rootroot00000000000000#ifndef ARGPARSE_FORMATTER_HPP #define ARGPARSE_FORMATTER_HPP #include namespace argparse { class ArgumentParser; class Formatter { public: virtual ~Formatter() {} virtual void set_parser(ArgumentParser* parser) = 0; virtual std::string format_usage() const = 0; virtual std::string format_description() const = 0; virtual std::string format_arguments() const = 0; virtual std::string format_epilog() const = 0; virtual std::string format_version() const = 0; }; class DefaultFormatter : public Formatter { public: DefaultFormatter(size_t option_arg_width=20, size_t total_width=80); void set_parser(ArgumentParser* parser) override; std::string format_usage() const override; std::string format_description() const override; std::string format_arguments() const override; std::string format_epilog() const override; std::string format_version() const override; private: size_t option_name_width_; size_t total_width_; ArgumentParser* parser_; }; } //namespace #endif libavif-0.0~git20211125.ee74d1b/src/argparse_util.cpp000066400000000000000000000074611415000114400217710ustar00rootroot00000000000000#include "argparse_util.hpp" #include #include namespace argparse { std::array split_leading_dashes(std::string str) { auto iter = str.begin(); while(*iter == '-') { ++iter; } std::string dashes(str.begin(), iter); std::string name(iter, str.end()); std::array array = {dashes, name}; return array; } bool is_argument(std::string str, const std::map>& arg_map) { for (const auto& kv : arg_map) { auto iter = arg_map.find(str); if (iter != arg_map.end()) { //Exact match to short/long option return true; } if (kv.first.size() == 2 && kv.first[0] == '-') { //Check iff this is a short option with no spaces if (str[0] == kv.first[0] && str[1] == kv.first[1]) { //Matches first two characters return true; } } } return false; } bool is_valid_choice(std::string str, const std::vector& choices) { if (choices.empty()) return true; auto find_iter = std::find(choices.begin(), choices.end(), str); if (find_iter == choices.end()) { return false; } return true; } std::string toupper(std::string str) { std::string upper; for (size_t i = 0; i < str.size(); ++i) { char C = ::toupper(str[i]); upper.push_back(C); } return upper; } std::string tolower(std::string str) { std::string lower; for (size_t i = 0; i < str.size(); ++i) { char C = ::tolower(str[i]); lower.push_back(C); } return lower; } char* strdup(const char* str) { size_t len = std::strlen(str); char* res = new char[len+1]; //+1 for terminator std::strcpy(res, str); return res; } std::vector wrap_width(std::string str, size_t width, std::vector break_strs) { std::vector wrapped_lines; size_t start = 0; size_t end = 0; size_t last_break = 0; for(end = 0; end < str.size(); ++end) { size_t len = end - start; if (len > width) { auto wrapped_line = std::string(str, start, last_break - start) + "\n"; wrapped_lines.push_back(wrapped_line); start = last_break; } //Find the next break for (const auto& brk_str : break_strs) { auto pos = str.find(brk_str, end); //FIXME: this is inefficient if (pos == end) { last_break = end + 1; } } //If there are embedded new-lines then take them as forced breaks char c = str[end]; if (c == '\n') { last_break = end + 1; auto wrapped_line = std::string(str, start, last_break - start); wrapped_lines.push_back(wrapped_line); start = last_break; } } auto last_line = std::string(str, start, end - start); wrapped_lines.push_back(last_line); return wrapped_lines; } std::string basename(std::string filepath) { #ifdef _WIN32 //Windows uses back-slash as directory divider auto pos = filepath.rfind('\\'); #else //*nix-like uses forward-slash as directory divider auto pos = filepath.rfind('/'); #endif if (pos == std::string::npos) { pos = 0; } else { pos += 1; } return std::string(filepath, pos, filepath.size() - pos); } } //namespace libavif-0.0~git20211125.ee74d1b/src/argparse_util.hpp000066400000000000000000000025721415000114400217740ustar00rootroot00000000000000#ifndef ARGPARSE_UTIL_HPP #define ARGPARSE_UTIL_HPP #include #include #include #include #include namespace argparse { class Argument; //Splits off the leading dashes of a string, returning the dashes (index 0) //and the rest of the string (index 1) std::array split_leading_dashes(std::string str); //Converts a string to upper case std::string toupper(std::string str); //Converts a string to lower case std::string tolower(std::string str); //Returns true if str represents a named argument starting with //'-' or '--' followed by one or more letters bool is_argument(std::string str, const std::map>& arg_map); //Returns true if str is in choices, or choices is empty bool is_valid_choice(std::string str, const std::vector& choices); //Returns 'str' interpreted as type T // Throws an exception if conversion fails template T as(std::string str); template std::string join(Container container, std::string join_str); char* strdup(const char* str); std::vector wrap_width(std::string str, size_t width, std::vector split_str={" ", "/"}); std::string basename(std::string filepath); } //namespace #include "argparse_util.tpp" #endif libavif-0.0~git20211125.ee74d1b/src/argparse_util.tpp000066400000000000000000000013271415000114400220050ustar00rootroot00000000000000#include #include "argparse.hpp" namespace argparse { template T as(std::string str) { std::stringstream ss(str); T val; ss >> val; if (!ss.good()) { std::stringstream msg; msg << "Failed to convert value '" << str << "'"; throw ArgParseError(msg.str().c_str()); } } template std::string join(Container container, std::string join_str) { std::stringstream ss; bool first = true; for (const auto& val : container) { if (!first) ss << join_str; ss << val; first = false; } return ss.str(); } } libavif-0.0~git20211125.ee74d1b/src/argparse_value.hpp000066400000000000000000000070441415000114400221320ustar00rootroot00000000000000#ifndef ARGPARSE_VALUE_HPP #define ARGPARSE_VALUE_HPP #include #include "argparse_error.hpp" namespace argparse { template class ConvertedValue { public: typedef T value_type; public: void set_value(T val) { errored_ = false; value_ = val; } void set_error(std::string msg) { errored_ = true; error_msg_ = msg; } T value() const { return value_; } std::string error() const { return error_msg_; } operator bool() { return valid(); } bool valid() const { return !errored_; } private: T value_ = T(); std::string error_msg_; bool errored_ = true; }; //How the value associated with an argumetn was initialized enum class Provenance { UNSPECIFIED,//The value was default constructed DEFAULT, //The value was set by a default (e.g. as a command-line argument default value) SPECIFIED, //The value was explicitly specified (e.g. explicitly specified on the command-line) INFERRED, //The value was inferred, or conditionally set based on other values }; /* * ArgValue represents the 'value' of a command-line option/argument * * It supports implicit conversion to the underlying value_type, which means it can * be seamlessly used as the value_type in most situations. * * It additionally tracks the provenance off the option, along with it's associated argument group. */ template class ArgValue { public: typedef T value_type; public: //Accessors //Automatic conversion to underlying value type operator T() const { return value_; } //Returns the value assoicated with this argument const T& value() const { return value_; } //Returns the provenance of this argument (i.e. how it was initialized) Provenance provenance() const { return provenance_; } //Returns the group this argument is associated with (or an empty string if none) const std::string& argument_group() const { return argument_group_; } const std::string& argument_name() const { return argument_name_; } public: //Mutators void set(ConvertedValue val, Provenance prov) { if (!val.valid()) { //If the value didn't convert properly, it should //have an error message so raise it throw ArgParseConversionError(val.error()); } value_ = val.value(); provenance_ = prov; } void set(T val, Provenance prov) { value_ = val; provenance_ = prov; } T& mutable_value(Provenance prov) { provenance_ = prov; return value_; } void set_argument_group(std::string grp) { argument_group_ = grp; } void set_argument_name(std::string name_str) { argument_name_ = name_str; } private: T value_ = T(); Provenance provenance_ = Provenance::UNSPECIFIED; std::string argument_group_ = ""; std::string argument_name_ = ""; }; //Automatically convert to the underlying type for ostream output template std::ostream& operator<<(std::ostream& os, const ArgValue t) { return os << T(t); } } #endif