File: cmdline_option.h

package info (click to toggle)
mrtrix3 3.0~rc3%2Bgit135-g2b8e7d0c2-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 34,248 kB
  • sloc: cpp: 117,101; python: 6,472; sh: 638; makefile: 226; xml: 39; ansic: 20
file content (451 lines) | stat: -rw-r--r-- 13,949 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
/*
 * Copyright (c) 2008-2018 the MRtrix3 contributors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at http://mozilla.org/MPL/2.0/
 *
 * MRtrix3 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * For more details, see http://www.mrtrix.org/
 */


#ifndef __cmdline_option_h__
#define __cmdline_option_h__

#include <cassert>
#include <limits>
#include <string>

#ifdef None
# undef None
#endif

#include "mrtrix.h"
#include "types.h"

namespace MR
{
  namespace App
  {

  /*! \defgroup CmdParse Command-Line Parsing
   * \brief Classes and functions to parse command-line arguments and options.
   *
   * For a detailed description of the command-line parsing interface, see the
   * \ref command_line_parsing page.
   * */

    //! \cond skip
    enum ArgType {
      Undefined,
      Text,
      Boolean,
      Integer,
      Float,
      ArgFileIn,
      ArgFileOut,
      ArgDirectoryIn,
      ArgDirectoryOut,
      Choice,
      ImageIn,
      ImageOut,
      IntSeq,
      FloatSeq,
      TracksIn,
      TracksOut,
      Various
    };

    using ArgFlags = int;
    constexpr ArgFlags None = 0;
    constexpr ArgFlags Optional = 0x1;
    constexpr ArgFlags AllowMultiple = 0x2;
    //! \endcond




    //! \addtogroup CmdParse
    // @{

    //! A class to specify a command-line argument
    /*! Command-line arguments that are accepted by a particular command are
     * specified as a vector of Arguments objects. Please refer to \ref
     * command_line_parsing for more information.
     *
     * The list of arguments is provided by adding to the ARGUMENTS vector, like this:
     * \code
     * ARGUMENTS
     *   + Argument ("input", "the input image")
     *     .type_image_in()
     *
     *   + Argument ("parameter",
     *        "the parameter to use during processing. Allowed values are "
     *        "between 0 and 10 (default = 1).")
     *     .type_float (0.0, 10.0)
     *
     *   + Argument ("output", "the output image")
     *     .type_image_out();
     * \endcode
     * The example above specifies that the application expects exactly 3
     * arguments, with the first one being an existing image to be used as input,
     * the second one being a floating-point value, and the last one being an
     * image to be created and used as output.
     *
     * There are a number of types that the argument can be specified as. The
     * argument can also be specified as optional (see optional() function), or
     * as multiple (see allow_multiple() function). Note that in this case only
     * one such argument can be optional and/or multiple, since more than one
     * such argument would lead to ambiguities when parsing the command-line.  */
    class Argument { NOMEMALIGN
      public:
        //! constructor
        /*! this is used to construct a command-line argument object, with a name
         * and description. If default arguments are used, the object corresponds
         * to the end-of-list specifier, as detailed in \ref command_line_parsing. */
        Argument (const char* name = nullptr, std::string description = std::string()) :
          id (name), desc (description), type (Undefined), flags (None)
        {
          memset (&limits, 0x00, sizeof (limits));
        }

        //! the argument name
        const char* id;
        //! the argument description
        std::string desc;
        //! the argument type
        ArgType  type;
        //! the argument flags (AllowMultiple & Optional)
        ArgFlags flags;

        //! a structure to store the various parameters of the Argument
        union {
          const char* const* choices;
          struct { NOMEMALIGN
            int64_t min, max;
          } i;
          struct { NOMEMALIGN
            default_type min, max;
          } f;
        } limits;


        operator bool () const {
          return id;
        }

        //! specifies that the argument is optional
        /*! For example:
         * \code
         * ARGUMENTS
         *   + Argument ("input", "the input image")
         *     .type_image_in()
         *     .optional()
         *     .allow_multiple();
         * \endcode
         * \note Only one argument can be specified as optional and/or multiple.
         */
        Argument& optional () {
          flags |= Optional;
          return *this;
        }

        //! specifies that multiple such arguments can be specified
        /*! See optional() for details. */
        Argument& allow_multiple () {
          flags |= AllowMultiple;
          return *this;
        }

        //! specifies that the argument should be a text string
        Argument& type_text () {
          assert (type == Undefined);
          type = Text;
          return *this;
        }

        //! specifies that the argument should be an input image
        Argument& type_image_in () {
          assert (type == Undefined);
          type = ImageIn;
          return *this;
        }

        //! specifies that the argument should be an output image
        Argument& type_image_out () {
          assert (type == Undefined);
          type = ImageOut;
          return *this;
        }

        //! specifies that the argument should be an integer
        /*! if desired, a range of allowed values can be specified. */
        Argument& type_integer (const int64_t min = std::numeric_limits<int64_t>::min(), const int64_t max = std::numeric_limits<int64_t>::max()) {
          assert (type == Undefined);
          type = Integer;
          limits.i.min = min;
          limits.i.max = max;
          return *this;
        }

        //! specifies that the argument should be a boolean
        /*! Valid responses are 0,no,false or any non-zero integer, yes, true. */
        Argument& type_bool () {
          assert (type == Undefined);
          type = Boolean;
          return *this;
        }

        //! specifies that the argument should be a floating-point value
        /*! if desired, a range of allowed values can be specified. */
        Argument& type_float (const default_type min = -std::numeric_limits<default_type>::infinity(),
                              const default_type max = std::numeric_limits<default_type>::infinity()) {
          assert (type == Undefined);
          type = Float;
          limits.f.min = min;
          limits.f.max = max;
          return *this;
        }

