36 delete opt; |
36 delete opt; |
37 } |
37 } |
38 |
38 |
39 // _________________________________________________________________________________________________ |
39 // _________________________________________________________________________________________________ |
40 // |
40 // |
41 void CommandLine::addOption (CommandLineOption* option) |
41 StringList CommandLine::process (int const argc, char* argv[]) |
42 { |
|
43 _options << option; |
|
44 } |
|
45 |
|
46 // _________________________________________________________________________________________________ |
|
47 // |
|
48 StringList CommandLine::process (int argc, char* argv[]) |
|
49 { |
42 { |
50 StringList args; |
43 StringList args; |
51 |
44 int const trueargc = argc; |
52 for (int argn = 1; argn < argc; ++argn) |
45 |
53 { |
46 for (int argn = 1; argn < trueargc; ++argn) |
54 String arg (argv[argn]); |
47 { |
|
48 String const arg (argv[argn]); |
55 |
49 |
56 if (arg == "--") |
50 if (arg == "--") |
57 { |
51 { |
58 // terminating option - write everything to args and be done with it. |
52 // terminating option - write everything to args and be done with it. |
59 while (++argn < argc) |
53 while (++argn < argc) |
60 args << argv[argn]; |
54 args << argv[argn]; |
61 |
55 |
62 break; |
56 break; |
63 } |
57 } |
64 |
58 |
65 if (arg[0] != '-') |
59 if (arg[0] != '-' or arg[1] == '\0') |
66 { |
60 { |
67 // non-option argument - pass to result |
61 // non-option argument - pass to result |
68 args << arg; |
62 args << arg; |
69 continue; |
63 continue; |
70 } |
64 } |
71 |
65 |
72 if (arg[1] != '-') |
66 if (arg[1] != '-' and arg[1] != '\0') |
73 { |
67 { |
74 // short-form options |
68 // short-form options |
75 for (int i = 1; i < arg.length(); ++i) |
69 for (int i = 1; i < arg.length(); ++i) |
76 { |
70 { |
77 CommandLineOption** optionptr = _options.find ([&](CommandLineOption* const& a) |
71 CommandLineOption** optionptr = _options.find ([&](CommandLineOption* const& a) |
78 { |
72 { |
79 return arg[i] == a->shortform(); |
73 return arg[i] == a->shortform(); |
80 }); |
74 }); |
81 |
75 |
82 if (not optionptr) |
76 if (not optionptr) |
83 { |
|
84 error ("unknown option -%1", arg[i]); |
77 error ("unknown option -%1", arg[i]); |
85 } |
|
86 |
78 |
87 CommandLineOption* option = *optionptr; |
79 CommandLineOption* option = *optionptr; |
88 |
80 |
89 if (option->isOfType<bool>()) |
81 if (option->isOfType<bool>()) |
90 { |
82 { |
91 // Bool options need no parameters |
83 // Bool options need no parameters |
92 option->handleValue (""); |
84 option->handleValue (""); |
93 continue; |
85 } |
94 } |
86 else |
95 |
87 { |
96 // Ensure we got a valid parameter coming up |
88 // Ensure we got a valid parameter coming up |
97 if (argn == argc - 1) |
89 if (argn == argc - 1) |
98 error ("option -%1 requires a parameter", option->describe()); |
90 error ("option -%1 requires a parameter", option->describe()); |
99 |
91 |
100 if (i != arg.length() - 1) |
92 if (i != arg.length() - 1) |
101 { |
93 { |
102 error ("option %1 requires a parameter but has option -%2 stacked on", |
94 error ("option %1 requires a parameter but has option -%2 stacked on", |
103 option->describe(), arg[i + 1]); |
95 option->describe(), arg[i + 1]); |
104 } |
96 } |
105 |
97 |
106 option->handleValue (argv[++argn]); |
98 option->handleValue (argv[++argn]); |
|
99 } |
107 } |
100 } |
108 } |
101 } |
109 else |
102 else |
110 { |
103 { |
111 // long-form options |
104 // long-form options |
132 if (not optionptr) |
125 if (not optionptr) |
133 error ("unknown option --%1", name); |
126 error ("unknown option --%1", name); |
134 |
127 |
135 if ((*optionptr)->isOfType<bool>() and not value.isEmpty()) |
128 if ((*optionptr)->isOfType<bool>() and not value.isEmpty()) |
136 error ("option %1 does not take a value", (*optionptr)->describe()); |
129 error ("option %1 does not take a value", (*optionptr)->describe()); |
137 |
130 |
138 (*optionptr)->handleValue (value); |
131 (*optionptr)->handleValue (value); |
139 } |
132 } |
140 } |
133 } |
141 |
134 |
142 return args; |
135 return args; |
143 } |
136 } |
144 |
137 |
145 // _________________________________________________________________________________________________ |
138 // _________________________________________________________________________________________________ |
146 // |
139 // |
147 void CommandLineOption::handleValue (String const& value) |
140 String CommandLine::describeOptions() const |
|
141 { |
|
142 StringList lines; |
|
143 |
|
144 for (CommandLineOption* option : _options) |
|
145 { |
|
146 String line (" "); |
|
147 |
|
148 if (option->shortform() != '\0') |
|
149 line += String ({'-', option->shortform(), '\0'}); |
|
150 else |
|
151 line += " "; |
|
152 |
|
153 line += " "; |
|
154 |
|
155 if (not option->longform().isEmpty()) |
|
156 { |
|
157 line += "--" + option->longform(); |
|
158 String description (option->describeArgument()); |
|
159 |
|
160 if (not description.isEmpty()) |
|
161 line += "=" + description; |
|
162 } |
|
163 |
|
164 lines << line; |
|
165 } |
|
166 |
|
167 int maxlength (0); |
|
168 |
|
169 for (String& line : lines) |
|
170 maxlength = max (maxlength, line.length()); |
|
171 |
|
172 maxlength += 2; |
|
173 ASSERT_EQ (lines.size(), _options.size()); |
|
174 |
|
175 for (int i = 0; i < lines.size(); ++i) |
|
176 { |
|
177 while (lines[i].length() < maxlength) |
|
178 lines[i] += " "; |
|
179 |
|
180 lines[i] += _options[i]->description(); |
|
181 } |
|
182 |
|
183 StringList extralines; |
|
184 |
|
185 for (CommandLineOption* option : _options) |
|
186 { |
|
187 String extradata = option->describeExtra(); |
|
188 |
|
189 if (not extradata.isEmpty()) |
|
190 { |
|
191 if (extralines.isEmpty()) |
|
192 extralines << ""; |
|
193 |
|
194 extralines << extradata; |
|
195 } |
|
196 } |
|
197 |
|
198 lines.merge (extralines); |
|
199 String result (lines.join ("\n")); |
|
200 return result; |
|
201 } |
|
202 |
|
203 // _________________________________________________________________________________________________ |
|
204 // |
|
205 void CommandLineOption::handleValue (const String& a) |
148 { |
206 { |
149 if (isOfType<bool>()) |
207 if (isOfType<bool>()) |
150 { |
208 { |
151 *reinterpret_cast<bool*> (pointer()) = value; |
209 pointer().setValue (true); |
152 } |
210 } |
153 elif (isOfType<int>()) |
211 elif (isOfType<int>()) |
154 { |
212 { |
155 bool ok; |
213 bool ok; |
156 *reinterpret_cast<int*> (pointer()) = value.toLong (&ok); |
214 pointer().setValue (a.toLong (&ok)); |
157 |
215 |
158 if (not ok) |
216 if (not ok) |
159 error ("bad integral value passed to %1", describe()); |
217 error ("bad integral value passed to %1", describe()); |
160 } |
218 } |
161 elif (isOfType<String>()) |
219 elif (isOfType<String>()) |
162 { |
220 { |
163 *reinterpret_cast<String*> (pointer()) = value; |
221 pointer().setValue (a); |
164 } |
222 } |
165 elif (isOfType<double>()) |
223 elif (isOfType<double>()) |
166 { |
224 { |
167 bool ok; |
225 bool ok; |
168 *reinterpret_cast<double*> (pointer()) = value.toDouble (&ok); |
226 pointer().setValue (a.toDouble (&ok)); |
169 |
227 |
170 if (not ok) |
228 if (not ok) |
171 error ("bad floating-point value passed to %1", describe()); |
229 error ("bad floating-point value passed to %1", describe()); |
172 } |
230 } |
173 else |
231 else |
174 { |
232 { |
175 error ("OMGWTFBBQ: %1 has an invalid type index", describe()); |
233 error ("OMGWTFBBQ: %1 has an invalid type index", describe()); |
176 } |
234 } |
177 } |
235 } |
|
236 |
|
237 // _________________________________________________________________________________________________ |
|
238 // |
|
239 String CommandLineOption::describeArgument() const |
|
240 { |
|
241 if (isOfType<int>()) |
|
242 return "INTEGER"; |
|
243 elif (isOfType<String>()) |
|
244 return "STRING"; |
|
245 elif (isOfType<double>()) |
|
246 return "FLOAT"; |
|
247 |
|
248 return ""; |
|
249 } |