// Copyright (C) 2019 The Android Open Source Project
//
// 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.
#ifndef CONFIG_FILE_H_
#define CONFIG_FILE_H_
#include <cassert>
#include <iosfwd>
#include <map>
#include <string>
namespace header_checker {
namespace utils {
class ConfigParser;
class ConfigSection {
public:
using MapType = std::map<std::string, std::string>;
using const_iterator = MapType::const_iterator;
public:
ConfigSection() = default;
ConfigSection(ConfigSection &&) = default;
ConfigSection &operator=(ConfigSection &&) = default;
bool HasProperty(const std::string &name) const {
return map_.find(name) != map_.end();
}
std::string GetProperty(const std::string &name) const {
auto &&it = map_.find(name);
if (it == map_.end()) {
return "";
}
return it->second;
}
std::string operator[](const std::string &name) const {
return GetProperty(name);
}
const_iterator begin() const {
return map_.begin();
}
const_iterator end() const {
return map_.end();
}
private:
ConfigSection(const ConfigSection &) = delete;
ConfigSection &operator=(const ConfigSection &) = delete;
private:
std::map<std::string, std::string> map_;
friend class ConfigParser;
};
class ConfigFile {
public:
using MapType = std::map<std::string, ConfigSection>;
using const_iterator = MapType::const_iterator;
public:
ConfigFile() = default;
ConfigFile(ConfigFile &&) = default;
ConfigFile &operator=(ConfigFile &&) = default;
bool HasSection(const std::string §ion_name) const {
return map_.find(section_name) != map_.end();
}
const ConfigSection &GetSection(const std::string §ion_name) const {
auto &&it = map_.find(section_name);
assert(it != map_.end());
return it->second;
}
const ConfigSection &operator[](const std::string §ion_name) const {
return GetSection(section_name);
}
bool HasProperty(const std::string §ion_name,
const std::string &property_name) const {
auto &&it = map_.find(section_name);
if (it == map_.end()) {
return false;
}
return it->second.HasProperty(property_name);
}
std::string GetProperty(const std::string §ion_name,
const std::string &property_name) const {
auto &&it = map_.find(section_name);
if (it == map_.end()) {
return "";
}
return it->second.GetProperty(property_name);
}
const_iterator begin() const {
return map_.begin();
}
const_iterator end() const {
return map_.end();
}
private:
ConfigFile(const ConfigFile &) = delete;
ConfigFile &operator=(const ConfigFile &) = delete;
private:
std::map<std::string, ConfigSection> map_;
friend class ConfigParser;
};
class ConfigParser {
public:
using ErrorListener = std::function<void (size_t, const char *)>;
public:
ConfigParser(std::istream &stream)
: stream_(stream), section_(nullptr) { }
ConfigFile ParseFile();
static ConfigFile ParseFile(std::istream &istream);
static ConfigFile ParseFile(const std::string &path);
void SetErrorListener(ErrorListener listener) {
error_listener_ = std::move(listener);
}
private:
void ParseLine(size_t line_no, std::string_view line);
void ReportError(size_t line_no, const char *cause) {
if (error_listener_) {
error_listener_(line_no, cause);
}
}
private:
ConfigParser(const ConfigParser &) = delete;
ConfigParser &operator=(const ConfigParser &) = delete;
private:
std::istream &stream_;
ErrorListener error_listener_;
ConfigSection *section_;
ConfigFile cfg_;
};
} // namespace utils
} // namespace header_checker
#endif // CONFIG_FILE_H_