        //! specifies that the argument should be selected from a predefined list
        /*! The list of allowed values must be specified as a nullptr-terminated
         * list of C strings. Here is an example usage:
         * \code
         * const char* mode_list [] = { "standard", "pedantic", "approx", nullptr };
         *
         * ARGUMENTS
         *   + Argument ("mode", "the mode of operation")
         *     .type_choice (mode_list);
         * \endcode
         * \note Each string in the list must be supplied in \b lowercase. */
        Argument& type_choice (const char* const* choices) {
          assert (type == Undefined);
          type = Choice;
          limits.choices = choices;
          return *this;
        }

        //! specifies that the argument should be an input file
        Argument& type_file_in () {
          assert (type == Undefined);
          type = ArgFileIn;
          return *this;
        }

        //! specifies that the argument should be an output file
        Argument& type_file_out () {
          assert (type == Undefined);
          type = ArgFileOut;
          return *this;
        }

        //! specifies that the argument should be an input directory
        Argument& type_directory_in () {
          assert (type == Undefined);
          type = ArgDirectoryIn;
          return *this;
        }

        //! specifies that the argument should be an output directory
        Argument& type_directory_out () {
          assert (type == Undefined);
          type = ArgDirectoryOut;
          return *this;
        }

        //! specifies that the argument should be a sequence of comma-separated integer values
        Argument& type_sequence_int () {
          assert (type == Undefined);
          type = IntSeq;
          return *this;
        }

        //! specifies that the argument should be a sequence of comma-separated floating-point values.
        Argument& type_sequence_float () {
          assert (type == Undefined);
          type = FloatSeq;
          return *this;
        }

        //! specifies that the argument should be an input tracks file
        Argument& type_tracks_in () {
          assert (type == Undefined);
          type = TracksIn;
          return *this;
        }

        //! specifies that the argument should be an output tracks file
        Argument& type_tracks_out () {
          assert (type == Undefined);
          type = TracksOut;
          return *this;
        }

        //! specifies that the argument could be one of various types
        Argument& type_various () {
          assert (type == Undefined);
          type = Various;
          return *this;
        }


        std::string syntax (int format) const;
        std::string usage () const;
    };






    //! A class to specify a command-line option
    /*! Command-line options that are accepted by a particular command are
     * specified as an array of Option objects, terminated with an empty
     * Option (constructed using default parameters). Please refer to \ref
     * command_line_parsing for more information.
     *
     * The list of options is provided using the OPTIONS macro, like this:
     * \code
     * OPTIONS
     *   + Option ("exact",
     *        "do not use approximations when processing")
     *
     *   + Option ("mask",
     *        "only perform processing within the voxels contained in "
     *        "the binary image specified")
     *     + Argument ("image").type_image_in()
     *
     *   + Option ("regularisation",
     *        "set the regularisation term")
     *     + Argument ("value").type_float (0.0, 1.0, 100.0)
     *
     *   Option ("dump",
     *        "dump all intermediate values to file")
     *     + Argument ("file").type_file();
     * \endcode
     * The example above specifies that the application accepts four options, in
     * addition to the standard ones (see \ref command_line_parsing for details).
     * The first option is a simple switch: specifying '-exact' on the
     * command line will cause the application to behave differently.
     * The next options all expect an additional argument, supplied using the
     * Argument class. Note that the description field of the Argument class is
     * unused in this case. Multiple additional arguments can be specified in
     * this way using the addition operator.
     *
     * Options can also be specified as required (see required() function), or
     * as multiple (see allow_multiple() function).
     */
    class Option : public vector<Argument> { NOMEMALIGN
      public:
        Option () : id (nullptr), flags (Optional) { }

        Option (const char* name, const std::string& description) :
          id (name), desc (description), flags (Optional) { }

        Option& operator+ (const Argument& arg) {
          push_back (arg);
          return *this;
        }
        operator bool () const {
          return id;
        }

        //! the option name
        const char* id;
        //! the option description
        std::string desc;
        //! option flags (AllowMultiple and/or Optional)
        ArgFlags flags;

        //! specifies that the option is required
        /*! An option specified as required must be supplied on the command line.
         * For example:
         * \code
         * OPTIONS
         *   + Option ("roi",
         *       "the region of interest over which to perform the processing. "
         *       "Mulitple such regions can be specified")
         *     .required()
         *     .allow_multiple()
         *     + Argument ("image").type_image_in();
         * \endcode
         */
        Option& required () {
          flags &= ~Optional;
          return (*this);
        }

        //! specifies that multiple such options can be specified
        /*! See required() for details. */
        Option& allow_multiple () {
          flags |= AllowMultiple;
          return *this;
        }

        bool is (const std::string& name) const {
          return name == id;
        }

        std::string syntax (int format) const;
        std::string usage () const;
    };






    //! a class to hold a named list of Option's
    /*! the name is used as the section heading for the options that follow.
     * For example:
     * \code
     * void usage () {
     *   ...
     *   OPTIONS
     *   + Option (...)
     *
     *   + OptionGroup ("Special options")
     *   + Option ("option1", ...)
     *   + Option ("option2", ...);
     * }
     * \endcode
     */
    class OptionGroup : public vector<Option> { NOMEMALIGN
      public:
        OptionGroup (const char* group_name = "OPTIONS") : name (group_name) { }
        const char* name;

        OptionGroup& operator+ (const Option& option) {
          push_back (option);
          return *this;
        }

        OptionGroup& operator+ (const Argument& argument) {
          assert (!empty());
          back() + argument;
          return *this;
        }

        Option& back () {
          if (empty())
            push_back (Option());
          return vector<Option>::back();
        }

        std::string header (int format) const;
        std::string contents (int format) const;
        static std::string footer (int format);
    };



  }

  //! @}
}

#endif