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:
2023-10-22 01:45:04 -07:00
parent 9a8dc08a4f
commit c5308dedba
10 changed files with 505 additions and 25 deletions

View File

@@ -80,7 +80,7 @@ hasKey(std::vector<std::string> argv)
}
cout << "not found\n";
return true;
return false;
}

View File

@@ -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
View 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

View File

@@ -28,7 +28,7 @@
namespace scsl {
namespace string {
namespace scstring {
std::vector<std::string>