00001 // 00002 // Copyright 2019 The Abseil Authors. 00003 // 00004 // Licensed under the Apache License, Version 2.0 (the "License"); 00005 // you may not use this file except in compliance with the License. 00006 // You may obtain a copy of the License at 00007 // 00008 // https://www.apache.org/licenses/LICENSE-2.0 00009 // 00010 // Unless required by applicable law or agreed to in writing, software 00011 // distributed under the License is distributed on an "AS IS" BASIS, 00012 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 // See the License for the specific language governing permissions and 00014 // limitations under the License. 00015 00016 #include "absl/flags/usage_config.h" 00017 00018 #include <iostream> 00019 #include <memory> 00020 00021 #include "absl/base/attributes.h" 00022 #include "absl/flags/internal/path_util.h" 00023 #include "absl/flags/internal/program_name.h" 00024 #include "absl/strings/str_cat.h" 00025 #include "absl/strings/strip.h" 00026 #include "absl/synchronization/mutex.h" 00027 00028 extern "C" { 00029 00030 // Additional report of fatal usage error message before we std::exit. Error is 00031 // fatal if is_fatal argument to ReportUsageError is true. 00032 ABSL_ATTRIBUTE_WEAK void AbslInternalReportFatalUsageError(absl::string_view) {} 00033 00034 } // extern "C" 00035 00036 namespace absl { 00037 namespace flags_internal { 00038 00039 namespace { 00040 00041 // -------------------------------------------------------------------- 00042 // Returns true if flags defined in the filename should be reported with 00043 // -helpshort flag. 00044 00045 bool ContainsHelpshortFlags(absl::string_view filename) { 00046 // By default we only want flags in binary's main. We expect the main 00047 // routine to reside in <program>.cc or <program>-main.cc or 00048 // <program>_main.cc, where the <program> is the name of the binary. 00049 auto suffix = flags_internal::Basename(filename); 00050 if (!absl::ConsumePrefix(&suffix, 00051 flags_internal::ShortProgramInvocationName())) 00052 return false; 00053 return absl::StartsWith(suffix, ".") || absl::StartsWith(suffix, "-main.") || 00054 absl::StartsWith(suffix, "_main."); 00055 } 00056 00057 // -------------------------------------------------------------------- 00058 // Returns true if flags defined in the filename should be reported with 00059 // -helppackage flag. 00060 00061 bool ContainsHelppackageFlags(absl::string_view filename) { 00062 // TODO(rogeeff): implement properly when registry is available. 00063 return ContainsHelpshortFlags(filename); 00064 } 00065 00066 // -------------------------------------------------------------------- 00067 // Generates program version information into supplied output. 00068 00069 std::string VersionString() { 00070 std::string version_str(flags_internal::ShortProgramInvocationName()); 00071 00072 version_str += "\n"; 00073 00074 #if !defined(NDEBUG) 00075 version_str += "Debug build (NDEBUG not #defined)\n"; 00076 #endif 00077 00078 return version_str; 00079 } 00080 00081 // -------------------------------------------------------------------- 00082 // Normalizes the filename specific to the build system/filesystem used. 00083 00084 std::string NormalizeFilename(absl::string_view filename) { 00085 // Skip any leading slashes 00086 auto pos = filename.find_first_not_of("\\/"); 00087 if (pos == absl::string_view::npos) return ""; 00088 00089 filename.remove_prefix(pos); 00090 return std::string(filename); 00091 } 00092 00093 // -------------------------------------------------------------------- 00094 00095 ABSL_CONST_INIT absl::Mutex custom_usage_config_guard(absl::kConstInit); 00096 ABSL_CONST_INIT FlagsUsageConfig* custom_usage_config 00097 GUARDED_BY(custom_usage_config_guard) = nullptr; 00098 00099 } // namespace 00100 00101 FlagsUsageConfig GetUsageConfig() { 00102 absl::MutexLock l(&custom_usage_config_guard); 00103 00104 if (custom_usage_config) return *custom_usage_config; 00105 00106 FlagsUsageConfig default_config; 00107 default_config.contains_helpshort_flags = &ContainsHelpshortFlags; 00108 default_config.contains_help_flags = &ContainsHelppackageFlags; 00109 default_config.contains_helppackage_flags = &ContainsHelppackageFlags; 00110 default_config.version_string = &VersionString; 00111 default_config.normalize_filename = &NormalizeFilename; 00112 00113 return default_config; 00114 } 00115 00116 void ReportUsageError(absl::string_view msg, bool is_fatal) { 00117 std::cerr << "ERROR: " << msg << std::endl; 00118 00119 if (is_fatal) { 00120 AbslInternalReportFatalUsageError(msg); 00121 } 00122 } 00123 00124 } // namespace flags_internal 00125 00126 void SetFlagsUsageConfig(FlagsUsageConfig usage_config) { 00127 absl::MutexLock l(&flags_internal::custom_usage_config_guard); 00128 00129 if (!usage_config.contains_helpshort_flags) 00130 usage_config.contains_helpshort_flags = 00131 flags_internal::ContainsHelpshortFlags; 00132 00133 if (!usage_config.contains_help_flags) 00134 usage_config.contains_help_flags = flags_internal::ContainsHelppackageFlags; 00135 00136 if (!usage_config.contains_helppackage_flags) 00137 usage_config.contains_helppackage_flags = 00138 flags_internal::ContainsHelppackageFlags; 00139 00140 if (!usage_config.version_string) 00141 usage_config.version_string = flags_internal::VersionString; 00142 00143 if (!usage_config.normalize_filename) 00144 usage_config.normalize_filename = flags_internal::NormalizeFilename; 00145 00146 if (flags_internal::custom_usage_config) 00147 *flags_internal::custom_usage_config = usage_config; 00148 else 00149 flags_internal::custom_usage_config = new FlagsUsageConfig(usage_config); 00150 } 00151 00152 } // namespace absl