tesseract v5.3.3.20231005
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
20namespace tesseract {
21static 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
34static 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
47static 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
60static 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
70static 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
80static 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
90static 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
100static 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
110static 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
116static 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
130static 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
168void 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:54
int value
const char * p
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:241