Add SimpleConfig.
https://godocs.io/git.wntrmute.dev/kyle/goutils/config is one of the more useful Go packages in my standard go library that gets used for building services. I needed something similar for another Shimmering Clarity project, and thus I figured I'd add it into SCSL.
This commit is contained in:
@@ -80,7 +80,7 @@ hasKey(std::vector<std::string> argv)
|
||||
}
|
||||
|
||||
cout << "not found\n";
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
/// PERFORMANCE OF THIS SOFTWARE.
|
||||
///
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
@@ -172,6 +171,18 @@ Flags::Register(std::string fName, std::string defaultValue, std::string fDescri
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Flags::Register(std::string fName, const char *defaultValue, std::string fDescription)
|
||||
{
|
||||
if (!this->Register(fName, FlagType::String, std::move(fDescription))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->flags[fName]->Value.s = new std::string(defaultValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
Flags::Size()
|
||||
{
|
||||
@@ -206,7 +217,7 @@ Flags::ParseStatus
|
||||
Flags::parseArg(int argc, char **argv, int &index)
|
||||
{
|
||||
std::string arg(argv[index]);
|
||||
string::TrimWhitespace(arg);
|
||||
scstring::TrimWhitespace(arg);
|
||||
|
||||
if (!std::regex_search(arg, isFlag)) {
|
||||
return ParseStatus::EndOfFlags;
|
||||
@@ -302,7 +313,7 @@ Flags::Usage(std::ostream &os, int exitCode)
|
||||
os << this->name << ":\t";
|
||||
auto indent = this->name.size() + 7;
|
||||
|
||||
string::WriteTabIndented(os, description, 72 - indent, indent / 8, false);
|
||||
scstring::WriteTabIndented(os, description, 72 - indent, indent / 8, false);
|
||||
os << "\n\n";
|
||||
|
||||
for (const auto &pair : this->flags) {
|
||||
@@ -312,16 +323,16 @@ Flags::Usage(std::ostream &os, int exitCode)
|
||||
argLine += "\t\t";
|
||||
break;
|
||||
case FlagType::Integer:
|
||||
argLine += "int\t\t";
|
||||
argLine += " int\t\t";
|
||||
break;
|
||||
case FlagType::UnsignedInteger:
|
||||
argLine += "uint\t\t";
|
||||
argLine += " uint\t\t";
|
||||
break;
|
||||
case FlagType::SizeT:
|
||||
argLine += "size_t\t";
|
||||
argLine += " size_t\t";
|
||||
break;
|
||||
case FlagType::String:
|
||||
argLine += "string\t";
|
||||
argLine += " string\t";
|
||||
break;
|
||||
case FlagType::Unknown:
|
||||
// fallthrough
|
||||
@@ -336,7 +347,7 @@ Flags::Usage(std::ostream &os, int exitCode)
|
||||
|
||||
os << argLine;
|
||||
indent = argLine.size();
|
||||
string::WriteTabIndented(os, pair.second->Description,
|
||||
scstring::WriteTabIndented(os, pair.second->Description,
|
||||
72-indent, (indent/8)+2, false);
|
||||
}
|
||||
|
||||
|
||||
189
src/sl/SimpleConfig.cc
Normal file
189
src/sl/SimpleConfig.cc
Normal file
@@ -0,0 +1,189 @@
|
||||
///
|
||||
/// \file src/sl/SimpleConfig.cc
|
||||
/// \author K. Isom <kyle@imap.cc>
|
||||
/// \date 2023-10-21
|
||||
/// \brief Simple project configuration.
|
||||
///
|
||||
/// This is an implementation of a simple global configuration system
|
||||
/// for projects based on a Go version I've used successfully in
|
||||
/// several projects.
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// Permission to use, copy, modify, and/or distribute this software for
|
||||
/// any purpose with or without fee is hereby granted, provided that
|
||||
/// the above copyright notice and this permission notice appear in all /// copies.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
|
||||
/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
/// PERFORMANCE OF THIS SOFTWARE.
|
||||
///
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
|
||||
#include <scsl/SimpleConfig.h>
|
||||
#include <scsl/StringUtil.h>
|
||||
|
||||
|
||||
namespace scsl {
|
||||
|
||||
|
||||
#if defined(SCSL_DESKTOP_BUILD)
|
||||
static SimpleConfig globalConfig;
|
||||
#endif
|
||||
|
||||
|
||||
static constexpr auto regexOpts = std::regex_constants::nosubs |
|
||||
std::regex_constants::optimize |
|
||||
std::regex_constants::ECMAScript;
|
||||
|
||||
static const std::regex commentLine("^\\s*#.*$", regexOpts);
|
||||
static const std::regex keyValueLine("^\\s*\\w+\\s*=\\s*\\w+", regexOpts);
|
||||
|
||||
|
||||
int
|
||||
SimpleConfig::LoadGlobal(const char *path)
|
||||
{
|
||||
return globalConfig.Load(path);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SimpleConfig::LoadGlobal(std::string &path)
|
||||
{
|
||||
return globalConfig.Load(path);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SimpleConfig::SetPrefixGlobal(const std::string prefix)
|
||||
{
|
||||
globalConfig.SetPrefix(prefix);
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string>
|
||||
SimpleConfig::KeyListGlobal()
|
||||
{
|
||||
return globalConfig.KeyList();
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
SimpleConfig::GetGlobal(std::string key)
|
||||
{
|
||||
return globalConfig.Get(key);
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
SimpleConfig::GetGlobal(std::string key, std::string defaultValue)
|
||||
{
|
||||
return globalConfig.Get(key, defaultValue);
|
||||
}
|
||||
|
||||
|
||||
SimpleConfig::SimpleConfig()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SimpleConfig::SimpleConfig(std::string prefix)
|
||||
: envPrefix(prefix)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SimpleConfig::Load(const char *path)
|
||||
{
|
||||
auto spath = std::string(path);
|
||||
return this->Load(spath);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SimpleConfig::Load(std::string &path)
|
||||
{
|
||||
std::ifstream configFile(path);
|
||||
std::string line;
|
||||
|
||||
while (std::getline(configFile, line)) {
|
||||
scstring::TrimWhitespace(line);
|
||||
if (line.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (std::regex_search(line, commentLine)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (std::regex_search(line, keyValueLine)) {
|
||||
auto pair = scstring::SplitKeyValuePair(line, "=");
|
||||
if (pair.size() < 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
this->vars[pair[0]] = pair[1];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SimpleConfig::SetPrefix(const std::string prefix)
|
||||
{
|
||||
this->envPrefix = std::move(prefix);
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
SimpleConfig::Get(std::string key)
|
||||
{
|
||||
return this->Get(key, "");
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
SimpleConfig::Get(std::string key, std::string defaultValue)
|
||||
{
|
||||
if (this->vars.count(key)) {
|
||||
return this->vars[key];
|
||||
}
|
||||
|
||||
auto envKey = this->envPrefix + key;
|
||||
|
||||
const char *envValue = getenv(envKey.c_str());
|
||||
if (envValue != nullptr) {
|
||||
this->vars[key] = std::string(envValue);
|
||||
return this->Get(key);
|
||||
}
|
||||
|
||||
this->vars[key] = defaultValue;
|
||||
return this->Get(key);
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string>
|
||||
SimpleConfig::KeyList()
|
||||
{
|
||||
std::vector<std::string> keyList;
|
||||
|
||||
for (auto &entry : this->vars) {
|
||||
keyList.push_back(entry.first);
|
||||
}
|
||||
|
||||
return keyList;
|
||||
}
|
||||
|
||||
|
||||
} // namespace SimpleConfig
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
|
||||
namespace scsl {
|
||||
namespace string {
|
||||
namespace scstring {
|
||||
|
||||
|
||||
std::vector<std::string>
|
||||
|
||||
Reference in New Issue
Block a user