| 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 | 2640 | bool arg_matches( | |
| 169 | const std::string& arg_in, const std::string& arg_name | ||
| 170 | ) { | ||
| 171 | 2640 | 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 | 2283 | bool check_arg_value( | |
| 205 | const std::string& name, const std::string& s | ||
| 206 | ) { | ||
| 207 | 2283 | ArgType type = get_arg_type(name); | |
| 208 |
4/4✓ Branch 0 taken 959 times.
✓ Branch 1 taken 1324 times.
✓ Branch 2 taken 398 times.
✓ Branch 3 taken 561 times.
|
2283 | if(type == ARG_UNDEFINED || type == ARG_STRING) { |
| 209 | 1722 | return true; | |
| 210 | } | ||
| 211 | |||
| 212 |
2/2✓ Branch 0 taken 107 times.
✓ Branch 1 taken 454 times.
|
561 | if(type == ARG_INT) { |
| 213 | int value; | ||
| 214 |
3/4✓ Branch 1 taken 107 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 106 times.
|
107 | 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 | 106 | return true; | |
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 |
2/2✓ Branch 0 taken 57 times.
✓ Branch 1 taken 397 times.
|
454 | if(type == ARG_DOUBLE) { |
| 222 | double value; | ||
| 223 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 56 times.
|
57 | 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 | 56 | return true; | |
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 230 |
2/2✓ Branch 0 taken 317 times.
✓ Branch 1 taken 80 times.
|
397 | if(type == ARG_BOOL) { |
| 231 | bool value; | ||
| 232 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 317 times.
|
317 | if(!String::from_string(s, value)) { |
| 233 | ✗ | return arg_value_error(name, s, "boolean"); | |
| 234 | } else { | ||
| 235 | 317 | return true; | |
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 239 |
1/2✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
|
80 | if(type == ARG_PERCENT) { |
| 240 |
1/2✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
|
80 | std::string s2 = s; |
| 241 |
4/8✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 80 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 80 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 80 times.
✗ Branch 10 not taken.
|
80 | if(s2.length() > 0 && s2[s2.length() - 1] == '%') { |
| 242 |
1/2✓ Branch 2 taken 80 times.
✗ Branch 3 not taken.
|
80 | s2.resize(s2.length() - 1); |
| 243 | } | ||
| 244 | double value; | ||
| 245 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 80 times.
|
80 | if(!String::from_string(s2, value)) { |
| 246 | ✗ | return arg_value_error(name, s, "percentage"); | |
| 247 | } else { | ||
| 248 | 80 | return true; | |
| 249 | } | ||
| 250 | 80 | } | |
| 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 | 251 | void parse_config_file( | |
| 267 | const std::string& config_filename, const std::string& program_name | ||
| 268 | ) { | ||
| 269 |
1/2✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
|
251 | std::string section = "*"; |
| 270 |
2/4✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 251 times.
|
251 | 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 | 251 | } | |
| 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 | 497 | void parse_config_file(int argc, char** argv) { | |
| 318 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 497 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
497 | geo_assert(argc >= 1); |
| 319 | std::string program_name = String::to_uppercase( | ||
| 320 |
2/4✓ Branch 1 taken 497 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 497 times.
✗ Branch 5 not taken.
|
994 | FileSystem::base_name(argv[0]) |
| 321 |
1/2✓ Branch 1 taken 497 times.
✗ Branch 2 not taken.
|
497 | ); |
| 322 | static bool init = false; | ||
| 323 |
2/2✓ Branch 0 taken 246 times.
✓ Branch 1 taken 251 times.
|
497 | if(init) { |
| 324 | 246 | return; | |
| 325 | } | ||
| 326 | 251 | init = true; | |
| 327 |
2/4✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 251 times.
✗ Branch 5 not taken.
|
753 | Logger::out("config") |
| 328 |
2/4✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 251 times.
✗ Branch 5 not taken.
|
251 | << "Configuration file name:" << config_file_name |
| 329 |
1/2✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
|
251 | << std::endl; |
| 330 |
2/4✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 251 times.
✗ Branch 5 not taken.
|
251 | Logger::out("config") |
| 331 |
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 | << "Home directory:" << FileSystem::home_directory() |
| 332 |
1/2✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
|
251 | << std::endl; |
| 333 | std::string config_filename = | ||
| 334 |
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.
|
251 | FileSystem::home_directory() + "/" + config_file_name; |
| 335 |
1/2✓ Branch 1 taken 251 times.
✗ Branch 2 not taken.
|
251 | parse_config_file(config_filename, program_name); |
| 336 |
2/2✓ Branch 2 taken 251 times.
✓ Branch 3 taken 246 times.
|
497 | } |
| 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 | 497 | bool parse_internal( | |
| 351 | int argc, char** argv, std::vector<std::string>& unparsed_args | ||
| 352 | ) { | ||
| 353 | 497 | geo_argc = argc; | |
| 354 | 497 | geo_argv = argv; | |
| 355 | |||
| 356 | 497 | parse_config_file(argc, argv); | |
| 357 | |||
| 358 | 497 | bool ok = true; | |
| 359 | 497 | desc_->argv0 = argv[0]; | |
| 360 | 497 | unparsed_args.clear(); | |
| 361 | |||
| 362 |
2/2✓ Branch 0 taken 1413 times.
✓ Branch 1 taken 497 times.
|
1910 | for(int i = 1; i < argc; i++) { |
| 363 | 1413 | std::vector<std::string> parsed_arg; | |
| 364 |
2/4✓ Branch 1 taken 1413 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1413 times.
✗ Branch 5 not taken.
|
1413 | String::split_string(argv[i], '=', parsed_arg); |
| 365 |
2/2✓ Branch 1 taken 664 times.
✓ Branch 2 taken 749 times.
|
1413 | if(parsed_arg.size() != 2) { |
| 366 |
2/4✓ Branch 1 taken 664 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 664 times.
✗ Branch 5 not taken.
|
1328 | unparsed_args.push_back(argv[i]); |
| 367 | } else { | ||
| 368 | 749 | if( | |
| 369 |
9/16✓ Branch 1 taken 749 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 749 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 727 times.
✓ Branch 8 taken 22 times.
✓ Branch 9 taken 697 times.
✓ Branch 10 taken 30 times.
✓ Branch 12 taken 749 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 719 times.
✓ Branch 15 taken 30 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
|
3723 | String::string_starts_with(parsed_arg[0], "dbg:") || |
| 370 |
2/4✓ Branch 3 taken 727 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 749 times.
✗ Branch 7 not taken.
|
1476 | desc_->args.find(parsed_arg[0]) != desc_->args.end() |
| 371 | ) { | ||
| 372 |
3/4✓ Branch 3 taken 719 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 717 times.
|
719 | if(!set_arg(parsed_arg[0], parsed_arg[1])) { |
| 373 | 2 | ok = false; | |
| 374 | } | ||
| 375 | } else { | ||
| 376 | |||
| 377 | 30 | std::vector<std::string> matches; | |
| 378 |
2/2✓ Branch 5 taken 2640 times.
✓ Branch 6 taken 30 times.
|
2670 | for( auto& it : desc_->args) { |
| 379 |
2/2✓ Branch 2 taken 28 times.
✓ Branch 3 taken 2612 times.
|
2640 | if(arg_matches(parsed_arg[0], it.first)) { |
| 380 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | matches.push_back(it.first); |
| 381 | } | ||
| 382 | } | ||
| 383 | |||
| 384 |
2/2✓ Branch 1 taken 28 times.
✓ Branch 2 taken 2 times.
|
30 | if(matches.size() == 1) { |
| 385 |
2/4✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
|
28 | 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 | 30 | } | |
| 405 | } | ||
| 406 | 1413 | } | |
| 407 | 497 | 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 | 11351 | std::string arg_group(const std::string& name) { | |
| 419 | 11351 | size_t pos = name.find(':'); | |
| 420 | return pos == std::string::npos | ||
| 421 |
2/4✓ Branch 0 taken 2093 times.
✓ Branch 1 taken 9258 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
13444 | ? std::string("global") |
| 422 |
4/6✓ Branch 0 taken 2093 times.
✓ Branch 1 taken 9258 times.
✓ Branch 3 taken 2093 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 9258 times.
✗ Branch 7 not taken.
|
24795 | : 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 | 251 | void initialize() { | |
| 557 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 251 times.
|
251 | desc_ = new CommandLineDesc; |
| 558 |
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.
|
753 | declare_arg_group("global", ""); |
| 559 | 251 | } | |
| 560 | |||
| 561 | 251 | void terminate() { | |
| 562 | 251 | ui_close_separator(); | |
| 563 |
1/2✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
|
251 | delete desc_; |
| 564 | 251 | desc_ = nullptr; | |
| 565 | 251 | } | |
| 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 | 251 | 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 251 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 247 times.
|
251 | if(!parse_internal(argc, argv, unparsed_args)) { |
| 614 | 4 | return false; | |
| 615 | } | ||
| 616 | |||
| 617 |
3/6✓ Branch 1 taken 247 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 247 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 247 times.
✗ Branch 8 not taken.
|
494 | if(arg_is_declared("profile")) { |
| 618 |
2/4✓ Branch 1 taken 247 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 247 times.
✗ Branch 5 not taken.
|
247 | std::string profile = get_arg("profile"); |
| 619 |
2/4✓ Branch 1 taken 247 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 247 times.
✗ Branch 4 not taken.
|
247 | if(profile != "default") { |
| 620 |
3/4✓ Branch 1 taken 247 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 246 times.
|
247 | if(!set_profile(profile)) { |
| 621 | 1 | return false; | |
| 622 | } | ||
| 623 | // Re-parse args to override values set by profiles | ||
| 624 | 246 | unparsed_args.clear(); | |
| 625 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | parse_internal(argc, argv, unparsed_args); |
| 626 | } | ||
| 627 |
2/2✓ Branch 1 taken 246 times.
✓ Branch 2 taken 1 times.
|
247 | } |
| 628 | |||
| 629 |
2/2✓ Branch 1 taken 327 times.
✓ Branch 2 taken 246 times.
|
573 | for(index_t i = 0; i < unparsed_args.size(); ++i) { |
| 630 | 327 | const std::string& arg = unparsed_args[i]; | |
| 631 | 327 | if( | |
| 632 |
1/2✓ Branch 1 taken 327 times.
✗ Branch 2 not taken.
|
327 | arg == "-h" || |
| 633 |
2/4✓ Branch 1 taken 327 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 327 times.
✗ Branch 4 not taken.
|
327 | arg == "-?" || |
| 634 |
4/8✓ Branch 0 taken 327 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 327 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 327 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 327 times.
|
981 | arg == "/h" || |
| 635 |
2/4✓ Branch 1 taken 327 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 327 times.
|
327 | arg == "/?" |
| 636 | ) { | ||
| 637 | ✗ | show_usage(additional_arg_specs, true); | |
| 638 | ✗ | exit(0); | |
| 639 | } | ||
| 640 |
2/4✓ Branch 1 taken 327 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 327 times.
|
327 | 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 327 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 327 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 327 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 327 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 327 times.
|
327 | 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 | 246 | index_t min_unparsed = 0; | |
| 668 | 246 | index_t max_unparsed = 0; | |
| 669 | 246 | std::vector<std::string> additional_args; | |
| 670 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | String::split_string(additional_arg_specs, ' ', additional_args); |
| 671 |
2/2✓ Branch 1 taken 451 times.
✓ Branch 2 taken 246 times.
|
697 | for(index_t i = 0; i < additional_args.size(); ++i) { |
| 672 | 451 | const std::string& arg = additional_args[i]; | |
| 673 |
5/6✓ Branch 1 taken 203 times.
✓ Branch 2 taken 248 times.
✓ Branch 5 taken 203 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 203 times.
✓ Branch 8 taken 248 times.
|
451 | if(arg[0] == '<' && arg[arg.length() - 1] == '>') { |
| 674 | 203 | ++max_unparsed; | |
| 675 | 248 | } else if( | |
| 676 | 248 | arg[0] == '<' && | |
| 677 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 248 times.
|
248 | arg[arg.length() - 2] == '>' && |
| 678 | ✗ | arg[arg.length() - 1] == '*' | |
| 679 | ) { | ||
| 680 | ✗ | min_unparsed=0; | |
| 681 | ✗ | max_unparsed=100000; | |
| 682 | } else { | ||
| 683 | 248 | ++max_unparsed; | |
| 684 | 248 | ++min_unparsed; | |
| 685 | } | ||
| 686 | } | ||
| 687 | |||
| 688 | 246 | if( | |
| 689 |
4/4✓ Branch 1 taken 243 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 239 times.
|
489 | unparsed_args.size() > max_unparsed || |
| 690 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 239 times.
|
243 | 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 239 times.
✗ Branch 2 not taken.
|
239 | nlPrintfFuncs(geogram_printf, geogram_fprintf); |
| 698 |
1/2✓ Branch 1 taken 239 times.
✗ Branch 2 not taken.
|
239 | nlInitialize(argc, argv); |
| 699 | #endif | ||
| 700 | 239 | if( | |
| 701 |
5/14✓ Branch 1 taken 239 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 239 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 239 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 239 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 239 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
1195 | CmdLine::arg_is_declared("nl:CUDA") && |
| 702 |
6/16✓ Branch 1 taken 239 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 239 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 239 times.
✓ Branch 8 taken 239 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 239 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 239 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
717 | 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 239 times.
✗ Branch 2 not taken.
|
239 | Stopwatch::initialize(); |
| 710 | |||
| 711 | 239 | return true; | |
| 712 | 246 | } | |
| 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 | 1936 | void declare_arg_group( | |
| 720 | const std::string& name, | ||
| 721 | const std::string& description, | ||
| 722 | ArgFlags flags | ||
| 723 | ) { | ||
| 724 |
2/4✓ Branch 2 taken 1936 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1936 times.
|
1936 | 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 | 1936 | Group group; | |
| 732 |
1/2✓ Branch 1 taken 1936 times.
✗ Branch 2 not taken.
|
1936 | group.name = name; |
| 733 |
1/2✓ Branch 1 taken 1936 times.
✗ Branch 2 not taken.
|
1936 | group.desc = description; |
| 734 | 1936 | group.flags = flags; | |
| 735 |
2/4✓ Branch 1 taken 1936 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1936 times.
✗ Branch 5 not taken.
|
1936 | desc_->groups[name] = group; |
| 736 |
1/2✓ Branch 1 taken 1936 times.
✗ Branch 2 not taken.
|
1936 | desc_->group_names.push_back(name); |
| 737 | 1936 | } | |
| 738 | |||
| 739 | 11351 | 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 11351 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 11351 times.
|
11351 | 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 | 11351 | Arg arg; | |
| 754 |
1/2✓ Branch 1 taken 11351 times.
✗ Branch 2 not taken.
|
11351 | arg.name = name; |
| 755 | 11351 | arg.type = type; | |
| 756 |
1/2✓ Branch 1 taken 11351 times.
✗ Branch 2 not taken.
|
11351 | arg.desc = description; |
| 757 | 11351 | arg.flags = flags; | |
| 758 |
2/4✓ Branch 1 taken 11351 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11351 times.
✗ Branch 5 not taken.
|
11351 | desc_->args[name] = arg; |
| 759 | |||
| 760 |
2/4✓ Branch 1 taken 11351 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11351 times.
✗ Branch 5 not taken.
|
11351 | Environment::instance()->set_value(name, default_value); |
| 761 | |||
| 762 |
1/2✓ Branch 1 taken 11351 times.
✗ Branch 2 not taken.
|
11351 | std::string group = arg_group(name); |
| 763 |
1/2✓ Branch 1 taken 11351 times.
✗ Branch 2 not taken.
|
11351 | auto it = desc_->groups.find(group); |
| 764 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 11351 times.
|
11351 | 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 11351 times.
✗ Branch 3 not taken.
|
11351 | it->second.args.push_back(name); |
| 772 |
2/4✓ Branch 1 taken 11351 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11351 times.
✗ Branch 5 not taken.
|
11351 | } |
| 773 | |||
| 774 | 8023 | ArgType get_arg_type(const std::string& name) { | |
| 775 |
1/2✓ Branch 1 taken 8023 times.
✗ Branch 2 not taken.
|
8023 | auto it = desc_->args.find(name); |
| 776 | 16046 | return it == desc_->args.end() | |
| 777 |
2/2✓ Branch 0 taken 3102 times.
✓ Branch 1 taken 4921 times.
|
8023 | ? ARG_UNDEFINED |
| 778 | 16046 | : 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 | 7896 | std::string get_arg(const std::string& name) { | |
| 789 | 7896 | Process::acquire_spinlock(lock); | |
| 790 | 7896 | std::string result = Environment::instance()->get_value(name); | |
| 791 | 7896 | Process::release_spinlock(lock); | |
| 792 | 7896 | return result; | |
| 793 | } | ||
| 794 | |||
| 795 | 1478 | bool arg_is_declared(const std::string& name) { | |
| 796 | 1478 | return get_arg_type(name) != ARG_UNDEFINED; | |
| 797 | } | ||
| 798 | |||
| 799 | 74 | int get_arg_int(const std::string& name) { | |
| 800 | 74 | ArgType type = get_arg_type(name); | |
| 801 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
74 | geo_assert_arg_type(type, ARG_INT); |
| 802 |
2/4✓ Branch 1 taken 74 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 74 times.
✗ Branch 5 not taken.
|
74 | return String::to_int(get_arg(name)); |
| 803 | } | ||
| 804 | |||
| 805 | 186 | unsigned int get_arg_uint(const std::string& name) { | |
| 806 | 186 | ArgType type = get_arg_type(name); | |
| 807 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 186 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
186 | geo_assert_arg_type(type, ARG_INT); |
| 808 |
2/4✓ Branch 1 taken 186 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 186 times.
✗ Branch 5 not taken.
|
186 | return String::to_uint(get_arg(name)); |
| 809 | } | ||
| 810 | |||
| 811 | 126 | double get_arg_double(const std::string& name) { | |
| 812 | 126 | ArgType type = get_arg_type(name); | |
| 813 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
126 | geo_assert_arg_type(type, ARG_DOUBLE); |
| 814 |
2/4✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 126 times.
✗ Branch 5 not taken.
|
126 | return String::to_double(get_arg(name)); |
| 815 | } | ||
| 816 | |||
| 817 | 150 | double get_arg_percent( | |
| 818 | const std::string& name, double reference | ||
| 819 | ) { | ||
| 820 |
1/2✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
|
150 | ArgType type = get_arg_type(name); |
| 821 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 150 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
150 | geo_assert_arg_type(type, ARG_PERCENT); |
| 822 | double result; | ||
| 823 |
1/2✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
|
150 | std::string s = get_arg(name); |
| 824 |
4/8✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 150 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 150 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 150 times.
✗ Branch 10 not taken.
|
150 | if(s.length() > 0 && s[s.length() - 1] == '%') { |
| 825 |
1/2✓ Branch 2 taken 150 times.
✗ Branch 3 not taken.
|
150 | s.resize(s.length() - 1); |
| 826 |
1/2✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
|
150 | result = String::to_double(s) * reference * 0.01; |
| 827 |
2/4✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
|
300 | Logger::out("CmdLine") |
| 828 |
4/8✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 150 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 150 times.
✗ Branch 11 not taken.
|
150 | << "using " << name << "=" << result |
| 829 |
4/8✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 150 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 150 times.
✗ Branch 11 not taken.
|
300 | << "(" << get_arg(name) << ")" |
| 830 |
1/2✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
|
150 | << std::endl; |
| 831 | } else { | ||
| 832 | ✗ | result = String::to_double(s); | |
| 833 | ✗ | Logger::out("CmdLine") | |
| 834 | ✗ | << "using " << name << "=" << result | |
| 835 | ✗ | << std::endl; | |
| 836 | } | ||
| 837 | 150 | return result; | |
| 838 | 150 | } | |
| 839 | |||
| 840 | 2217 | bool get_arg_bool(const std::string& name) { | |
| 841 | 2217 | ArgType type = get_arg_type(name); | |
| 842 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 2217 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
2217 | geo_assert_arg_type(type, ARG_BOOL); |
| 843 |
4/6✓ Branch 1 taken 2217 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2217 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2171 times.
✓ Branch 7 taken 46 times.
|
4388 | return Environment::instance()->has_value(name) && |
| 844 |
6/10✓ Branch 1 taken 2171 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2171 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 602 times.
✓ Branch 7 taken 1569 times.
✓ Branch 8 taken 2171 times.
✓ Branch 9 taken 46 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
4388 | String::to_bool(get_arg(name)); |
| 845 | } | ||
| 846 | |||
| 847 | 2283 | bool set_arg(const std::string& name, const std::string& value) { | |
| 848 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2281 times.
|
2283 | if(!check_arg_value(name, value)) { |
| 849 | 2 | return false; | |
| 850 | } | ||
| 851 | 2281 | Process::acquire_spinlock(lock); | |
| 852 | 2281 | Environment::instance()->set_value(name, value); | |
| 853 | 2281 | Process::release_spinlock(lock); | |
| 854 | 2281 | return true; | |
| 855 | } | ||
| 856 | |||
| 857 | 229 | void set_arg(const std::string& name, Numeric::int32 value) { | |
| 858 | 229 | ArgType type = get_arg_type(name); | |
| 859 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 229 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
229 | geo_assert_arg_type( |
| 860 | type, ARG_INT | ARG_DOUBLE | ARG_PERCENT | ARG_STRING | ||
| 861 | ); | ||
| 862 |
2/4✓ Branch 1 taken 229 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 229 times.
✗ Branch 5 not taken.
|
229 | set_arg(name, String::to_string(value)); |
| 863 | 229 | } | |
| 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 | 229 | void set_arg(const std::string& name, double value) { | |
| 890 | 229 | ArgType type = get_arg_type(name); | |
| 891 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 229 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
229 | geo_assert_arg_type(type, ARG_DOUBLE | ARG_PERCENT | ARG_STRING); |
| 892 |
2/4✓ Branch 1 taken 229 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 229 times.
✗ Branch 5 not taken.
|
229 | set_arg(name, String::to_string(value)); |
| 893 | 229 | } | |
| 894 | |||
| 895 | 274 | void set_arg(const std::string& name, bool value) { | |
| 896 | 274 | ArgType type = get_arg_type(name); | |
| 897 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 274 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
274 | geo_assert_arg_type(type, ARG_BOOL | ARG_STRING); |
| 898 |
2/4✓ Branch 1 taken 274 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 274 times.
✗ Branch 5 not taken.
|
274 | set_arg(name, String::to_string(value)); |
| 899 | 274 | } | |
| 900 | |||
| 901 | 689 | void set_arg_percent(const std::string& name, double value) { | |
| 902 | 689 | ArgType type = get_arg_type(name); | |
| 903 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 689 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
689 | geo_assert_arg_type(type, ARG_PERCENT | ARG_STRING); |
| 904 |
3/6✓ Branch 1 taken 689 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 689 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 689 times.
✗ Branch 8 not taken.
|
689 | set_arg(name, String::to_string(value) + "%"); |
| 905 | 689 | } | |
| 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 | 6566 | inline std::ostream& ui_out() { | |
| 990 | 6566 | 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 | 25700 | bool is_redirected() { | |
| 1012 | static bool initialized = false; | ||
| 1013 | static bool result; | ||
| 1014 |
2/2✓ Branch 0 taken 251 times.
✓ Branch 1 taken 25449 times.
|
25700 | if(!initialized) { |
| 1015 | #ifdef GEO_OS_WINDOWS | ||
| 1016 | result = !_isatty(1); | ||
| 1017 | #else | ||
| 1018 | 251 | result = !isatty(1); | |
| 1019 | #endif | ||
| 1020 | 251 | initialized = true; | |
| 1021 | } | ||
| 1022 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 25700 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
25700 | 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 | 5944 | void ui_separator() { | |
| 1077 |
3/6✓ Branch 2 taken 5944 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5944 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5944 times.
✗ Branch 8 not taken.
|
5944 | if(Logger::instance()->is_quiet() || is_redirected()) { |
| 1078 | 5944 | 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 | 311 | 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 311 times.
|
311 | if(Logger::instance()->is_quiet()) { |
| 1101 | ✗ | return; | |
| 1102 | } | ||
| 1103 | |||
| 1104 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 311 times.
|
311 | 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 311 times.
✗ Branch 2 not taken.
|
311 | if(is_redirected()) { |
| 1123 | 311 | ui_out() << std::endl; | |
| 1124 |
6/6✓ Branch 1 taken 14 times.
✓ Branch 2 taken 297 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 304 times.
|
311 | if(short_title != "" && title != "") { |
| 1125 | 7 | ui_out() << "=[" << short_title << "]=[" | |
| 1126 | 7 | << title << "]=" << std::endl; | |
| 1127 | } else { | ||
| 1128 |
1/2✓ Branch 1 taken 304 times.
✗ Branch 2 not taken.
|
304 | std::string s = title + short_title; |
| 1129 |
4/8✓ Branch 2 taken 304 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 304 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 304 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 304 times.
✗ Branch 12 not taken.
|
304 | ui_out() << "=[" << s << "]=" << std::endl; |
| 1130 | 304 | } | |
| 1131 | 311 | 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 | 5874 | 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 | 5874 | ui_message(message, feature_max_length + 5); | |
| 1170 | 5874 | } | |
| 1171 | |||
| 1172 | 5944 | void ui_message( | |
| 1173 | const std::string& message, | ||
| 1174 | index_t wrap_margin | ||
| 1175 | ) { | ||
| 1176 |
2/4✓ Branch 1 taken 5944 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5944 times.
|
5944 | if(Logger::instance()->is_quiet()) { |
| 1177 | 5944 | return; | |
| 1178 | } | ||
| 1179 | |||
| 1180 |
1/2✓ Branch 0 taken 5944 times.
✗ Branch 1 not taken.
|
5944 | if(!ui_separator_opened) { |
| 1181 |
1/2✓ Branch 1 taken 5944 times.
✗ Branch 2 not taken.
|
5944 | ui_separator(); |
| 1182 | } | ||
| 1183 | |||
| 1184 |
2/4✓ Branch 1 taken 5944 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5944 times.
✗ Branch 4 not taken.
|
5944 | if(is_redirected()) { |
| 1185 |
1/2✓ Branch 2 taken 5944 times.
✗ Branch 3 not taken.
|
5944 | ui_out() << message; |
| 1186 | 5944 | 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 | 50 | void ui_clear_line() { | |
| 1238 |
3/6✓ Branch 2 taken 50 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 50 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 50 times.
✗ Branch 8 not taken.
|
50 | if(Logger::instance()->is_quiet() || is_redirected()) { |
| 1239 | 50 | return; | |
| 1240 | } | ||
| 1241 | |||
| 1242 | ✗ | ui_pad('\b', ui_terminal_width()); | |
| 1243 | ✗ | ui_out() << std::flush; | |
| 1244 | } | ||
| 1245 | |||
| 1246 | 251 | void ui_close_separator() { | |
| 1247 |
1/2✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
|
251 | if(!ui_separator_opened) { |
| 1248 | 251 | 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 | 997 | 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 997 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 997 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 997 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 997 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 997 times.
✗ Branch 12 not taken.
|
997 | if(Logger::instance()->is_quiet() || is_redirected()) { |
| 1272 | 997 | 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 | 43 | void ui_progress_time( | |
| 1323 | const std::string& task_name, double elapsed, bool clear | ||
| 1324 | ) { | ||
| 1325 |
2/4✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 43 times.
|
43 | if(Logger::instance()->is_quiet()) { |
| 1326 | ✗ | return; | |
| 1327 | } | ||
| 1328 | |||
| 1329 |
1/2✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
|
43 | std::ostringstream os; |
| 1330 |
1/2✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
|
86 | os << ui_feature(task_name) |
| 1331 |
3/6✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 43 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 43 times.
✗ Branch 8 not taken.
|
43 | << "Elapsed time: " << elapsed |
| 1332 |
1/2✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
|
43 | << "s\n"; |
| 1333 | |||
| 1334 |
1/2✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
|
43 | if(clear) { |
| 1335 |
1/2✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
|
43 | ui_clear_line(); |
| 1336 | } | ||
| 1337 |
2/4✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 43 times.
✗ Branch 5 not taken.
|
43 | ui_message(os.str()); |
| 1338 | 43 | } | |
| 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 | 12506 | std::string ui_feature( | |
| 1360 | const std::string& feat_in, bool show | ||
| 1361 | ) { | ||
| 1362 |
2/2✓ Branch 1 taken 79 times.
✓ Branch 2 taken 12427 times.
|
12506 | if(feat_in.empty()) { |
| 1363 |
1/2✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
|
79 | return feat_in; |
| 1364 | } | ||
| 1365 | |||
| 1366 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 12401 times.
|
12427 | 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 12401 times.
✗ Branch 2 not taken.
|
12401 | std::string result = feat_in; |
| 1371 |
2/4✓ Branch 1 taken 12401 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 12401 times.
|
12401 | if(!is_redirected()) { |
| 1372 | ✗ | result = result.substr(0, feature_max_length); | |
| 1373 | } | ||
| 1374 |
2/2✓ Branch 1 taken 12314 times.
✓ Branch 2 taken 87 times.
|
12401 | if(result.length() < feature_max_length) { |
| 1375 |
1/2✓ Branch 2 taken 12314 times.
✗ Branch 3 not taken.
|
12314 | result.append(feature_max_length - result.length(), ' '); |
| 1376 | } | ||
| 1377 |
2/4✓ Branch 1 taken 12401 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12401 times.
✗ Branch 5 not taken.
|
12401 | return "o-[" + result + "] "; |
| 1378 | 12401 | } | |
| 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 |