| // Copyright 2016 The SwiftShader Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "Configurator.hpp" |
| #include "Debug.hpp" |
| |
| #include <algorithm> |
| #include <fstream> |
| #include <istream> |
| |
| namespace { |
| inline std::string trimSpaces(const std::string &str) |
| { |
| std::string trimmed = str; |
| trimmed.erase(trimmed.begin(), std::find_if(trimmed.begin(), trimmed.end(), [](unsigned char c) { |
| return !std::isspace(c); |
| })); |
| trimmed.erase(std::find_if(trimmed.rbegin(), trimmed.rend(), [](unsigned char c) { |
| return !std::isspace(c); |
| }).base(), |
| trimmed.end()); |
| return trimmed; |
| } |
| } // namespace |
| |
| namespace sw { |
| |
| Configurator::Configurator(const std::string &filePath) |
| { |
| std::fstream file(filePath, std::ios::in); |
| if(file.fail()) |
| { |
| return; |
| } |
| readConfiguration(file); |
| file.close(); |
| } |
| |
| Configurator::Configurator(std::istream &str) |
| { |
| readConfiguration(str); |
| } |
| |
| bool Configurator::readConfiguration(std::istream &str) |
| { |
| std::string line; |
| std::string sectionName; |
| |
| int lineNumber = 0; |
| while(getline(str, line)) |
| { |
| ++lineNumber; |
| if(line.length()) |
| { |
| if(line[line.length() - 1] == '\r') |
| { |
| line = line.substr(0, line.length() - 1); |
| } |
| |
| if(!isprint(line[0])) |
| { |
| sw::warn("Cannot parse line %d of configuration, skipping line\n", lineNumber); |
| return false; |
| } |
| |
| std::string::size_type pLeft = line.find_first_of(";#[="); |
| |
| if(pLeft != std::string::npos) |
| { |
| switch(line[pLeft]) |
| { |
| case '[': |
| { |
| std::string::size_type pRight = line.find_last_of("]"); |
| |
| if(pRight != std::string::npos && pRight > pLeft) |
| { |
| sectionName = trimSpaces(line.substr(pLeft + 1, pRight - pLeft - 1)); |
| if(!sectionName.length()) |
| { |
| sw::warn("Found empty section name at line %d of configuration\n", lineNumber); |
| } |
| } |
| } |
| break; |
| case '=': |
| { |
| std::string key = trimSpaces(line.substr(0, pLeft)); |
| std::string value = trimSpaces(line.substr(pLeft + 1)); |
| if(!key.length() || !value.length()) |
| { |
| sw::warn("Cannot parse key-value pair at line %d of configuration (key or value is empty), skipping key-value pair\n", lineNumber); |
| } |
| else |
| { |
| sections[sectionName].keyValuePairs[key] = value; |
| } |
| } |
| break; |
| case ';': |
| case '#': |
| // Ignore comments |
| break; |
| } |
| } |
| } |
| } |
| |
| return sections.size() > 0; |
| } |
| |
| void Configurator::writeFile(const std::string &filePath, const std::string &title) |
| { |
| std::fstream file(filePath, std::ios::out); |
| if(file.fail()) |
| { |
| return; |
| } |
| |
| file << "; " << title << std::endl |
| << std::endl; |
| |
| for(const auto &[sectionName, section] : sections) |
| { |
| file << "[" << sectionName << "]" << std::endl; |
| for(const auto &[key, value] : section.keyValuePairs) |
| { |
| file << key << "=" << value << std::endl; |
| } |
| file << std::endl; |
| } |
| |
| file.close(); |
| } |
| |
| std::optional<std::string> Configurator::getValueIfExists(const std::string §ionName, const std::string &keyName) const |
| { |
| const auto section = sections.find(sectionName); |
| if(section == sections.end()) |
| { |
| return std::nullopt; |
| } |
| |
| const auto keyValue = section->second.keyValuePairs.find(keyName); |
| if(keyValue == section->second.keyValuePairs.end()) |
| { |
| return std::nullopt; |
| } |
| |
| return keyValue->second; |
| } |
| |
| std::string Configurator::getValue(const std::string §ionName, const std::string &keyName, const std::string &defaultValue) const |
| { |
| const auto value = getValueIfExists(sectionName, keyName); |
| if(value) |
| { |
| return *value; |
| } |
| return defaultValue; |
| } |
| |
| void Configurator::addValue(const std::string §ionName, const std::string &keyName, const std::string &value) |
| { |
| sections[sectionName].keyValuePairs[keyName] = value; |
| } |
| |
| bool Configurator::getBoolean(const std::string §ionName, const std::string &keyName, bool defaultValue) const |
| { |
| auto strValue = getValueIfExists(sectionName, keyName); |
| if(!strValue) |
| { |
| return defaultValue; |
| } |
| |
| std::stringstream ss{ *strValue }; |
| |
| bool val; |
| ss >> val; |
| if(ss.fail()) |
| { |
| // Accept "true" and "false" as well. |
| ss.clear(); |
| ss >> std::boolalpha >> val; |
| } |
| return val; |
| } |
| |
| double Configurator::getFloat(const std::string §ionName, const std::string &keyName, double defaultValue) const |
| { |
| auto strValue = getValueIfExists(sectionName, keyName); |
| if(!strValue) |
| { |
| return defaultValue; |
| } |
| |
| std::stringstream ss{ *strValue }; |
| |
| double val = 0; |
| ss >> val; |
| return val; |
| } |
| } // namespace sw |