1 /*
2 * Medical Image Registration ToolKit (MIRTK)
3 *
4 * Copyright 2013-2015 Imperial College London
5 * Copyright 2013-2015 Andreas Schuh
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #ifndef MIRTK_Options_H
21 #define MIRTK_Options_H
22
23 #include "mirtk/Path.h"
24 #include "mirtk/Stream.h"
25
26 #include "mirtk/Parallel.h"
27 #include "mirtk/Profiling.h"
28 #include "mirtk/Terminal.h"
29
30 #include "mirtk/CommonExport.h"
31
32
33 /*
34 \file mirtk/Options.h
35 \brief Simple command-line parsing library.
36
37 The macros defined by this module should reduce the number of lines of code
38 required to parse simple command-line arguments in the main function of a
39 program. Use them for example as follows:
40
41 \code
42 for (ALL_OPTIONS) {
43 if (OPTION("-steps" )) NumberOfIntegrationSteps = atoi(ARGUMENT);
44 else if (OPTION("-iters" )) NumberOfBCHSteps = atoi(ARGUMENT);
45 else if (OPTION("-terms" )) NumberOfBCHTerms = atoi(ARGUMENT);
46 else if (OPTION("-smooth")) SmoothBCHApproximation = true;
47 else HANDLE_COMMON_OR_UNKNOWN_OPTION();
48 }
49 \endcode
50
51 If your program has positional arguments which have to be specified by the
52 user before the optional arguments, use the following code instead:
53
54 \code
55 REQUIRES_POSARGS(2);
56 const char *input_file = POSARG(1);
57 const char *output_file = POSARG(2);
58 for (ALL_OPTIONS) {
59 // same as above
60 }
61 \endcode
62
63 Other uses including options with multiple arguments may look like this:
64 \code
65 REQUIRES_POSARGS(0);
66 DISCARD_PARSED_OPTIONS();
67 int x = 1, y = 1, z = 1, t = 1;
68 double dx = 1, dy = 1, dz = 1, dt = 1;
69 for (ALL_OPTIONS) {
70 // -dim <x> <y> <z> <t>
71 if (OPTION("-dim")) {
72 x = atoi(ARGUMENT);
73 y = atoi(ARGUMENT);
74 z = atoi(ARGUMENT);
75 t = atoi(ARGUMENT);
76 } else if (OPTION("-pixdim")) {
77 dx = atof(ARGUMENT);
78 dy = atof(ARGUMENT);
79 dz = atof(ARGUMENT);
80 dt = atof(ARGUMENT);
81 } else HANDLE_COMMON_OPTION();
82 }
83 // do something, then parse remaining options
84 bool foo = false;
85 for (ALL_OPTIONS) {
86 if (OPTION("-foo")) foo = true;
87 else HANDLE_UNKNOWN_OPTION();
88 }
89 \endcode
90 */
91
92
93 namespace mirtk {
94
95 // =============================================================================
96 // Global standard options
97 // =============================================================================
98
99 /// Verbosity of output messages
100 MIRTK_Common_EXPORT extern int verbose;
101
102 /// Debug level, e.g., amount of intermediate data to write to disk
103 /// This flag can be combined with verbose after parsing the command options.
104 /// For example, "if (debug) verbose = 100;", or treated separately.
105 MIRTK_Common_EXPORT extern int debug;
106
107 // =============================================================================
108 // Standard options
109 // =============================================================================
110
111 /// Check if given option is a standard option
112 bool IsStandardOption(const char *);
113
114 /// Parse standard option
115 void ParseStandardOption(int &, int &, char *[]);
116
117 //// Print standard options of any IRTK command
118 void PrintStandardOptions(ostream &);
119
120 //// Print common options of any IRTK command
121 void PrintCommonOptions(ostream &);
122
123 // =============================================================================
124 // Command helper macros
125 // =============================================================================
126
127 // -----------------------------------------------------------------------------
128 /// Print warning and continue
129 #define Warning(msg) \
130 cerr << "Warning: " << msg << endl
131
132 // -----------------------------------------------------------------------------
133 /// Print error message and exit with error code 1
134 #define FatalError(msg) \
135 do { \
136 cerr << "Error: " << msg << endl; \
137 exit(1); \
138 } while (false)
139
140 // -----------------------------------------------------------------------------
141 #define EXECNAME BaseName(argv[0]).c_str()
142 #define ARGIDX _i
143 #define OPTIDX ARGIDX
144 #define OPTNAME _option
145 #define DISCARD_PARSED_POSARGS() _discard_parsed_posargs = true
146 #define DISCARD_PARSED_OPTIONS() _discard_parsed_options = true
147 #define DISCARD_PARSED_ARGUMENTS() _discard_parsed_options = _discard_parsed_posargs = true
148 #define KEEP_PARSED_POSARGS() _discard_parsed_posargs = false
149 #define KEEP_PARSED_OPTIONS() _discard_parsed_options = false
150 #define KEEP_PARSED_ARGUMENTS() _discard_parsed_options = _discard_parsed_posargs = false
151 #define ALL_ARGUMENTS int ARGIDX = 1; ARGIDX < argc; ARGIDX++
152 #define ALL_POSARGS int ARGIDX = 1; ARGIDX <= _numposarg; ARGIDX++
153 #define OPTIONAL_POSARGS int ARGIDX = _posargc + 1; ARGIDX < argc && argv[ARGIDX][0] != '-'; ARGIDX++
154 #define ARGUMENTS_AFTER(pos) int ARGIDX = (pos)+1; ARGIDX < argc; ARGIDX++
155 #define ALL_OPTIONS ARGUMENTS_AFTER(_numposarg == -1 ? _posargc : _numposarg)
156 #define POSARG(i) _GetPositionalArgument((i), argc, argv)
157 #define NUM_POSARGS (_numposarg == -1 ? _GetNumberOfPositionalArguments(argc, argv) : _numposarg)
158 #define IS_OPTION _IsOption(OPTIDX, argc, argv)
159 #define OPTION(opt) _IsOption(OPTIDX, argc, argv, opt)
160 #define ARGUMENT _GetOptionArgument(OPTIDX, argc, argv)
161 #define HAS_ARGUMENT _IsArgument(OPTIDX, argc, argv)
162 #define HELP_OPTION (OPTION("-h") || OPTION("-help") || OPTION("--help"))
163 #define VERSION_OPTION (OPTION("-version") || OPTION("--version") || OPTION("-revision"))
164 #define STANDARD_OPTION IsStandardOption (argv[OPTIDX])
165 #define PARALLEL_OPTION IsParallelOption (argv[OPTIDX])
166 #define PROFILING_OPTION IsProfilingOption (argv[OPTIDX])
167 #define TERMINAL_OPTION IsTerminalOption (argv[OPTIDX])
168 #define PARSE_STANDARD_OPTION() ParseStandardOption (OPTIDX, argc, argv)
169 #define PARSE_PARALLEL_OPTION() ParseParallelOption (OPTIDX, argc, argv)
170 #define PARSE_PROFILING_OPTION() ParseProfilingOption(OPTIDX, argc, argv)
171 #define PARSE_TERMINAL_OPTION() ParseTerminalOption (OPTIDX, argc, argv)
172 #define PARSE_ARGUMENT(value) _ParseArgument(OPTNAME, ARGUMENT, value)
173
174 // -----------------------------------------------------------------------------
175 #define REQUIRES_POSARGS(n) \
176 do { \
177 _posargc = n; \
178 for (ALL_ARGUMENTS) { \
179 if (HELP_OPTION ) HANDLE_HELP_OPTION(); \
180 else if (VERSION_OPTION) HANDLE_VERSION_OPTION(); \
181 } \
182 if (argc <= _posargc) { \
183 PrintHelp(EXECNAME); \
184 exit(1); \
185 } \
186 _numposarg = NUM_POSARGS; \
187 if (_numposarg < _posargc) _numposarg = _posargc; \
188 } while (false)
189
190 // -----------------------------------------------------------------------------
191 #define EXPECTS_POSARGS(n) \
192 REQUIRES_POSARGS(n); \
193 do { \
194 if (NUM_POSARGS > n) { \
195 PrintHelp(EXECNAME); \
196 cout << endl; \
197 cerr << "Error: Too many positional arguments!" << endl; \
198 exit(1); \
199 } \
200 } while (false)
201
202 // -----------------------------------------------------------------------------
203 #define HANDLE_HELP_OPTION() \
204 do { PrintHelp(EXECNAME); exit(0); } while (false)
205
206 // -----------------------------------------------------------------------------
207 #define HANDLE_VERSION_OPTION() \
208 PARSE_STANDARD_OPTION()
209
210 // -----------------------------------------------------------------------------
211 #define HANDLE_UNKNOWN_OPTION() \
212 do { \
213 PrintHelp(EXECNAME); \
214 cout << endl; \
215 cerr << "Error: Unknown option " << argv[OPTIDX] << " (index=" << OPTIDX << ")" << endl; \
216 exit(1); \
217 } while (false)
218
219 // -----------------------------------------------------------------------------
220 #define HANDLE_STANDARD_OPTION() \
221 if (HELP_OPTION ) HANDLE_HELP_OPTION(); \
222 else if (VERSION_OPTION ) HANDLE_VERSION_OPTION(); \
223 else if (STANDARD_OPTION ) PARSE_STANDARD_OPTION()
224
225 // -----------------------------------------------------------------------------
226 #define HANDLE_STANDARD_OR_UNKNOWN_OPTION() \
227 if (HELP_OPTION ) HANDLE_HELP_OPTION(); \
228 else if (VERSION_OPTION ) HANDLE_VERSION_OPTION(); \
229 else if (STANDARD_OPTION ) PARSE_STANDARD_OPTION(); \
230 else HANDLE_UNKNOWN_OPTION()
231
232 // -----------------------------------------------------------------------------
233 #define HANDLE_BOOLEAN_OPTION(name, var) \
234 if (OPTION("-" name)) { \
235 if (HAS_ARGUMENT) PARSE_ARGUMENT(var); \
236 else var = true; \
237 } else if (OPTION("-no" name)) \
238 var = false
239
240 // -----------------------------------------------------------------------------
241 #define HANDLE_BOOL_OPTION(name) \
242 HANDLE_BOOLEAN_OPTION(#name, name)
243
244 // -----------------------------------------------------------------------------
245 #define HANDLE_COMMON_OPTION() \
246 if (HELP_OPTION ) HANDLE_HELP_OPTION(); \
247 else if (VERSION_OPTION ) HANDLE_VERSION_OPTION(); \
248 else if (STANDARD_OPTION ) PARSE_STANDARD_OPTION(); \
249 else if (PARALLEL_OPTION ) PARSE_PARALLEL_OPTION(); \
250 else if (PROFILING_OPTION) PARSE_PROFILING_OPTION(); \
251 else if (TERMINAL_OPTION ) PARSE_TERMINAL_OPTION()
252
253 // -----------------------------------------------------------------------------
254 #define HANDLE_COMMON_OR_UNKNOWN_OPTION() \
255 if (HELP_OPTION ) HANDLE_HELP_OPTION(); \
256 else if (VERSION_OPTION ) HANDLE_VERSION_OPTION(); \
257 else if (STANDARD_OPTION ) PARSE_STANDARD_OPTION(); \
258 else if (PARALLEL_OPTION ) PARSE_PARALLEL_OPTION(); \
259 else if (PROFILING_OPTION) PARSE_PROFILING_OPTION(); \
260 else if (TERMINAL_OPTION ) PARSE_TERMINAL_OPTION(); \
261 else HANDLE_UNKNOWN_OPTION()
262
263 // -----------------------------------------------------------------------------
264 #define HANDLE_HELP_OR_VERSION() \
265 do { \
266 for (ALL_ARGUMENTS) { \
267 if (HELP_OPTION ) HANDLE_HELP_OPTION(); \
268 else if (VERSION_OPTION) HANDLE_VERSION_OPTION(); \
269 } \
270 } while (false)
271
272 // =============================================================================
273 // Private global variables/functions used by command-line parsing macros
274 // =============================================================================
275
276 MIRTK_Common_EXPORT extern int _posargc; // Number of required positional arguments
277 MIRTK_Common_EXPORT extern int _numposarg; // Number of positional arguments
278 MIRTK_Common_EXPORT extern bool _discard_parsed_posargs; // Whether to discard or keep parsed positional arguments
279 MIRTK_Common_EXPORT extern bool _discard_parsed_options; // Whether to discard or keep parsed options
280 MIRTK_Common_EXPORT extern const char *_option; // Current option being parsed
281
282 int _GetNumberOfPositionalArguments(int, char *[]);
283
284 void _DiscardArgument (int &, int &, char *[]);
285 bool _IsOption (int &, int &, char *[], const char * = NULL);
286 bool _IsArgument (int, int &, char *[]);
287 char *_GetPositionalArgument(int, int &, char *[]);
288 char *_GetOptionArgument (int &, int &, char *[]);
289
290 // -----------------------------------------------------------------------------
291 template <class T>
_ParseArgument(const char * opt,const char * arg,T & value)292 void _ParseArgument(const char *opt, const char *arg, T &value)
293 {
294 if (!FromString(arg, value)) {
295 FatalError("Invalid " << opt << " argument: " << arg);
296 }
297 }
298
299
300 } // namespace mirtk
301
302 #endif // MIRTK_Options_H
303