hikyuu2/hikyuu_cpp/hikyuu/utilities/IniParser.cpp

388 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>
2019-12-31 23:18:30 +08:00
#include "arithmetic.h"
2015-01-07 01:26:14 +08:00
#include "IniParser.h"
namespace hku {
//用于记录分析文件时的格式错误信息(行号、错误的行内容)
//仅限IniParser内部使用
class ParsingError {
public:
2019-11-10 19:45:57 +08:00
ParsingError() {
m_haveError = false;
}
2015-01-07 01:26:14 +08:00
void append(size_t lineno, const std::string& line);
2019-11-10 19:45:57 +08:00
bool haveError() {
return m_haveError;
}
std::string str() {
return m_info.str();
}
2015-01-07 01:26:14 +08:00
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;
}
}
2019-11-10 19:45:57 +08:00
IniParser::IniParser() {}
2015-01-07 01:26:14 +08:00
2019-11-10 19:45:57 +08:00
IniParser::~IniParser() {}
2015-01-07 01:26:14 +08:00
/**
* ini文件
* @details ini文件后
* @throw std::invalid_argument
* @throw std::logic_error
* @param filename
*/
void IniParser::read(const std::string& filename) {
2015-01-07 01:26:14 +08:00
std::ifstream inifile(filename.c_str(), std::ifstream::in);
if (!inifile) {
throw(std::invalid_argument("Can't read file(" + filename + ")!"));
}
2019-11-10 19:45:57 +08:00
size_t line_no = 0; //当前行号,用于记录错误信息
2015-01-07 01:26:14 +08:00
ParsingError parsing_error; //记录格式分析错误
std::string section;
std::string key;
std::string value;
std::string line_str;
while (std::getline(inifile, line_str)) {
line_no++;
2019-12-31 23:18:30 +08:00
trim(line_str);
2015-01-07 01:26:14 +08:00
//空行或注释行,跳过
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);
2019-12-31 23:18:30 +08:00
trim(line_str);
2015-01-07 01:26:14 +08:00
}
2019-11-10 19:45:57 +08:00
// section行
2015-01-07 01:26:14 +08:00
if (line_str.at(0) == '[') {
size_t len = line_str.size();
2019-11-10 19:45:57 +08:00
if (line_str[len - 1] != ']') {
2015-01-07 01:26:14 +08:00
parsing_error.append(line_no, line_str);
continue;
}
2019-11-10 19:45:57 +08:00
section.assign(line_str, 1, len - 2);
2019-12-31 23:18:30 +08:00
trim(section);
2019-11-10 19:45:57 +08:00
if (section.empty()) {
2015-01-07 01:26:14 +08:00
parsing_error.append(line_no, line_str);
continue;
}
m_sections[section];
2019-11-10 19:45:57 +08:00
} else {
2015-01-07 01:26:14 +08:00
if (section.empty()) {
parsing_error.append(line_no, "Missing section header!");
break; //缺少section定义后续无须处理直接跳出循环
}
pos = line_str.find('=');
2019-11-10 19:45:57 +08:00
if (pos == std::string::npos || pos == line_str.size() - 1) {
2015-01-07 01:26:14 +08:00
parsing_error.append(line_no, line_str);
continue;
}
key.assign(line_str, 0, pos);
2019-12-31 23:18:30 +08:00
trim(key);
2015-01-07 01:26:14 +08:00
if (key.empty()) {
parsing_error.append(line_no, line_str);
continue;
}
2019-11-10 19:45:57 +08:00
value.assign(line_str, pos + 1, std::string::npos);
2019-12-31 23:18:30 +08:00
trim(value);
2015-01-07 01:26:14 +08:00
if (value.empty()) {
parsing_error.append(line_no, line_str);
continue;
}
m_sections[section][key] = value;
}
}
2019-11-10 19:45:57 +08:00
if (parsing_error.haveError()) {
2015-01-07 01:26:14 +08:00
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 {
2019-11-10 19:45:57 +08:00
if (m_sections.count(section) == 0) {
2015-01-07 01:26:14 +08:00
return false;
}
2019-11-10 19:45:57 +08:00
// if(m_sections[section].count(option) == 0) {
if (m_sections.find(section)->second.count(option) == 0) {
2015-01-07 01:26:14 +08:00
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
2019-11-10 19:45:57 +08:00
* @param default_str
* option值时option值
2015-01-07 01:26:14 +08:00
* std::invalid_argument异常
*/
std::string IniParser::get(const std::string& section, const std::string& option,
const std::string& default_str) const {
2015-01-07 01:26:14 +08:00
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) {
2019-11-10 19:45:57 +08:00
if (default_str.empty()) {
2015-01-07 01:26:14 +08:00
throw(std::invalid_argument("No option(" + option + ") in section(" + section + ")"));
2019-11-10 19:45:57 +08:00
} else {
2015-01-07 01:26:14 +08:00
result.assign(default_str);
2019-12-31 23:18:30 +08:00
trim(result);
2015-01-07 01:26:14 +08:00
}
2019-11-10 19:45:57 +08:00
} else {
2015-01-07 01:26:14 +08:00
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值时
*
*/
2020-06-27 19:04:15 +08:00
int IniParser::getInt(const std::string& section, const std::string& option,
const std::string& default_str) const {
2019-12-31 23:18:30 +08:00
int result = 0;
size_t remain = 0;
2015-01-07 01:26:14 +08:00
//先检查default_str是否可以转换为int
if (!default_str.empty()) {
2019-12-31 23:18:30 +08:00
result = std::stoi(default_str, &remain);
if (remain != default_str.size()) {
2015-01-07 01:26:14 +08:00
throw(std::invalid_argument("Invalid default value: " + default_str));
}
}
std::string value_str = get(section, option, default_str);
2019-12-31 23:18:30 +08:00
remain = 0;
2020-11-01 14:01:08 +08:00
result = std::stoi(value_str, &remain); // cppcheck-suppress redundantAssignment
2020-06-27 19:04:15 +08:00
if (remain != value_str.size()) {
2019-12-31 23:18:30 +08:00
throw(std::invalid_argument("This option cannot be converted to an integer! " + value_str));
2015-01-07 01:26:14 +08:00
}
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值时
*
*/
2020-06-27 19:04:15 +08:00
float IniParser::getFloat(const std::string& section, const std::string& option,
const std::string& default_str) const {
2015-01-07 01:26:14 +08:00
float result;
2019-12-31 23:18:30 +08:00
size_t remain = 0;
2015-01-07 01:26:14 +08:00
//先检查default_str是否可以转换为float
if (!default_str.empty()) {
2019-12-31 23:18:30 +08:00
result = std::stof(default_str, &remain);
if (remain != default_str.size()) {
2015-01-07 01:26:14 +08:00
throw(std::invalid_argument("Invalid default value: " + default_str));
}
}
std::string value_str = get(section, option, default_str);
2019-12-31 23:18:30 +08:00
remain = 0;
2020-11-01 14:01:08 +08:00
result = std::stof(value_str, &remain); // cppcheck-suppress redundantAssignment
2019-12-31 23:18:30 +08:00
if (remain != value_str.size()) {
throw(std::invalid_argument("This option cannot be converted to an float! " + value_str));
2015-01-07 01:26:14 +08:00
}
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,
2019-11-10 19:45:57 +08:00
const std::string& default_str) const {
2015-01-07 01:26:14 +08:00
double result;
2019-12-31 23:18:30 +08:00
size_t remain = 0;
2015-01-07 01:26:14 +08:00
//先检查default_str是否可以转换为float
if (!default_str.empty()) {
2019-12-31 23:18:30 +08:00
result = std::stod(default_str, &remain);
if (remain != default_str.size()) {
2015-01-07 01:26:14 +08:00
throw(std::invalid_argument("Invalid default value: " + default_str));
}
}
std::string value_str = get(section, option, default_str);
2019-12-31 23:18:30 +08:00
remain = 0;
2020-11-01 14:01:08 +08:00
result = std::stod(value_str, &remain); // cppcheck-suppress redundantAssignment
2019-12-31 23:18:30 +08:00
if (remain != value_str.size()) {
throw(std::invalid_argument("This option cannot be converted to an double! " + value_str));
2015-01-07 01:26:14 +08:00
}
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值时
*
*/
2020-06-27 19:04:15 +08:00
bool IniParser::getBool(const std::string& section, const std::string& option,
const std::string& default_str) const {
2015-01-07 01:26:14 +08:00
//先检查default_str是否可以转换为bool
std::string new_default_str(default_str);
if (!default_str.empty()) {
if (new_default_str != "1" && new_default_str != "0") {
2019-12-31 23:18:30 +08:00
to_upper(new_default_str);
2015-01-07 01:26:14 +08:00
if (new_default_str == "TRUE" || new_default_str == "YES" || new_default_str == "ON") {
new_default_str.assign("1");
2020-06-27 19:04:15 +08:00
} else if (new_default_str == "FALSE" || new_default_str == "NO" ||
new_default_str == "OFF") {
2015-01-07 01:26:14 +08:00
new_default_str.assign("0");
2019-11-10 19:45:57 +08:00
} else {
2015-01-07 01:26:14 +08:00
throw(std::invalid_argument("Invalid default value: " + default_str));
}
}
}
std::string value_str = get(section, option, new_default_str);
2019-11-10 19:45:57 +08:00
if (value_str == "1") {
2015-01-07 01:26:14 +08:00
return true;
}
2019-11-10 19:45:57 +08:00
if (value_str == "0") {
2015-01-07 01:26:14 +08:00
return false;
}
2019-12-31 23:18:30 +08:00
to_upper(value_str);
2019-11-10 19:45:57 +08:00
if (value_str == "TRUE" || value_str == "YES" || value_str == "ON") {
2015-01-07 01:26:14 +08:00
return true;
}
2019-11-10 19:45:57 +08:00
if (value_str == "FALSE" || value_str == "NO" || value_str == "OFF") {
2015-01-07 01:26:14 +08:00
return false;
}
throw(std::domain_error(value_str + " can not be translated to bool!"));
}
2019-11-10 19:45:57 +08:00
} // namespace hku