blob: 1d8371d55e68fde5f68208be3abe9ef2fe4bd9c9 [file] [log] [blame]
Ratan Guptaed123a32017-06-15 09:07:31 +05301#include "config_parser.hpp"
Ratan Guptaed123a32017-06-15 09:07:31 +05302
William A. Kennington IIIbc52d932022-08-18 16:34:02 -07003#include <functional>
4#include <iterator>
William A. Kennington III61ef4f22022-08-18 16:29:09 -07005#include <stdplus/exception.hpp>
6#include <stdplus/fd/create.hpp>
7#include <stdplus/fd/line.hpp>
8#include <utility>
Ratan Guptaed123a32017-06-15 09:07:31 +05309
10namespace phosphor
11{
12namespace network
13{
14namespace config
15{
16
William A. Kennington III25511a12022-08-04 16:32:28 -070017Parser::Parser(const fs::path& filename)
Ratan Guptaed123a32017-06-15 09:07:31 +053018{
William A. Kennington III25511a12022-08-04 16:32:28 -070019 setFile(filename);
Ratan Guptaed123a32017-06-15 09:07:31 +053020}
21
William A. Kennington III25511a12022-08-04 16:32:28 -070022const ValueList& Parser::getValues(std::string_view section,
23 std::string_view key) const noexcept
Ratan Guptaed123a32017-06-15 09:07:31 +053024{
William A. Kennington III25511a12022-08-04 16:32:28 -070025 static const ValueList empty;
26 auto sit = sections.find(section);
27 if (sit == sections.end())
Ratan Guptaed123a32017-06-15 09:07:31 +053028 {
William A. Kennington III25511a12022-08-04 16:32:28 -070029 return empty;
Ratan Guptaed123a32017-06-15 09:07:31 +053030 }
Ratan Guptac27170a2017-11-22 15:44:42 +053031
William A. Kennington III25511a12022-08-04 16:32:28 -070032 auto kit = sit->second.find(key);
33 if (kit == sit->second.end())
Ratan Guptac27170a2017-11-22 15:44:42 +053034 {
William A. Kennington III25511a12022-08-04 16:32:28 -070035 return empty;
Ratan Guptac27170a2017-11-22 15:44:42 +053036 }
37
William A. Kennington III25511a12022-08-04 16:32:28 -070038 return kit->second;
Ratan Guptaed123a32017-06-15 09:07:31 +053039}
40
William A. Kennington III61ef4f22022-08-18 16:29:09 -070041inline bool isspace(char c) noexcept
Ratan Guptaed123a32017-06-15 09:07:31 +053042{
William A. Kennington III61ef4f22022-08-18 16:29:09 -070043 return c == ' ' || c == '\t';
Ratan Guptaed123a32017-06-15 09:07:31 +053044}
45
William A. Kennington III61ef4f22022-08-18 16:29:09 -070046inline bool iscomment(char c) noexcept
47{
48 return c == '#' || c == ';';
49}
50
51static void removePadding(std::string_view& str) noexcept
52{
53 size_t idx = str.size();
54 for (; idx > 0 && isspace(str[idx - 1]); idx--)
55 ;
56 str.remove_suffix(str.size() - idx);
57
58 idx = 0;
59 for (; idx < str.size() && isspace(str[idx]); idx++)
60 ;
61 str.remove_prefix(idx);
62}
63
64struct Parse
65{
William A. Kennington IIIbc52d932022-08-18 16:34:02 -070066 std::reference_wrapper<const fs::path> filename;
William A. Kennington III61ef4f22022-08-18 16:29:09 -070067 SectionMap sections;
William A. Kennington IIIbc52d932022-08-18 16:34:02 -070068 KeyValuesMap* section;
69 std::vector<std::string> warnings;
70 size_t lineno;
71
72 inline Parse(const fs::path& filename) :
73 filename(filename), section(nullptr), lineno(0)
74 {
75 }
William A. Kennington III61ef4f22022-08-18 16:29:09 -070076
77 void pumpSection(std::string_view line)
78 {
79 auto cpos = line.find(']');
William A. Kennington IIIbc52d932022-08-18 16:34:02 -070080 if (cpos == line.npos)
81 {
82 warnings.emplace_back(fmt::format("{}:{}: Section missing ]",
83 filename.get().native(), lineno));
84 }
85 else
86 {
87 for (auto c : line.substr(cpos + 1))
88 {
89 if (!isspace(c))
90 {
91 warnings.emplace_back(
92 fmt::format("{}:{}: Characters outside section name",
93 filename.get().native(), lineno));
94 break;
95 }
96 }
97 }
William A. Kennington III61ef4f22022-08-18 16:29:09 -070098 auto s = line.substr(0, cpos);
99 auto it = sections.find(s);
100 if (it == sections.end())
101 {
102 std::tie(it, std::ignore) =
103 sections.emplace(Section(s), KeyValuesMap{});
104 }
105 section = &it->second;
106 }
107
108 void pumpKV(std::string_view line)
109 {
110 auto epos = line.find('=');
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700111 std::vector<std::string> new_warnings;
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700112 if (epos == line.npos)
113 {
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700114 new_warnings.emplace_back(fmt::format(
115 "{}:{}: KV missing `=`", filename.get().native(), lineno));
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700116 }
117 auto k = line.substr(0, epos);
118 removePadding(k);
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700119 if (section == nullptr)
120 {
121 new_warnings.emplace_back(
122 fmt::format("{}:{}: Key `{}` missing section",
123 filename.get().native(), lineno, k));
124 }
125 if (!new_warnings.empty())
126 {
127 warnings.insert(warnings.end(),
128 std::make_move_iterator(new_warnings.begin()),
129 std::make_move_iterator(new_warnings.end()));
130 return;
131 }
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700132 auto v = line.substr(epos + 1);
133 removePadding(v);
134
135 auto it = section->find(k);
136 if (it == section->end())
137 {
138 std::tie(it, std::ignore) = section->emplace(Key(k), ValueList{});
139 }
140 it->second.emplace_back(v);
141 }
142
143 void pump(std::string_view line)
144 {
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700145 lineno++;
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700146 for (size_t i = 0; i < line.size(); ++i)
147 {
148 auto c = line[i];
149 if (iscomment(c))
150 {
151 return;
152 }
153 else if (c == '[')
154 {
155 return pumpSection(line.substr(i + 1));
156 }
157 else if (!isspace(c))
158 {
159 return pumpKV(line.substr(i));
160 }
161 }
162 }
163};
164
William A. Kennington III25511a12022-08-04 16:32:28 -0700165void Parser::setFile(const fs::path& filename)
Ratan Guptaed123a32017-06-15 09:07:31 +0530166{
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700167 Parse parse(filename);
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700168
169 try
Ratan Guptaed123a32017-06-15 09:07:31 +0530170 {
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700171 auto fd = stdplus::fd::open(filename.c_str(),
172 stdplus::fd::OpenAccess::ReadOnly);
173 stdplus::fd::LineReader reader(fd);
174 while (true)
Ratan Guptaed123a32017-06-15 09:07:31 +0530175 {
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700176 parse.pump(*reader.readLine());
Ratan Guptaed123a32017-06-15 09:07:31 +0530177 }
178 }
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700179 catch (const stdplus::exception::Eof&)
180 {
181 }
182 catch (const std::exception& e)
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700183 {
184 // TODO: Pass exceptions once callers can handle them
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700185 parse.warnings.emplace_back(
186 fmt::format("{}: Read error: {}", filename.native(), e.what()));
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700187 }
188
189 this->sections = std::move(parse.sections);
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700190 this->warnings = std::move(parse.warnings);
Ratan Guptaed123a32017-06-15 09:07:31 +0530191}
192
Gunnar Mills57d9c502018-09-14 14:42:34 -0500193} // namespace config
194} // namespace network
195} // namespace phosphor