C/C++ 解析ini檔案
阿新 • • 發佈:2018-12-25
C/C++ 解析ini檔案
c++版本
/*
* inicpp.h
*
* Created on: 26 Dec 2015
* Author: Fabian Meyer
* License: MIT
*/
#ifndef INICPP_H_
#define INICPP_H_
#include <algorithm>
#include <fstream>
#include <istream>
#include <map>
#include <sstream>
#include <stdexcept>
namespace ini
{
class IniField
{
private:
std::string value_;
public:
IniField() : value_()
{}
IniField(const std::string &value) : value_(value)
{}
IniField(const IniField &field) : value_(field.value_)
{}
~IniField()
{}
template <typename T>
T as() const
{
return static_cast<T>(*this);
}
/**********************************************************************
* Assignment Operators
*********************************************************************/
IniField &operator =(const char *value)
{
value_ = std::string(value);
return *this;
}
IniField &operator=(const std::string &value)
{
value_ = value;
return *this;
}
IniField &operator=(const IniField &field)
{
value_ = field.value_;
return *this;
}
IniField &operator=(const int value)
{
std::stringstream ss;
ss << value;
value_ = ss.str();
return *this;
}
IniField &operator=(const unsigned int value)
{
std::stringstream ss;
ss << value;
value_ = ss.str();
return *this;
}
IniField &operator=(const double value)
{
std::stringstream ss;
ss << value;
value_ = ss.str();
return *this;
}
IniField &operator=(const float value)
{
std::stringstream ss;
ss << value;
value_ = ss.str();
return *this;
}
IniField &operator=(const bool value)
{
if(value)
value_ = "true";
else
value_ = "false";
return *this;
}
/**********************************************************************
* Cast Operators
*********************************************************************/
explicit operator const char *() const
{
return value_.c_str();
}
explicit operator std::string() const
{
return value_;
}
explicit operator int() const
{
char *endptr;
// check if decimal
int result = std::strtol(value_.c_str(), &endptr, 10);
if(*endptr == '\0')
return result;
// check if octal
result = std::strtol(value_.c_str(), &endptr, 8);
if(*endptr == '\0')
return result;
// check if hex
result = std::strtol(value_.c_str(), &endptr, 16);
if(*endptr == '\0')
return result;
throw std::invalid_argument("field is not an int");
}
explicit operator unsigned int() const
{
char *endptr;
// check if decimal
int result = std::strtoul(value_.c_str(), &endptr, 10);
if(*endptr == '\0')
return result;
// check if octal
result = std::strtoul(value_.c_str(), &endptr, 8);
if(*endptr == '\0')
return result;
// check if hex
result = std::strtoul(value_.c_str(), &endptr, 16);
if(*endptr == '\0')
return result;
throw std::invalid_argument("field is not an unsigned int");
}
explicit operator float() const
{
return std::stof(value_);
}
explicit operator double() const
{
return std::stod(value_);
}
explicit operator bool() const
{
std::string str(value_);
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
if(str == "TRUE")
return true;
else if(str == "FALSE")
return false;
else
throw std::invalid_argument("field is not a bool");
}
};
class IniSection : public std::map<std::string, IniField>
{
public:
IniSection()
{}
~IniSection()
{}
};
class IniFile : public std::map<std::string, IniSection>
{
private:
char fieldSep_;
char comment_;
public:
IniFile() : IniFile('=', '#')
{}
IniFile(const char fieldSep, const char comment)
: fieldSep_(fieldSep), comment_(comment)
{}
IniFile(const std::string &filename,
const char fieldSep = '=',
const char comment = '#')
: IniFile(fieldSep, comment)
{
load(filename);
}
IniFile(std::istream &is,
const char fieldSep = '=',
const char comment = '#')
: IniFile(fieldSep, comment)
{
decode(is);
}
~IniFile()
{}
void setFieldSep(const char sep)
{
fieldSep_ = sep;
}
void setCommentChar(const char comment)
{
comment_ = comment;
}
void decode(std::istream &is)
{
clear();
int lineNo = 0;
IniSection *currentSection = NULL;
// iterate file by line
while(!is.eof() && !is.fail())
{
std::string line;
std::getline(is, line, '\n');
++lineNo;
// skip if line is empty
if(line.size() == 0)
continue;
// skip if line is a comment
if(line[0] == comment_)
continue;
if(line[0] == '[')
{
// line is a section
// check if the section is also closed on same line
std::size_t pos = line.find("]");
if(pos == std::string::npos)
{
std::stringstream ss;
ss << "l" << lineNo
<< ": ini parsing failed, section not closed";
throw std::logic_error(ss.str());
}
// check if the section name is empty
if(pos == 1)
{
std::stringstream ss;
ss << "l" << lineNo
<< ": ini parsing failed, section is empty";
throw std::logic_error(ss.str());
}
// check if there is a newline following closing bracket
if(pos + 1 != line.length())
{
std::stringstream ss;
ss << "l" << lineNo
<< ": ini parsing failed, no end of line after "
"section";
throw std::logic_error(ss.str());
}
// retrieve section name
std::string secName = line.substr(1, pos - 1);
currentSection = &((*this)[secName]);
}
else
{
// line is a field definition
// check if section was already opened
if(currentSection == NULL)
{
std::stringstream ss;
ss << "l" << lineNo
<< ": ini parsing failed, field has no section";
throw std::logic_error(ss.str());
}
// find key value separator
std::size_t pos = line.find(fieldSep_);
if(pos == std::string::npos)
{
std::stringstream ss;
ss << "l" << lineNo
<< ": ini parsing failed, no '=' found";
throw std::logic_error(ss.str());
}
// retrieve field name and value
std::string name = line.substr(0, pos);
std::string value = line.substr(pos + 1, std::string::npos);
(*currentSection)[name] = value;
}
}
}
void decode(const std::string &content)
{
std::istringstream ss(content);
decode(ss);
}
void load(const std::string &fileName)
{
std::ifstream is(fileName.c_str());
decode(is);
}
void encode(std::ostream &os) const
{
// iterate through all sections in this file
for(const auto &filePair : *this)
{
os << "[" << filePair.first << "]" << std::endl;
// iterate through all fields in the section
for(const auto &secPair : filePair.second)
os << secPair.first << fieldSep_
<< secPair.second.as<std::string>() << std::endl;
}
}
std::string encode() const
{
std::ostringstream ss;
encode(ss);
return ss.str();
}
void save(const std::string &fileName) const
{
std::ofstream os(fileName.c_str());
encode(os);
}
};
}
#endif
#include "inicpp.h"
void main()
{
#if 1//read
ini::IniFile myIni;
myIni.load("sysconfig.ini");
float min = myIni["Frequecy"]["min"].as<float>();
float max = myIni["Frequecy"]["max"].as<float>();
float def = myIni["Frequecy"]["default"].as<float>();
float step = myIni["Frequecy"]["step"].as<float>();
std::string unit = myIni["Frequecy"]["unit"].as<std::string>();
qDebug() << "******************";
qDebug() << "min:"<<min;
qDebug() << "max:"<<max;
qDebug() << "def:"<<def;
qDebug() << "step:"<<step;
//qDebug() << unit;
#endif
#if 1//write
ini::IniFile sysIni;
sysIni["Frequecy"]["min"] = 1.0;
sysIni["Frequecy"]["max"] = 18.0;
sysIni["Frequecy"]["default"] = 1.0;
sysIni["Frequecy"]["step"] = 0.5;
sysIni["Frequecy"]["unit"] = "MHz";
sysIni.save("sysconfig.ini");
#endif
}