usage_config.cc (5594B)
1 // 2 // Copyright 2019 The Abseil Authors. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // https://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 #include "absl/flags/usage_config.h" 17 18 #include <functional> 19 #include <iostream> 20 #include <string> 21 22 #include "absl/base/attributes.h" 23 #include "absl/base/config.h" 24 #include "absl/base/const_init.h" 25 #include "absl/base/no_destructor.h" 26 #include "absl/base/thread_annotations.h" 27 #include "absl/flags/internal/path_util.h" 28 #include "absl/flags/internal/program_name.h" 29 #include "absl/strings/match.h" 30 #include "absl/strings/string_view.h" 31 #include "absl/strings/strip.h" 32 #include "absl/synchronization/mutex.h" 33 34 extern "C" { 35 36 // Additional report of fatal usage error message before we std::exit. Error is 37 // fatal if is_fatal argument to ReportUsageError is true. 38 ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL( 39 AbslInternalReportFatalUsageError)(absl::string_view) {} 40 41 } // extern "C" 42 43 namespace absl { 44 ABSL_NAMESPACE_BEGIN 45 namespace flags_internal { 46 47 namespace { 48 49 // -------------------------------------------------------------------- 50 // Returns true if flags defined in the filename should be reported with 51 // -helpshort flag. 52 53 bool ContainsHelpshortFlags(absl::string_view filename) { 54 // By default we only want flags in binary's main. We expect the main 55 // routine to reside in <program>.cc or <program>-main.cc or 56 // <program>_main.cc, where the <program> is the name of the binary 57 // (without .exe on Windows). 58 auto suffix = flags_internal::Basename(filename); 59 auto program_name = flags_internal::ShortProgramInvocationName(); 60 absl::string_view program_name_ref = program_name; 61 #if defined(_WIN32) 62 absl::ConsumeSuffix(&program_name_ref, ".exe"); 63 #endif 64 if (!absl::ConsumePrefix(&suffix, program_name_ref)) 65 return false; 66 return absl::StartsWith(suffix, ".") || absl::StartsWith(suffix, "-main.") || 67 absl::StartsWith(suffix, "_main."); 68 } 69 70 // -------------------------------------------------------------------- 71 // Returns true if flags defined in the filename should be reported with 72 // -helppackage flag. 73 74 bool ContainsHelppackageFlags(absl::string_view filename) { 75 // TODO(rogeeff): implement properly when registry is available. 76 return ContainsHelpshortFlags(filename); 77 } 78 79 // -------------------------------------------------------------------- 80 // Generates program version information into supplied output. 81 82 std::string VersionString() { 83 std::string version_str(flags_internal::ShortProgramInvocationName()); 84 85 version_str += "\n"; 86 87 #if !defined(NDEBUG) 88 version_str += "Debug build (NDEBUG not #defined)\n"; 89 #endif 90 91 return version_str; 92 } 93 94 // -------------------------------------------------------------------- 95 // Normalizes the filename specific to the build system/filesystem used. 96 97 std::string NormalizeFilename(absl::string_view filename) { 98 // Skip any leading slashes 99 auto pos = filename.find_first_not_of("\\/"); 100 if (pos == absl::string_view::npos) return ""; 101 102 filename.remove_prefix(pos); 103 return std::string(filename); 104 } 105 106 // -------------------------------------------------------------------- 107 108 absl::Mutex* CustomUsageConfigMutex() { 109 static absl::NoDestructor<absl::Mutex> mutex; 110 return mutex.get(); 111 } 112 ABSL_CONST_INIT FlagsUsageConfig* custom_usage_config 113 ABSL_GUARDED_BY(CustomUsageConfigMutex()) 114 ABSL_PT_GUARDED_BY(CustomUsageConfigMutex()) = nullptr; 115 116 } // namespace 117 118 FlagsUsageConfig GetUsageConfig() { 119 absl::MutexLock l(CustomUsageConfigMutex()); 120 121 if (custom_usage_config) return *custom_usage_config; 122 123 FlagsUsageConfig default_config; 124 default_config.contains_helpshort_flags = &ContainsHelpshortFlags; 125 default_config.contains_help_flags = &ContainsHelppackageFlags; 126 default_config.contains_helppackage_flags = &ContainsHelppackageFlags; 127 default_config.version_string = &VersionString; 128 default_config.normalize_filename = &NormalizeFilename; 129 130 return default_config; 131 } 132 133 void ReportUsageError(absl::string_view msg, bool is_fatal) { 134 std::cerr << "ERROR: " << msg << std::endl; 135 136 if (is_fatal) { 137 ABSL_INTERNAL_C_SYMBOL(AbslInternalReportFatalUsageError)(msg); 138 } 139 } 140 141 } // namespace flags_internal 142 143 void SetFlagsUsageConfig(FlagsUsageConfig usage_config) { 144 absl::MutexLock l(flags_internal::CustomUsageConfigMutex()); 145 146 if (!usage_config.contains_helpshort_flags) 147 usage_config.contains_helpshort_flags = 148 flags_internal::ContainsHelpshortFlags; 149 150 if (!usage_config.contains_help_flags) 151 usage_config.contains_help_flags = flags_internal::ContainsHelppackageFlags; 152 153 if (!usage_config.contains_helppackage_flags) 154 usage_config.contains_helppackage_flags = 155 flags_internal::ContainsHelppackageFlags; 156 157 if (!usage_config.version_string) 158 usage_config.version_string = flags_internal::VersionString; 159 160 if (!usage_config.normalize_filename) 161 usage_config.normalize_filename = flags_internal::NormalizeFilename; 162 163 if (flags_internal::custom_usage_config) 164 *flags_internal::custom_usage_config = usage_config; 165 else 166 flags_internal::custom_usage_config = new FlagsUsageConfig(usage_config); 167 } 168 169 ABSL_NAMESPACE_END 170 } // namespace absl