mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-29 20:23:55 +00:00
118 lines
3.0 KiB
C++
118 lines
3.0 KiB
C++
#pragma once
|
|
|
|
// Distributed under the LGPL v2.1 license. See accompanying
|
|
// file LICENSE or https://github.com/CLIUtils/CLI11 for details.
|
|
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
|
|
#include "CLI/StringTools.hpp"
|
|
|
|
|
|
namespace CLI {
|
|
namespace detail {
|
|
|
|
inline std::string inijoin(std::vector<std::string> args) {
|
|
std::ostringstream s;
|
|
size_t start = 0;
|
|
for (const auto& arg : args) {
|
|
if(start++ > 0)
|
|
s << " ";
|
|
|
|
auto it = std::find_if(arg.begin(), arg.end(), [](char ch){ return std::isspace<char>(ch , std::locale());});
|
|
if(it == arg.end())
|
|
s << arg;
|
|
else if(arg.find("\"") == std::string::npos)
|
|
s << "\"" << arg << "\"";
|
|
else
|
|
s << "\'" << arg << "\'";
|
|
}
|
|
|
|
return s.str();
|
|
}
|
|
|
|
struct ini_ret_t {
|
|
/// This is the full name with dots
|
|
std::string fullname;
|
|
|
|
/// Listing of inputs
|
|
std::vector<std::string> inputs;
|
|
|
|
/// Current parent level
|
|
size_t level = 0;
|
|
|
|
/// Return parent or empty string, based on level
|
|
///
|
|
/// Level 0, a.b.c would return a
|
|
/// Level 1, a.b.c could return b
|
|
std::string parent () const {
|
|
std::vector<std::string> plist = detail::split(fullname, '.');
|
|
if(plist.size() > (level+1))
|
|
return plist[level];
|
|
else
|
|
return "";
|
|
}
|
|
|
|
/// Return name
|
|
std::string name () const {
|
|
std::vector<std::string> plist = detail::split(fullname, '.');
|
|
return plist.at(plist.size()-1);
|
|
}
|
|
};
|
|
|
|
/// Internal parsing function
|
|
std::vector<ini_ret_t> parse_ini(std::istream &input) {
|
|
std::string name, line;
|
|
std::string section = "default";
|
|
|
|
std::vector<ini_ret_t> output;
|
|
|
|
while(getline(input, line)) {
|
|
std::vector<std::string> items;
|
|
|
|
detail::trim(line);
|
|
size_t len = line.length();
|
|
if(len > 1 && line[0] == '[' && line[len-1] == ']') {
|
|
section = line.substr(1,len-2);
|
|
} else if (len > 0 && line[0] != ';') {
|
|
output.emplace_back();
|
|
ini_ret_t& out = output.back();
|
|
|
|
// Find = in string, split and recombine
|
|
auto pos = line.find("=");
|
|
if(pos != std::string::npos) {
|
|
name = detail::trim_copy(line.substr(0,pos));
|
|
std::string item = detail::trim_copy(line.substr(pos+1));
|
|
items = detail::split_up(item);
|
|
} else {
|
|
name = detail::trim_copy(line);
|
|
items = {"ON"};
|
|
}
|
|
|
|
if(detail::to_lower(section) == "default")
|
|
out.fullname = name;
|
|
else
|
|
out.fullname = section + "." + name;
|
|
|
|
out.inputs.insert(std::end(out.inputs), std::begin(items), std::end(items));
|
|
}
|
|
}
|
|
return output;
|
|
}
|
|
|
|
/// Parse an INI file, throw an error (ParseError:INIParseError or FileError) on failure
|
|
std::vector<ini_ret_t> parse_ini(const std::string &name) {
|
|
|
|
std::ifstream input{name};
|
|
if(!input.good())
|
|
throw FileError(name);
|
|
|
|
return parse_ini(input);
|
|
}
|
|
|
|
|
|
}
|
|
}
|