Config: Add case-insensitive ini file parser
This commit is contained in:
		
							parent
							
								
									b8c3e74275
								
							
						
					
					
						commit
						eb037a3779
					
				
					 5 changed files with 183 additions and 17 deletions
				
			
		| 
						 | 
				
			
			@ -110,6 +110,7 @@ set(MAIN_HEADERS
 | 
			
		|||
	src/flashable.h
 | 
			
		||||
	src/font.h
 | 
			
		||||
	src/input.h
 | 
			
		||||
	src/iniconfig.h
 | 
			
		||||
	src/plane.h
 | 
			
		||||
	src/scene.h
 | 
			
		||||
	src/sprite.h
 | 
			
		||||
| 
						 | 
				
			
			@ -167,6 +168,7 @@ set(MAIN_SOURCE
 | 
			
		|||
	src/filesystem.cpp
 | 
			
		||||
	src/font.cpp
 | 
			
		||||
	src/input.cpp
 | 
			
		||||
	src/iniconfig.cpp
 | 
			
		||||
	src/plane.cpp
 | 
			
		||||
	src/scene.cpp
 | 
			
		||||
	src/sprite.cpp
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								mkxp.pro
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								mkxp.pro
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -89,6 +89,7 @@ HEADERS += \
 | 
			
		|||
	src/flashable.h \
 | 
			
		||||
	src/font.h \
 | 
			
		||||
	src/input.h \
 | 
			
		||||
	src/iniconfig.h \
 | 
			
		||||
	src/plane.h \
 | 
			
		||||
	src/scene.h \
 | 
			
		||||
	src/sprite.h \
 | 
			
		||||
| 
						 | 
				
			
			@ -145,6 +146,7 @@ SOURCES += \
 | 
			
		|||
	src/filesystem.cpp \
 | 
			
		||||
	src/font.cpp \
 | 
			
		||||
	src/input.cpp \
 | 
			
		||||
	src/iniconfig.cpp \
 | 
			
		||||
	src/plane.cpp \
 | 
			
		||||
	src/scene.cpp \
 | 
			
		||||
	src/sprite.cpp \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,6 +33,7 @@
 | 
			
		|||
#include "debugwriter.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
#include "sdl-util.h"
 | 
			
		||||
#include "iniconfig.h"
 | 
			
		||||
 | 
			
		||||
#ifdef INI_ENCODING
 | 
			
		||||
extern "C" {
 | 
			
		||||
| 
						 | 
				
			
			@ -357,26 +358,32 @@ void Config::readGameINI()
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	po::options_description podesc;
 | 
			
		||||
	podesc.add_options()
 | 
			
		||||
	        ("Game.Title", po::value<std::string>())
 | 
			
		||||
	        ("Game.Scripts", po::value<std::string>())
 | 
			
		||||
	        ;
 | 
			
		||||
 | 
			
		||||
	po::variables_map vm;
 | 
			
		||||
	std::string iniFilename = execName + ".ini";
 | 
			
		||||
	SDLRWStream iniFile(iniFilename.c_str(), "r");
 | 
			
		||||
 | 
			
		||||
	if (iniFile)
 | 
			
		||||
	{
 | 
			
		||||
		try
 | 
			
		||||
		INIConfiguration ic;
 | 
			
		||||
		if(ic.load(iniFile.stream()))
 | 
			
		||||
		{
 | 
			
		||||
			po::store(po::parse_config_file(iniFile.stream(), podesc, true), vm);
 | 
			
		||||
			po::notify(vm);
 | 
			
		||||
			GUARD_ALL( game.title = ic.getStringProperty("Game", "Title"); );
 | 
			
		||||
			GUARD_ALL( game.scripts = ic.getStringProperty("Game", "Scripts"); );
 | 
			
		||||
 | 
			
		||||
			strReplace(game.scripts, '\\', '/');
 | 
			
		||||
 | 
			
		||||
			if (game.title.empty())
 | 
			
		||||
			{
 | 
			
		||||
				Debug() << iniFilename + ": Could not find Game.Title property";
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (game.scripts.empty())
 | 
			
		||||
			{
 | 
			
		||||
				Debug() << iniFilename + ": Could not find Game.Scripts property";
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		catch (po::error &error)
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			Debug() << iniFilename + ":" << error.what();
 | 
			
		||||
			Debug() << iniFilename + ": Failed to parse ini file";
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
| 
						 | 
				
			
			@ -384,11 +391,6 @@ void Config::readGameINI()
 | 
			
		|||
		Debug() << "FAILED to open" << iniFilename;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	GUARD_ALL( game.title = vm["Game.Title"].as<std::string>(); );
 | 
			
		||||
	GUARD_ALL( game.scripts = vm["Game.Scripts"].as<std::string>(); );
 | 
			
		||||
 | 
			
		||||
	strReplace(game.scripts, '\\', '/');
 | 
			
		||||
 | 
			
		||||
#ifdef INI_ENCODING
 | 
			
		||||
	/* Can add more later */
 | 
			
		||||
	const char *languages[] =
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										114
									
								
								src/iniconfig.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/iniconfig.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,114 @@
 | 
			
		|||
#include "iniconfig.h"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
 | 
			
		||||
std::string toLowerCase(const std::string& str)
 | 
			
		||||
{
 | 
			
		||||
	std::string lower = str;
 | 
			
		||||
	std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
 | 
			
		||||
	return lower;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
std::string trim(const std::string& str, const std::string& chars = "\t\n\v\f\r ")
 | 
			
		||||
{
 | 
			
		||||
	std::string trimmed = str;
 | 
			
		||||
	trimmed.erase(trimmed.find_last_not_of(chars) + 1);
 | 
			
		||||
	trimmed.erase(0, trimmed.find_first_not_of(chars));
 | 
			
		||||
	return trimmed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
INIConfiguration::Section::Section (const std::string& sname) : m_Name (sname), m_PropertyMap()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool INIConfiguration::Section::getStringProperty (const std::string& name, std::string& outPropStr) const
 | 
			
		||||
{
 | 
			
		||||
	try
 | 
			
		||||
	{
 | 
			
		||||
		outPropStr = m_PropertyMap.at(toLowerCase(name)).m_Value;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	catch (std::out_of_range& oorexcept)
 | 
			
		||||
	{
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool INIConfiguration::load (std::istream& is)
 | 
			
		||||
{
 | 
			
		||||
	if (!is.good())
 | 
			
		||||
	{
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::string currSectionName;
 | 
			
		||||
 | 
			
		||||
	std::string line;
 | 
			
		||||
	std::getline (is, line);
 | 
			
		||||
 | 
			
		||||
	while (!is.eof() && !is.bad())
 | 
			
		||||
	{
 | 
			
		||||
		if (line[0] == '[')
 | 
			
		||||
		{
 | 
			
		||||
			currSectionName = line.substr (1, line.find_last_of (']') - 1);
 | 
			
		||||
		}
 | 
			
		||||
		else if (line[0] != '#' && line.length() > 2)
 | 
			
		||||
		{
 | 
			
		||||
			int crloc = line.length() - 1;
 | 
			
		||||
 | 
			
		||||
			if (crloc >= 0  && line[crloc] == '\r') //check for Windows-style newline
 | 
			
		||||
				line.resize (crloc);                //and correct
 | 
			
		||||
 | 
			
		||||
			size_t equalsPos = line.find_first_of ("=");
 | 
			
		||||
 | 
			
		||||
			if (equalsPos != std::string::npos)
 | 
			
		||||
			{
 | 
			
		||||
				std::string key = line.substr (0, equalsPos);
 | 
			
		||||
				std::string val = line.substr (equalsPos + 1);
 | 
			
		||||
 | 
			
		||||
				addProperty (currSectionName, key , val);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		std::getline (is, line);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (is.bad())
 | 
			
		||||
	{
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
std::string INIConfiguration::getStringProperty(const std::string& sname, const std::string& name, const std::string& def) const
 | 
			
		||||
{
 | 
			
		||||
	auto sectionIt = m_SectionMap.find(toLowerCase(sname));
 | 
			
		||||
 | 
			
		||||
	if (sectionIt != m_SectionMap.end())
 | 
			
		||||
	{
 | 
			
		||||
		std::string prop;
 | 
			
		||||
 | 
			
		||||
		if(sectionIt->second.getStringProperty(name, prop))
 | 
			
		||||
		{
 | 
			
		||||
			return prop;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return def;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void INIConfiguration::addProperty (const std::string& sname, const std::string& name, const std::string& val)
 | 
			
		||||
{
 | 
			
		||||
	if (m_SectionMap.find (toLowerCase(sname)) == m_SectionMap.end())
 | 
			
		||||
	{
 | 
			
		||||
		m_SectionMap.emplace (toLowerCase(sname), Section (sname));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Section::Property p;
 | 
			
		||||
	p.m_Name = trim(name);
 | 
			
		||||
	p.m_Value = trim(val);
 | 
			
		||||
 | 
			
		||||
	m_SectionMap.at (toLowerCase(sname)).m_PropertyMap[toLowerCase(p.m_Name)] = p;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								src/iniconfig.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/iniconfig.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
#ifndef INICONFIG_H
 | 
			
		||||
#define INICONFIG_H
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <map>
 | 
			
		||||
 | 
			
		||||
class INIConfiguration
 | 
			
		||||
{
 | 
			
		||||
	class Section
 | 
			
		||||
	{
 | 
			
		||||
		friend class INIConfiguration;
 | 
			
		||||
 | 
			
		||||
		struct Property
 | 
			
		||||
		{
 | 
			
		||||
			std::string m_Name;
 | 
			
		||||
			std::string m_Value;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		typedef std::map<std::string, Property> property_map;
 | 
			
		||||
	public:
 | 
			
		||||
		Section (const Section& s) = default;
 | 
			
		||||
		Section (Section&& s) = default;
 | 
			
		||||
 | 
			
		||||
		bool getStringProperty (const std::string& name, std::string& outPropStr) const;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		explicit Section (const std::string& name);
 | 
			
		||||
 | 
			
		||||
		std::string m_Name;
 | 
			
		||||
		property_map m_PropertyMap;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	typedef std::map<std::string, Section> section_map;
 | 
			
		||||
public:
 | 
			
		||||
	bool load (std::istream& inStream);
 | 
			
		||||
 | 
			
		||||
	std::string getStringProperty(const std::string& sname, const std::string& name, const std::string& def = "") const;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	void addProperty (const std::string& sname, const std::string& name, const std::string& val);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	section_map m_SectionMap;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // INICONFIG_H
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue