Options.h
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>
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
void ParseStandardOption(int &, int &, char *[])
Parse standard option.
MIRTK_Common_EXPORT int verbose
Verbosity of output messages.
MIRTK_Common_EXPORT int debug
Definition: Options.h:105
Definition: IOConfig.h:41
bool IsStandardOption(const char *)
Check if given option is a standard option.
bool FromString(const char *str, EnergyMeasure &value)
Convert energy measure string to enumeration value.