cmdline.cc (3336B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 #include "tools/cmdline.h" 7 8 #include <memory> 9 #include <string> 10 11 namespace jpegxl { 12 namespace tools { 13 14 void CommandLineParser::PrintHelp() const { 15 // Use stdout, not stderr, so help can easily be grepped. 16 FILE* out = stdout; 17 fprintf(out, "Usage: %s", program_name_ ? program_name_ : "command"); 18 19 for (const auto& option : options_) { 20 if (option->positional()) { 21 if (option->verbosity_level() > verbosity) continue; 22 if (option->required()) { 23 fprintf(out, " %s", option->help_flags().c_str()); 24 } else { 25 fprintf(out, " [%s]", option->help_flags().c_str()); 26 } 27 } 28 } 29 fprintf(out, " [OPTIONS...]\n"); 30 31 bool showed_all = true; 32 int max_verbosity = 0; 33 for (const auto& option : options_) { 34 max_verbosity = std::max(option->verbosity_level(), max_verbosity); 35 if (option->verbosity_level() > verbosity) { 36 showed_all = false; 37 continue; 38 } 39 if (option->help_only()) { 40 fprintf(out, "%s\n", option->help_text()); 41 continue; 42 } 43 fprintf(out, " %s\n", option->help_flags().c_str()); 44 const char* help_text = option->help_text(); 45 if (help_text) { 46 fprintf(out, " %s\n", help_text); 47 } 48 } 49 fprintf(out, "\n -h, --help\n Prints this help message. "); 50 if (showed_all) { 51 fprintf(out, "All options are shown above.\n"); 52 } else { 53 fprintf(out, "Add -v (up to a total of %i times) to see more options.\n", 54 max_verbosity); 55 } 56 } 57 58 bool CommandLineParser::Parse(int argc, const char* argv[]) { 59 if (argc) program_name_ = argv[0]; 60 int i = 1; // argv[0] is the program name. 61 // if false, stop matching options and take only positional arguments 62 bool parse_options = true; 63 while (i < argc) { 64 if (!strcmp("-h", argv[i]) || !strcmp("--help", argv[i])) { 65 help_ = true; 66 i++; 67 continue; 68 } 69 if (!strcmp("-v", argv[i]) || !strcmp("--verbose", argv[i])) { 70 verbosity++; 71 } 72 // after "--", filenames starting with "-" can be used 73 if (!strcmp("--", argv[i])) { 74 parse_options = false; 75 i++; 76 continue; 77 } 78 // special case: "-" is a filename denoting stdin or stdout 79 bool parse_this_option = true; 80 if (!strcmp("-", argv[i])) { 81 parse_this_option = false; 82 } 83 bool found = false; 84 for (const auto& option : options_) { 85 if (option->Match(argv[i], parse_options && parse_this_option)) { 86 // Parsing advances the value i on success. 87 const char* arg = argv[i]; 88 if (!option->Parse(argc, argv, &i)) { 89 fprintf(stderr, "Error parsing flag %s\n", arg); 90 return false; 91 } 92 found = true; 93 break; 94 } 95 } 96 if (!found) { 97 // No option matched argv[i]. 98 fprintf(stderr, "Unknown argument: %s\n", argv[i]); 99 return false; 100 } 101 } 102 return true; 103 } 104 105 void CommandLineParser::VerbosePrintf(int min_verbosity, const char* format, 106 ...) const { 107 if (min_verbosity > verbosity) return; 108 va_list args; 109 va_start(args, format); 110 vfprintf(stderr, format, args); 111 fflush(stderr); 112 va_end(args); 113 } 114 115 } // namespace tools 116 } // namespace jpegxl