@@ -20,10 +20,63 @@ bool is_valid_path(const std::string& path) {
20
20
return !path.empty () && path[0 ] == ' /' ;
21
21
}
22
22
23
- } // namespace
23
+ void parse_option (ClientOptionsParser::option_t & option,
24
+ ClientOptionsParser::option_set_t & processed_options,
25
+ ClientOptionsParser::arguments_set_t & args) {
26
+ if (auto found = args[0 ].find (' =' ); found == std::string::npos) {
27
+ // In case form 1) is used, we discard the '--<option>'
28
+ args.erase (args.begin ());
29
+ // store the 'arg1'
30
+ option.value .push_back (args.front ());
31
+ option.original_tokens .push_back (args.front ());
32
+ }
33
+ else {
34
+ // Otherwise, form 2) is used, and the first positional value must be
35
+ // taken by tokenizing the option '--<option>=<arg1>'
36
+ std::string arg = args[0 ].substr (found + 1 );
37
+ option.value .push_back (arg);
38
+ option.original_tokens .push_back (arg);
39
+ }
40
+ // Discard the option at the front
41
+ args.erase (args.begin ());
42
+ }
24
43
25
- ClientOptionsParser::option_set_t ClientOptionsParser::operator ()(ClientOptionsParser::arguments_set_t & args) {
26
- option_set_t processed_options;
44
+ template <typename PREDICATE>
45
+ void parse_positional_arguments (
46
+ ClientOptionsParser::option_t & option,
47
+ ClientOptionsParser::option_set_t & processed_options,
48
+ ClientOptionsParser::arguments_set_t & args,
49
+ size_t maximum_positional_args,
50
+ PREDICATE predicate = [](const std::string&) { return true ; }) {
51
+
52
+ // Collect up to N positional arguments, that satisfy the predicate
53
+ for (size_t i = 0 ; i < maximum_positional_args && !args.empty (); ++i) {
54
+ // Take each of the positional values as an option value
55
+ std::string& arg = args.front ();
56
+ // Once we find the first argument that doesn't satify the predicate,
57
+ // we stop collecting arguments
58
+ if (!predicate (arg)) {
59
+ break ;
60
+ }
61
+ option.value .push_back (arg);
62
+ option.original_tokens .push_back (arg);
63
+
64
+ // Remove the argument value
65
+ args.erase (args.begin ());
66
+ }
67
+ }
68
+
69
+ void parse_positional_arguments (ClientOptionsParser::option_t & option,
70
+ ClientOptionsParser::option_set_t & processed_options,
71
+ ClientOptionsParser::arguments_set_t & args,
72
+ size_t maximum_positional_args) {
73
+
74
+ // Collect up to N positional arguments
75
+ parse_positional_arguments (
76
+ option, processed_options, args, maximum_positional_args, [](const std::string&) { return true ; });
77
+ }
78
+
79
+ void parse_alter (ClientOptionsParser::option_set_t & processed_options, ClientOptionsParser::arguments_set_t & args) {
27
80
28
81
// *** Important! ***
29
82
// This custom handler is needed to ensure that the "--alter" option
@@ -36,59 +89,56 @@ ClientOptionsParser::option_set_t ClientOptionsParser::operator()(ClientOptionsP
36
89
// 1) --alter arg1 arg2 arg3 (arg4) path [path [path [...]]]
37
90
// 2) --alter=arg1 arg2 arg3 (arg4) path [path [path [...]]]
38
91
39
- if ( ecf::algorithm::starts_with (args[ 0 ], " -- alter" )) {
92
+ ClientOptionsParser:: option_t alter{std::string{ " alter" }, {}};
40
93
41
- option_t alter{std::string{ " alter " }, {}} ;
94
+ parse_option ( alter, processed_options, args) ;
42
95
43
- if (auto found = args[0 ].find (' =' ); found == std::string::npos) {
44
- // In case form 1) is used, we discard the '--alter'
45
- args.erase (args.begin ());
46
- // store the 'arg1'
47
- alter.value .push_back (args.front ());
48
- alter.original_tokens .push_back (args.front ());
49
- }
50
- else {
51
- // Otherwise, form 2) is used, and the first positional value must be
52
- // taken by tokenizing the option '--alter=arg1'
53
- std::string arg = args[0 ].substr (found + 1 );
54
- alter.value .push_back (arg);
55
- alter.original_tokens .push_back (arg);
56
- }
57
- // Discard the option at the front
58
- args.erase (args.begin ());
96
+ // Collect up to 4 positional arguments, that are not paths
97
+ parse_positional_arguments (
98
+ alter, processed_options, args, 4 , [](const std::string& arg) { return !is_valid_path (arg); });
59
99
60
- // Collect (non path) positional arguments
61
- const size_t maximum_positional_args = 4 ;
62
- for (size_t i = 0 ; i < maximum_positional_args && !args.empty (); ++i) {
63
- // Take each of the positional values as an option value
64
- std::string& arg = args.front ();
65
- // Once we find the first path argument we stop collecting arguments
66
- if (is_valid_path (arg)) {
67
- break ;
68
- }
69
- alter.value .push_back (arg);
70
- alter.original_tokens .push_back (arg);
71
-
72
- // Remove the argument value
73
- args.erase (args.begin ());
74
- }
100
+ // Collect remaining positional arguments, that are paths
101
+ parse_positional_arguments (
102
+ alter, processed_options, args, std::numeric_limits<size_t >::max (), [](const std::string& arg) {
103
+ return is_valid_path (arg);
104
+ });
75
105
76
- // Collect only paths
77
- for (; !args.empty ();) {
78
- // Take each of the positional values as an option value
79
- std::string& arg = args.front ();
80
- // Once we find a (non path) argument, we stop collections arguments
81
- if (!is_valid_path (arg)) {
82
- break ;
83
- }
84
- alter.value .push_back (arg);
85
- alter.original_tokens .push_back (arg);
86
-
87
- // Remove the argument value
88
- args.erase (args.begin ());
89
- }
106
+ processed_options.push_back (alter);
107
+ }
108
+
109
+ void parse_label (ClientOptionsParser::option_set_t & processed_options, ClientOptionsParser::arguments_set_t & args) {
110
+
111
+ // *** Important! ***
112
+ // This custom handler is needed to ensure that the "--alter" option
113
+ // special value parameters are handled correctly. For example,
114
+ // values starting with -, such as "-j64".
115
+ //
116
+ // The custom handling will consider that 2 positional values (not
117
+ // to be confused with positional arguments) are provided with the
118
+ // --label option, as per one of the following forms:
119
+ // 1) --label arg1 arg2
120
+ // 2) --label=arg1 arg2
121
+
122
+ ClientOptionsParser::option_t label{std::string{" label" }, {}};
123
+
124
+ parse_option (label, processed_options, args);
90
125
91
- processed_options.push_back (alter);
126
+ // Collect 1 positional argument (i.e. the label value)
127
+ parse_positional_arguments (label, processed_options, args, 1 );
128
+
129
+ processed_options.push_back (label);
130
+ }
131
+
132
+ } // namespace
133
+
134
+ ClientOptionsParser::option_set_t ClientOptionsParser::operator ()(ClientOptionsParser::arguments_set_t & args) {
135
+ option_set_t processed_options;
136
+
137
+ if (ecf::algorithm::starts_with (args[0 ], " --alter" )) {
138
+ parse_alter (processed_options, args);
139
+ }
140
+ else if (ecf::algorithm::starts_with (args[0 ], " --label" )) {
141
+ parse_label (processed_options, args);
92
142
}
93
143
return processed_options;
94
144
}
0 commit comments