32 m_sAppDescription = std::move(sAppDescription);
37 m_Args = std::span(argv, argc);
44 [](
const char*
const pszValue)
46 cstring_view svValue(pszValue);
47 return svValue ==
"--help" || svValue ==
"-h";
55 cstring_view svRuntimeName;
58 std::map<cstring_view, std::vector<data_with_runtime_name>> groups;
59 for (
const auto& [svRuntimeName, data] : m_VariableData)
61 groups[data.svGroupName].push_back(data_with_runtime_name { { data }, svRuntimeName });
64 for (std::vector<data_with_runtime_name>& lines : groups | std::views::values)
68 [](
const data_with_runtime_name& left,
const data_with_runtime_name& right)
70 return left.bRequired > right.bRequired && left.svFullCommandLineName > right.svFullCommandLineName;
77 constexpr cstring_view svRequired =
"required ";
79 size_t nMaxFullCommandLineNameLength = 0;
80 size_t nMaxShortCommandLineNameLength = 0;
81 size_t nMaxTypeNameLength = 0;
82 size_t nMaxRequiredNameLength = 0;
83 for (
const std::vector<data_with_runtime_name>& lines : groups | std::views::values)
85 for (
const data_with_runtime_name& line : lines)
87 nMaxFullCommandLineNameLength =
88 std::max(nMaxFullCommandLineNameLength, line.svFullCommandLineName.size());
89 nMaxShortCommandLineNameLength =
90 std::max(nMaxShortCommandLineNameLength, line.svShortCommandLineName.size());
91 nMaxTypeNameLength = std::max(nMaxTypeNameLength, line.svTypeName.size());
92 nMaxRequiredNameLength = std::max(
93 nMaxRequiredNameLength,
94 line.bRequired ? svRequired.size() : line.pTToString(m_Variables.at(line.svRuntimeName)).size());
99 sHelp +=
"Using formats: [--key], [-k], [--key=value], [-k=value], [--key value], [-k value]\n\n";
101 if (!m_sAppDescription.empty())
104 for (
const auto& [svGroupName, lines] : groups)
106 if (!svGroupName.empty())
109 sHelp +=
"General options:\n";
112 "------------------------------------------------------------------------------------------------------"
113 "------------------\n";
115 for (
const data_with_runtime_name& line : lines)
118 "{:<{}} {:<{}} {:<{}} {:<{}}{}\n",
119 line.svFullCommandLineName,
120 nMaxFullCommandLineNameLength,
121 line.svShortCommandLineName,
122 nMaxShortCommandLineNameLength,
125 line.bRequired ? svRequired
126 : cstring_view(line.pTToString(m_Variables.at(line.svRuntimeName)) +
" "),
127 nMaxRequiredNameLength,
136 sHelp +=
"This app doesn't have any command line arguments.\n\n";
137 if (!m_sAppDescription.empty())
148 std::unordered_map<cstring_view, std::any> variables;
151 for (
const auto& [svRuntimeName, value] : m_DefaultVariables)
152 if (!m_Variables.contains(svRuntimeName))
153 variables[svRuntimeName] = value;
156 for (
const auto& [svRuntimeName, data] : m_VariableData)
158 if (
const char* pszEnvValue = std::getenv(
cstring(data.svEnvName).
c_str()))
160 std::optional<std::any> optValue = data.pStringToT(pszEnvValue);
164 variables[svRuntimeName] = std::move(*optValue);
169 for (
size_t i = 1; i < m_Args.size(); ++i)
171 const cstring_view svArgument = m_Args[i];
173 bool bShortKey =
false;
175 cstring_view svValue;
177 svKey = cstring_view(svArgument.begin(), svArgument.end());
178 if (svArgument.starts_with(
"--"))
182 else if (svArgument.starts_with(
"-"))
189 qx::verbosity::warning,
190 "Invalid command argument format: {}. "
191 "Use \"--key=value\", \"--key value\", \"-k value\", \"--key\", \"-k\" instead.",
197 if (
const size_t nEqualPos = svKey.find(
'='); nEqualPos != cstring_view::npos)
199 svValue = cstring_view(svKey.begin() + nEqualPos + 1, svKey.end());
200 svKey = cstring_view(svKey.begin(), svKey.begin() + nEqualPos);
203 else if (i + 1 < m_Args.size())
205 const cstring_view svNextArgument = m_Args[i + 1];
207 if (!svNextArgument.starts_with(
"-"))
209 svValue = svNextArgument;
226 QX_LOG(qx::verbosity::warning,
"Empty command argument key: {}.",
qx::to_string(svArgument));
232 QX_LOG(qx::verbosity::warning,
"Empty command argument value: {}.",
qx::to_string(svArgument));
236 for (
const auto& [svRuntimeName, data] : m_VariableData)
238 const bool bNameMatches =
239 bShortKey && svKey == data.svShortCommandLineName || !bShortKey && svKey == data.svFullCommandLineName;
243 std::optional<std::any> optValue = data.pStringToT(svValue);
247 variables[svRuntimeName] = std::move(*optValue);
252 bool bAllRequiredVariablesPresent =
true;
253 for (
const auto& [svRuntimeName, data] : m_VariableData)
255 if (data.bRequired && !variables.contains(svRuntimeName))
257 QX_LOG(qx::verbosity::error,
"Required variable missing: {}.",
qx::to_string(data.svFullCommandLineName));
258 bAllRequiredVariablesPresent =
false;
263 for (
const auto& [svRuntimeName, value] : variables)
264 m_Variables[svRuntimeName] = value;
266 return bAllRequiredVariablesPresent;
272 auto it = m_Variables.find(svRuntimeName);
273 if (it == m_Variables.end())
275 it = m_DefaultVariables.find(svRuntimeName);
276 if (it == m_DefaultVariables.end())
280 const auto* pValue = std::any_cast<typename details::layered_config_variable_type<T>::type>(&it->second);
291 const auto it = m_DefaultVariables.find(svRuntimeName);
292 if (it == m_DefaultVariables.end())
295 if (!std::any_cast<
typename details::layered_config_variable_type<T>::type>(&it->second))
298 m_Variables[svRuntimeName] =
typename details::layered_config_variable_type<T>::type(std::move(value));
308 void layered_configs_manager::add_variable(
309 cstring_view svRuntimeName,
311 T defaultValue) noexcept
313 m_VariableData[svRuntimeName] = data;
314 m_DefaultVariables[svRuntimeName] =
typename details::layered_config_variable_type<T>::type(defaultValue);
requires format_acceptable_args_c< char_t, args_t... > void append_format(const format_string_type< std::type_identity_t< args_t >... > sFormat, args_t &&... args) noexcept
Append the formatted string to the current one.
const_pointer c_str() const noexcept
Get pointer to string zero terminated.
void reset() noexcept
Clear all variables and command line arguments. You should call parse() after that to set variables a...
std::optional< T > get(cstring_view svRuntimeName) const noexcept
Get variable value by runtime name.
void set_app_description(cstring sAppDescription) noexcept
Set app description. It will be shown in help message.
bool parse() noexcept
Parse command line arguments, environment variables, and default values.
bool set(cstring_view svRuntimeName, T value) noexcept
Set variable value by runtime name. Only set if the variable type matches.
bool show_help() const noexcept
Show help message if "--help" or "-h" argument is present in command line arguments.
void set_args(int argc, char *argv[]) noexcept
Set command line arguments.
bool contains_if(fwd_it_t itBegin, fwd_it_t itEnd, const predicate_t &predicate)
Check if at least one of range's elements satisfies a predicate.
#define QX_LOG(eVerbosity,...)
Log message.
void sort(random_it_t begin, random_it_t end, compare_t compare=compare_t())
Sort by the most suitable algorithm.
void to_string(string &out, cstring_view stringView, const std::locale &locale=std::locale())
Convert a char string to common string type.