GCC Code Coverage Report


Directory: ./
File: basic/command_line.cpp
Date: 2026-09-27 03:24:14
Exec Total Coverage
Lines: 385 660 58.3%
Functions: 44 59 74.6%
Branches: 396 1266 31.3%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #include <geogram/basic/command_line.h>
41 #include <geogram/basic/command_line_args.h>
42 #include <geogram/basic/environment.h>
43 #include <geogram/basic/file_system.h>
44 #include <geogram/basic/logger.h>
45 #include <geogram/basic/stopwatch.h>
46 #include <geogram/basic/process.h>
47 #include <geogram/bibliography/bibliography.h>
48 #include <geogram/NL/nl.h>
49 #include <iostream>
50 #include <iomanip>
51
52 #if defined(GEO_OS_LINUX) || defined(GEO_OS_APPLE)
53 #include <sys/ioctl.h>
54 #include <stdio.h>
55 #include <unistd.h>
56 #include <termios.h>
57 #endif
58
59 #ifdef GEO_OS_WINDOWS
60 #include <io.h> // for _isatty()
61 #endif
62
63 /**
64 * \brief Checks argument type
65 * \details Checks if argument type \p type is in allowed types \p
66 * allowed_types or is undefined. Multiple types can be specified in \p
67 * allowed_types by bit-OR'ing the values defined in enum
68 * GEO::CmdLine::ArgType.
69 * \param[in] type the type to be tested
70 * \param[in] allowed_types argument types allowed for \p type.
71 * \retval true if type is in \p allowed_types
72 * \retval false otherwise
73 * \see GEO::CmdLine::ArgType
74 */
75 #define geo_assert_arg_type(type, allowed_types) \
76 geo_assert(((type) & ~(allowed_types)) == 0)
77
78 namespace {
79
80 using namespace GEO;
81 using namespace CmdLine;
82
83 std::string config_file_name = "geogram.ini";
84 bool auto_create_args = false;
85 bool loaded_config_file = false;
86
87 int geo_argc = 0;
88 char** geo_argv = nullptr;
89
90 // True if displaying help in a way that
91 // it will be easily processed by help2man
92 bool man_mode = false;
93
94 Process::spinlock lock = GEOGRAM_SPINLOCK_INIT;
95
96 /**
97 * \brief Command line argument
98 * \details Arg stores information about command line arguments:
99 */
100 struct Arg {
101 /** \brief The argument name */
102 std::string name;
103 /** \brief The argument description */
104 std::string desc;
105 /** \brief The argument type */
106 ArgType type;
107 /** \brief The argument flags */
108 ArgFlags flags;
109 };
110
111 /** \brief Stores command line arguments by name */
112 typedef std::map<std::string, Arg> Args;
113
114 /**
115 * \brief Stores the list of all arguments in a group
116 * \see ArgGroup
117 */
118 typedef std::vector<std::string> GroupArgs;
119
120 /**
121 * \brief Command line argument group
122 * \details ArgGroup stores information about command line argument groups
123 */
124 struct Group {
125 /** \brief The group name */
126 std::string name;
127 /** \brief The group description */
128 std::string desc;
129 /** \brief The group flags */
130 ArgFlags flags;
131 /** \brief The list of arguments in the group */
132 GroupArgs args;
133 };
134
135 /** \brief Stores command line argument groups by name */
136 typedef std::map<std::string, Group> Groups;
137
138 /** \brief List of group names ordered in declaration order */
139 typedef std::vector<std::string> GroupNames;
140
141 /**
142 * \brief Command line private data
143 */
144 struct CommandLineDesc {
145 /** \brief Program name */
146 std::string argv0;
147 /** \brief Table of all declared arguments indexed by name */
148 Args args;
149 /** \brief Table of all declared groups indexed by name */
150 Groups groups;
151 /** \brief Oredered list of declared group names */
152 GroupNames group_names;
153 };
154
155 /** \brief Maximum length of a feature name */
156 const unsigned int feature_max_length = 12;
157
158 /** \brief Pointer to command line private data */
159 CommandLineDesc* desc_ = nullptr;
160
161 /**
162 * \brief Checks if an argument name matches a sub-strung
163 * \param[in] arg_in the sub-string to match
164 * \param[in] arg_name the argument name
165 * \retval true if \p arg_name contains \p arg_in
166 * \retval false otherwise
167 */
168 2992 bool arg_matches(
169 const std::string& arg_in, const std::string& arg_name
170 ) {
171 2992 return arg_name.find(arg_in) != std::string::npos;
172 }
173
174 /**
175 * \brief Prints bad argument value error message
176 * \param[in] name the argument name
177 * \param[in] s the bad value
178 * \param[in] type the argument type
179 * \return \c false
180 */
181 2 bool arg_value_error(
182 const std::string& name,
183 const std::string& s, const char* type
184 ) {
185 2 Logger::instance()->set_quiet(false);
186
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 Logger::err("CmdLine")
187 << "Argument " << name << " received a bad value: '"
188
7/14
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 2 times.
✗ Branch 20 not taken.
2 << s << "' is not a " << type << " value"
189
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 << std::endl;
190 2 return false;
191 }
192
193 /**
194 * \brief Checks the value of an argument
195 * \details This function is used by parse_internal() to check the values
196 * passed to arguments on the command line. It verifies that the string \p
197 * s is convertible to the declared type of argument \p name (see
198 * declare_arg()).
199 * \param[in] name the argument name
200 * \param[in] s the string value of the argument
201 * \retval true if string \p s is convertible to the type of the argument
202 * \retval false otherwise
203 */
204 2327 bool check_arg_value(
205 const std::string& name, const std::string& s
206 ) {
207 2327 ArgType type = get_arg_type(name);
208
4/4
✓ Branch 0 taken 981 times.
✓ Branch 1 taken 1346 times.
✓ Branch 2 taken 398 times.
✓ Branch 3 taken 583 times.
2327 if(type == ARG_UNDEFINED || type == ARG_STRING) {
209 1744 return true;
210 }
211
212
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 473 times.
583 if(type == ARG_INT) {
213 int value;
214
3/4
✓ Branch 1 taken 110 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 109 times.
110 if(!String::from_string(s, value)) {
215
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 return arg_value_error(name, s, "integer");
216 } else {
217 109 return true;
218 }
219 }
220
221
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 413 times.
473 if(type == ARG_DOUBLE) {
222 double value;
223
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 59 times.
60 if(!String::from_string(s, value)) {
224
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 return arg_value_error(name, s, "floating point");
225 } else {
226 59 return true;
227 }
228 }
229
230
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 83 times.
413 if(type == ARG_BOOL) {
231 bool value;
232
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 330 times.
330 if(!String::from_string(s, value)) {
233 ✗ return arg_value_error(name, s, "boolean");
234 } else {
235 330 return true;
236 }
237 }
238
239
1/2
✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
83 if(type == ARG_PERCENT) {
240
1/2
✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
83 std::string s2 = s;
241
4/8
✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 83 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 83 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 83 times.
✗ Branch 10 not taken.
83 if(s2.length() > 0 && s2[s2.length() - 1] == '%') {
242
1/2
✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
83 s2.resize(s2.length() - 1);
243 }
244 double value;
245
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 83 times.
83 if(!String::from_string(s2, value)) {
246 ✗ return arg_value_error(name, s, "percentage");
247 } else {
248 83 return true;
249 }
250 83 }
251
252 ✗ return false;
253 }
254
255
256 /**
257 * \brief Parses the configuration file in the home directory.
258 * \details The configuration file "geogram.ini" in the home directory
259 * has name=value pairs for pre-initializing command line arguments.
260 * In addition it has sections indicated by square-breacketed names.
261 * Only the arguments in the section with the same name as the program
262 * are taken into account. Section [*] refers to all possible programs.
263 * \param[in] config_filename the name of the configuration file
264 * \param[in] program_name the name of the program
265 */
266 255 void parse_config_file(
267 const std::string& config_filename, const std::string& program_name
268 ) {
269
1/2
✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
255 std::string section = "*";
270
2/4
✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 255 times.
255 if(FileSystem::is_file(config_filename)) {
271 ✗ std::ifstream in(config_filename.c_str());
272 ✗ std::string line;
273 ✗ while(std::getline(in,line)) {
274 ✗ if(
275 ✗ line.length() >= 3 && line[0] == '[' &&
276 ✗ line[line.length()-1] == ']'
277 ) {
278 ✗ section = String::to_uppercase(
279 ✗ line.substr(1,line.length()-2)
280 ✗ );
281 ✗ } else if(section == program_name || section == "*") {
282 ✗ size_t pos = line.find("=");
283 ✗ if(pos != std::string::npos) {
284 ✗ std::string argname = line.substr(0,pos);
285 std::string argval = line.substr(
286 ✗ pos+1,line.length()-pos-1
287 ✗ );
288 ✗ if(CmdLine::arg_is_declared(argname)) {
289 ✗ CmdLine::set_arg(argname, argval);
290 } else {
291 ✗ if(auto_create_args) {
292 ✗ CmdLine::declare_arg(argname, argval, "...");
293 } else {
294 ✗ Logger::warn("config") << argname
295 << "=" << argval
296 ✗ << " ignored"
297 ✗ << std::endl;
298 }
299 }
300 ✗ }
301 }
302 }
303 ✗ loaded_config_file= true;
304 ✗ }
305 255 }
306
307 /**
308 * \brief Parses the configuration file in the home directory.
309 * \details The configuration file "geogram.ini" in the home directory
310 * has name=value pairs for pre-initializing command line arguments.
311 * In addition it has sections indicated by square-breacketed names.
312 * Only the arguments in the section with the same name as the program
313 * are taken into account. Section [*] refers to all possible programs.
314 * \param[in] argc number of arguments passed to main()
315 * \param[in] argv array of command line arguments passed to main()
316 */
317 505 void parse_config_file(int argc, char** argv) {
318
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 505 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
505 geo_assert(argc >= 1);
319 std::string program_name = String::to_uppercase(
320
2/4
✓ Branch 1 taken 505 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 505 times.
✗ Branch 5 not taken.
1010 FileSystem::base_name(argv[0])
321
1/2
✓ Branch 1 taken 505 times.
✗ Branch 2 not taken.
505 );
322 static bool init = false;
323
2/2
✓ Branch 0 taken 250 times.
✓ Branch 1 taken 255 times.
505 if(init) {
324 250 return;
325 }
326 255 init = true;
327
2/4
✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 255 times.
✗ Branch 5 not taken.
765 Logger::out("config")
328
2/4
✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 255 times.
✗ Branch 5 not taken.
255 << "Configuration file name:" << config_file_name
329
1/2
✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
255 << std::endl;
330
2/4
✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 255 times.
✗ Branch 5 not taken.
255 Logger::out("config")
331
3/6
✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 255 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 255 times.
✗ Branch 8 not taken.
510 << "Home directory:" << FileSystem::home_directory()
332
1/2
✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
255 << std::endl;
333 std::string config_filename =
334
3/6
✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 255 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 255 times.
✗ Branch 8 not taken.
255 FileSystem::home_directory() + "/" + config_file_name;
335
1/2
✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
255 parse_config_file(config_filename, program_name);
336
2/2
✓ Branch 2 taken 255 times.
✓ Branch 3 taken 250 times.
505 }
337
338 /**
339 * \brief Parses the command line arguments
340 * \details This analyzes command line arguments passed to the main()
341 * program in \p argc and \p argv. Arguments not matching program
342 * options declared with declare_arg() are stored in output vector \p
343 * unparsed_args.
344 * \param[in] argc number of arguments passed to main()
345 * \param[in] argv array of command line arguments passed to main()
346 * \param[out] unparsed_args output vector of unparsed arguments
347 * \retval true if the command line arguments are successfully parsed
348 * \retval false otherwise
349 */
350 505 bool parse_internal(
351 int argc, char** argv, std::vector<std::string>& unparsed_args
352 ) {
353 505 geo_argc = argc;
354 505 geo_argv = argv;
355
356 505 parse_config_file(argc, argv);
357
358 505 bool ok = true;
359 505 desc_->argv0 = argv[0];
360 505 unparsed_args.clear();
361
362
2/2
✓ Branch 0 taken 1445 times.
✓ Branch 1 taken 505 times.
1950 for(int i = 1; i < argc; i++) {
363 1445 std::vector<std::string> parsed_arg;
364
2/4
✓ Branch 1 taken 1445 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1445 times.
✗ Branch 5 not taken.
1445 String::split_string(argv[i], '=', parsed_arg);
365
2/2
✓ Branch 1 taken 680 times.
✓ Branch 2 taken 765 times.
1445 if(parsed_arg.size() != 2) {
366
2/4
✓ Branch 1 taken 680 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 680 times.
✗ Branch 5 not taken.
1360 unparsed_args.push_back(argv[i]);
367 } else {
368 765 if(
369
9/16
✓ Branch 1 taken 765 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 765 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 743 times.
✓ Branch 8 taken 22 times.
✓ Branch 9 taken 709 times.
✓ Branch 10 taken 34 times.
✓ Branch 12 taken 765 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 731 times.
✓ Branch 15 taken 34 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
3803 String::string_starts_with(parsed_arg[0], "dbg:") ||
370
2/4
✓ Branch 3 taken 743 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 765 times.
✗ Branch 7 not taken.
1508 desc_->args.find(parsed_arg[0]) != desc_->args.end()
371 ) {
372
3/4
✓ Branch 3 taken 731 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 729 times.
731 if(!set_arg(parsed_arg[0], parsed_arg[1])) {
373 2 ok = false;
374 }
375 } else {
376
377 34 std::vector<std::string> matches;
378
2/2
✓ Branch 5 taken 2992 times.
✓ Branch 6 taken 34 times.
3026 for( auto& it : desc_->args) {
379
2/2
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 2960 times.
2992 if(arg_matches(parsed_arg[0], it.first)) {
380
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 matches.push_back(it.first);
381 }
382 }
383
384
2/2
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 2 times.
34 if(matches.size() == 1) {
385
2/4
✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 32 times.
32 if(!set_arg(matches[0], parsed_arg[1])) {
386 ✗ ok = false;
387 }
388
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 } else if(matches.size() >= 2) {
389 ✗ ok = false;
390 ✗ Logger::instance()->set_quiet(false);
391 ✗ Logger::err("CmdLine")
392 ✗ << "Argument is ambiguous: " << argv[i]
393 ✗ << std::endl
394 << "Possible matches: "
395 ✗ << String::join_strings(matches, ' ')
396 ✗ << std::endl;
397 } else {
398 2 ok = false;
399
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 Logger::instance()->set_quiet(false);
400
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
6 Logger::err("CmdLine")
401
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
2 << "Invalid argument: " << parsed_arg[0]
402
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 << std::endl;
403 }
404 34 }
405 }
406 1445 }
407 505 return ok;
408 }
409
410 /**
411 * \brief Extracts the group name from an argument
412 * \details If the command line argument \p name has the form
413 * "group:arg", then "group" is returned, otherwise the argument is
414 * considered to be global and the "global" group is returned.
415 * \param[in] name the name of the argument
416 * \return the group name or "global"
417 */
418 11535 std::string arg_group(const std::string& name) {
419 11535 size_t pos = name.find(':');
420 return pos == std::string::npos
421
2/4
✓ Branch 0 taken 2119 times.
✓ Branch 1 taken 9416 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
13654 ? std::string("global")
422
4/6
✓ Branch 0 taken 2119 times.
✓ Branch 1 taken 9416 times.
✓ Branch 3 taken 2119 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 9416 times.
✗ Branch 7 not taken.
25189 : name.substr(0, pos);
423 }
424
425
426 /**
427 * \brief Gets an argument as a string for display.
428 * \param[in] arg_name the name of the argument.
429 * \return a string with the value of the argument for
430 * display.
431 * \details It ignores least significant digits for floating
432 * point arguments.
433 */
434 70 std::string get_display_arg(const std::string& arg_name) {
435 70 CmdLine::ArgType arg_type = get_arg_type(arg_name);
436 70 std::string result;
437
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 64 times.
70 if(arg_type == CmdLine::ARG_DOUBLE) {
438
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 double x = CmdLine::get_arg_double(arg_name);
439
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 result = String::to_display_string(x);
440
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 53 times.
64 } else if(arg_type == CmdLine::ARG_PERCENT) {
441
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 double x = CmdLine::get_arg_percent(arg_name, 100.0);
442
2/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
11 result = String::to_display_string(x) + "%";
443 } else {
444
1/2
✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
53 result = CmdLine::get_arg(arg_name);
445
2/4
✓ Branch 2 taken 53 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 53 times.
53 if(result.length() > ui_terminal_width()/2) {
446 // TODO: fix display long lines in terminal
447 // (that trigger infinite loop for now)
448 ✗ result = "...";
449 }
450 }
451 70 return result;
452 ✗ }
453
454 /**
455 * \brief Private data used for printing ArgGroup details
456 */
457 struct Line {
458 std::string name;
459 std::string value;
460 std::string desc;
461 };
462
463 /**
464 * \brief Prints arguments of a group
465 * \details This function is called by show_usage() to display help on a
466 * group of arguments. It displays a fancy box that summarizes all
467 * arguments of the group \p group. By default, only standard arguments
468 * are displayed. If parameter \p advanced is set to \c true, the function
469 * also displays advanced arguments.
470 * \param[in] group the group name
471 * \param[in] advanced boolean flag that controls the display of
472 * advanced arguments in the group.
473 * \see show_usage()
474 */
475 59 void show_group(const std::string& group, bool advanced) {
476
477
1/2
✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
59 auto it = desc_->groups.find(group);
478
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 59 times.
59 if(it == desc_->groups.end()) {
479 45 return;
480 }
481
482 59 const Group& g = it->second;
483 59 bool advanced_group = g.flags & ARG_ADVANCED;
484
3/4
✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 14 times.
59 if(!advanced && advanced_group) {
485 45 return;
486 }
487
488
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if(advanced_group) {
489 ✗ ui_separator(g.desc, "*" + g.name);
490 } else {
491
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 ui_separator(g.desc, g.name);
492 }
493
494 // Step 1:
495 // Build a vector of lines that contain the various elements to
496 // print for the argument, and compute the maximum width of the
497 // argument names followed by their default value. This will allow
498 // us to align the closing paren of the default value.
499
500 14 std::vector<Line> lines;
501 14 index_t max_left_width = 0;
502
503
2/2
✓ Branch 1 taken 103 times.
✓ Branch 2 taken 14 times.
117 for(size_t i = 0; i < g.args.size(); i++) {
504
1/2
✓ Branch 2 taken 103 times.
✗ Branch 3 not taken.
103 auto ita = desc_->args.find(g.args[i]);
505
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 103 times.
103 if(ita == desc_->args.end()) {
506 33 continue;
507 }
508
509 103 const Arg& arg = ita->second;
510 103 bool advanced_arg = arg.flags & ARG_ADVANCED;
511
3/4
✓ Branch 0 taken 103 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 70 times.
103 if(!advanced && advanced_arg) {
512 33 continue;
513 }
514
515
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
70 const char* name_marker = (advanced_arg && !man_mode) ? "*" : " ";
516
517 70 Line line;
518
1/2
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
70 line.name = name_marker + arg.name;
519
3/6
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 70 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 70 times.
✗ Branch 8 not taken.
70 line.value = " (=" + get_display_arg(arg.name) + ") : ";
520
1/2
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
70 line.desc = arg.desc;
521
1/2
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
70 lines.push_back(line);
522
523 140 max_left_width = std::max(
524 70 index_t(line.name.length() + line.value.length()),
525 max_left_width
526 );
527 70 }
528
529 // Step 2:
530 // Print the lines constructed in step 1 with default values
531 // right aligned.
532
533
2/2
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 14 times.
84 for(size_t i = 0; i < lines.size(); i++) {
534 70 const Line& line = lines[i];
535 70 int value_width = int(max_left_width - line.name.length());
536
1/2
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
70 std::ostringstream os;
537 70 os << line.name
538 70 << std::setw(value_width) << line.value
539
3/6
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 70 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 70 times.
✗ Branch 10 not taken.
70 << line.desc
540
1/2
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
70 << std::endl;
541
2/4
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 70 times.
✗ Branch 5 not taken.
70 ui_message(os.str(), max_left_width);
542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if(man_mode) {
543 ✗ ui_message("\n");
544 }
545 70 }
546 14 }
547
548 }
549
550 /****************************************************************************/
551
552 namespace GEO {
553
554 namespace CmdLine {
555
556 255 void initialize() {
557
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 255 times.
255 desc_ = new CommandLineDesc;
558
3/6
✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 255 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 255 times.
✗ Branch 8 not taken.
765 declare_arg_group("global", "");
559 255 }
560
561 255 void terminate() {
562 255 ui_close_separator();
563
1/2
✓ Branch 0 taken 255 times.
✗ Branch 1 not taken.
255 delete desc_;
564 255 desc_ = nullptr;
565 255 }
566
567 ✗ int argc() {
568 ✗ return geo_argc;
569 }
570
571 ✗ char** argv() {
572 ✗ return geo_argv;
573 }
574
575 ✗ void set_config_file_name(
576 const std::string& filename, bool auto_create
577 ) {
578 ✗ config_file_name = filename;
579 ✗ auto_create_args = auto_create;
580 ✗ }
581
582 ✗ std::string get_config_file_name() {
583 ✗ return config_file_name;
584 }
585
586 ✗ void load_config(
587 const std::string& filename, const std::string& program_name
588 ) {
589 ✗ parse_config_file(filename, program_name);
590 ✗ }
591
592 ✗ void save_config(const std::string& filename) {
593 ✗ std::ofstream out(filename);
594 ✗ if(!out) {
595 ✗ Logger::err("CmdLine") << filename << ": could not create"
596 ✗ << std::endl;
597 }
598 ✗ for(const auto& arg: desc_->args) {
599 ✗ const std::string& argname = arg.first;
600 ✗ out << argname << "=" << get_arg(argname) << std::endl;
601 }
602 ✗ }
603
604
605 ✗ bool config_file_loaded() {
606 ✗ return loaded_config_file;
607 }
608
609 255 bool parse(
610 int argc, char** argv, std::vector<std::string>& unparsed_args,
611 const std::string& additional_arg_specs
612 ) {
613
3/4
✓ Branch 1 taken 255 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 251 times.
255 if(!parse_internal(argc, argv, unparsed_args)) {
614 4 return false;
615 }
616
617
3/6
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 251 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 251 times.
✗ Branch 8 not taken.
502 if(arg_is_declared("profile")) {
618
2/4
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 251 times.
✗ Branch 5 not taken.
251 std::string profile = get_arg("profile");
619
2/4
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 251 times.
✗ Branch 4 not taken.
251 if(profile != "default") {
620
3/4
✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 250 times.
251 if(!set_profile(profile)) {
621 1 return false;
622 }
623 // Re-parse args to override values set by profiles
624 250 unparsed_args.clear();
625
1/2
✓ Branch 1 taken 250 times.
✗ Branch 2 not taken.
250 parse_internal(argc, argv, unparsed_args);
626 }
627
2/2
✓ Branch 1 taken 250 times.
✓ Branch 2 taken 1 times.
251 }
628
629
2/2
✓ Branch 1 taken 335 times.
✓ Branch 2 taken 250 times.
585 for(index_t i = 0; i < unparsed_args.size(); ++i) {
630 335 const std::string& arg = unparsed_args[i];
631 335 if(
632
1/2
✓ Branch 1 taken 335 times.
✗ Branch 2 not taken.
335 arg == "-h" ||
633
2/4
✓ Branch 1 taken 335 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 335 times.
✗ Branch 4 not taken.
335 arg == "-?" ||
634
4/8
✓ Branch 0 taken 335 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 335 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 335 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 335 times.
1005 arg == "/h" ||
635
2/4
✓ Branch 1 taken 335 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 335 times.
335 arg == "/?"
636 ) {
637 ✗ show_usage(additional_arg_specs, true);
638 ✗ exit(0);
639 }
640
2/4
✓ Branch 1 taken 335 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 335 times.
335 if(arg == "--help") {
641 ✗ CmdLine::set_arg("log:pretty",false);
642 ✗ man_mode = true;
643 ✗ show_usage(additional_arg_specs, true);
644 ✗ exit(0);
645 }
646
5/10
✓ Branch 1 taken 335 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 335 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 335 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 335 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 335 times.
335 if(arg == "--version" || arg == "--v") {
647 ✗ std::cout << std::endl;
648 ✗ std::cout << " " << FileSystem::base_name(argv[0])
649 << " "
650 ✗ << Environment::instance()->get_value("version")
651 << " (built "
652 ✗ << Environment::instance()->get_value(
653 ✗ "release_date")
654 ✗ << ")"
655 ✗ << std::endl
656 ✗ << " Copyright (C) Inria 2000-2022"
657 ✗ << std::endl
658 ✗ << " License: <https://github.com/BrunoLevy/geogram/blob/main/LICENSE>"
659 ✗ << std::endl
660 ✗ << " Website: <https://github.com/BrunoLevy/geogram>"
661 ✗ << std::endl;
662 ✗ std::cout << std::endl;
663 ✗ exit(0);
664 }
665 }
666
667 250 index_t min_unparsed = 0;
668 250 index_t max_unparsed = 0;
669 250 std::vector<std::string> additional_args;
670
1/2
✓ Branch 1 taken 250 times.
✗ Branch 2 not taken.
250 String::split_string(additional_arg_specs, ' ', additional_args);
671
2/2
✓ Branch 1 taken 459 times.
✓ Branch 2 taken 250 times.
709 for(index_t i = 0; i < additional_args.size(); ++i) {
672 459 const std::string& arg = additional_args[i];
673
5/6
✓ Branch 1 taken 206 times.
✓ Branch 2 taken 253 times.
✓ Branch 5 taken 206 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 206 times.
✓ Branch 8 taken 253 times.
459 if(arg[0] == '<' && arg[arg.length() - 1] == '>') {
674 206 ++max_unparsed;
675 253 } else if(
676 253 arg[0] == '<' &&
677
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 253 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 253 times.
253 arg[arg.length() - 2] == '>' &&
678 ✗ arg[arg.length() - 1] == '*'
679 ) {
680 ✗ min_unparsed=0;
681 ✗ max_unparsed=100000;
682 } else {
683 253 ++max_unparsed;
684 253 ++min_unparsed;
685 }
686 }
687
688 250 if(
689
4/4
✓ Branch 1 taken 247 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 243 times.
497 unparsed_args.size() > max_unparsed ||
690
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 243 times.
247 unparsed_args.size() < min_unparsed
691 ) {
692
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 show_usage(additional_arg_specs);
693 7 return false;
694 }
695
696 #ifndef GEOGRAM_PSM
697
1/2
✓ Branch 1 taken 243 times.
✗ Branch 2 not taken.
243 nlPrintfFuncs(geogram_printf, geogram_fprintf);
698
1/2
✓ Branch 1 taken 243 times.
✗ Branch 2 not taken.
243 nlInitialize(argc, argv);
699 #endif
700 243 if(
701
5/14
✓ Branch 1 taken 243 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 243 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 243 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 243 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 243 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1215 CmdLine::arg_is_declared("nl:CUDA") &&
702
6/16
✓ Branch 1 taken 243 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 243 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 243 times.
✓ Branch 8 taken 243 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 243 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 243 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
729 CmdLine::get_arg_bool("nl:CUDA")
703 ) {
704 ✗ geo_cite("DBLP:journals/paapp/BuatoisCL09");
705 }
706
707 // Re-initialize stopwatch so that it will enable
708 // global log if sys:stats is set.
709
1/2
✓ Branch 1 taken 243 times.
✗ Branch 2 not taken.
243 Stopwatch::initialize();
710
711 243 return true;
712 250 }
713
714 2 bool parse(int argc, char** argv) {
715 2 std::vector<std::string> unparsed_args;
716
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
4 return parse(argc, argv, unparsed_args, "");
717 2 }
718
719 1969 void declare_arg_group(
720 const std::string& name,
721 const std::string& description,
722 ArgFlags flags
723 ) {
724
2/4
✓ Branch 2 taken 1969 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1969 times.
1969 if(desc_->groups.find(name) != desc_->groups.end()) {
725 ✗ Logger::err("CmdLine")
726 ✗ << "Group is multiply defined: " << name
727 ✗ << std::endl;
728 ✗ return;
729 }
730
731 1969 Group group;
732
1/2
✓ Branch 1 taken 1969 times.
✗ Branch 2 not taken.
1969 group.name = name;
733
1/2
✓ Branch 1 taken 1969 times.
✗ Branch 2 not taken.
1969 group.desc = description;
734 1969 group.flags = flags;
735
2/4
✓ Branch 1 taken 1969 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1969 times.
✗ Branch 5 not taken.
1969 desc_->groups[name] = group;
736
1/2
✓ Branch 1 taken 1969 times.
✗ Branch 2 not taken.
1969 desc_->group_names.push_back(name);
737 1969 }
738
739 11535 void declare_arg(
740 const std::string& name,
741 ArgType type,
742 const std::string& default_value,
743 const std::string& description,
744 ArgFlags flags
745 ) {
746
2/4
✓ Branch 2 taken 11535 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 11535 times.
11535 if(desc_->args.find(name) != desc_->args.end()) {
747 ✗ Logger::err("CmdLine")
748 ✗ << "Argument is multiply defined: " << name
749 ✗ << std::endl;
750 ✗ return;
751 }
752
753 11535 Arg arg;
754
1/2
✓ Branch 1 taken 11535 times.
✗ Branch 2 not taken.
11535 arg.name = name;
755 11535 arg.type = type;
756
1/2
✓ Branch 1 taken 11535 times.
✗ Branch 2 not taken.
11535 arg.desc = description;
757 11535 arg.flags = flags;
758
2/4
✓ Branch 1 taken 11535 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11535 times.
✗ Branch 5 not taken.
11535 desc_->args[name] = arg;
759
760
2/4
✓ Branch 1 taken 11535 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11535 times.
✗ Branch 5 not taken.
11535 Environment::instance()->set_value(name, default_value);
761
762
1/2
✓ Branch 1 taken 11535 times.
✗ Branch 2 not taken.
11535 std::string group = arg_group(name);
763
1/2
✓ Branch 1 taken 11535 times.
✗ Branch 2 not taken.
11535 auto it = desc_->groups.find(group);
764
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 11535 times.
11535 if(it == desc_->groups.end()) {
765 ✗ Logger::err("CmdLine")
766 ✗ << "Argument group does not exist: " << name
767 ✗ << std::endl;
768 ✗ return;
769 }
770
771
1/2
✓ Branch 2 taken 11535 times.
✗ Branch 3 not taken.
11535 it->second.args.push_back(name);
772
2/4
✓ Branch 1 taken 11535 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11535 times.
✗ Branch 5 not taken.
11535 }
773
774 8198 ArgType get_arg_type(const std::string& name) {
775
1/2
✓ Branch 1 taken 8198 times.
✗ Branch 2 not taken.
8198 auto it = desc_->args.find(name);
776 16396 return it == desc_->args.end()
777
2/2
✓ Branch 0 taken 3169 times.
✓ Branch 1 taken 5029 times.
8198 ? ARG_UNDEFINED
778 16396 : it->second.type;
779 }
780
781 ✗ std::string get_arg_desc(const std::string& name) {
782 ✗ auto it = desc_->args.find(name);
783 ✗ return it == desc_->args.end()
784 ✗ ? ""
785 ✗ : it->second.desc;
786 }
787
788 7984 std::string get_arg(const std::string& name) {
789 7984 Process::acquire_spinlock(lock);
790 7984 std::string result = Environment::instance()->get_value(name);
791 7984 Process::release_spinlock(lock);
792 7984 return result;
793 }
794
795 1502 bool arg_is_declared(const std::string& name) {
796 1502 return get_arg_type(name) != ARG_UNDEFINED;
797 }
798
799 77 int get_arg_int(const std::string& name) {
800 77 ArgType type = get_arg_type(name);
801
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
77 geo_assert_arg_type(type, ARG_INT);
802
2/4
✓ Branch 1 taken 77 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 77 times.
✗ Branch 5 not taken.
77 return String::to_int(get_arg(name));
803 }
804
805 195 unsigned int get_arg_uint(const std::string& name) {
806 195 ArgType type = get_arg_type(name);
807
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
195 geo_assert_arg_type(type, ARG_INT);
808
2/4
✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 195 times.
✗ Branch 5 not taken.
195 return String::to_uint(get_arg(name));
809 }
810
811 129 double get_arg_double(const std::string& name) {
812 129 ArgType type = get_arg_type(name);
813
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 129 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
129 geo_assert_arg_type(type, ARG_DOUBLE);
814
2/4
✓ Branch 1 taken 129 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 129 times.
✗ Branch 5 not taken.
129 return String::to_double(get_arg(name));
815 }
816
817 158 double get_arg_percent(
818 const std::string& name, double reference
819 ) {
820
1/2
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
158 ArgType type = get_arg_type(name);
821
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 158 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
158 geo_assert_arg_type(type, ARG_PERCENT);
822 double result;
823
1/2
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
158 std::string s = get_arg(name);
824
4/8
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 158 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 158 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 158 times.
✗ Branch 10 not taken.
158 if(s.length() > 0 && s[s.length() - 1] == '%') {
825
1/2
✓ Branch 2 taken 158 times.
✗ Branch 3 not taken.
158 s.resize(s.length() - 1);
826
1/2
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
158 result = String::to_double(s) * reference * 0.01;
827
2/4
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 158 times.
✗ Branch 5 not taken.
316 Logger::out("CmdLine")
828
4/8
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 158 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 158 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 158 times.
✗ Branch 11 not taken.
158 << "using " << name << "=" << result
829
4/8
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 158 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 158 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 158 times.
✗ Branch 11 not taken.
316 << "(" << get_arg(name) << ")"
830
1/2
✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
158 << std::endl;
831 } else {
832 ✗ result = String::to_double(s);
833 ✗ Logger::out("CmdLine")
834 ✗ << "using " << name << "=" << result
835 ✗ << std::endl;
836 }
837 158 return result;
838 158 }
839
840 2275 bool get_arg_bool(const std::string& name) {
841 2275 ArgType type = get_arg_type(name);
842
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 2275 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2275 geo_assert_arg_type(type, ARG_BOOL);
843
4/6
✓ Branch 1 taken 2275 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2275 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2214 times.
✓ Branch 7 taken 61 times.
4489 return Environment::instance()->has_value(name) &&
844
6/10
✓ Branch 1 taken 2214 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2214 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 619 times.
✓ Branch 7 taken 1595 times.
✓ Branch 8 taken 2214 times.
✓ Branch 9 taken 61 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
4489 String::to_bool(get_arg(name));
845 }
846
847 2327 bool set_arg(const std::string& name, const std::string& value) {
848
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2325 times.
2327 if(!check_arg_value(name, value)) {
849 2 return false;
850 }
851 2325 Process::acquire_spinlock(lock);
852 2325 Environment::instance()->set_value(name, value);
853 2325 Process::release_spinlock(lock);
854 2325 return true;
855 }
856
857 233 void set_arg(const std::string& name, Numeric::int32 value) {
858 233 ArgType type = get_arg_type(name);
859
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 233 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
233 geo_assert_arg_type(
860 type, ARG_INT | ARG_DOUBLE | ARG_PERCENT | ARG_STRING
861 );
862
2/4
✓ Branch 1 taken 233 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 233 times.
✗ Branch 5 not taken.
233 set_arg(name, String::to_string(value));
863 233 }
864
865 18 void set_arg(const std::string& name, Numeric::uint32 value) {
866 18 ArgType type = get_arg_type(name);
867
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
18 geo_assert_arg_type(
868 type, ARG_INT | ARG_DOUBLE | ARG_PERCENT | ARG_STRING
869 );
870
2/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
18 set_arg(name, String::to_string(value));
871 18 }
872
873 ✗ void set_arg(const std::string& name, Numeric::int64 value) {
874 ✗ ArgType type = get_arg_type(name);
875 ✗ geo_assert_arg_type(
876 type, ARG_INT | ARG_DOUBLE | ARG_PERCENT | ARG_STRING
877 );
878 ✗ set_arg(name, String::to_string(value));
879 ✗ }
880
881 ✗ void set_arg(const std::string& name, Numeric::uint64 value) {
882 ✗ ArgType type = get_arg_type(name);
883 ✗ geo_assert_arg_type(
884 type, ARG_INT | ARG_DOUBLE | ARG_PERCENT | ARG_STRING
885 );
886 ✗ set_arg(name, String::to_string(value));
887 ✗ }
888
889 233 void set_arg(const std::string& name, double value) {
890 233 ArgType type = get_arg_type(name);
891
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 233 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
233 geo_assert_arg_type(type, ARG_DOUBLE | ARG_PERCENT | ARG_STRING);
892
2/4
✓ Branch 1 taken 233 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 233 times.
✗ Branch 5 not taken.
233 set_arg(name, String::to_string(value));
893 233 }
894
895 280 void set_arg(const std::string& name, bool value) {
896 280 ArgType type = get_arg_type(name);
897
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 280 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
280 geo_assert_arg_type(type, ARG_BOOL | ARG_STRING);
898
2/4
✓ Branch 1 taken 280 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 280 times.
✗ Branch 5 not taken.
280 set_arg(name, String::to_string(value));
899 280 }
900
901 701 void set_arg_percent(const std::string& name, double value) {
902 701 ArgType type = get_arg_type(name);
903
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 701 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
701 geo_assert_arg_type(type, ARG_PERCENT | ARG_STRING);
904
3/6
✓ Branch 1 taken 701 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 701 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 701 times.
✗ Branch 8 not taken.
701 set_arg(name, String::to_string(value) + "%");
905 701 }
906
907 ✗ void get_arg_groups(std::vector<std::string>& groups) {
908 ✗ groups.clear();
909 ✗ for(auto& it : desc_->group_names) {
910 ✗ groups.push_back(it);
911 }
912 ✗ }
913
914 ✗ void get_arg_names_in_group(
915 const std::string& group, std::vector<std::string>& arg_names
916 ) {
917 ✗ arg_names.clear();
918 ✗ auto it = desc_->groups.find(group);
919 ✗ if(it == desc_->groups.end()) {
920 ✗ return;
921 }
922 ✗ const Group& g = it->second;
923 ✗ for(auto jt: g.args) {
924 ✗ arg_names.push_back(jt);
925 ✗ }
926 }
927
928 7 void show_usage(const std::string& additional_args, bool advanced) {
929
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 std::string program_name = FileSystem::base_name(desc_->argv0);
930
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 Logger::instance()->set_quiet(false);
931
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
14 Logger::out("")
932 << "Usage: " << program_name << " "
933 << additional_args
934
6/12
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 7 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 7 times.
✗ Branch 17 not taken.
7 << " <parameter=value>*" << std::endl;
935
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if(!advanced) {
936
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
21 Logger::out("")
937 << "Showing basic parameters (use " << program_name
938
3/6
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
7 << " -h to see advanced parameters)"
939
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 << std::endl;
940 }
941
942
2/2
✓ Branch 2 taken 59 times.
✓ Branch 3 taken 7 times.
73 for(auto& it : desc_->group_names) {
943
1/2
✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
59 show_group(it, advanced);
944 }
945 7 }
946
947 105 void get_args(std::vector<std::string>& args) {
948 105 args.clear();
949
2/2
✓ Branch 5 taken 4363 times.
✓ Branch 6 taken 105 times.
4468 for(auto& it : desc_->args) {
950
3/6
✓ Branch 1 taken 4363 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4363 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4363 times.
✗ Branch 8 not taken.
4363 std::string cur_arg = it.first + "=" + get_arg(it.first);
951
1/2
✓ Branch 1 taken 4363 times.
✗ Branch 2 not taken.
4363 args.push_back(cur_arg);
952 4363 }
953 105 }
954 }
955 }
956
957 // =================== Console logging utilies =====================
958
959 namespace {
960
961 using namespace GEO;
962 using namespace CmdLine;
963
964 /** Keeps length of a feature name */
965 bool ui_separator_opened = false;
966
967 /** Width of the current terminal */
968 index_t ui_term_width = 79;
969
970 /** Terminal left margin */
971 index_t ui_left_margin = 0;
972
973 /** Terminal right margin */
974 index_t ui_right_margin = 0;
975
976 /** Characters of the progress wheel */
977 const char working[] = {'|', '/', '-', '\\'};
978
979 /** Current index in the progress wheel */
980 index_t working_index = 0;
981
982 /** Characters of the progress wave */
983 const char waves[] = {',', '.', 'o', 'O', '\'', 'O', 'o', '.', ','};
984
985 /**
986 * \brief Gets the console output stream
987 * \return a reference to a std::ostream
988 */
989 6775 inline std::ostream& ui_out() {
990 6775 return std::cout;
991 }
992
993 /**
994 * \brief Prints a sequence of identical chars
995 * \param[in] c the character to print
996 * \param[in] nb the number of characters to print
997 */
998 ✗ inline void ui_pad(char c, size_t nb) {
999 ✗ for(index_t i = 0; i < nb; i++) {
1000 ✗ std::cout << c;
1001 }
1002 ✗ }
1003
1004 /**
1005 * \brief Checks if the standard output is redirected
1006 * \details It is used by the various console formatting functions to
1007 * determine if messages are printed in pretty mode or not.
1008 * \retval true if the console is redirected to a file
1009 * \retval false otherwise
1010 */
1011 26334 bool is_redirected() {
1012 static bool initialized = false;
1013 static bool result;
1014
2/2
✓ Branch 0 taken 255 times.
✓ Branch 1 taken 26079 times.
26334 if(!initialized) {
1015 #ifdef GEO_OS_WINDOWS
1016 result = !_isatty(1);
1017 #else
1018 255 result = !isatty(1);
1019 #endif
1020 255 initialized = true;
1021 }
1022
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26334 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
26334 return result || !Logger::instance()->is_pretty();
1023 }
1024
1025 /**
1026 * \brief Recomputes the width of the terminal
1027 */
1028 53 void update_ui_term_width() {
1029 #ifdef GEO_OS_EMSCRIPTEN
1030 return; // ioctl not implemented under emscripten
1031 #else
1032 #ifndef GEO_OS_WINDOWS
1033
2/4
✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 53 times.
✗ Branch 4 not taken.
53 if(is_redirected()) {
1034 53 return;
1035 }
1036 struct winsize w;
1037 ✗ ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
1038 ✗ ui_term_width = w.ws_col;
1039 ✗ if(ui_term_width < 20) {
1040 ✗ ui_term_width = 79;
1041 }
1042 ✗ if(ui_term_width <= 82) {
1043 ✗ ui_left_margin = 0;
1044 ✗ ui_right_margin = 0;
1045 ✗ } else if(ui_term_width < 90) {
1046 ✗ ui_left_margin = 2;
1047 ✗ ui_right_margin = 2;
1048 } else {
1049 ✗ ui_left_margin = 4;
1050 ✗ ui_right_margin = 4;
1051 }
1052 #endif
1053 #endif
1054 }
1055
1056 /**
1057 * \brief Safe unsigned subtraction
1058 * \return a - b if a > b, 0 otherwise
1059 */
1060 ✗ inline size_t sub(size_t a, size_t b) {
1061 ✗ return a > b ? a - b : 0;
1062 }
1063 }
1064
1065 namespace GEO {
1066
1067 namespace CmdLine {
1068
1069 53 index_t ui_terminal_width() {
1070 53 index_t ui_term_width_bkp = ui_term_width;
1071
1/2
✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
53 update_ui_term_width();
1072 53 ui_term_width = std::min(ui_term_width, ui_term_width_bkp);
1073 53 return ui_term_width;
1074 }
1075
1076 6141 void ui_separator() {
1077
3/6
✓ Branch 2 taken 6141 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 6141 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 6141 times.
✗ Branch 8 not taken.
6141 if(Logger::instance()->is_quiet() || is_redirected()) {
1078 6141 return;
1079 }
1080
1081 ✗ update_ui_term_width();
1082 ✗ ui_separator_opened = true;
1083
1084 ✗ ui_out() << " ";
1085 ✗ ui_pad(' ', ui_left_margin);
1086 ✗ ui_pad(
1087 '_',
1088 ✗ sub(ui_terminal_width(), 2 + ui_left_margin + ui_right_margin)
1089 );
1090 ✗ ui_out() << " " << std::endl;
1091
1092 // Force a blank line under the separator
1093 ✗ ui_message("\n");
1094 }
1095
1096 317 void ui_separator(
1097 const std::string& title,
1098 const std::string& short_title
1099 ) {
1100
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 317 times.
317 if(Logger::instance()->is_quiet()) {
1101 ✗ return;
1102 }
1103
1104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 317 times.
317 if(man_mode) {
1105 ✗ if(title == "") {
1106 ✗ return;
1107 }
1108 ✗ ui_out() << std::endl;
1109 ✗ std::string shortt = short_title;
1110 ✗ if(shortt.length() > 0 && shortt[0] == '*') {
1111 ✗ shortt = shortt.substr(1, shortt.length()-1);
1112 ✗ ui_out() << title << " (\"" << shortt << ":*\" options, advanced)"
1113 ✗ << std::endl;
1114 } else {
1115 ✗ ui_out() << title << " (\"" << shortt << ":*\" options)"
1116 ✗ << std::endl;
1117 }
1118 ✗ ui_out() << std::endl << std::endl;
1119 ✗ return;
1120 ✗ }
1121
1122
1/2
✓ Branch 1 taken 317 times.
✗ Branch 2 not taken.
317 if(is_redirected()) {
1123 317 ui_out() << std::endl;
1124
6/6
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 303 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 310 times.
317 if(short_title != "" && title != "") {
1125 7 ui_out() << "=[" << short_title << "]=["
1126 7 << title << "]=" << std::endl;
1127 } else {
1128
1/2
✓ Branch 1 taken 310 times.
✗ Branch 2 not taken.
310 std::string s = title + short_title;
1129
4/8
✓ Branch 2 taken 310 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 310 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 310 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 310 times.
✗ Branch 12 not taken.
310 ui_out() << "=[" << s << "]=" << std::endl;
1130 310 }
1131 317 return;
1132 }
1133
1134 ✗ update_ui_term_width();
1135 ✗ ui_separator_opened = true;
1136
1137 ✗ size_t L = title.length() + short_title.length();
1138
1139 ✗ ui_out() << " ";
1140 ✗ ui_pad(' ', ui_left_margin);
1141 ✗ ui_pad('_', L + 14);
1142 ✗ ui_out() << std::endl;
1143
1144 ✗ ui_pad(' ', ui_left_margin);
1145 ✗ if(short_title != "" && title != "") {
1146 ✗ ui_out() << " _/ ==[" << short_title << "]====["
1147 ✗ << title << "]== \\";
1148 } else {
1149 ✗ std::string s = title + short_title;
1150 ✗ ui_out() << " _/ =====[" << s << "]===== \\";
1151 ✗ }
1152
1153 ✗ ui_pad(
1154 '_',
1155 sub(
1156 ✗ ui_terminal_width(),
1157 ✗ 19 + L + ui_left_margin + ui_right_margin
1158 )
1159 );
1160 ✗ ui_out() << std::endl;
1161
1162 // Force a blank line under the separator
1163 ✗ ui_message("\n");
1164 }
1165
1166 6071 void ui_message(const std::string& message) {
1167 // By default, wrap to the column that is right after the feature
1168 // name and its decorations.
1169 6071 ui_message(message, feature_max_length + 5);
1170 6071 }
1171
1172 6141 void ui_message(
1173 const std::string& message,
1174 index_t wrap_margin
1175 ) {
1176
2/4
✓ Branch 1 taken 6141 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6141 times.
6141 if(Logger::instance()->is_quiet()) {
1177 6141 return;
1178 }
1179
1180
1/2
✓ Branch 0 taken 6141 times.
✗ Branch 1 not taken.
6141 if(!ui_separator_opened) {
1181
1/2
✓ Branch 1 taken 6141 times.
✗ Branch 2 not taken.
6141 ui_separator();
1182 }
1183
1184
2/4
✓ Branch 1 taken 6141 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6141 times.
✗ Branch 4 not taken.
6141 if(is_redirected()) {
1185
1/2
✓ Branch 2 taken 6141 times.
✗ Branch 3 not taken.
6141 ui_out() << message;
1186 6141 return;
1187 }
1188
1189 ✗ std::string cur = message;
1190 size_t maxL =
1191 ✗ sub(ui_terminal_width(), 4 + ui_left_margin + ui_right_margin);
1192 ✗ index_t wrap = 0;
1193
1194 for(;;) {
1195 ✗ std::size_t newline = cur.find('\n');
1196 ✗ if(newline != std::string::npos && newline < maxL) {
1197 // Got a new line that occurs before the right border
1198 // We cut before the newline and pad with spaces
1199 ✗ ui_pad(' ', ui_left_margin);
1200 ✗ ui_out() << "| ";
1201 ✗ ui_pad(' ', wrap);
1202 ✗ ui_out() << cur.substr(0, newline);
1203 ✗ ui_pad(' ', sub(maxL,newline));
1204 ✗ ui_out() << " |" << std::endl;
1205 ✗ cur = cur.substr(newline + 1);
1206 ✗ } else if(cur.length() > maxL) {
1207 // The line length runs past the right border
1208 // We cut the string just before the border
1209 ✗ ui_pad(' ', ui_left_margin);
1210 ✗ ui_out() << "| ";
1211 ✗ ui_pad(' ', wrap);
1212 ✗ ui_out() << cur.substr(0, maxL);
1213 ✗ ui_out() << " |" << std::endl;
1214 ✗ cur = cur.substr(maxL);
1215 ✗ } else if(cur.length() != 0) {
1216 // Print the remaining portion of the string
1217 // and pad with spaces
1218 ✗ ui_pad(' ', ui_left_margin);
1219 ✗ ui_out() << "| ";
1220 ✗ ui_pad(' ', wrap);
1221 ✗ ui_out() << cur;
1222 ✗ ui_pad(' ', sub(maxL,cur.length()));
1223 ✗ ui_out() << " |";
1224 ✗ break;
1225 } else {
1226 // No more chars to print
1227 ✗ break;
1228 }
1229
1230 ✗ if(wrap == 0) {
1231 ✗ wrap = wrap_margin;
1232 ✗ maxL = sub(maxL,wrap_margin);
1233 }
1234 ✗ }
1235 ✗ }
1236
1237 52 void ui_clear_line() {
1238
3/6
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 52 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 52 times.
✗ Branch 8 not taken.
52 if(Logger::instance()->is_quiet() || is_redirected()) {
1239 52 return;
1240 }
1241
1242 ✗ ui_pad('\b', ui_terminal_width());
1243 ✗ ui_out() << std::flush;
1244 }
1245
1246 255 void ui_close_separator() {
1247
1/2
✓ Branch 0 taken 255 times.
✗ Branch 1 not taken.
255 if(!ui_separator_opened) {
1248 255 return;
1249 }
1250
1251 ✗ if(Logger::instance()->is_quiet() || is_redirected()) {
1252 ✗ return;
1253 }
1254
1255 ✗ ui_pad(' ', ui_left_margin);
1256 ✗ ui_out() << '\\';
1257 ✗ ui_pad(
1258 '_',
1259 ✗ sub(ui_terminal_width(), 2 + ui_left_margin + ui_right_margin)
1260 );
1261 ✗ ui_out() << '/';
1262 ✗ ui_out() << std::endl;
1263
1264 ✗ ui_separator_opened = false;
1265 }
1266
1267 1034 void ui_progress(
1268 const std::string& task_name, index_t val, index_t percent,
1269 bool clear
1270 ) {
1271
5/10
✓ Branch 1 taken 1034 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1034 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1034 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1034 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1034 times.
✗ Branch 12 not taken.
1034 if(Logger::instance()->is_quiet() || is_redirected()) {
1272 1034 return;
1273 }
1274
1275 ✗ working_index++;
1276
1277 ✗ std::ostringstream os;
1278
1279 ✗ if(percent != val) {
1280 ✗ os << ui_feature(task_name)
1281 << "("
1282 ✗ << working[(working_index % sizeof(working))]
1283 << ")-["
1284 ✗ << std::setw(3) << percent
1285 << "%]-["
1286 ✗ << std::setw(3) << val
1287 ✗ << "]--[";
1288 } else {
1289 ✗ os << ui_feature(task_name)
1290 << "("
1291 ✗ << working[(working_index % sizeof(working))]
1292 << ")-["
1293 ✗ << std::setw(3) << percent
1294 ✗ << "%]--------[";
1295 }
1296
1297 size_t max_L =
1298 ✗ sub(ui_terminal_width(), 43 + ui_left_margin + ui_right_margin);
1299
1300 ✗ max_L -= size_t(std::log10(std::max(double(val),1.0)));
1301 ✗ max_L += 2;
1302
1303 ✗ if(val > max_L) {
1304 // No space enough to expand the progress bar
1305 // Do some animation...
1306 ✗ for(index_t i = 0; i < max_L; i++) {
1307 ✗ os << waves[((val - i + working_index) % sizeof(waves))];
1308 }
1309 } else {
1310 ✗ for(index_t i = 0; i < val; i++) {
1311 ✗ os << "o";
1312 }
1313 }
1314 ✗ os << " ]";
1315
1316 ✗ if(clear) {
1317 ✗ ui_clear_line();
1318 }
1319 ✗ ui_message(os.str());
1320 ✗ }
1321
1322 45 void ui_progress_time(
1323 const std::string& task_name, double elapsed, bool clear
1324 ) {
1325
2/4
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 45 times.
45 if(Logger::instance()->is_quiet()) {
1326 ✗ return;
1327 }
1328
1329
1/2
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
45 std::ostringstream os;
1330
1/2
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
90 os << ui_feature(task_name)
1331
3/6
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 45 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 45 times.
✗ Branch 8 not taken.
45 << "Elapsed time: " << elapsed
1332
1/2
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
45 << "s\n";
1333
1334
1/2
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
45 if(clear) {
1335
1/2
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
45 ui_clear_line();
1336 }
1337
2/4
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 45 times.
✗ Branch 5 not taken.
45 ui_message(os.str());
1338 45 }
1339
1340 ✗ void ui_progress_canceled(
1341 const std::string& task_name,
1342 double elapsed, index_t percent, bool clear
1343 ) {
1344 ✗ if(Logger::instance()->is_quiet()) {
1345 ✗ return;
1346 }
1347
1348 ✗ std::ostringstream os;
1349 ✗ os << ui_feature(task_name)
1350 ✗ << "Task canceled after " << elapsed
1351 ✗ << "s (" << percent << "%)\n";
1352
1353 ✗ if(clear) {
1354 ✗ ui_clear_line();
1355 }
1356 ✗ ui_message(os.str());
1357 ✗ }
1358
1359 12703 std::string ui_feature(
1360 const std::string& feat_in, bool show
1361 ) {
1362
2/2
✓ Branch 1 taken 81 times.
✓ Branch 2 taken 12622 times.
12703 if(feat_in.empty()) {
1363
1/2
✓ Branch 1 taken 81 times.
✗ Branch 2 not taken.
81 return feat_in;
1364 }
1365
1366
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 12596 times.
12622 if(!show) {
1367
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
52 return std::string(feature_max_length + 5, ' ');
1368 }
1369
1370
1/2
✓ Branch 1 taken 12596 times.
✗ Branch 2 not taken.
12596 std::string result = feat_in;
1371
2/4
✓ Branch 1 taken 12596 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 12596 times.
12596 if(!is_redirected()) {
1372 ✗ result = result.substr(0, feature_max_length);
1373 }
1374
2/2
✓ Branch 1 taken 12507 times.
✓ Branch 2 taken 89 times.
12596 if(result.length() < feature_max_length) {
1375
1/2
✓ Branch 2 taken 12507 times.
✗ Branch 3 not taken.
12507 result.append(feature_max_length - result.length(), ' ');
1376 }
1377
2/4
✓ Branch 1 taken 12596 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12596 times.
✗ Branch 5 not taken.
12596 return "o-[" + result + "] ";
1378 12596 }
1379 }
1380 }
1381
1382 #ifdef GEO_OS_ANDROID
1383 namespace {
1384 android_app* android_app_ = nullptr;
1385 }
1386
1387 namespace GEO {
1388 namespace CmdLine {
1389 void set_android_app(android_app* app) {
1390 android_app_ = app;
1391 }
1392
1393 android_app* get_android_app() {
1394 return android_app_;
1395 }
1396 }
1397 }
1398 #endif
1399