1212#include < cstdlib>
1313#include < ctime>
1414#include < cctype>
15+ #include < cmath>
16+ #include < optional>
17+ #include < stdexcept>
1518
1619using namespace std ::string_literals;
1720
@@ -32,31 +35,95 @@ void help(int argc, char **argv, const std::string &help_message)
3235 }
3336}
3437
35- const auto usage = " Usage: adapt [-h] [P|N] [param_filename]" s;
38+ const auto usage = " Usage: adapt [-h|--help] [--flat GG ] [P|N] [param_filename]" s;
3639
37- std::pair<Sign, std::string> cmd_line ( int argc, char *argv[]) {
40+ struct CommandLineOptions {
3841 Sign sign = Sign::POS ;
39- if (argc >= 2 ) {
40- const auto first_char = std::toupper (static_cast <unsigned char >(argv[1 ][0 ]));
41- switch (first_char) {
42- case ' P' : sign = Sign::POS ; break ;
43- case ' N' : sign = Sign::NEG ; break ;
44- default : std::cerr << usage << std::endl; exit (1 );
42+ std::string param_fn = " param" ;
43+ std::optional<double > flat_gamma;
44+ };
45+
46+ auto uppercase (std::string text) {
47+ for (auto &ch : text) { ch = static_cast <char >(std::toupper (static_cast <unsigned char >(ch))); }
48+ return text;
49+ }
50+
51+ bool parse_sign_arg (const std::string &arg, Sign &sign) {
52+ const auto token = uppercase (arg);
53+ if (token == " P" || token == " POS" || token == " POSITIVE" ) {
54+ sign = Sign::POS ;
55+ return true ;
56+ }
57+ if (token == " N" || token == " NEG" || token == " NEGATIVE" ) {
58+ sign = Sign::NEG ;
59+ return true ;
60+ }
61+ return false ;
62+ }
63+
64+ double parse_flat_gamma (const std::string &value) {
65+ std::size_t parsed = 0 ;
66+ double gamma = 0.0 ;
67+ try {
68+ gamma = std::stod (value, &parsed);
69+ } catch (const std::exception &) {
70+ throw std::invalid_argument (" --flat expects a positive finite number." );
71+ }
72+ if (parsed != value.size () || !(std::isfinite (gamma) && gamma > 0.0 )) {
73+ throw std::invalid_argument (" --flat expects a positive finite number." );
74+ }
75+ return gamma;
76+ }
77+
78+ CommandLineOptions cmd_line (int argc, char *argv[]) {
79+ CommandLineOptions options;
80+ bool sign_set = false ;
81+ bool param_set = false ;
82+
83+ for (int i = 1 ; i < argc; i++) {
84+ const std::string arg = argv[i];
85+ if (arg == " -h" || arg == " --help" ) {
86+ std::cout << usage << std::endl;
87+ exit (EXIT_SUCCESS );
88+ }
89+ if (arg == " --flat" ) {
90+ if (options.flat_gamma ) { throw std::invalid_argument (" --flat specified more than once.\n " + usage); }
91+ if (i + 1 >= argc) { throw std::invalid_argument (" Missing value for --flat.\n " + usage); }
92+ options.flat_gamma = parse_flat_gamma (argv[++i]);
93+ continue ;
94+ }
95+ if (arg.starts_with (" --flat=" )) {
96+ if (options.flat_gamma ) { throw std::invalid_argument (" --flat specified more than once.\n " + usage); }
97+ options.flat_gamma = parse_flat_gamma (arg.substr (7 ));
98+ continue ;
4599 }
100+ if (!arg.empty () && arg[0 ] == ' -' ) { throw std::invalid_argument (" Unknown option: " + arg + " \n " + usage); }
101+
102+ Sign parsed_sign;
103+ if (parse_sign_arg (arg, parsed_sign)) {
104+ if (sign_set) { throw std::invalid_argument (" Sign specified more than once.\n " + usage); }
105+ options.sign = parsed_sign;
106+ sign_set = true ;
107+ continue ;
108+ }
109+
110+ if (param_set) { throw std::invalid_argument (" Unexpected argument: " + arg + " \n " + usage); }
111+ options.param_fn = arg;
112+ param_set = true ;
46113 }
47- const std::string param_fn = argc == 3 ? std::string (argv[ 2 ]) : " param " ;
48- std::cout << " # ++ " << (sign == Sign::POS ? " POSITIVE" : " NEGATIVE" ) << std::endl;
49- return {sign, param_fn} ;
114+
115+ std::cout << " # ++ " << (options. sign == Sign::POS ? " POSITIVE" : " NEGATIVE" ) << std::endl;
116+ return options ;
50117}
51118
52119int main (int argc, char *argv[]) {
53120 try {
54121 const clock_t start_clock = clock ();
55122 about ();
56123 help (argc, argv, usage);
57- const auto [sign, param_fn] = cmd_line (argc, argv);
58- Params P (param_fn);
59- Adapt calc (P, sign);
124+ const auto options = cmd_line (argc, argv);
125+ Params P (options. param_fn );
126+ Adapt calc (P, options. sign , options. flat_gamma );
60127 calc.run ();
61128 const clock_t end_clock = clock ();
62129 std::cout << " # Elapsed " << double (end_clock - start_clock) / CLOCKS_PER_SEC << " s" << std::endl;
0 commit comments