diff --git a/Makefile b/Makefile
index bc32c18..a1a1d21 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-# This Makefile was generated using MakeGen v1.1.8 made by Tim Håkansson
+# This Makefile was generated using MakeGen v1.3.0 made by Tim Håkansson
# and is licensed under MIT. Full source of the project can be found at
# https://github.com/Thraix/MakeGen
CC=@g++
@@ -7,8 +7,8 @@ MKDIR_P=mkdir -p
BIN=bin/
OBJPATH=$(BIN)intermediates
INCLUDES=
-OBJECTS=$(OBJPATH)/ConfigCLI.o $(OBJPATH)/ConfigFile.o $(OBJPATH)/HFileGen.o $(OBJPATH)/IncludeDeps.o $(OBJPATH)/Makefile.o $(OBJPATH)/Utils.o $(OBJPATH)/main.o
-CFLAGS=$(INCLUDES) -std=c++17 -c -w -g3 -D_DEBUG
+OBJECTS=$(OBJPATH)/ConfigCLI.o $(OBJPATH)/ConfigFile.o $(OBJPATH)/HFileGen.o $(OBJPATH)/IncludeDeps.o $(OBJPATH)/Makefile.o $(OBJPATH)/Utils.o $(OBJPATH)/ConfigFileConf.o $(OBJPATH)/main.o $(OBJPATH)/XML.o $(OBJPATH)/XMLObject.o
+CFLAGS=$(INCLUDES) -std=c++17 -c -w -g3
LIBDIR=
LDFLAGS=
LIBS=$(LIBDIR)
@@ -33,24 +33,33 @@ $(OUTPUT): $(OBJECTS)
install: all
$(info Installing MakeGen to /usr/bin/)
@cp $(OUTPUT) /usr/bin/makegen
-$(OBJPATH)/ConfigCLI.o : src/ConfigCLI.cpp src/Common.h src/ConfigCLI.h src/ConfigFile.h
- $(info -[14%]- $<)
+$(OBJPATH)/ConfigCLI.o : src/ConfigCLI.cpp src/Common.h src/ConfigCLI.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h
+ $(info -[10%]- $<)
$(CC) $(CFLAGS) -o $@ $<
-$(OBJPATH)/ConfigFile.o : src/ConfigFile.cpp src/ConfigFile.h src/FileUtils.h src/Common.h src/Utils.h
- $(info -[28%]- $<)
+$(OBJPATH)/ConfigFile.o : src/ConfigFile.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h src/compatibility/ConfigFileConf.h src/xml/XML.h
+ $(info -[20%]- $<)
$(CC) $(CFLAGS) -o $@ $<
-$(OBJPATH)/HFileGen.o : src/HFileGen.cpp src/FileUtils.h src/Common.h src/Utils.h src/ConfigFile.h src/HFileGen.h
- $(info -[42%]- $<)
+$(OBJPATH)/HFileGen.o : src/HFileGen.cpp src/FileUtils.h src/Common.h src/Utils.h src/HFileGen.h src/ConfigFile.h src/ConfigUtils.h src/xml/XMLObject.h
+ $(info -[30%]- $<)
$(CC) $(CFLAGS) -o $@ $<
-$(OBJPATH)/IncludeDeps.o : src/IncludeDeps.cpp src/Common.h src/IncludeDeps.h src/ConfigFile.h src/FileUtils.h src/Utils.h
- $(info -[57%]- $<)
+$(OBJPATH)/IncludeDeps.o : src/IncludeDeps.cpp src/Common.h src/IncludeDeps.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h
+ $(info -[40%]- $<)
$(CC) $(CFLAGS) -o $@ $<
-$(OBJPATH)/Makefile.o : src/Makefile.cpp src/IncludeDeps.h src/ConfigFile.h src/FileUtils.h src/Common.h src/Utils.h src/Makefile.h
- $(info -[71%]- $<)
+$(OBJPATH)/Makefile.o : src/Makefile.cpp src/IncludeDeps.h src/ConfigFile.h src/ConfigUtils.h src/Common.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h src/Makefile.h
+ $(info -[50%]- $<)
$(CC) $(CFLAGS) -o $@ $<
-$(OBJPATH)/Utils.o : src/Utils.cpp src/FileUtils.h src/Common.h src/Utils.h src/ConfigFile.h
- $(info -[85%]- $<)
+$(OBJPATH)/Utils.o : src/Utils.cpp src/ConfigFile.h src/ConfigUtils.h src/Common.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h
+ $(info -[60%]- $<)
$(CC) $(CFLAGS) -o $@ $<
-$(OBJPATH)/main.o : src/main.cpp src/Common.h src/ConfigCLI.h src/ConfigFile.h src/FileUtils.h src/Utils.h src/HFileGen.h src/Makefile.h src/Timer.h
+$(OBJPATH)/ConfigFileConf.o : src/compatibility/ConfigFileConf.cpp src/compatibility/ConfigFileConf.h
+ $(info -[70%]- $<)
+ $(CC) $(CFLAGS) -o $@ $<
+$(OBJPATH)/main.o : src/main.cpp src/Common.h src/ConfigCLI.h src/ConfigFile.h src/ConfigUtils.h src/FileUtils.h src/Utils.h src/xml/XMLObject.h src/HFileGen.h src/Makefile.h src/Timer.h
+ $(info -[80%]- $<)
+ $(CC) $(CFLAGS) -o $@ $<
+$(OBJPATH)/XML.o : src/xml/XML.cpp src/xml/XML.h src/xml/XMLObject.h src/xml/XMLException.h
+ $(info -[90%]- $<)
+ $(CC) $(CFLAGS) -o $@ $<
+$(OBJPATH)/XMLObject.o : src/xml/XMLObject.cpp src/xml/XMLException.h src/xml/XMLObject.h
$(info -[100%]- $<)
$(CC) $(CFLAGS) -o $@ $<
diff --git a/makegen.conf b/makegen.conf
deleted file mode 100644
index e445d05..0000000
--- a/makegen.conf
+++ /dev/null
@@ -1,19 +0,0 @@
-#libs
-#libdirs
-#includedirs
-#defines
-_DEBUG
-#compileflags
-#dependencies
-#srcdir
-src/
-#outputdir
-bin/
-#projectname
-MakeGen
-#outputname
-makegen
-#executable
-true
-#generatehfile
-false
diff --git a/makegen.xml b/makegen.xml
new file mode 100644
index 0000000..c1f7e8d
--- /dev/null
+++ b/makegen.xml
@@ -0,0 +1,22 @@
+
+
+ false
+ MakeGen.h
+ bin/
+ makegen
+ executable
+ MakeGen
+ src/
+
+
+ _DEBUG
+ false
+ MakeGen.h
+ bin/
+ makegen
+ executable
+ MakeGen
+ src/
+
+ v1.3.0
+
diff --git a/src/Common.h b/src/Common.h
index 84cf89b..5a91d5e 100755
--- a/src/Common.h
+++ b/src/Common.h
@@ -9,10 +9,10 @@
// Major changes, might not be backwards compatible
#define MAKEGEN_VERSION_MAJOR 1
-// Release, should be backwards compatible
-#define MAKEGEN_VERSION_RELEASE 2
+// Release, should be backwards compatible with any minor version
+#define MAKEGEN_VERSION_RELEASE 3
// Minor changes, generally bug fixes
-#define MAKEGEN_VERSION_MINOR 1
+#define MAKEGEN_VERSION_MINOR 0
#define MAKEGEN_VERSION ("v" STR(MAKEGEN_VERSION_MAJOR) "." STR(MAKEGEN_VERSION_RELEASE) "." STR(MAKEGEN_VERSION_MINOR))
@@ -29,9 +29,9 @@ const static unsigned int FLAG_SIMPLE = BIT(9);
const static unsigned int FLAG_CONFIG = BIT(10);
-#define LOG_INFO(...) Log(__VA_ARGS__); std::cout << std::endl
-#define LOG_WARNING(...) Log(__VA_ARGS__); std::cout << std::endl
-#define LOG_ERROR(...) Log(__VA_ARGS__); std::cout << std::endl
+#define LOG_INFO(...) LogHelper(__VA_ARGS__)
+#define LOG_WARNING(...) LogHelper(__VA_ARGS__)
+#define LOG_ERROR(...) LogHelper(__VA_ARGS__)
template
void Log(const T& var)
@@ -45,3 +45,18 @@ void Log(const T& var, const Ts& ...vars)
Log(var);
Log(vars...);
}
+
+template
+void LogHelper(const T& var)
+{
+ Log(var);
+ std::cout << std::endl;
+}
+
+template
+void LogHelper(const T& var, const Ts& ...vars)
+{
+ Log(var);
+ Log(vars...);
+ std::cout << std::endl;
+}
diff --git a/src/ConfigCLI.cpp b/src/ConfigCLI.cpp
index b188905..2114971 100644
--- a/src/ConfigCLI.cpp
+++ b/src/ConfigCLI.cpp
@@ -8,7 +8,7 @@
void ConfigCLI::DisplayCLIHelp()
{
LOG_INFO(1+(char*)R"(
-MakeGen conf is used to create, modify and query the makegen.conf file.
+MakeGen conf is used to create, modify and query the makegen.xml file.
Usage: makegen conf [] [--help]
@@ -49,7 +49,7 @@ Usage: makegen conf add []
Valid settings are:
library Library
- libdir Library directory
+ librarydir Library directory
includedir Include directory
define Preprocessor define
cflag g++ compiler flags
@@ -65,7 +65,7 @@ Usage: makegen conf remove [<
Valid settings are
library Library name
- libdir Library directory
+ librarydir Library directory
includedir Include directory
define Preprocessor define
cflag g++ compiler flags
@@ -81,13 +81,13 @@ Usage: makegen conf set
Valid string settings are:
outputdir Directory of the compiled output
- output Name of the output executable/library
- name Name of the project
+ outputname Name of the output executable/library
+ projectname Name of the project
+ outputtype Type of the output, valid values are executable, sharedlibrary
+ and staticlibrary
hfile Name of the generated project h-file
Valid boolean settings are:
- executable Specifies if the project be compiled as executable or library
- shared Specifies if the library should be compiled as shared.
genhfile Specifies if MakeGen should generate a project h-file
Boolean values can be set to either true/t/yes/y or false/f/no/n)");
@@ -102,50 +102,42 @@ Usage: makegen conf get
Valid settings are:
library Library name
- libdir Library directory
+ librarydir Library directory
includedir Include directory
define Preprocessor define
cflag g++ compiler flags
dependency Project which current project depends on
outputdir Directory of the compiled output
- output Name of the output executable/library
- name Name of the project
+ outputname Name of the output executable/library
+ outputtype Type of the output, valid values are executable, sharedlibrary
+ and staticlibrary
+ projectname Name of the project
hfile Name of the generated project h-file
- executable Specifies if the project be compiled as executable or library
- shared Specifies if the library should be compiled as shared.
genhfile Specifies if MakeGen should generate a project h-file)");
}
-std::map*> ConfigCLI::GetSettingVectorMap(ConfigFile& config)
-{
- return {
- {"library",&config.libs},
- {"libdir",&config.libdirs},
- {"includedir",&config.includedirs},
- {"define",&config.defines},
- {"cflag",&config.flags},
- {"dependency",&config.dependencies}
- };
-}
-
-std::map ConfigCLI::GetSettingStringMap(ConfigFile& config)
+ConfigSetting ConfigCLI::CLIStringToSetting(const std::string& s)
{
- return {
- {"outputdir", &config.outputdir},
- {"output", &config.outputname},
- {"name", &config.projectname},
- {"hfile", &config.hFile},
- };
-}
-
-std::map ConfigCLI::GetSettingBoolMap(ConfigFile& config)
-{
- return {
- {"executable", &config.executable},
- {"shared", &config.shared},
- {"genhfile", &config.generateHFile}
+ static std::map map{
+ {"srcdir", ConfigSetting::SourceDir},
+ {"outputdir", ConfigSetting::OutputDir},
+ {"outputname", ConfigSetting::OutputName},
+ {"outputtype", ConfigSetting::OutputType},
+ {"projectname", ConfigSetting::ProjectName},
+ {"hfile", ConfigSetting::HFileName},
+ {"library", ConfigSetting::Library},
+ {"librarydir", ConfigSetting::LibraryDir},
+ {"includedir", ConfigSetting::IncludeDir},
+ {"define", ConfigSetting::Define},
+ {"cflag", ConfigSetting::CFlag},
+ {"dependency", ConfigSetting::Dependency},
+ {"genhfile", ConfigSetting::GenerateHFile},
};
+ auto it = map.find(s);
+ if(it == map.end())
+ return ConfigSetting::Invalid;
+ return it->second;
}
int ConfigCLI::Gen(int argc, char** argv)
@@ -168,7 +160,7 @@ int ConfigCLI::Gen(int argc, char** argv)
}
if(option == "default")
{
- ConfigFile{}.Save();
+ ConfigFile{FileUtils::GetRealPath("."),0}.Save();
return 0;
}
else
@@ -191,25 +183,24 @@ int ConfigCLI::Add(int argc, char** argv, ConfigFile& config)
return 1;
}
- auto settingMap = GetSettingVectorMap(config);
- auto it = settingMap.find(argv[1]);
- if(it == settingMap.end())
+ ConfigSetting setting = CLIStringToSetting(argv[1]);
+ if(!ConfigUtils::IsVectorSetting(setting))
{
- LOG_ERROR("Invalid setting: ", argv[1]);
+ if(setting == ConfigSetting::Invalid)
+ {
+ LOG_ERROR("No such setting: ", argv[1]);
+ }
+ else
+ {
+ LOG_ERROR("Cannot remove setting which only supports one argument");
+ LOG_ERROR("use set instead.");
+ }
return 1;
}
-
- std::vector* setting = it->second;
- std::set settingSet{setting->begin(), setting->end()};
for(int i = 2; i* setting = it->second;
- std::set settingSet{setting->begin(), setting->end()};
for(int i = 2; isecond) = true;
- else if(b == "false" || b == "f" || b == "no" || b == "n")
- *it2->second = false;
else
{
- LOG_ERROR("Invalid boolean value: ", argv[2]);
- return 1;
+ LOG_ERROR("Cannot set setting which supports multiple arguments");
+ LOG_ERROR("use add or remove instead.");
}
- config.Save();
- return 0;
+ return 1;
}
- *it1->second = argv[2];
+
+ config.SetSettingString(setting, argv[2]);
config.Save();
return 0;
}
@@ -308,29 +288,9 @@ int ConfigCLI::Get(int argc, char** argv, ConfigFile& config)
LOG_ERROR("get needs exactly one parameter");
return 1;
}
- auto settingVectorMap = GetSettingVectorMap(config);
- auto itV = settingVectorMap.find(argv[1]);
- if(itV == settingVectorMap.end())
- {
- auto settingStringMap = GetSettingStringMap(config);
- auto itS = settingStringMap.find(argv[1]);
- if(itS == settingStringMap.end())
- {
- auto settingBoolMap = GetSettingBoolMap(config);
- auto itB = settingBoolMap.find(argv[1]);
- if(itB == settingBoolMap.end())
- {
- LOG_ERROR("Invalid setting: ", argv[1]);
- return 1;
- }
- bool* t = itB->second;
- LOG_INFO(*itB->second ? "true" : "false");
- return 0;
- }
- LOG_INFO(*itS->second);
- return 0;
- }
- for(auto it = itV->second->begin(); it != itV->second->end(); ++it)
+ ConfigSetting setting = CLIStringToSetting(argv[1]);
+ std::vector vector = config.GetSetting(setting);
+ for(auto it = vector.begin(); it != vector.end(); ++it)
{
LOG_INFO(*it);
}
@@ -351,7 +311,7 @@ int ConfigCLI::Main(int argc, char** argv)
{
if(config)
{
- LOG_ERROR("Config file already exist (makegen.conf)");
+ LOG_ERROR("Config file already exist (", CONFIG_FILENAME, ")");
return 1;
}
return Gen(argc-1, &argv[1]);
diff --git a/src/ConfigCLI.h b/src/ConfigCLI.h
index 88335a1..4335ae6 100644
--- a/src/ConfigCLI.h
+++ b/src/ConfigCLI.h
@@ -14,9 +14,7 @@ struct ConfigCLI
static void DisplaySetHelp();
static void DisplayGetHelp();
- static std::map*> GetSettingVectorMap(ConfigFile& config);
- static std::map GetSettingStringMap(ConfigFile& config);
- static std::map GetSettingBoolMap(ConfigFile& config);
+ static ConfigSetting CLIStringToSetting(const std::string& s);
static int Gen(int argc, char** argv);
static int Add(int argc, char** argv, ConfigFile& config);
diff --git a/src/ConfigFile.cpp b/src/ConfigFile.cpp
index dbdf676..2b2ae32 100755
--- a/src/ConfigFile.cpp
+++ b/src/ConfigFile.cpp
@@ -1,43 +1,327 @@
#include "ConfigFile.h"
#include "FileUtils.h"
+#include "compatibility/ConfigFileConf.h"
+#include "xml/XML.h"
#include
#include
-#define FLAG_NONE 0
-#define FLAG_VECTOR 1
-#define FLAG_STRING 2
-#define FLAG_BOOL 3
-
-ConfigFile::ConfigFile()
- : outputdir("bin/"), srcdir("src/"), outputname(""), projectname(FileUtils::GetCurrentDirectory()), hFile(""), executable(true), shared(true), generateHFile(false)
+ConfigFile::ConfigFile(const std::string& path, int)
+ : configPath{path}
{
// Converts project name (current directory) to lowercase
// and replace whitespace with underscore
- std::transform(
- projectname.begin(),
- projectname.end(),
- std::back_inserter(outputname),
- [](unsigned char c)
- {
- if(c == ' ')
- return '_';
- return (char)std::tolower(c);
- });
+ // Create xml
+ XMLObject makegen("makegen", {}, std::map>{});
- // Removes all other characters
- auto it = std::remove_if(
- outputname.begin(),
- outputname.end(),
- [](unsigned char c)
- {
- return (c < '0' || c > '9') && (c < 'a' || c > 'z') && c != '_';
- });
- outputname.erase(it, outputname.end());
+ // Version, target and configuration is probably going to be used in the future
+ makegen.AddXMLObject(XMLObject("version", {}, "v1.3.0"));
+ makegen.AddXMLObject(XMLObject("target", {}, "Release"));
- // Add suffix
- outputname += ".out";
+ XMLObject configuration("configuration", {{"name", "Release"}}, std::map>{});
+ configuration.AddXMLObject(XMLObject("projectname", {}, ConfigUtils::GetDefaultProjectName(configPath)));
+ configuration.AddXMLObject(XMLObject("outputname", {}, ConfigUtils::GetDefaultOutputName(configPath)));
+ configuration.AddXMLObject(XMLObject("srcdir", {}, "src/"));
+ configuration.AddXMLObject(XMLObject("outputdir", {}, "bin/"));
+ configuration.AddXMLObject(XMLObject("hfilename", {}, ConfigUtils::GetDefaultHFileName(configPath)));
+ configuration.AddXMLObject(XMLObject("outputtype", {}, "executable"));
+ configuration.AddXMLObject(XMLObject("generatehfile", {}, "false"));
+
+ makegen.AddXMLObject(configuration);
+ config = makegen;
+ Init();
+}
+
+ConfigFile::ConfigFile(const std::string& path)
+ : config{XML::FromFile(path + CONFIG_FILENAME)}, configPath{path}
+{
+ Init();
+}
+
+ConfigFile::ConfigFile(XMLObject& config, const std::string& path)
+ : config{config}, configPath{path}
+{
+ Init();
+}
+
+void ConfigFile::Init()
+{
+ const std::vector* targetXml = config.GetObjectPtr("target");
+ target = "Release";
+ if(!targetXml || targetXml->size() == 0)
+ {
+ LOG_ERROR("No target found in config file. Using target=", target);
+ return;
+ }
+
+ if(targetXml->size() > 1)
+ LOG_ERROR("To many targets in config file. Using target=", (*targetXml)[0].GetText());
+ if(targetXml->size() > 0)
+ target = (*targetXml)[0].GetText();
+}
+
+std::string& ConfigFile::GetSettingString(ConfigSetting setting)
+{
+ // Adding it to the cache since we need to return a reference
+ if(!ConfigUtils::IsStringSetting(setting))
+ {
+ LOG_ERROR("Invalid string setting");
+ return cache.strings.emplace("invalid", "").first->second;
+ }
+
+ std::string sSetting = ConfigUtils::GetSettingName(setting);
+ auto it = cache.strings.find(sSetting);
+ if(it != cache.strings.end())
+ return it->second;
+
+ const std::vector* values = GetConfiguration().GetObjectPtr(sSetting);
+
+ // No value found, using default
+ if(values == nullptr)
+ return cache.strings.emplace(sSetting, ConfigUtils::GetDefaultSettingString(setting, configPath)).first->second;
+
+ if(values->size() != 1)
+ {
+ LOG_ERROR("To many arguments for setting using first: ", (int)setting, "=", (*values)[0].GetText());
+ }
+ std::string s = (*values)[0].GetText();
+ if(ConfigUtils::IsDirectory(setting) && s[s.size()-1] != '/')
+ s += '/';
+ return cache.strings.emplace(sSetting, s).first->second;
+}
+
+bool ConfigFile::GetSettingBool(ConfigSetting setting)
+{
+ if(setting == ConfigSetting::Invalid)
+ {
+ LOG_ERROR("Invalid config setting");
+ return false;
+ }
+ std::string sSetting = ConfigUtils::GetSettingName(setting);
+ auto it = cache.bools.find(sSetting);
+ if(it != cache.bools.end())
+ return it->second;
+
+ const std::vector* values = GetConfiguration().GetObjectPtr(sSetting);//,
+
+ if(values == nullptr)
+ return cache.bools.emplace(sSetting, ConfigUtils::GetDefaultSettingBool(setting)).first->second;
+
+ if(values->size() != 1)
+ {
+ LOG_ERROR("To many arguments for setting using first: ", (int)setting, "=", (*values)[0].GetText());
+ }
+ return cache.bools.emplace(sSetting, (*values)[0].GetText() == "true").first->second;
+}
+
+std::vector& ConfigFile::GetSettingVectorString(ConfigSetting setting)
+{
+ std::string sSetting = ConfigUtils::GetSettingName(setting);
+ auto it = cache.vecStrings.find(sSetting);
+ if(it != cache.vecStrings.end())
+ return it->second;
+
+ const std::vector* values = GetConfiguration().GetObjectPtr(sSetting);
+ if(values == nullptr)
+ return cache.vecStrings.emplace(sSetting, std::vector{}).first->second;
+
+ std::vector strings;
+ strings.reserve(values->size());
+ for(auto it = values->begin(); it != values->end(); ++it)
+ {
+ if(it->GetText() == "")
+ continue;
+ std::string s = it->GetText();
+ if(ConfigUtils::IsDirectory(setting) && s[s.size()-1] != '/')
+ s += '/';
+ strings.push_back(s);
+ }
+
+ return cache.vecStrings.emplace(sSetting, strings).first->second;
+}
+
+std::vector ConfigFile::GetSetting(ConfigSetting setting)
+{
+ if(ConfigUtils::IsStringSetting(setting))
+ return {GetSettingString(setting)};
+ else if(ConfigUtils::IsVectorSetting(setting))
+ return GetSettingVectorString(setting);
+ else if(ConfigUtils::IsBoolSetting(setting))
+ return {GetSettingBool(setting) ? "true" : "false"};
+ else
+ {
+ LOG_ERROR("Invalid config setting");
+ return {};
+ }
+}
+
+bool ConfigFile::SetSettingString(ConfigSetting setting, const std::string& value)
+{
+ // Check if valid enum
+ std::string s = value;
+ std::string sSetting = ConfigUtils::GetSettingName(setting);
+ if(ConfigUtils::IsStringSetting(setting))
+ {
+ if(ConfigUtils::IsDirectory(setting) && s[s.size()-1] != '/')
+ {
+ s += '/';
+ }
+ auto it = cache.strings.find(sSetting);
+ // Update cache
+ if(it != cache.strings.end())
+ it->second = s;
+ else
+ cache.strings.emplace(sSetting, s);
+ }
+ else if(ConfigUtils::IsBoolSetting(setting))
+ {
+ if(s == "true" || s == "t" || s == "yes" || s == "y")
+ s = "true";
+ else if(s == "false" || s == "f" || s == "no" || s == "n")
+ s = "false";
+ else
+ {
+ LOG_ERROR("Invalid boolean value: ", s);
+ return false;
+ }
+
+ auto it = cache.bools.find(sSetting);
+ // Update cache
+ if(it != cache.bools.end())
+ it->second = s == "true";
+ else
+ cache.bools.emplace(sSetting, value == "true");
+ }
+ else
+ {
+ LOG_ERROR("Not a string setting");
+ return false;
+ }
+
+ XMLObject& configuration = GetConfiguration();
+ std::vector* values = configuration.GetObjectPtr(sSetting);
+ if(values == nullptr)
+ configuration.AddXMLObject({sSetting, {}, s});
+ else if(values->size() > 1)
+ LOG_ERROR("Multiple values of setting, changing first: ", sSetting, "=", s);
+ else
+ (*values)[0].SetText(s);
+ return true;
+}
+
+bool ConfigFile::AddSettingVectorString(ConfigSetting setting, const std::string& value)
+{
+ // Check if valid enum
+ if(ConfigUtils::IsVectorSetting(setting))
+ {
+ std::string s = value;
+ if(ConfigUtils::IsDirectory(setting) && s[s.size()-1] != '/')
+ {
+ s += '/';
+ }
+ std::string sSetting = ConfigUtils::GetSettingName(setting);
+ auto it = cache.vecStrings.find(sSetting);
+
+ // Update cache
+ if(it != cache.vecStrings.end())
+ it->second.push_back(s);
+ else
+ cache.vecStrings.emplace(sSetting, std::vector{s});
+
+ GetConfiguration().AddXMLObject({sSetting, {}, s});
+ }
+ else
+ {
+ LOG_ERROR("Not a vector setting");
+ return false;
+ }
+ return true;
+}
+
+bool ConfigFile::RemoveSettingVectorString(ConfigSetting setting, const std::string& value)
+{
+ // Check if valid enum
+ if(ConfigUtils::IsVectorSetting(setting))
+ {
+ std::string s = value;
+ if(ConfigUtils::IsDirectory(setting) && s[s.size()-1] != '/')
+ {
+ s += '/';
+ }
+ std::string sSetting = ConfigUtils::GetSettingName(setting);
+
+ auto it = cache.vecStrings.find(sSetting);
+ if(it != cache.vecStrings.end())
+ {
+ // Update cache
+ for(auto itVec = it->second.begin(); itVec != it->second.end(); ++itVec)
+ {
+ if(*itVec == s)
+ {
+ it->second.erase(itVec);
+ }
+ }
+ }
+
+ std::vector* values = GetConfiguration().GetObjectPtr(sSetting);
+ bool found = false;
+ for(auto it = values->begin(); it != values->end();++it)
+ {
+ if(it->GetText() == s)
+ {
+ values->erase(it);
+ found = true;
+ break;
+ }
+ }
+ if(!found)
+ {
+ LOG_ERROR("Couldn't find value: ", s);
+ return false;
+ }
+ }
+ else
+ {
+ LOG_ERROR("Not a vector setting");
+ return false;
+ }
+ return false;
+}
+
+XMLObject& ConfigFile::GetConfiguration()
+{
+ std::vector* configurations = config.GetObjectPtr("configuration");
+ if(configurations == nullptr || configurations->size() == 0)
+ {
+ LOG_ERROR("No configuration in makegen.xml");
+ assert(false);
+ }
+ for(auto it = configurations->begin(); it != configurations->end(); ++it)
+ {
+ if(!it->HasAttribute("name"))
+ {
+ LOG_ERROR("No name attribute in configuration tag");
+ continue;
+ }
+ if(it->GetAttribute("name") == target)
+ {
+ return *it;
+ }
+ }
+
+ LOG_ERROR("Couldn\'t find given target in config file. Using target=", (*configurations)[0].HasAttribute("name") ? (*configurations)[0].GetAttribute("name") : "");
+ return (*configurations)[0];
+}
+
+const std::string& ConfigFile::GetConfigPath() const
+{
+ return configPath;;
+}
+
+ConfigFile& ConfigFile::GetDependencyConfig(size_t i)
+{
+ return dependencyConfigs[i];
}
std::optional ConfigFile::GetConfigFile(const std::string& filepath)
@@ -55,27 +339,39 @@ std::optional ConfigFile::GetConfigFile(const std::string& filepath,
return {};
}
+ bool oldFile = false;
std::ifstream f(filepath + CONFIG_FILENAME);
+ if(!f.good())
+ {
+ ConfigFileConf::CreateXMLFile(realPath);
+ // try to read an old config file
+ f.close();
+ f = std::ifstream(filepath + CONFIG_FILENAME);
+ }
+
// Check if the file exists
if(f.good())
{
f.close();
- ConfigFile conf = ConfigFile::Load(realPath);
+ ConfigFile conf = ConfigFile(filepath);
+ if(conf.hasInitError)
+ return {};
loadedConfigs.emplace(realPath, conf);
+ std::vector& dependencies = conf.GetSettingVectorString(ConfigSetting::Dependency);
// Create dependency config files.
- for(size_t i = 0; i < conf.dependencies.size();++i)
+ for(size_t i = 0; i < dependencies.size();++i)
{
- std::optional dep = GetConfigFile(conf.configPath + conf.dependencies[i], loadedConfigs);
+ std::optional dep = GetConfigFile(conf.configPath + dependencies[i], loadedConfigs);
if(dep)
{
conf.dependencyConfigs.push_back(*dep);
- conf.dependencies[i] = dep->configPath;
+ dependencies[i] = dep->configPath;
}
else
{
// Remove the dependency since it is already accounted for
- conf.dependencies.erase(conf.dependencies.begin() + i);
+ dependencies.erase(dependencies.begin() + i);
--i;
}
}
@@ -84,124 +380,6 @@ std::optional ConfigFile::GetConfigFile(const std::string& filepath,
return {};
}
-
-ConfigFile ConfigFile::Load(const std::string& filepath)
-{
- ConfigFile conf;
- conf.configPath = filepath;
- unsigned int loadFlag = 0;
-
- std::vector* vec;
- std::string* s;
- bool* b;
-
- bool isDirectory = false;
-
- std::ifstream file(filepath+CONFIG_FILENAME);
- std::string line;
-
- if(file.is_open())
- {
- // config name, { pointer to memory, isDirectory}
- std::map> strings =
- {
- {"#srcdir", {&conf.srcdir, true}},
- {"#outputdir", {&conf.outputdir, true}},
- {"#outputname", {&conf.outputname, false}},
- {"#projectname", {&conf.projectname, false}},
- {"#hfile", {&conf.hFile, false}},
- };
-
- // config name, { pointer to memory, isDirectory}
- std::map*, bool>> vectors =
- {
- {"#libs", {&conf.libs, false}},
- {"#libdirs", {&conf.libdirs, true}},
- {"#includedirs", {&conf.includedirs, true}},
- {"#compileflags", {&conf.flags, false}},
- {"#defines", {&conf.defines, false}},
- {"#dependencies", {&conf.dependencies, true}},
- };
-
- std::map booleans =
- {
- {"#executable", &conf.executable},
- {"#shared", &conf.shared},
- {"#generatehfile", &conf.generateHFile},
- };
-
- while(std::getline(file,line))
- {
- if(line == "")
- continue;
- if(line[0]=='#')
- {
- // The format is a bit wacky, but it is this way since we do not want
- // to use map::find for all maps. This way we gain some optimization.
- auto&& itStr{strings.find(line)};
- if(itStr != strings.end())
- {
- s = itStr->second.first;
- isDirectory = itStr->second.second;
- loadFlag = FLAG_STRING;
- }
- else
- {
- auto&& itVec{vectors.find(line)};
- if(itVec != vectors.end())
- {
- vec = itVec->second.first;
- isDirectory = itVec->second.second;
- loadFlag = FLAG_VECTOR;
- }
- else
- {
- auto&& itBool{booleans.find(line)};
- if(itBool != booleans.end())
- {
- b = itBool->second;
- loadFlag = FLAG_BOOL;
- }
- else
- {
- LOG_ERROR("Invalid flag: ", line);
- loadFlag = FLAG_NONE;
- }
- }
- }
- }
- else
- {
- if(loadFlag == FLAG_STRING)
- {
- if(isDirectory && line[line.size()-1] != '/')
- line += '/';
- *s = line;
- }
- else if(loadFlag == FLAG_VECTOR)
- {
- if(isDirectory && line[line.size()-1] != '/')
- {;
- line += '/';
- }
- vec->push_back(line);
- }
- else if(loadFlag == FLAG_BOOL)
- {
- if(line == "true")
- *b = true;
- else
- *b = false;
- }
- }
- }
- }
- if(conf.hFile == "")
- conf.hFile = conf.projectname+".h";
-
- return conf;
-}
-
void ConfigFile::InputBoolean(const std::string& inputText, bool& b)
{
std::string input;
@@ -248,90 +426,74 @@ void ConfigFile::InputMultiple(const std::string& inputText, std::vector libs, libdirs, includedirs, defines, compileFlags, dependencies;
+ std::string srcdir, outputdir, projectname, outputname, hFile;
+
+ InputBoolean("Should it be compiled as an executable? (y/n)", executable);
// If it isn't an executable there is not need to have libraries
- if(conf.executable)
+ if(executable)
{
- InputMultiple("Enter library:", conf.libs,false);
- InputMultiple("Enter library directory:", conf.libdirs,true);
- InputMultiple("Enter project dependencies:", conf.dependencies,true);
+ InputMultiple("Enter library:", libs,false);
+ InputMultiple("Enter library directory:", libdirs,true);
+ InputMultiple("Enter project dependencies:", dependencies,true);
}
else
{
- InputBoolean("Should it be compiled as a shared library? (y/n)", conf.shared);
- InputBoolean("Should it compile a project h-file? (y/n):", conf.generateHFile);
- if(conf.generateHFile)
+ InputBoolean("Should it be compiled as a shared library? (y/n)", shared);
+ InputBoolean("Should it compile a project h-file? (y/n):", generateHFile);
+ if(generateHFile)
{
- InputString("Enter the project h-file name (relative to source directory): ", conf.hFile, false, false);
+ InputString("Enter the project h-file name (relative to source directory): ", hFile, false, false);
}
}
- InputMultiple("Enter include directory:", conf.includedirs, true);
- InputString("Enter source directories:", conf.srcdir, true, false);
- InputMultiple("Enter preprocessor definitions:", conf.defines, false);
- InputMultiple("Enter compile flags:", conf.flags, false);
- InputString("Enter output directory (default: bin):", conf.outputdir, true, true);
- if(conf.outputdir == "")
- conf.outputdir = "bin/";
- InputString("Enter a name for the project:", conf.projectname, false, false);
- InputString("Enter a name for the output file:", conf.outputname, false, false);
- return conf;
+ InputMultiple("Enter include directory:", includedirs, true);
+ InputString("Enter source directories:", srcdir, true, false);
+ InputMultiple("Enter preprocessor definitions:", defines, false);
+ InputMultiple("Enter compile flags:", compileFlags, false);
+ InputString("Enter output directory (default: bin):", outputdir, true, true);
+ if(outputdir == "")
+ outputdir = "bin/";
+ InputString("Enter a name for the project:", projectname, false, false);
+ InputString("Enter a name for the output file:", outputname, false, false);
+
+
+ // Create xml
+ XMLObject makegen("makegen", {}, std::map>{});
+
+ // Version, target and configuration is probably going to be used in the future
+ makegen.AddXMLObject(XMLObject("version", {}, "v1.3.0"));
+ makegen.AddXMLObject(XMLObject("target", {}, "Release"));
+
+ XMLObject configuration("configuration", {{"name", "Release"}}, std::map>{});
+ configuration.AddXMLObject(XMLObject("projectname", {}, projectname));
+ configuration.AddXMLObject(XMLObject("outputname", {}, outputname));
+ configuration.AddXMLObject(XMLObject("srcdir", {}, srcdir));
+ configuration.AddXMLObject(XMLObject("outputdir", {}, outputdir));
+ configuration.AddXMLObject(XMLObject("hfilename", {}, hFile));
+ configuration.AddXMLObject(XMLObject("outputtype", {},
+ executable ? "executable" : (shared ? "sharedlibrary" : "staticlibrary")));
+ configuration.AddXMLObject(XMLObject("generatehfile", {}, generateHFile ? "true" : "false"));
+
+ for(auto it = libs.begin();it != libs.end(); ++it)
+ configuration.AddXMLObject({"library",{},*it});
+ for(auto it = libdirs.begin();it != libdirs.end(); ++it)
+ configuration.AddXMLObject({"librarydir",{},*it});
+ for(auto it = includedirs.begin();it != includedirs.end(); ++it)
+ configuration.AddXMLObject({"includedir",{},*it});
+ for(auto it = defines.begin();it != defines.end(); ++it)
+ configuration.AddXMLObject({"define",{},*it});
+ for(auto it = compileFlags.begin();it != compileFlags.end(); ++it)
+ configuration.AddXMLObject({"cflag",{},*it});
+ for(auto it = dependencies.begin();it != dependencies.end(); ++it)
+ configuration.AddXMLObject({"dependency",{},*it});
+
+ makegen.AddXMLObject(configuration);
+ return ConfigFile{makegen, FileUtils::GetRealPath("./")};
}
void ConfigFile::Save() const
{
- std::ofstream file("makegen.conf");
- file << "#libs" << std::endl;
- for(auto it = libs.begin();it!=libs.end();++it)
- {
- file << *it << std::endl;
- }
- file << "#libdirs" << std::endl;
- for(auto it = libdirs.begin();it!=libdirs.end();++it)
- {
- file << *it << std::endl;
- }
- file << "#includedirs" << std::endl;
- for(auto it = includedirs.begin();it!=includedirs.end();++it)
- {
- file << *it << std::endl;
- }
- file << "#defines" << std::endl;
- for(auto it = defines.begin();it!=defines.end();++it)
- {
- file << *it << std::endl;
- }
- file << "#compileflags" << std::endl;
- for(auto it = flags.begin();it!=flags.end();++it)
- {
- file << *it << std::endl;
- }
- file << "#dependencies" << std::endl;
- for(auto it = dependencies.begin();it!=dependencies.end();++it)
- {
- file << *it << std::endl;
- }
- file << "#srcdir" << std::endl;
- file << srcdir << std::endl;
- file << "#outputdir" << std::endl;
- file << outputdir << std::endl;
- file << "#projectname" << std::endl;
- file << projectname << std::endl;
- file << "#outputname" << std::endl;
- file << outputname << std::endl;
- file << "#executable" << std::endl;
- file << (executable ? "true" : "false") << std::endl;
- file << "#generatehfile" << std::endl;
- file << (generateHFile ? "true" : "false") << std::endl;
- if(generateHFile)
- {
- file << "#hfile" << std::endl;
- file << hFile << std::endl;
- }
- if(!executable)
- {
- file << "#shared" << std::endl;
- file << (shared ? "true" : "false") << std::endl;
- }
- file.close();
+ std::ofstream file("makegen.xml");
+ file << config;
}
diff --git a/src/ConfigFile.h b/src/ConfigFile.h
index 3d9b36b..e058497 100755
--- a/src/ConfigFile.h
+++ b/src/ConfigFile.h
@@ -1,40 +1,58 @@
#pragma once
+#include "ConfigUtils.h"
+#include "xml/XMLObject.h"
+
#include