32 m_sAppDescription = std::move(sAppDescription);
37 if (argc <= 0 || argv ==
nullptr)
43 m_Args = std::span(argv,
static_cast<size_t>(argc));
50 [](
const char*
const pszValue)
52 cstring_view svValue(pszValue);
53 return svValue ==
"--help" || svValue ==
"-h";
61 cstring_view svRuntimeName;
64 std::map<cstring_view, std::vector<data_with_runtime_name>> groups;
65 for (
const auto& [svRuntimeName, data] : m_VariableData)
67 groups[data.svGroupName].emplace_back(data, svRuntimeName);
70 for (std::vector<data_with_runtime_name>& lines : groups | std::views::values)
74 [](
const data_with_runtime_name& left,
const data_with_runtime_name& right)
76 return left.bRequired > right.bRequired && left.svFullCommandLineName > right.svFullCommandLineName;
83 constexpr cstring_view svRequired =
"required ";
85 size_t nMaxFullCommandLineNameLength = 0;
86 size_t nMaxShortCommandLineNameLength = 0;
87 size_t nMaxTypeNameLength = 0;
88 size_t nMaxRequiredNameLength = 0;
89 for (
const std::vector<data_with_runtime_name>& lines : groups | std::views::values)
91 for (
const data_with_runtime_name& line : lines)
93 nMaxFullCommandLineNameLength =
94 std::max(nMaxFullCommandLineNameLength, line.svFullCommandLineName.size());
95 nMaxShortCommandLineNameLength =
96 std::max(nMaxShortCommandLineNameLength, line.svShortCommandLineName.size());
97 nMaxTypeNameLength = std::max(nMaxTypeNameLength, line.svTypeName.size());
98 nMaxRequiredNameLength = std::max(
99 nMaxRequiredNameLength,
100 line.bRequired ? svRequired.size() : line.pTToString(m_Variables.at(line.svRuntimeName)).size());
105 sHelp +=
"Using formats: [--key], [-k], [--key=value], [-k=value], [--key value], [-k value]\n\n";
107 if (!m_sAppDescription.empty())
110 for (
const auto& [svGroupName, lines] : groups)
112 if (!svGroupName.empty())
115 sHelp +=
"General options:\n";
118 "------------------------------------------------------------------------------------------------------"
119 "------------------\n";
121 for (
const data_with_runtime_name& line : lines)
124 "{:<{}} {:<{}} {:<{}} {:<{}}{}\n",
125 line.svFullCommandLineName,
126 nMaxFullCommandLineNameLength,
127 line.svShortCommandLineName,
128 nMaxShortCommandLineNameLength,
131 line.bRequired ? svRequired
132 : cstring_view(line.pTToString(m_Variables.at(line.svRuntimeName)) +
" "),
133 nMaxRequiredNameLength,
142 sHelp +=
"This app doesn't have any command line arguments.\n\n";
143 if (!m_sAppDescription.empty())
154 std::unordered_map<cstring_view, std::any> variables;
157 for (
const auto& [svRuntimeName, value] : m_DefaultVariables)
158 if (!m_Variables.contains(svRuntimeName))
159 variables[svRuntimeName] = value;
162 for (
const auto& [svRuntimeName, data] : m_VariableData)
164 if (
const char* pszEnvValue = std::getenv(
cstring(data.svEnvName).
c_str()))
166 std::optional<std::any> optValue = data.pStringToT(pszEnvValue);
170 variables[svRuntimeName] = std::move(*optValue);
175 for (
size_t i = 1; i < m_Args.size(); ++i)
177 const cstring_view svArgument = m_Args[i];
179 bool bShortKey =
false;
181 cstring_view svValue;
183 svKey = cstring_view(svArgument.begin(), svArgument.end());
184 if (svArgument.starts_with(
"--"))
188 else if (svArgument.starts_with(
"-"))
195 qx::verbosity::warning,
196 "Invalid command argument format: {}. "
197 "Use \"--key=value\", \"--key value\", \"-k value\", \"--key\", \"-k\" instead.",
203 if (
const size_t nEqualPos = svKey.find(
'='); nEqualPos != cstring_view::npos)
205 svValue = cstring_view(svKey.begin() + nEqualPos + 1, svKey.end());
206 svKey = cstring_view(svKey.begin(), svKey.begin() + nEqualPos);
209 else if (i + 1 < m_Args.size())
211 const cstring_view svNextArgument = m_Args[i + 1];
213 if (!svNextArgument.starts_with(
"-"))
215 svValue = svNextArgument;
232 QX_LOG(qx::verbosity::warning,
"Empty command argument key: {}.",
qx::to_string(svArgument));
238 QX_LOG(qx::verbosity::warning,
"Empty command argument value: {}.",
qx::to_string(svArgument));
242 for (
const auto& [svRuntimeName, data] : m_VariableData)
244 const bool bNameMatches =
245 bShortKey && svKey == data.svShortCommandLineName || !bShortKey && svKey == data.svFullCommandLineName;
249 std::optional<std::any> optValue = data.pStringToT(svValue);
253 variables[svRuntimeName] = std::move(*optValue);
258 bool bAllRequiredVariablesPresent =
true;
259 for (
const auto& [svRuntimeName, data] : m_VariableData)
261 if (data.bRequired && !variables.contains(svRuntimeName))
263 QX_LOG(qx::verbosity::error,
"Required variable missing: {}.",
qx::to_string(data.svFullCommandLineName));
264 bAllRequiredVariablesPresent =
false;
269 for (
const auto& [svRuntimeName, value] : variables)
270 m_Variables[svRuntimeName] = value;
272 return bAllRequiredVariablesPresent;
278 auto it = m_Variables.find(svRuntimeName);
279 if (it == m_Variables.end())
281 it = m_DefaultVariables.find(svRuntimeName);
282 if (it == m_DefaultVariables.end())
286 const auto* pValue = std::any_cast<typename details::layered_config_variable_type<T>::type>(&it->second);
297 const auto it = m_DefaultVariables.find(svRuntimeName);
298 if (it == m_DefaultVariables.end())
301 if (!std::any_cast<
typename details::layered_config_variable_type<T>::type>(&it->second))
304 m_Variables[svRuntimeName] =
typename details::layered_config_variable_type<T>::type(std::move(value));
314 void layered_configs_manager::add_variable(
315 cstring_view svRuntimeName,
317 T defaultValue) noexcept
319 m_VariableData[svRuntimeName] = data;
320 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.