mirror of
https://github.com/mariiaan/minipp.git
synced 2026-05-14 10:11:17 +02:00
Projektdateien hinzufügen.
This commit is contained in:
28
minipp.sln
Normal file
28
minipp.sln
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.12.35707.178 d17.12
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minipp", "minipp\minipp.vcxproj", "{F0C52CC0-DB78-4E1A-982F-EE565764C5AF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F0C52CC0-DB78-4E1A-982F-EE565764C5AF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F0C52CC0-DB78-4E1A-982F-EE565764C5AF}.Debug|x64.Build.0 = Debug|x64
|
||||
{F0C52CC0-DB78-4E1A-982F-EE565764C5AF}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{F0C52CC0-DB78-4E1A-982F-EE565764C5AF}.Debug|x86.Build.0 = Debug|Win32
|
||||
{F0C52CC0-DB78-4E1A-982F-EE565764C5AF}.Release|x64.ActiveCfg = Release|x64
|
||||
{F0C52CC0-DB78-4E1A-982F-EE565764C5AF}.Release|x64.Build.0 = Release|x64
|
||||
{F0C52CC0-DB78-4E1A-982F-EE565764C5AF}.Release|x86.ActiveCfg = Release|Win32
|
||||
{F0C52CC0-DB78-4E1A-982F-EE565764C5AF}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
139
minipp/minipp.vcxproj
Normal file
139
minipp/minipp.vcxproj
Normal file
@@ -0,0 +1,139 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{f0c52cc0-db78-4e1a-982f-ee565764c5af}</ProjectGuid>
|
||||
<RootNamespace>minipp</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="minipp\minipp.hpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="test.cpp" />
|
||||
<ClCompile Include="minipp\minipp.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
30
minipp/minipp.vcxproj.filters
Normal file
30
minipp/minipp.vcxproj.filters
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Quelldateien">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Headerdateien">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Ressourcendateien">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="minipp\minipp.hpp">
|
||||
<Filter>Headerdateien</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="minipp\minipp.cpp">
|
||||
<Filter>Quelldateien</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="test.cpp">
|
||||
<Filter>Quelldateien</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
436
minipp/minipp/minipp.cpp
Normal file
436
minipp/minipp/minipp.cpp
Normal file
@@ -0,0 +1,436 @@
|
||||
#include "minipp.hpp"
|
||||
#include <fstream>
|
||||
|
||||
#define MINIPP_ENABLE_DEBUG_OUTPUT true
|
||||
|
||||
#if MINIPP_ENABLE_DEBUG_OUTPUT
|
||||
#include <iostream>
|
||||
#define COUT(msg) std::cout << msg << std::endl
|
||||
#else
|
||||
#define COUT(msg)
|
||||
#endif
|
||||
|
||||
#define ASSERT(condition) if (!condition) abort();
|
||||
|
||||
#define COUT_SYNTAX_ERROR(line, msg) COUT("Error in line " << line << ": " << msg)
|
||||
|
||||
minipp::MiniPPFile::Section::~Section()
|
||||
{
|
||||
for (auto& pair : m_values)
|
||||
delete pair.second;
|
||||
for (auto& pair : m_subSections)
|
||||
delete pair.second;
|
||||
}
|
||||
|
||||
minipp::MiniPPFile::Section* minipp::MiniPPFile::Section::GetSubSection(const std::string& key, EResult* result) const noexcept
|
||||
{
|
||||
auto pathIndex = key.find('.');
|
||||
std::string thisKey = key;
|
||||
std::string rest;
|
||||
if (pathIndex != std::string::npos)
|
||||
{
|
||||
thisKey = key.substr(0, pathIndex);
|
||||
rest = key.substr(pathIndex + 1);
|
||||
}
|
||||
|
||||
auto it = m_subSections.find(thisKey);
|
||||
if (it == m_subSections.end())
|
||||
{
|
||||
COUT("Sub-Section not found: " << thisKey);
|
||||
if (result != nullptr)
|
||||
*result = EResult::SectionNotPresent;
|
||||
return nullptr;
|
||||
}
|
||||
if (result != nullptr)
|
||||
*result = EResult::Success;
|
||||
if (rest.empty())
|
||||
return it->second;
|
||||
return it->second->GetSubSection(rest, result);
|
||||
}
|
||||
|
||||
minipp::MiniPPFile::Section* minipp::MiniPPFile::Section::SetSubSection(const std::string& name, std::unique_ptr<Section> value, bool allowOverwrite, EResult* result) noexcept
|
||||
{
|
||||
if (m_subSections.find(name) != m_subSections.end())
|
||||
if (!allowOverwrite)
|
||||
{
|
||||
if (result != nullptr)
|
||||
*result = EResult::SectionAlreadyPresent;
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
delete m_subSections[name];
|
||||
|
||||
auto val = value.release();
|
||||
m_subSections[name] = val;
|
||||
if (result != nullptr)
|
||||
*result = EResult::Success;
|
||||
return val;
|
||||
}
|
||||
|
||||
minipp::MiniPPFile::StringValue::StringValue(const std::string& str) : m_value(str) {}
|
||||
|
||||
minipp::EResult minipp::MiniPPFile::StringValue::Parse(const std::string& str) noexcept
|
||||
{
|
||||
m_value = "";
|
||||
for (size_t i = 0; i < str.size(); ++i)
|
||||
{
|
||||
if (str[i] == '\\')
|
||||
{
|
||||
if (i + 1 >= str.size())
|
||||
return EResult::FormatError;
|
||||
|
||||
switch (str[i + 1])
|
||||
{
|
||||
case '\"':
|
||||
m_value.push_back('\"');
|
||||
break;
|
||||
case 'n':
|
||||
m_value.push_back('\n');
|
||||
break;
|
||||
case 't':
|
||||
m_value.push_back('\t');
|
||||
break;
|
||||
case 'r':
|
||||
m_value.push_back('\r');
|
||||
break;
|
||||
case '\\':
|
||||
m_value.push_back('\\');
|
||||
break;
|
||||
default:
|
||||
return EResult::FormatError;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
else if (str[i] == '"')
|
||||
return EResult::FormatError;
|
||||
else
|
||||
m_value.push_back(str[i]);
|
||||
}
|
||||
return EResult::Success;
|
||||
}
|
||||
|
||||
minipp::EResult minipp::MiniPPFile::StringValue::ToString(std::string& destination) const noexcept
|
||||
{
|
||||
std::string sanitizedValue = m_value;
|
||||
for (size_t i = 0; i < sanitizedValue.size(); ++i)
|
||||
{
|
||||
switch (sanitizedValue[i])
|
||||
{
|
||||
case '\n':
|
||||
sanitizedValue.replace(i, 1, "\\n");
|
||||
i++;
|
||||
break;
|
||||
case '\t':
|
||||
sanitizedValue.replace(i, 1, "\\t");
|
||||
i++;
|
||||
break;
|
||||
case '\r':
|
||||
sanitizedValue.replace(i, 1, "\\r");
|
||||
i++;
|
||||
break;
|
||||
case '\\':
|
||||
sanitizedValue.insert(i, 1, '\\');
|
||||
i++;
|
||||
break;
|
||||
case '\"':
|
||||
sanitizedValue.insert(i, 1, '\\');
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
destination = "\"" + sanitizedValue + "\"";
|
||||
return EResult::Success;
|
||||
}
|
||||
|
||||
const std::string& minipp::MiniPPFile::StringValue::GetValue() const noexcept
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
minipp::EResult minipp::MiniPPFile::Parse(const std::string& path) noexcept
|
||||
{
|
||||
std::ifstream ifs;
|
||||
ifs.open(path);
|
||||
if (!ifs.is_open())
|
||||
return EResult::FileIOError;
|
||||
|
||||
int64_t lineCounter = 0;
|
||||
|
||||
Section* currentSection = nullptr;
|
||||
|
||||
std::string currentLine;
|
||||
while (std::getline(ifs, currentLine))
|
||||
{
|
||||
++lineCounter;
|
||||
Tools::StringTrim(currentLine);
|
||||
if (currentLine.empty())
|
||||
continue;
|
||||
char firstChar = currentLine[0];
|
||||
char lastChar = currentLine[currentLine.size() - 1];
|
||||
|
||||
if (firstChar == '#')
|
||||
continue;
|
||||
|
||||
if (firstChar == '[')
|
||||
{
|
||||
if (lastChar != ']')
|
||||
{
|
||||
COUT_SYNTAX_ERROR(lineCounter, "Expected ']' at the end of the line.");
|
||||
return EResult::FormatError;
|
||||
}
|
||||
std::string sectionName = currentLine.substr(1, currentLine.size() - 2);
|
||||
Tools::StringTrim(sectionName);
|
||||
if (sectionName.empty())
|
||||
{
|
||||
COUT_SYNTAX_ERROR(lineCounter, "Expected section path. Found empty section begin notation.");
|
||||
return EResult::FormatError;
|
||||
}
|
||||
// Create section tree
|
||||
Section* ubSection = &m_rootSection;
|
||||
|
||||
std::vector<std::string> sectionPath = Tools::SplitByDelimiter(sectionName, '.');
|
||||
for (size_t i = 0; i < sectionPath.size(); ++i)
|
||||
{
|
||||
const std::string& sectionName = sectionPath[i];
|
||||
if (!Tools::IsNameValid(sectionName))
|
||||
{
|
||||
COUT_SYNTAX_ERROR(lineCounter, "Invalid section name. (\"" << sectionName << "\") May only contain [a - z][A - Z][0 - 9] and _.");
|
||||
return EResult::FormatError;
|
||||
}
|
||||
|
||||
EResult result;
|
||||
ubSection->SetSubSection(sectionName, std::make_unique<Section>(), false, &result); // if this fails, the section is already present
|
||||
if (result == EResult::SectionAlreadyPresent && i == sectionPath.size() - 1)
|
||||
{
|
||||
COUT_SYNTAX_ERROR(lineCounter, "All (sub-) sections may only be defined once.");
|
||||
return EResult::FormatError;
|
||||
}
|
||||
ubSection = ubSection->GetSubSection(sectionName, &result);
|
||||
ASSERT(Tools::IsResultOk(result)); // should never happen
|
||||
}
|
||||
currentSection = ubSection;
|
||||
continue;
|
||||
}
|
||||
if (currentSection == nullptr)
|
||||
{
|
||||
COUT_SYNTAX_ERROR(lineCounter, "Expected section begin before key-value pair.");
|
||||
return EResult::FormatError;
|
||||
}
|
||||
|
||||
int64_t keyValueDelimiterIndex = Tools::FirstIndexOf(currentLine, '=');
|
||||
if (keyValueDelimiterIndex == -1)
|
||||
{
|
||||
COUT_SYNTAX_ERROR(lineCounter, "Expected '=' in line.");
|
||||
return EResult::FormatError;
|
||||
}
|
||||
auto keyValuePair = Tools::SplitInTwo(currentLine, keyValueDelimiterIndex);
|
||||
Tools::StringTrim(keyValuePair.first);
|
||||
Tools::StringTrim(keyValuePair.second);
|
||||
if (keyValuePair.first.empty())
|
||||
{
|
||||
COUT_SYNTAX_ERROR(lineCounter, "Expected key in line.");
|
||||
return EResult::FormatError;
|
||||
}
|
||||
if (keyValuePair.second.empty())
|
||||
{
|
||||
COUT_SYNTAX_ERROR(lineCounter, "Empty keys are not allowed");
|
||||
return EResult::FormatError;
|
||||
}
|
||||
std::string& value = keyValuePair.second;
|
||||
char valueFirstChar = value.front();
|
||||
char valueLastChar = value.back();
|
||||
if (valueFirstChar == '"')
|
||||
{
|
||||
if (valueLastChar != '"')
|
||||
{
|
||||
COUT_SYNTAX_ERROR(lineCounter, "Expected '\"' at the end of the value.");
|
||||
return EResult::FormatError;
|
||||
}
|
||||
// is string
|
||||
value = value.substr(1, value.size() - 2);
|
||||
StringValue strValue;
|
||||
auto parseResult = strValue.Parse(value);
|
||||
if (!Tools::IsResultOk(parseResult))
|
||||
{
|
||||
COUT_SYNTAX_ERROR(lineCounter, "Invalid string value.");
|
||||
return EResult::FormatError;
|
||||
}
|
||||
currentSection->SetValue(keyValuePair.first, strValue, false);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
IntValue intValue;
|
||||
auto parseResult = intValue.Parse(value);
|
||||
if (!Tools::IsResultOk(parseResult))
|
||||
{
|
||||
COUT_SYNTAX_ERROR(lineCounter, "Invalid integer value.");
|
||||
return EResult::FormatError;
|
||||
}
|
||||
currentSection->SetValue(keyValuePair.first, intValue, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return EResult::Success;
|
||||
}
|
||||
|
||||
void minipp::MiniPPFile::Write(const std::string& path) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
bool minipp::MiniPPFile::Tools::StringStartsWith(const std::string& str, const std::string& beg)
|
||||
{
|
||||
if (str.size() < beg.size())
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < beg.size(); ++i)
|
||||
if (str[i] != beg[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool minipp::MiniPPFile::Tools::StringEndsWith(const std::string& str, const std::string& end)
|
||||
{
|
||||
if (str.size() < end.size())
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < end.size(); ++i)
|
||||
if (str[str.size() - i - 1] != end[end.size() - i - 1])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void minipp::MiniPPFile::Tools::StringTrim(std::string& str)
|
||||
{
|
||||
if (str.empty())
|
||||
return;
|
||||
|
||||
size_t start = 0;
|
||||
size_t end = str.size() - 1;
|
||||
while (str[start] == ' ' || str[start] == '\t')
|
||||
start++;
|
||||
while (str[end] == ' ' || str[end] == '\t')
|
||||
end--;
|
||||
|
||||
str = str.substr(start, end - start + 1);
|
||||
}
|
||||
|
||||
bool minipp::MiniPPFile::Tools::IsNameValid(const std::string& name) noexcept
|
||||
{
|
||||
for (const char c : name)
|
||||
{
|
||||
if (
|
||||
(c >= 'a' && c <= 'z') ||
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
(c == '_'))
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t minipp::MiniPPFile::Tools::FirstIndexOf(const std::string& str, char c) noexcept
|
||||
{
|
||||
int64_t index = 0;
|
||||
for (const char ch : str)
|
||||
{
|
||||
if (ch == c)
|
||||
return index;
|
||||
++index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int64_t minipp::MiniPPFile::Tools::LastIndexOf(const std::string& str, char c) noexcept
|
||||
{
|
||||
int64_t index = str.size() - 1;
|
||||
for (int64_t i = str.size() - 1; i >= 0; --i)
|
||||
{
|
||||
if (str[i] == c)
|
||||
return index;
|
||||
--index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> minipp::MiniPPFile::Tools::SplitInTwo(const std::string& str, int64_t firstLength) noexcept
|
||||
{
|
||||
return std::make_pair(str.substr(0, firstLength), str.substr(firstLength + 1));
|
||||
}
|
||||
|
||||
std::vector<std::string> minipp::MiniPPFile::Tools::SplitByDelimiter(const std::string& str, char delimiter) noexcept
|
||||
{
|
||||
std::vector<std::string> elements;
|
||||
std::string tmp;
|
||||
|
||||
for (const char c : str)
|
||||
{
|
||||
if (c == delimiter)
|
||||
{
|
||||
elements.push_back(tmp);
|
||||
tmp.clear();
|
||||
}
|
||||
else
|
||||
tmp.push_back(c);
|
||||
}
|
||||
|
||||
if (!tmp.empty())
|
||||
elements.push_back(tmp);
|
||||
return elements;
|
||||
}
|
||||
|
||||
bool minipp::MiniPPFile::Tools::IsResultOk(EResult result) noexcept
|
||||
{
|
||||
return static_cast<int32_t>(result) > 0;
|
||||
}
|
||||
|
||||
void minipp::MiniPPFile::Tools::RemoveAll(std::string& str, char old)
|
||||
{
|
||||
str.erase(std::remove(str.begin(), str.end(), old), str.end());
|
||||
}
|
||||
|
||||
bool minipp::MiniPPFile::Tools::IsIntegerDecimal(const std::string& str) noexcept
|
||||
{
|
||||
for (size_t i = 0; i < str.size(); ++i)
|
||||
if (str[i] < '0' || str[i] > '9')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
minipp::MiniPPFile::IntValue::IntValue(int64_t value) : m_value(value) {}
|
||||
|
||||
minipp::EResult minipp::MiniPPFile::IntValue::Parse(const std::string& str) noexcept
|
||||
{
|
||||
std::string sanitizedValue = str;
|
||||
Tools::RemoveAll(sanitizedValue, '_');
|
||||
if (sanitizedValue.empty())
|
||||
return EResult::FormatError;
|
||||
|
||||
char lastCharacter = str.back();
|
||||
auto rest = str.substr(0, str.size() - 1);
|
||||
if (lastCharacter == 'h')
|
||||
m_value = std::stoll(rest, nullptr, 16);
|
||||
else if (lastCharacter == 'b')
|
||||
m_value = std::stoll(rest, nullptr, 2);
|
||||
else
|
||||
{
|
||||
if (!Tools::IsIntegerDecimal(sanitizedValue))
|
||||
return EResult::FormatError;
|
||||
m_value = std::stoll(sanitizedValue);
|
||||
}
|
||||
return EResult::Success;
|
||||
}
|
||||
|
||||
minipp::EResult minipp::MiniPPFile::IntValue::ToString(std::string& destination) const noexcept
|
||||
{
|
||||
destination = std::to_string(m_value);
|
||||
return EResult::Success;
|
||||
}
|
||||
|
||||
int64_t minipp::MiniPPFile::IntValue::GetValue() const noexcept
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
141
minipp/minipp/minipp.hpp
Normal file
141
minipp/minipp/minipp.hpp
Normal file
@@ -0,0 +1,141 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace minipp
|
||||
{
|
||||
enum class EResult
|
||||
{
|
||||
/* Errors */
|
||||
KeyNotPresent = -1,
|
||||
KeyAlreadyPresent = -2,
|
||||
SectionNotPresent = -3,
|
||||
SectionAlreadyPresent = -4,
|
||||
FileIOError = -5,
|
||||
InvalidDataType = -6,
|
||||
FormatError = -7,
|
||||
|
||||
/* OK Codes*/
|
||||
Success = 1,
|
||||
ValueOverwritten,
|
||||
ValueOverwrittenAndDataTypeChanged
|
||||
};
|
||||
|
||||
class MiniPPFile
|
||||
{
|
||||
private:
|
||||
class Tools
|
||||
{
|
||||
public:
|
||||
static bool StringStartsWith(const std::string& str, const std::string& beg);
|
||||
static bool StringEndsWith(const std::string& str, const std::string& end);
|
||||
static void StringTrim(std::string& str);
|
||||
static bool IsNameValid(const std::string& name) noexcept;
|
||||
static int64_t FirstIndexOf(const std::string& str, char c) noexcept;
|
||||
static int64_t LastIndexOf(const std::string& str, char c) noexcept;
|
||||
static std::pair<std::string, std::string> SplitInTwo(const std::string& str, int64_t firstLength) noexcept;
|
||||
static std::vector<std::string> SplitByDelimiter(const std::string& str, char delimiter) noexcept;
|
||||
static bool IsResultOk(EResult result) noexcept;
|
||||
static void RemoveAll(std::string& str, char old);
|
||||
static bool IsIntegerDecimal(const std::string& str) noexcept;
|
||||
};
|
||||
|
||||
public:
|
||||
class Value
|
||||
{
|
||||
public:
|
||||
virtual EResult Parse(const std::string& str) noexcept = 0;
|
||||
virtual EResult ToString(std::string& destination) const noexcept = 0;
|
||||
};
|
||||
|
||||
class StringValue : public Value
|
||||
{
|
||||
private:
|
||||
std::string m_value;
|
||||
|
||||
public:
|
||||
StringValue() = default;
|
||||
StringValue(const std::string& str);
|
||||
EResult Parse(const std::string& str) noexcept override;
|
||||
EResult ToString(std::string& destination) const noexcept override;
|
||||
const std::string& GetValue() const noexcept;
|
||||
};
|
||||
|
||||
class IntValue : public Value
|
||||
{
|
||||
private:
|
||||
int64_t m_value = 0;
|
||||
|
||||
public:
|
||||
IntValue() = default;
|
||||
IntValue(int64_t value);
|
||||
EResult Parse(const std::string& str) noexcept override;
|
||||
EResult ToString(std::string& destination) const noexcept override;
|
||||
int64_t GetValue() const noexcept;
|
||||
};
|
||||
|
||||
class Section
|
||||
{
|
||||
private:
|
||||
std::unordered_map<std::string, Value*> m_values;
|
||||
std::unordered_map<std::string, Section*> m_subSections;
|
||||
|
||||
public:
|
||||
Section() = default;
|
||||
~Section();
|
||||
Section(const Section&) = delete;
|
||||
Section& operator=(const Section&) = delete;
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
EResult GetValue(T** target, const std::string& key) noexcept
|
||||
{
|
||||
auto it = m_values.find(key);
|
||||
if (it == m_values.end())
|
||||
return EResult::KeyNotPresent;
|
||||
|
||||
auto val = dynamic_cast<T*>(it->second);
|
||||
if (val == nullptr)
|
||||
return EResult::InvalidDataType;
|
||||
|
||||
*target = val;
|
||||
return EResult::Success;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
EResult SetValue(const std::string& name, const T& value, bool allowOverwrite = false) noexcept
|
||||
{
|
||||
if (m_values.find(name) != m_values.end())
|
||||
if (!allowOverwrite)
|
||||
return EResult::KeyAlreadyPresent;
|
||||
else
|
||||
delete m_values[name];
|
||||
|
||||
m_values[name] = new T(value);
|
||||
return EResult::Success;
|
||||
}
|
||||
|
||||
public:
|
||||
Section* GetSubSection(const std::string& key, EResult* result = nullptr) const noexcept;
|
||||
Section* SetSubSection(const std::string& name, std::unique_ptr<Section> value, bool allowOverwrite = false, EResult* result = nullptr) noexcept;
|
||||
};
|
||||
|
||||
public:
|
||||
MiniPPFile() = default;
|
||||
|
||||
private:
|
||||
Section m_rootSection{};
|
||||
|
||||
public:
|
||||
EResult Parse(const std::string& path) noexcept;
|
||||
void Write(const std::string& path) noexcept;
|
||||
|
||||
public:
|
||||
const Section& GetRoot() const noexcept { return m_rootSection; }
|
||||
Section& GetRoot() noexcept { return m_rootSection; }
|
||||
};
|
||||
}
|
||||
22
minipp/test.cpp
Normal file
22
minipp/test.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "minipp/minipp.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
minipp::MiniPPFile file;
|
||||
auto result = file.Parse("test.mini");
|
||||
|
||||
auto& section = file.GetRoot();
|
||||
|
||||
minipp::MiniPPFile::Section* profileSection = section.GetSubSection("profile", &result);
|
||||
|
||||
minipp::MiniPPFile::IntValue* value;
|
||||
auto result1 = profileSection->GetValue(&value, "window_width");
|
||||
|
||||
auto result2 = value->GetValue();
|
||||
|
||||
auto marianProfile = section.GetSubSection("profile.marian", &result);
|
||||
minipp::MiniPPFile::StringValue* dockOutlinerType;
|
||||
marianProfile->GetValue(&dockOutlinerType, "dock_outliner");
|
||||
|
||||
return 0;
|
||||
}
|
||||
10
minipp/test.mini
Normal file
10
minipp/test.mini
Normal file
@@ -0,0 +1,10 @@
|
||||
[profile]
|
||||
dock_outliner="left"
|
||||
window_width=1000000b
|
||||
window_height=fh
|
||||
|
||||
[profile.marian]
|
||||
dock_outliner="ri\\ght\\"
|
||||
|
||||
[profile.toyb]
|
||||
dock_outliner="top"
|
||||
Reference in New Issue
Block a user