hikyuu2/hikyuu_cpp/hikyuu_utils/iniparser/IniParser.cpp

391 lines
13 KiB
C++
Raw Normal View History

2015-01-07 01:26:14 +08:00
/*
* IniFile.cpp
*
* Created on: 2010-5-19
* Author: fasiondog
*/
#include <iostream>
#include <sstream>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include "IniParser.h"
namespace hku {
//用于记录分析文件时的格式错误信息(行号、错误的行内容)
//仅限IniParser内部使用
class ParsingError {
public:
ParsingError() { m_haveError = false; }
void append(size_t lineno, const std::string& line);
bool haveError() { return m_haveError; }
std::string str() { return m_info.str(); }
private:
std::stringstream m_info;
bool m_haveError;
};
void ParsingError::append(size_t lineno, const std::string& line) {
m_info << "\n\t[line " << lineno << "] " << line;
if (!m_haveError) {
m_haveError = true;
}
}
IniParser::IniParser() {
}
IniParser::~IniParser() {
}
/**
* ini文件
* @details ini文件后
* @throw std::invalid_argument
* @throw std::logic_error
* @param filename
*/
void IniParser::read(const std::string& filename) throw(std::invalid_argument, std::logic_error) {
std::ifstream inifile(filename.c_str(), std::ifstream::in);
if (!inifile) {
throw(std::invalid_argument("Can't read file(" + filename + ")!"));
}
size_t line_no = 0; //当前行号,用于记录错误信息
ParsingError parsing_error; //记录格式分析错误
std::string section;
std::string key;
std::string value;
std::string line_str;
while (std::getline(inifile, line_str)) {
line_no++;
boost::trim(line_str);
//空行或注释行,跳过
if (line_str.empty() || line_str.at(0) == ';') {
continue;
}
//检查第一个出现的注释符,并将其及其之后的字符清除
size_t pos = line_str.find(';');
if (pos != std::string::npos) {
line_str.assign(line_str, 0, pos);
boost::trim(line_str);
}
//section行
if (line_str.at(0) == '[') {
size_t len = line_str.size();
if(line_str[len-1] != ']') {
parsing_error.append(line_no, line_str);
continue;
}
section.assign(line_str, 1, len-2);
boost::trim(section);
if(section.empty()) {
parsing_error.append(line_no, line_str);
continue;
}
m_sections[section];
}else {
if (section.empty()) {
parsing_error.append(line_no, "Missing section header!");
break; //缺少section定义后续无须处理直接跳出循环
}
pos = line_str.find('=');
if(pos == std::string::npos || pos == line_str.size()-1){
parsing_error.append(line_no, line_str);
continue;
}
key.assign(line_str, 0, pos);
boost::trim(key);
if (key.empty()) {
parsing_error.append(line_no, line_str);
continue;
}
value.assign(line_str, pos+1, std::string::npos);
boost::trim(value);
if (value.empty()) {
parsing_error.append(line_no, line_str);
continue;
}
m_sections[section][key] = value;
}
}
if (parsing_error.haveError()){
inifile.close();
throw(std::logic_error(parsing_error.str()));
}
inifile.close();
}
/**
*
*/
void IniParser::clear() {
m_sections.clear();
}
/**
* section是否存在
*/
bool IniParser::hasSection(const std::string& section) const {
return m_sections.count(section) ? true : false;
}
/**
* option是否存在
*/
bool IniParser::hasOption(const std::string& section, const std::string& option) const {
if(m_sections.count(section) == 0) {
return false;
}
//if(m_sections[section].count(option) == 0) {
if(m_sections.find(section)->second.count(option) == 0) {
return false;
}
return true;
}
/**
* secton
* @return section列表
*/
IniParser::StringListPtr IniParser::getSectionList() const {
StringListPtr result(new std::list<std::string>);
section_map_type::const_iterator iter = m_sections.begin();
for (; iter != m_sections.end(); ++iter) {
result->push_back(iter->first);
}
return result;
}
/**
* Section下的所有option
* @throw section不存在std::invalid_argument异常
* @param section section
* @return section下所有option列表
*/
IniParser::StringListPtr IniParser::getOptionList(const std::string& section) const {
if (m_sections.count(section) == 0) {
throw(std::invalid_argument("No section: " + section));
}
StringListPtr result(new std::list<std::string>);
item_map_type option_map = m_sections.find(section)->second;
item_map_type::const_iterator iter = option_map.begin();
for (; iter != option_map.end(); ++iter) {
result->push_back(iter->first);
}
return result;
}
/**
* option值
* @throw std::invalid_argument option不存在对应值
* @param section section
* @param option option
* @param default_str option值时option值
* std::invalid_argument异常
*/
std::string IniParser::get(const std::string& section, const std::string& option,
const std::string& default_str) const
throw(std::invalid_argument) {
std::string result;
if (m_sections.count(section) == 0) {
throw(std::invalid_argument("No section: " + section));
}
if (m_sections.find(section)->second.count(option) == 0) {
if(default_str.empty()) {
throw(std::invalid_argument("No option(" + option + ") in section(" + section + ")"));
}else {
result.assign(default_str);
boost::trim(result);
}
}else {
result.assign(m_sections.find(section)->second.find(option)->second);
}
return result;
}
/**
* option值int类型
* @throw std::invalid_argument option不存在对应值;
* int类型时option值是否存在都将抛出该异常
* @throw std::domain_error option值int类型时
* @param section section
* @param option option
* @param default_str option值时
*
*/
int IniParser::getInt(const std::string& section, const std::string& option,
const std::string& default_str) const {
int result;
//先检查default_str是否可以转换为int
if (!default_str.empty()) {
try{
result = boost::lexical_cast<int>(default_str);
}catch(boost::bad_lexical_cast&){
throw(std::invalid_argument("Invalid default value: " + default_str));
}
}
std::string value_str = get(section, option, default_str);
try{
result = boost::lexical_cast<int>(value_str);
}catch(boost::bad_lexical_cast& e) {
throw(std::domain_error(e.what()));
}
return result;
}
/**
* option值float类型
* @throw std::invalid_argument option不存在对应值;
* float类型时option值是否存在都将抛出该异常
* @throw std::domain_error option值float类型时
* @param section section
* @param option option
* @param default_str option值时
*
*/
float IniParser::getFloat(const std::string& section, const std::string& option,
const std::string& default_str) const {
float result;
//先检查default_str是否可以转换为float
if (!default_str.empty()) {
try{
result = boost::lexical_cast<float>(default_str);
}catch(boost::bad_lexical_cast&){
throw(std::invalid_argument("Invalid default value: " + default_str));
}
}
std::string value_str = get(section, option, default_str);
try{
result = boost::lexical_cast<float>(value_str);
}catch(boost::bad_lexical_cast& e) {
throw(std::domain_error(e.what()));
}
return result;
}
/**
* option值double类型
* @throw std::invalid_argument option不存在对应值;
* double类型时option值是否存在都将抛出该异常
* @throw std::domain_error option值double类型时
* @param section section
* @param option option
* @param default_str option值时
*
*/
double IniParser::getDouble(const std::string& section, const std::string& option,
const std::string& default_str) const {
double result;
//先检查default_str是否可以转换为float
if (!default_str.empty()) {
try{
result = boost::lexical_cast<double>(default_str);
}catch(boost::bad_lexical_cast&){
throw(std::invalid_argument("Invalid default value: " + default_str));
}
}
std::string value_str = get(section, option, default_str);
try{
result = boost::lexical_cast<double>(value_str);
}catch(boost::bad_lexical_cast& e) {
throw(std::domain_error(e.what()));
}
return result;
}
/**
* option值bool类型
* @details option表示为true时1|true|yes|on \n
* option表示为false时0|false|no|off
* @throw std::invalid_argument option不存在对应值;
* bool类型时option值是否存在都将抛出该异常
* @throw std::domain_error option值bool类型时
* @param section section
* @param option option
* @param default_str option值时
*
*/
bool IniParser::getBool(const std::string& section, const std::string& option,
const std::string& default_str) const {
//先检查default_str是否可以转换为bool
std::string new_default_str(default_str);
if (!default_str.empty()) {
if (new_default_str != "1" && new_default_str != "0") {
boost::to_upper(new_default_str);
if (new_default_str == "TRUE" || new_default_str == "YES" || new_default_str == "ON") {
new_default_str.assign("1");
}else if (new_default_str == "FALSE" || new_default_str == "NO" || new_default_str == "OFF") {
new_default_str.assign("0");
}else {
throw(std::invalid_argument("Invalid default value: " + default_str));
}
}
}
std::string value_str = get(section, option, new_default_str);
if(value_str == "1") {
return true;
}
if(value_str == "0") {
return false;
}
boost::to_upper(value_str);
if(value_str == "TRUE" || value_str == "YES" || value_str == "ON") {
return true;
}
if(value_str == "FALSE" || value_str == "NO" || value_str == "OFF") {
return false;
}
throw(std::domain_error(value_str + " can not be translated to bool!"));
}
} /* namespace */