1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef CONFIG_FILE_H_
16 #define CONFIG_FILE_H_
17 
18 #include <cassert>
19 #include <iosfwd>
20 #include <map>
21 #include <string>
22 
23 
24 namespace header_checker {
25 namespace utils {
26 
27 
28 class ConfigParser;
29 
30 
31 class ConfigSection {
32  public:
33   using MapType = std::map<std::string, std::string>;
34   using const_iterator = MapType::const_iterator;
35 
36 
37  public:
38   ConfigSection() = default;
39   ConfigSection(ConfigSection &&) = default;
40   ConfigSection &operator=(ConfigSection &&) = default;
41 
HasProperty(const std::string & name)42   bool HasProperty(const std::string &name) const {
43     return map_.find(name) != map_.end();
44   }
45 
GetProperty(const std::string & name)46   std::string GetProperty(const std::string &name) const {
47     auto &&it = map_.find(name);
48     if (it == map_.end()) {
49       return "";
50     }
51     return it->second;
52   }
53 
54   std::string operator[](const std::string &name) const {
55     return GetProperty(name);
56   }
57 
begin()58   const_iterator begin() const {
59     return map_.begin();
60   }
61 
end()62   const_iterator end() const {
63     return map_.end();
64   }
65 
66 
67  private:
68   ConfigSection(const ConfigSection &) = delete;
69   ConfigSection &operator=(const ConfigSection &) = delete;
70 
71 
72  private:
73   std::map<std::string, std::string> map_;
74 
75   friend class ConfigParser;
76 };
77 
78 
79 class ConfigFile {
80  public:
81   using MapType = std::map<std::string, ConfigSection>;
82   using const_iterator = MapType::const_iterator;
83 
84 
85  public:
86   ConfigFile() = default;
87   ConfigFile(ConfigFile &&) = default;
88   ConfigFile &operator=(ConfigFile &&) = default;
89 
HasSection(const std::string & section_name)90   bool HasSection(const std::string &section_name) const {
91     return map_.find(section_name) != map_.end();
92   }
93 
GetSection(const std::string & section_name)94   const ConfigSection &GetSection(const std::string &section_name) const {
95     auto &&it = map_.find(section_name);
96     assert(it != map_.end());
97     return it->second;
98   }
99 
100   const ConfigSection &operator[](const std::string &section_name) const {
101     return GetSection(section_name);
102   }
103 
HasProperty(const std::string & section_name,const std::string & property_name)104   bool HasProperty(const std::string &section_name,
105                    const std::string &property_name) const {
106     auto &&it = map_.find(section_name);
107     if (it == map_.end()) {
108       return false;
109     }
110     return it->second.HasProperty(property_name);
111   }
112 
GetProperty(const std::string & section_name,const std::string & property_name)113   std::string GetProperty(const std::string &section_name,
114                           const std::string &property_name) const {
115     auto &&it = map_.find(section_name);
116     if (it == map_.end()) {
117       return "";
118     }
119     return it->second.GetProperty(property_name);
120   }
121 
begin()122   const_iterator begin() const {
123     return map_.begin();
124   }
125 
end()126   const_iterator end() const {
127     return map_.end();
128   }
129 
130 
131  private:
132   ConfigFile(const ConfigFile &) = delete;
133   ConfigFile &operator=(const ConfigFile &) = delete;
134 
135 
136  private:
137   std::map<std::string, ConfigSection> map_;
138 
139   friend class ConfigParser;
140 };
141 
142 
143 class ConfigParser {
144  public:
145   using ErrorListener = std::function<void (size_t, const char *)>;
146 
147 
148  public:
ConfigParser(std::istream & stream)149   ConfigParser(std::istream &stream)
150       : stream_(stream), section_(nullptr) { }
151 
152   ConfigFile ParseFile();
153 
154   static ConfigFile ParseFile(std::istream &istream);
155 
156   static ConfigFile ParseFile(const std::string &path);
157 
SetErrorListener(ErrorListener listener)158   void SetErrorListener(ErrorListener listener) {
159     error_listener_ = std::move(listener);
160   }
161 
162 
163  private:
164   void ParseLine(size_t line_no, std::string_view line);
165 
ReportError(size_t line_no,const char * cause)166   void ReportError(size_t line_no, const char *cause) {
167     if (error_listener_) {
168       error_listener_(line_no, cause);
169     }
170   }
171 
172 
173  private:
174   ConfigParser(const ConfigParser &) = delete;
175   ConfigParser &operator=(const ConfigParser &) = delete;
176 
177 
178  private:
179   std::istream &stream_;
180 
181   ErrorListener error_listener_;
182 
183   ConfigSection *section_;
184 
185   ConfigFile cfg_;
186 };
187 
188 
189 }  // namespace utils
190 }  // namespace header_checker
191 
192 
193 #endif  // CONFIG_FILE_H_
194