1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2016 Imperial College London
5  * Copyright 2013-2016 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 #include "mirtk/Options.h"
21 
22 #include "mirtk/String.h"
23 #include "mirtk/Stream.h"
24 #include "mirtk/Version.h"   // PrintVersion/PrintRevision
25 #include "mirtk/Terminal.h"  // PrintTerminalOptions
26 #include "mirtk/Parallel.h"  // PrintParallelOptions
27 #include "mirtk/Profiling.h" // PrintProfilingOptions
28 
29 #include "mirtk/CommonExport.h"
30 
31 
32 namespace mirtk {
33 
34 
35 // =============================================================================
36 // Global standard options
37 // =============================================================================
38 
39 // Default: No verbose output messages
40 MIRTK_Common_EXPORT int verbose = 0;
41 
42 // Default: No debug output
43 MIRTK_Common_EXPORT int debug = 0;
44 
45 // =============================================================================
46 // Help
47 // =============================================================================
48 
49 MIRTK_Common_EXPORT int         _posargc                = 0;
50 MIRTK_Common_EXPORT int         _numposarg              = -1;
51 MIRTK_Common_EXPORT bool        _discard_parsed_posargs = false;
52 MIRTK_Common_EXPORT bool        _discard_parsed_options = false;
53 MIRTK_Common_EXPORT const char *_option                 = NULL;
54 
55 // -----------------------------------------------------------------------------
IsStandardOption(const char * arg)56 bool IsStandardOption(const char *arg)
57 {
58   _option = NULL;
59   if      (strcmp(arg, "-v")        == 0) _option = "-v";
60   else if (strcmp(arg, "-verbose")  == 0) _option = "-verbose";
61   else if (strcmp(arg, "-debug")    == 0) _option = "-debug";
62   else if (strcmp(arg, "-revision") == 0) _option = "-revision";
63   else if (strcmp(arg, "-version")  == 0 || strcmp(arg, "--version") == 0) _option = "-version";
64   return (_option != NULL);
65 }
66 
67 // -----------------------------------------------------------------------------
ParseStandardOption(int & OPTIDX,int & argc,char * argv[])68 void ParseStandardOption(int &OPTIDX, int &argc, char *argv[])
69 {
70   if (OPTION("-v") || OPTION("-verbose")) {
71     if (HAS_ARGUMENT) verbose  = atoi(ARGUMENT);
72     else              verbose += 1;
73   } else if (OPTION("-debug")) {
74     if (HAS_ARGUMENT) debug  = atoi(ARGUMENT);
75     else              debug += 1;
76   } else if (OPTION("-version") || OPTION("--version")) {
77     if (HAS_ARGUMENT) {
78       if (!FromString(ARGUMENT, version) || version > current_version) {
79         cerr << "Invalid [-]-version argument" << endl;
80         exit(1);
81       }
82     } else {
83       PrintVersion(cout, EXECNAME);
84       exit(0);
85     }
86   } else if (OPTION("-revision")) {
87     PrintRevision(cout);
88     exit(0);
89   }
90 }
91 
92 // -----------------------------------------------------------------------------
PrintStandardOptions(ostream & out)93 void PrintStandardOptions(ostream &out)
94 {
95   out << endl;
96   out << "Standard options:" << endl;
97   out << "  -v, -verbose [n]             Increase/Set verbosity of output messages. (default: " << verbose << ")" << endl;
98   out << "  -debug [level]               Increase/Set debug level for output of intermediate results. (default: " << debug << ")" << endl;
99   out << "  -[-]version [major.minor]    Print version and exit or set version to emulate." << endl;
100   out << "  -revision                    Print revision (or version) number only and exit." << endl;
101   out << "  -h, -[-]help                 Print help and exit." << endl;
102 }
103 
104 // -----------------------------------------------------------------------------
PrintCommonOptions(ostream & out)105 void PrintCommonOptions(ostream &out)
106 {
107   PrintStandardOptions (out);
108   PrintTerminalOptions (out);
109   PrintParallelOptions (out);
110   PrintProfilingOptions(out);
111 }
112 
113 // =============================================================================
114 // Private functions used by command-line parsing macros
115 // =============================================================================
116 
117 // -----------------------------------------------------------------------------
_IsOptionName(const char * arg)118 inline bool _IsOptionName(const char *arg)
119 {
120   return arg[0] == '-' && (arg[1] == '-' || !IsNumber(arg));
121 }
122 
123 // -----------------------------------------------------------------------------
_GetNumberOfPositionalArguments(int argc,char * argv[])124 int _GetNumberOfPositionalArguments(int argc, char *argv[])
125 {
126   int n = 1;
127   while (n < argc && !_IsOptionName(argv[n])) n++;
128   return n - 1;
129 }
130 
131 // -----------------------------------------------------------------------------
_DiscardArgument(int & i,int & argc,char * argv[])132 void _DiscardArgument(int &i, int &argc, char *argv[])
133 {
134   for (int j = i; j < argc; j++) argv[j] = argv[j+1];
135   argv[argc--] = NULL;
136   i--;
137 }
138 
139 // -----------------------------------------------------------------------------
_IsOption(int & i,int & argc,char * argv[],const char * opt)140 bool _IsOption(int &i, int &argc, char *argv[], const char *opt)
141 {
142   if ((opt == NULL && _IsOptionName(argv[i])) || (opt != NULL && strcmp(argv[i], opt) == 0)) {
143     if (_discard_parsed_options) _DiscardArgument(i, argc, argv);
144     _option = argv[i];
145     return true;
146   } else {
147     _option = NULL;
148     return false;
149   }
150 }
151 
152 // -----------------------------------------------------------------------------
_IsArgument(int i,int & argc,char * argv[])153 bool _IsArgument(int i, int &argc, char *argv[])
154 {
155   return (i+1 < argc && !_IsOptionName(argv[i+1]));
156 }
157 
158 // -----------------------------------------------------------------------------
_GetPositionalArgument(int i,int & argc,char * argv[])159 char *_GetPositionalArgument(int i, int &argc, char *argv[])
160 {
161   if (i >= argc) {
162     cerr << "Error: Not all required arguments specified!" << endl;
163     exit(1);
164   }
165   if (_posargc < i) _posargc = i;
166   char *arg = argv[i];
167   return arg;
168 }
169 
170 // -----------------------------------------------------------------------------
_GetOptionArgument(int & i,int & argc,char * argv[])171 char *_GetOptionArgument(int &i, int &argc, char *argv[])
172 {
173   if (_option) {
174     i++;
175     if (i >= argc) {
176       cerr << "Error: Option";
177       if (_option) cerr << " " << _option;
178       cerr << " requires more arguments than specified!" << endl;
179       exit(1);
180     }
181   } else {
182     if (i >= argc) {
183       cerr << "Error: Not all required arguments specified!" << endl;
184       exit(1);
185     }
186     if (_posargc < i) _posargc = i;
187   }
188   char *arg = argv[i];
189   if (_discard_parsed_options) _DiscardArgument(i, argc, argv);
190   return arg;
191 }
192 
193 
194 } // namespace mirtk
195