tesseract  5.0.0
commandlineflags.cpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 // http://www.apache.org/licenses/LICENSE-2.0
5 // Unless required by applicable law or agreed to in writing, software
6 // distributed under the License is distributed on an "AS IS" BASIS,
7 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8 // See the License for the specific language governing permissions and
9 // limitations under the License.
10 
11 #include "commandlineflags.h"
12 #include <tesseract/baseapi.h> // TessBaseAPI::Version
13 #include <cmath> // for std::isnan, NAN
14 #include <locale> // for std::locale::classic
15 #include <sstream> // for std::stringstream
16 #include <vector> // for std::vector
17 #include "errcode.h"
18 #include "tprintf.h" // for tprintf
19 
20 namespace tesseract {
21 static bool IntFlagExists(const char *flag_name, int32_t *value) {
22  std::string full_flag_name("FLAGS_");
23  full_flag_name += flag_name;
24  std::vector<IntParam *> empty;
25  auto *p =
26  ParamUtils::FindParam<IntParam>(full_flag_name.c_str(), GlobalParams()->int_params, empty);
27  if (p == nullptr) {
28  return false;
29  }
30  *value = (int32_t)(*p);
31  return true;
32 }
33 
34 static bool DoubleFlagExists(const char *flag_name, double *value) {
35  std::string full_flag_name("FLAGS_");
36  full_flag_name += flag_name;
37  std::vector<DoubleParam *> empty;
38  auto *p = ParamUtils::FindParam<DoubleParam>(full_flag_name.c_str(),
39  GlobalParams()->double_params, empty);
40  if (p == nullptr) {
41  return false;
42  }
43  *value = static_cast<double>(*p);
44  return true;
45 }
46 
47 static bool BoolFlagExists(const char *flag_name, bool *value) {
48  std::string full_flag_name("FLAGS_");
49  full_flag_name += flag_name;
50  std::vector<BoolParam *> empty;
51  auto *p =
52  ParamUtils::FindParam<BoolParam>(full_flag_name.c_str(), GlobalParams()->bool_params, empty);
53  if (p == nullptr) {
54  return false;
55  }
56  *value = bool(*p);
57  return true;
58 }
59 
60 static bool StringFlagExists(const char *flag_name, const char **value) {
61  std::string full_flag_name("FLAGS_");
62  full_flag_name += flag_name;
63  std::vector<StringParam *> empty;
64  auto *p = ParamUtils::FindParam<StringParam>(full_flag_name.c_str(),
65  GlobalParams()->string_params, empty);
66  *value = (p != nullptr) ? p->c_str() : nullptr;
67  return p != nullptr;
68 }
69 
70 static void SetIntFlagValue(const char *flag_name, const int32_t new_val) {
71  std::string full_flag_name("FLAGS_");
72  full_flag_name += flag_name;
73  std::vector<IntParam *> empty;
74  auto *p =
75  ParamUtils::FindParam<IntParam>(full_flag_name.c_str(), GlobalParams()->int_params, empty);
76  ASSERT_HOST(p != nullptr);
77  p->set_value(new_val);
78 }
79 
80 static void SetDoubleFlagValue(const char *flag_name, const double new_val) {
81  std::string full_flag_name("FLAGS_");
82  full_flag_name += flag_name;
83  std::vector<DoubleParam *> empty;
84  auto *p = ParamUtils::FindParam<DoubleParam>(full_flag_name.c_str(),
85  GlobalParams()->double_params, empty);
86  ASSERT_HOST(p != nullptr);
87  p->set_value(new_val);
88 }
89 
90 static void SetBoolFlagValue(const char *flag_name, const bool new_val) {
91  std::string full_flag_name("FLAGS_");
92  full_flag_name += flag_name;
93  std::vector<BoolParam *> empty;
94  auto *p =
95  ParamUtils::FindParam<BoolParam>(full_flag_name.c_str(), GlobalParams()->bool_params, empty);
96  ASSERT_HOST(p != nullptr);
97  p->set_value(new_val);
98 }
99 
100 static void SetStringFlagValue(const char *flag_name, const char *new_val) {
101  std::string full_flag_name("FLAGS_");
102  full_flag_name += flag_name;
103  std::vector<StringParam *> empty;
104  auto *p = ParamUtils::FindParam<StringParam>(full_flag_name.c_str(),
105  GlobalParams()->string_params, empty);
106  ASSERT_HOST(p != nullptr);
107  p->set_value(std::string(new_val));
108 }
109 
110 static bool SafeAtoi(const char *str, int *val) {
111  char *endptr = nullptr;
112  *val = strtol(str, &endptr, 10);
113  return endptr != nullptr && *endptr == '\0';
114 }
115 
116 static bool SafeAtod(const char *str, double *val) {
117  double d = NAN;
118  std::stringstream stream(str);
119  // Use "C" locale for reading double value.
120  stream.imbue(std::locale::classic());
121  stream >> d;
122  *val = 0;
123  bool success = !std::isnan(d);
124  if (success) {
125  *val = d;
126  }
127  return success;
128 }
129 
130 static void PrintCommandLineFlags() {
131  const char *kFlagNamePrefix = "FLAGS_";
132  const int kFlagNamePrefixLen = strlen(kFlagNamePrefix);
133  for (auto &param : GlobalParams()->int_params) {
134  if (!strncmp(param->name_str(), kFlagNamePrefix, kFlagNamePrefixLen)) {
135  printf(" --%s %s (type:int default:%d)\n",
136  param->name_str() + kFlagNamePrefixLen,
137  param->info_str(), int32_t(*param));
138  }
139  }
140  for (auto &param : GlobalParams()->double_params) {
141  if (!strncmp(param->name_str(), kFlagNamePrefix,
142  kFlagNamePrefixLen)) {
143  printf(" --%s %s (type:double default:%g)\n",
144  param->name_str() + kFlagNamePrefixLen,
145  param->info_str(),
146  static_cast<double>(*param));
147  }
148  }
149  for (auto &param : GlobalParams()->bool_params) {
150  if (!strncmp(param->name_str(), kFlagNamePrefix, kFlagNamePrefixLen)) {
151  printf(" --%s %s (type:bool default:%s)\n",
152  param->name_str() + kFlagNamePrefixLen,
153  param->info_str(),
154  bool(*param) ? "true" : "false");
155  }
156  }
157  for (auto &param : GlobalParams()->string_params) {
158  if (!strncmp(param->name_str(), kFlagNamePrefix,
159  kFlagNamePrefixLen)) {
160  printf(" --%s %s (type:string default:%s)\n",
161  param->name_str() + kFlagNamePrefixLen,
162  param->info_str(),
163  param->c_str());
164  }
165  }
166 }
167 
168 void ParseCommandLineFlags(const char *usage, int *argc, char ***argv, const bool remove_flags) {
169  if (*argc == 1) {
170  printf("USAGE: %s\n", usage);
171  PrintCommandLineFlags();
172  exit(0);
173  }
174 
175  if (*argc > 1 && (!strcmp((*argv)[1], "-v") || !strcmp((*argv)[1], "--version"))) {
176  printf("%s\n", TessBaseAPI::Version());
177  exit(0);
178  }
179 
180  int i;
181  for (i = 1; i < *argc; ++i) {
182  const char *current_arg = (*argv)[i];
183  // If argument does not start with a hyphen then break.
184  if (current_arg[0] != '-') {
185  break;
186  }
187  // Position current_arg after startings hyphens. We treat a sequence of
188  // one or two consecutive hyphens identically.
189  ++current_arg;
190  if (current_arg[0] == '-') {
191  ++current_arg;
192  }
193  // If this is asking for usage, print the help message and abort.
194  if (!strcmp(current_arg, "help")) {
195  printf("Usage:\n %s [OPTION ...]\n\n", usage);
196  PrintCommandLineFlags();
197  exit(0);
198  }
199  // Find the starting position of the value if it was specified in this
200  // string.
201  const char *equals_position = strchr(current_arg, '=');
202  const char *rhs = nullptr;
203  if (equals_position != nullptr) {
204  rhs = equals_position + 1;
205  }
206  // Extract the flag name.
207  std::string lhs;
208  if (equals_position == nullptr) {
209  lhs = current_arg;
210  } else {
211  lhs.assign(current_arg, equals_position - current_arg);
212  }
213  if (!lhs.length()) {
214  tprintf("ERROR: Bad argument: %s\n", (*argv)[i]);
215  exit(1);
216  }
217 
218  // Find the flag name in the list of global flags.
219  // int32_t flag
220  int32_t int_val;
221  if (IntFlagExists(lhs.c_str(), &int_val)) {
222  if (rhs != nullptr) {
223  if (!strlen(rhs)) {
224  // Bad input of the format --int_flag=
225  tprintf("ERROR: Bad argument: %s\n", (*argv)[i]);
226  exit(1);
227  }
228  if (!SafeAtoi(rhs, &int_val)) {
229  tprintf("ERROR: Could not parse int from %s in flag %s\n", rhs, (*argv)[i]);
230  exit(1);
231  }
232  } else {
233  // We need to parse the next argument
234  if (i + 1 >= *argc) {
235  tprintf("ERROR: Could not find value argument for flag %s\n", lhs.c_str());
236  exit(1);
237  } else {
238  ++i;
239  if (!SafeAtoi((*argv)[i], &int_val)) {
240  tprintf("ERROR: Could not parse int32_t from %s\n", (*argv)[i]);
241  exit(1);
242  }
243  }
244  }
245  SetIntFlagValue(lhs.c_str(), int_val);
246  continue;
247  }
248 
249  // double flag
250  double double_val;
251  if (DoubleFlagExists(lhs.c_str(), &double_val)) {
252  if (rhs != nullptr) {
253  if (!strlen(rhs)) {
254  // Bad input of the format --double_flag=
255  tprintf("ERROR: Bad argument: %s\n", (*argv)[i]);
256  exit(1);
257  }
258  if (!SafeAtod(rhs, &double_val)) {
259  tprintf("ERROR: Could not parse double from %s in flag %s\n", rhs, (*argv)[i]);
260  exit(1);
261  }
262  } else {
263  // We need to parse the next argument
264  if (i + 1 >= *argc) {
265  tprintf("ERROR: Could not find value argument for flag %s\n", lhs.c_str());
266  exit(1);
267  } else {
268  ++i;
269  if (!SafeAtod((*argv)[i], &double_val)) {
270  tprintf("ERROR: Could not parse double from %s\n", (*argv)[i]);
271  exit(1);
272  }
273  }
274  }
275  SetDoubleFlagValue(lhs.c_str(), double_val);
276  continue;
277  }
278 
279  // Bool flag. Allow input forms --flag (equivalent to --flag=true),
280  // --flag=false, --flag=true, --flag=0 and --flag=1
281  bool bool_val;
282  if (BoolFlagExists(lhs.c_str(), &bool_val)) {
283  if (rhs == nullptr) {
284  // --flag form
285  bool_val = true;
286  } else {
287  if (!strlen(rhs)) {
288  // Bad input of the format --bool_flag=
289  tprintf("ERROR: Bad argument: %s\n", (*argv)[i]);
290  exit(1);
291  }
292  if (!strcmp(rhs, "false") || !strcmp(rhs, "0")) {
293  bool_val = false;
294  } else if (!strcmp(rhs, "true") || !strcmp(rhs, "1")) {
295  bool_val = true;
296  } else {
297  tprintf("ERROR: Could not parse bool from flag %s\n", (*argv)[i]);
298  exit(1);
299  }
300  }
301  SetBoolFlagValue(lhs.c_str(), bool_val);
302  continue;
303  }
304 
305  // string flag
306  const char *string_val;
307  if (StringFlagExists(lhs.c_str(), &string_val)) {
308  if (rhs != nullptr) {
309  string_val = rhs;
310  } else {
311  // Pick the next argument
312  if (i + 1 >= *argc) {
313  tprintf("ERROR: Could not find string value for flag %s\n", lhs.c_str());
314  exit(1);
315  } else {
316  string_val = (*argv)[++i];
317  }
318  }
319  SetStringFlagValue(lhs.c_str(), string_val);
320  continue;
321  }
322 
323  // Flag was not found. Exit with an error message.
324  tprintf("ERROR: Non-existent flag %s\n", (*argv)[i]);
325  exit(1);
326  } // for each argv
327  if (remove_flags) {
328  (*argv)[i - 1] = (*argv)[0];
329  (*argv) += (i - 1);
330  (*argc) -= (i - 1);
331  }
332 }
333 
334 } // namespace tesseract
#define ASSERT_HOST(x)
Definition: errcode.h:59
void ParseCommandLineFlags(const char *usage, int *argc, char ***argv, const bool remove_flags)
void tprintf(const char *format,...)
Definition: tprintf.cpp:41
tesseract::ParamsVectors * GlobalParams()
Definition: params.cpp:36
static const char * Version()
Definition: baseapi.cpp:238