GCC Code Coverage Report


Directory: ./
File: basic/command_line.cpp
Date: 2026-09-27 03:22:43
Exec Total Coverage
Lines: 385 659 58.4%
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 2816 bool arg_matches(
169 const std::string& arg_in, const std::string& arg_name
170 ) {
171 2816 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 2314 bool check_arg_value(
205 const std::string& name, const std::string& s
206 ) {
207 2314 ArgType type = get_arg_type(name);
208
4/4
✓ Branch 0 taken 976 times.
✓ Branch 1 taken 1338 times.
✓ Branch 2 taken 396 times.
✓ Branch 3 taken 580 times.
2314 if(type == ARG_UNDEFINED || type == ARG_STRING) {
209 1734 return true;
210 }
211
212
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 472 times.
580 if(type == ARG_INT) {
213 int value;
214
3/4
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 107 times.
108 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 107 return true;
218 }
219 }
220
221
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 412 times.
472 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 329 times.
✓ Branch 1 taken 83 times.
412 if(type == ARG_BOOL) {
231 bool value;
232
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 329 times.
329 if(!String::from_string(s, value)) {
233 ✗ return arg_value_error(name, s, "boolean");
234 } else {
235 329 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 253 void parse_config_file(
267 const std::string& config_filename, const std::string& program_name
268 ) {
269
1/2
✓ Branch 1 taken 253 times.
✗ Branch 2 not taken.
253 std::string section = "*";
270
2/4
✓ Branch 1 taken 253 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 253 times.
253 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 253 }
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 501 void parse_config_file(int argc, char** argv) {
318
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 501 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
501 geo_assert(argc >= 1);
319 std::string program_name = String::to_uppercase(
320
2/4
✓ Branch 1 taken 501 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 501 times.
✗ Branch 5 not taken.
1002 FileSystem::base_name(argv[0])
321
1/2
✓ Branch 1 taken 501 times.
✗ Branch 2 not taken.
501 );
322 static bool init = false;
323
2/2
✓ Branch 0 taken 248 times.
✓ Branch 1 taken 253 times.
501 if(init) {
324 248 return;
325 }
326 253 init = true;
327
2/4
✓ Branch 1 taken 253 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 253 times.
✗ Branch 5 not taken.
759 Logger::out("config")
328
2/4
✓ Branch 1 taken 253 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 253 times.
✗ Branch 5 not taken.
253 << "Configuration file name:" << config_file_name
329
1/2
✓ Branch 1 taken 253 times.
✗ Branch 2 not taken.
253 << std::endl;
330
2/4
✓ Branch 1 taken 253 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 253 times.
✗ Branch 5 not taken.
253 Logger::out("config")
331
3/6
✓ Branch 1 taken 253 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 253 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 253 times.
✗ Branch 8 not taken.
506 << "Home directory:" << FileSystem::home_directory()
332
1/2
✓ Branch 1 taken 253 times.
✗ Branch 2 not taken.
253 << std::endl;
333 std::string config_filename =
334
3/6
✓ Branch 1 taken 253 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 253 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 253 times.
✗ Branch 8 not taken.
253 FileSystem::home_directory() + "/" + config_file_name;
335
1/2
✓ Branch 1 taken 253 times.
✗ Branch 2 not taken.
253 parse_config_file(config_filename, program_name);
336
2/2
✓ Branch 2 taken 253 times.
✓ Branch 3 taken 248 times.
501 }
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 501 bool parse_internal(
351 int argc, char** argv, std::vector<std::string>& unparsed_args
352 ) {
353 501 geo_argc = argc;
354 501 geo_argv = argv;
355
356 501 parse_config_file(argc, argv);
357
358 501 bool ok = true;
359 501 desc_->argv0 = argv[0];
360 501 unparsed_args.clear();
361
362
2/2
✓ Branch 0 taken 1433 times.
✓ Branch 1 taken 501 times.
1934 for(int i = 1; i < argc; i++) {
363 1433 std::vector<std::string> parsed_arg;
364
2/4
✓ Branch 1 taken 1433 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1433 times.
✗ Branch 5 not taken.
1433 String::split_string(argv[i], '=', parsed_arg);
365
2/2
✓ Branch 1 taken 672 times.
✓ Branch 2 taken 761 times.
1433 if(parsed_arg.size() != 2) {
366
2/4
✓ Branch 1 taken 672 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 672 times.
✗ Branch 5 not taken.
1344 unparsed_args.push_back(argv[i]);
367 } else {
368 761 if(
369
9/16
✓ Branch 1 taken 761 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 761 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 739 times.
✓ Branch 8 taken 22 times.
✓ Branch 9 taken 707 times.
✓ Branch 10 taken 32 times.
✓ Branch 12 taken 761 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 729 times.
✓ Branch 15 taken 32 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
3783 String::string_starts_with(parsed_arg[0], "dbg:") ||
370
2/4
✓ Branch 3 taken 739 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 761 times.
✗ Branch 7 not taken.
1500 desc_->args.find(parsed_arg[0]) != desc_->args.end()
371 ) {
372
3/4
✓ Branch 3 taken 729 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 727 times.
729 if(!set_arg(parsed_arg[0], parsed_arg[1])) {
373 2 ok = false;
374 }
375 } else {
376
377 32 std::vector<std::string> matches;
378
2/2
✓ Branch 5 taken 2816 times.
✓ Branch 6 taken 32 times.
2848 for( auto& it : desc_->args) {
379
2/2
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 2786 times.
2816 if(arg_matches(parsed_arg[0], it.first)) {
380
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 matches.push_back(it.first);
381 }
382 }
383
384
2/2
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 2 times.
32 if(matches.size() == 1) {
385
2/4
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 30 times.
30 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 32 }
405 }
406 1433 }
407 501 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 11417 std::string arg_group(const std::string& name) {
419 11417 size_t pos = name.find(':');
420 return pos == std::string::npos
421
2/4
✓ Branch 0 taken 2107 times.
✓ Branch 1 taken 9310 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
13524 ? std::string("global")
422
4/6
✓ Branch 0 taken 2107 times.
✓ Branch 1 taken 9310 times.
✓ Branch 3 taken 2107 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 9310 times.
✗ Branch 7 not taken.
24941 : 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 253 void initialize() {
557
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 253 times.
253 desc_ = new CommandLineDesc;
558
3/6
✓ Branch 1 taken 253 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 253 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 253 times.
✗ Branch 8 not taken.
759 declare_arg_group("global", "");
559 253 }
560
561 253 void terminate() {
562 253 ui_close_separator();
563
1/2
✓ Branch 0 taken 253 times.
✗ Branch 1 not taken.
253 delete desc_;
564 253 desc_ = nullptr;
565 253 }
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 253 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 253 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 249 times.
253 if(!parse_internal(argc, argv, unparsed_args)) {
614 4 return false;
615 }
616
617
3/6
✓ Branch 1 taken 249 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 249 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 249 times.
✗ Branch 8 not taken.
498 if(arg_is_declared("profile")) {
618
2/4
✓ Branch 1 taken 249 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 249 times.
✗ Branch 5 not taken.
249 std::string profile = get_arg("profile");
619
2/4
✓ Branch 1 taken 249 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 249 times.
✗ Branch 4 not taken.
249 if(profile != "default") {
620
3/4
✓ Branch 1 taken 249 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 248 times.
249 if(!set_profile(profile)) {
621 1 return false;
622 }
623 // Re-parse args to override values set by profiles
624 248 unparsed_args.clear();
625
1/2
✓ Branch 1 taken 248 times.
✗ Branch 2 not taken.
248 parse_internal(argc, argv, unparsed_args);
626 }
627
2/2
✓ Branch 1 taken 248 times.
✓ Branch 2 taken 1 times.
249 }
628
629
2/2
✓ Branch 1 taken 331 times.
✓ Branch 2 taken 248 times.
579 for(index_t i = 0; i < unparsed_args.size(); ++i) {
630 331 const std::string& arg = unparsed_args[i];
631 331 if(
632
1/2
✓ Branch 1 taken 331 times.
✗ Branch 2 not taken.
331 arg == "-h" ||
633
2/4
✓ Branch 1 taken 331 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 331 times.
✗ Branch 4 not taken.
331 arg == "-?" ||
634
4/8
✓ Branch 0 taken 331 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 331 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 331 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 331 times.
993 arg == "/h" ||
635
2/4
✓ Branch 1 taken 331 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 331 times.
331 arg == "/?"
636 ) {
637 ✗ show_usage(additional_arg_specs, true);
638 ✗ exit(0);
639 }
640
2/4
✓ Branch 1 taken 331 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 331 times.
331 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 331 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 331 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 331 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 331 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 331 times.
331 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 248 index_t min_unparsed = 0;
668 248 index_t max_unparsed = 0;
669 248 std::vector<std::string> additional_args;
670
1/2
✓ Branch 1 taken 248 times.
✗ Branch 2 not taken.
248 String::split_string(additional_arg_specs, ' ', additional_args);
671
2/2
✓ Branch 1 taken 455 times.
✓ Branch 2 taken 248 times.
703 for(index_t i = 0; i < additional_args.size(); ++i) {
672 455 const std::string& arg = additional_args[i];
673
5/6
✓ Branch 1 taken 205 times.
✓ Branch 2 taken 250 times.
✓ Branch 5 taken 205 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 205 times.
✓ Branch 8 taken 250 times.
455 if(arg[0] == '<' && arg[arg.length() - 1] == '>') {
674 205 ++max_unparsed;
675 250 } else if(
676 250 arg[0] == '<' &&
677
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 250 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 250 times.
250 arg[arg.length() - 2] == '>' &&
678 ✗ arg[arg.length() - 1] == '*'
679 ) {
680 ✗ min_unparsed=0;
681 ✗ max_unparsed=100000;
682 } else {
683 250 ++max_unparsed;
684 250 ++min_unparsed;
685 }
686 }
687
688 248 if(
689
6/6
✓ Branch 1 taken 245 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 241 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 241 times.
493 unparsed_args.size() > max_unparsed ||
690 245 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 241 times.
✗ Branch 2 not taken.
241 nlPrintfFuncs(geogram_printf, geogram_fprintf);
698
1/2
✓ Branch 1 taken 241 times.
✗ Branch 2 not taken.
241 nlInitialize(argc, argv);
699 #endif
700 241 if(
701
5/14
✓ Branch 1 taken 241 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 241 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 241 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 241 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 241 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
1205 CmdLine::arg_is_declared("nl:CUDA") &&
702
6/16
✓ Branch 1 taken 241 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 241 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 241 times.
✓ Branch 8 taken 241 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 241 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 241 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
723 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 241 times.
✗ Branch 2 not taken.
241 Stopwatch::initialize();
710
711 241 return true;
712 248 }
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 1948 void declare_arg_group(
720 const std::string& name,
721 const std::string& description,
722 ArgFlags flags
723 ) {
724
2/4
✓ Branch 2 taken 1948 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1948 times.
1948 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 1948 Group group;
732
1/2
✓ Branch 1 taken 1948 times.
✗ Branch 2 not taken.
1948 group.name = name;
733
1/2
✓ Branch 1 taken 1948 times.
✗ Branch 2 not taken.
1948 group.desc = description;
734 1948 group.flags = flags;
735
2/4
✓ Branch 1 taken 1948 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1948 times.
✗ Branch 5 not taken.
1948 desc_->groups[name] = group;
736
1/2
✓ Branch 1 taken 1948 times.
✗ Branch 2 not taken.
1948 desc_->group_names.push_back(name);
737 1948 }
738
739 11417 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 11417 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 11417 times.
11417 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 11417 Arg arg;
754
1/2
✓ Branch 1 taken 11417 times.
✗ Branch 2 not taken.
11417 arg.name = name;
755 11417 arg.type = type;
756
1/2
✓ Branch 1 taken 11417 times.
✗ Branch 2 not taken.
11417 arg.desc = description;
757 11417 arg.flags = flags;
758
2/4
✓ Branch 1 taken 11417 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11417 times.
✗ Branch 5 not taken.
11417 desc_->args[name] = arg;
759
760
2/4
✓ Branch 1 taken 11417 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11417 times.
✗ Branch 5 not taken.
11417 Environment::instance()->set_value(name, default_value);
761
762
1/2
✓ Branch 1 taken 11417 times.
✗ Branch 2 not taken.
11417 std::string group = arg_group(name);
763
1/2
✓ Branch 1 taken 11417 times.
✗ Branch 2 not taken.
11417 auto it = desc_->groups.find(group);
764
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 11417 times.
11417 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 11417 times.
✗ Branch 3 not taken.
11417 it->second.args.push_back(name);
772
2/4
✓ Branch 1 taken 11417 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11417 times.
✗ Branch 5 not taken.
11417 }
773
774 8135 ArgType get_arg_type(const std::string& name) {
775
1/2
✓ Branch 1 taken 8135 times.
✗ Branch 2 not taken.
8135 auto it = desc_->args.find(name);
776 16270 return it == desc_->args.end()
777
2/2
✓ Branch 0 taken 3150 times.
✓ Branch 1 taken 4985 times.
8135 ? ARG_UNDEFINED
778 16270 : 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 7950 std::string get_arg(const std::string& name) {
789 7950 Process::acquire_spinlock(lock);
790 7950 std::string result = Environment::instance()->get_value(name);
791 7950 Process::release_spinlock(lock);
792 7950 return result;
793 }
794
795 1490 bool arg_is_declared(const std::string& name) {
796 1490 return get_arg_type(name) != ARG_UNDEFINED;
797 }
798
799 75 int get_arg_int(const std::string& name) {
800 75 ArgType type = get_arg_type(name);
801
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 75 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
75 geo_assert_arg_type(type, ARG_INT);
802
2/4
✓ Branch 1 taken 75 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 75 times.
✗ Branch 5 not taken.
75 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 128 double get_arg_double(const std::string& name) {
812 128 ArgType type = get_arg_type(name);
813
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
128 geo_assert_arg_type(type, ARG_DOUBLE);
814
2/4
✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 128 times.
✗ Branch 5 not taken.
128 return String::to_double(get_arg(name));
815 }
816
817 157 double get_arg_percent(
818 const std::string& name, double reference
819 ) {
820
1/2
✓ Branch 1 taken 157 times.
✗ Branch 2 not taken.
157 ArgType type = get_arg_type(name);
821
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 157 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
157 geo_assert_arg_type(type, ARG_PERCENT);
822 double result;
823
1/2
✓ Branch 1 taken 157 times.
✗ Branch 2 not taken.
157 std::string s = get_arg(name);
824
4/8
✓ Branch 1 taken 157 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 157 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 157 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 157 times.
✗ Branch 10 not taken.
157 if(s.length() > 0 && s[s.length() - 1] == '%') {
825
1/2
✓ Branch 2 taken 157 times.
✗ Branch 3 not taken.
157 s.resize(s.length() - 1);
826
1/2
✓ Branch 1 taken 157 times.
✗ Branch 2 not taken.
157 result = String::to_double(s) * reference * 0.01;
827
2/4
✓ Branch 1 taken 157 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 157 times.
✗ Branch 5 not taken.
314 Logger::out("CmdLine")
828
4/8
✓ Branch 1 taken 157 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 157 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 157 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 157 times.
✗ Branch 11 not taken.
157 << "using " << name << "=" << result
829
4/8
✓ Branch 1 taken 157 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 157 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 157 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 157 times.
✗ Branch 11 not taken.
314 << "(" << get_arg(name) << ")"
830
1/2
✓ Branch 1 taken 157 times.
✗ Branch 2 not taken.
157 << std::endl;
831 } else {
832 ✗ result = String::to_double(s);
833 ✗ Logger::out("CmdLine")
834 ✗ << "using " << name << "=" << result
835 ✗ << std::endl;
836 }
837 157 return result;
838 157 }
839
840 2248 bool get_arg_bool(const std::string& name) {
841 2248 ArgType type = get_arg_type(name);
842
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 2248 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2248 geo_assert_arg_type(type, ARG_BOOL);
843
4/6
✓ Branch 1 taken 2248 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2248 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2188 times.
✓ Branch 7 taken 60 times.
4436 return Environment::instance()->has_value(name) &&
844
6/10
✓ Branch 1 taken 2188 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2188 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 612 times.
✓ Branch 7 taken 1576 times.
✓ Branch 8 taken 2188 times.
✓ Branch 9 taken 60 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
4436 String::to_bool(get_arg(name));
845 }
846
847 2314 bool set_arg(const std::string& name, const std::string& value) {
848
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2312 times.
2314 if(!check_arg_value(name, value)) {
849 2 return false;
850 }
851 2312 Process::acquire_spinlock(lock);
852 2312 Environment::instance()->set_value(name, value);
853 2312 Process::release_spinlock(lock);
854 2312 return true;
855 }
856
857 232 void set_arg(const std::string& name, Numeric::int32 value) {
858 232 ArgType type = get_arg_type(name);
859
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 232 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
232 geo_assert_arg_type(
860 type, ARG_INT | ARG_DOUBLE | ARG_PERCENT | ARG_STRING
861 );
862
2/4
✓ Branch 1 taken 232 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 232 times.
✗ Branch 5 not taken.
232 set_arg(name, String::to_string(value));
863 232 }
864
865 ✗ void set_arg(const std::string& name, Numeric::uint32 value) {
866 ✗ ArgType type = get_arg_type(name);
867 ✗ geo_assert_arg_type(
868 type, ARG_INT | ARG_DOUBLE | ARG_PERCENT | ARG_STRING
869 );
870 ✗ set_arg(name, String::to_string(value));
871 ✗ }
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 18 void set_arg(const std::string& name, Numeric::uint64 value) {
882 18 ArgType type = get_arg_type(name);
883
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(
884 type, ARG_INT | ARG_DOUBLE | ARG_PERCENT | ARG_STRING
885 );
886
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));
887 18 }
888
889 232 void set_arg(const std::string& name, double value) {
890 232 ArgType type = get_arg_type(name);
891
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 232 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
232 geo_assert_arg_type(type, ARG_DOUBLE | ARG_PERCENT | ARG_STRING);
892
2/4
✓ Branch 1 taken 232 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 232 times.
✗ Branch 5 not taken.
232 set_arg(name, String::to_string(value));
893 232 }
894
895 278 void set_arg(const std::string& name, bool value) {
896 278 ArgType type = get_arg_type(name);
897
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 278 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
278 geo_assert_arg_type(type, ARG_BOOL | ARG_STRING);
898
2/4
✓ Branch 1 taken 278 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 278 times.
✗ Branch 5 not taken.
278 set_arg(name, String::to_string(value));
899 278 }
900
901 698 void set_arg_percent(const std::string& name, double value) {
902 698 ArgType type = get_arg_type(name);
903
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 698 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
698 geo_assert_arg_type(type, ARG_PERCENT | ARG_STRING);
904
3/6
✓ Branch 1 taken 698 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 698 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 698 times.
✗ Branch 8 not taken.
698 set_arg(name, String::to_string(value) + "%");
905 698 }
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 6678 inline std::ostream& ui_out() {
990 6678 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 26093 bool is_redirected() {
1012 static bool initialized = false;
1013 static bool result;
1014
2/2
✓ Branch 0 taken 253 times.
✓ Branch 1 taken 25840 times.
26093 if(!initialized) {
1015 #ifdef GEO_OS_WINDOWS
1016 result = !_isatty(1);
1017 #else
1018 253 result = !isatty(1);
1019 #endif
1020 253 initialized = true;
1021 }
1022
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26093 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
26093 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 6048 void ui_separator() {
1077
3/6
✓ Branch 2 taken 6048 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 6048 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 6048 times.
✗ Branch 8 not taken.
6048 if(Logger::instance()->is_quiet() || is_redirected()) {
1078 6048 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 315 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 315 times.
315 if(Logger::instance()->is_quiet()) {
1101 ✗ return;
1102 }
1103
1104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 315 times.
315 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 315 times.
✗ Branch 2 not taken.
315 if(is_redirected()) {
1123 315 ui_out() << std::endl;
1124
6/6
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 301 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 308 times.
315 if(short_title != "" && title != "") {
1125 7 ui_out() << "=[" << short_title << "]=["
1126 7 << title << "]=" << std::endl;
1127 } else {
1128
1/2
✓ Branch 1 taken 308 times.
✗ Branch 2 not taken.
308 std::string s = title + short_title;
1129
4/8
✓ Branch 2 taken 308 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 308 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 308 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 308 times.
✗ Branch 12 not taken.
308 ui_out() << "=[" << s << "]=" << std::endl;
1130 308 }
1131 315 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 5978 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 5978 ui_message(message, feature_max_length + 5);
1170 5978 }
1171
1172 6048 void ui_message(
1173 const std::string& message,
1174 index_t wrap_margin
1175 ) {
1176
2/4
✓ Branch 1 taken 6048 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6048 times.
6048 if(Logger::instance()->is_quiet()) {
1177 6048 return;
1178 }
1179
1180
1/2
✓ Branch 0 taken 6048 times.
✗ Branch 1 not taken.
6048 if(!ui_separator_opened) {
1181
1/2
✓ Branch 1 taken 6048 times.
✗ Branch 2 not taken.
6048 ui_separator();
1182 }
1183
1184
2/4
✓ Branch 1 taken 6048 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6048 times.
✗ Branch 4 not taken.
6048 if(is_redirected()) {
1185
1/2
✓ Branch 2 taken 6048 times.
✗ Branch 3 not taken.
6048 ui_out() << message;
1186 6048 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 45 void ui_clear_line() {
1238
3/6
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 45 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 45 times.
✗ Branch 8 not taken.
45 if(Logger::instance()->is_quiet() || is_redirected()) {
1239 45 return;
1240 }
1241
1242 ✗ ui_pad('\b', ui_terminal_width());
1243 ✗ ui_out() << std::flush;
1244 }
1245
1246 253 void ui_close_separator() {
1247
1/2
✓ Branch 0 taken 253 times.
✗ Branch 1 not taken.
253 if(!ui_separator_opened) {
1248 253 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 1082 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 1082 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1082 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1082 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1082 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1082 times.
✗ Branch 12 not taken.
1082 if(Logger::instance()->is_quiet() || is_redirected()) {
1272 1082 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 38 void ui_progress_time(
1323 const std::string& task_name, double elapsed, bool clear
1324 ) {
1325
2/4
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 38 times.
38 if(Logger::instance()->is_quiet()) {
1326 ✗ return;
1327 }
1328
1329
1/2
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
38 std::ostringstream os;
1330
1/2
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
76 os << ui_feature(task_name)
1331
3/6
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 38 times.
✗ Branch 8 not taken.
38 << "Elapsed time: " << elapsed
1332
1/2
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
38 << "s\n";
1333
1334
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 if(clear) {
1335
1/2
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
38 ui_clear_line();
1336 }
1337
2/4
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 38 times.
✗ Branch 5 not taken.
38 ui_message(os.str());
1338 38 }
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 12610 std::string ui_feature(
1360 const std::string& feat_in, bool show
1361 ) {
1362
2/2
✓ Branch 1 taken 81 times.
✓ Branch 2 taken 12529 times.
12610 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 27 times.
✓ Branch 1 taken 12502 times.
12529 if(!show) {
1367
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
54 return std::string(feature_max_length + 5, ' ');
1368 }
1369
1370
1/2
✓ Branch 1 taken 12502 times.
✗ Branch 2 not taken.
12502 std::string result = feat_in;
1371
2/4
✓ Branch 1 taken 12502 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 12502 times.
12502 if(!is_redirected()) {
1372 ✗ result = result.substr(0, feature_max_length);
1373 }
1374
2/2
✓ Branch 1 taken 12417 times.
✓ Branch 2 taken 85 times.
12502 if(result.length() < feature_max_length) {
1375
1/2
✓ Branch 2 taken 12417 times.
✗ Branch 3 not taken.
12417 result.append(feature_max_length - result.length(), ' ');
1376 }
1377
2/4
✓ Branch 1 taken 12502 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12502 times.
✗ Branch 5 not taken.
12502 return "o-[" + result + "] ";
1378 12502 }
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