blob: 80f71e7eeeca2e98c37c95cbe3b6e41ac77a775b [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 IIIa520a392022-08-08 12:17:34 -07003#include <fmt/compile.h>
4#include <fmt/format.h>
5
William A. Kennington IIIbc52d932022-08-18 16:34:02 -07006#include <functional>
7#include <iterator>
William A. Kennington III61ef4f22022-08-18 16:29:09 -07008#include <stdplus/exception.hpp>
9#include <stdplus/fd/create.hpp>
10#include <stdplus/fd/line.hpp>
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -070011#include <string>
William A. Kennington III61ef4f22022-08-18 16:29:09 -070012#include <utility>
Ratan Guptaed123a32017-06-15 09:07:31 +053013
14namespace phosphor
15{
16namespace network
17{
18namespace config
19{
20
William A. Kennington III150753f2022-08-05 15:20:54 -070021using std::literals::string_view_literals::operator""sv;
22
23bool icaseeq(std::string_view in, std::string_view expected) noexcept
24{
25 return std::equal(in.begin(), in.end(), expected.begin(), expected.end(),
26 [](auto a, auto b) { return tolower(a) == b; });
27}
28
29std::optional<bool> parseBool(std::string_view in) noexcept
30{
31 if (in == "1"sv || icaseeq(in, "yes"sv) || icaseeq(in, "y"sv) ||
32 icaseeq(in, "true"sv) || icaseeq(in, "t"sv) || icaseeq(in, "on"sv))
33 {
34 return true;
35 }
36 if (in == "0"sv || icaseeq(in, "no"sv) || icaseeq(in, "n"sv) ||
37 icaseeq(in, "false"sv) || icaseeq(in, "f"sv) || icaseeq(in, "off"sv))
38 {
39 return false;
40 }
41 return std::nullopt;
42}
43
William A. Kennington IIIa520a392022-08-08 12:17:34 -070044fs::path pathForIntfConf(const fs::path& dir, std::string_view intf)
45{
46 return dir / fmt::format(FMT_COMPILE("00-bmc-{}.network"), intf);
47}
48
49fs::path pathForIntfDev(const fs::path& dir, std::string_view intf)
50{
51 return dir / fmt::format(FMT_COMPILE("{}.netdev"), intf);
52}
53
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -070054const std::string*
55 SectionMap::getLastValueString(std::string_view section,
56 std::string_view key) const noexcept
57{
58 auto sit = find(section);
59 if (sit == end())
60 {
61 return nullptr;
62 }
63 for (auto it = sit->second.rbegin(); it != sit->second.rend(); ++it)
64 {
65 auto kit = it->find(key);
66 if (kit == it->end() || kit->second.empty())
67 {
68 continue;
69 }
70 return &kit->second.back();
71 }
72 return nullptr;
73}
74
75std::vector<std::string> SectionMap::getValueStrings(std::string_view section,
76 std::string_view key) const
77{
78 return getValues(section, key,
79 [](const Value& v) { return std::string(v); });
80}
81
William A. Kennington III25511a12022-08-04 16:32:28 -070082Parser::Parser(const fs::path& filename)
Ratan Guptaed123a32017-06-15 09:07:31 +053083{
William A. Kennington III25511a12022-08-04 16:32:28 -070084 setFile(filename);
Ratan Guptaed123a32017-06-15 09:07:31 +053085}
86
William A. Kennington III61ef4f22022-08-18 16:29:09 -070087inline bool isspace(char c) noexcept
Ratan Guptaed123a32017-06-15 09:07:31 +053088{
William A. Kennington III61ef4f22022-08-18 16:29:09 -070089 return c == ' ' || c == '\t';
Ratan Guptaed123a32017-06-15 09:07:31 +053090}
91
William A. Kennington III61ef4f22022-08-18 16:29:09 -070092inline bool iscomment(char c) noexcept
93{
94 return c == '#' || c == ';';
95}
96
97static void removePadding(std::string_view& str) noexcept
98{
99 size_t idx = str.size();
100 for (; idx > 0 && isspace(str[idx - 1]); idx--)
101 ;
102 str.remove_suffix(str.size() - idx);
103
104 idx = 0;
105 for (; idx < str.size() && isspace(str[idx]); idx++)
106 ;
107 str.remove_prefix(idx);
108}
109
110struct Parse
111{
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700112 std::reference_wrapper<const fs::path> filename;
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700113 SectionMap sections;
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700114 KeyValuesMap* section;
115 std::vector<std::string> warnings;
116 size_t lineno;
117
118 inline Parse(const fs::path& filename) :
119 filename(filename), section(nullptr), lineno(0)
120 {
121 }
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700122
123 void pumpSection(std::string_view line)
124 {
125 auto cpos = line.find(']');
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700126 if (cpos == line.npos)
127 {
128 warnings.emplace_back(fmt::format("{}:{}: Section missing ]",
129 filename.get().native(), lineno));
130 }
131 else
132 {
133 for (auto c : line.substr(cpos + 1))
134 {
135 if (!isspace(c))
136 {
137 warnings.emplace_back(
138 fmt::format("{}:{}: Characters outside section name",
139 filename.get().native(), lineno));
140 break;
141 }
142 }
143 }
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700144 auto s = line.substr(0, cpos);
145 auto it = sections.find(s);
146 if (it == sections.end())
147 {
148 std::tie(it, std::ignore) =
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700149 sections.emplace(Section(s), KeyValuesMapList{});
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700150 }
William A. Kennington IIIe21a5cf2022-08-09 12:19:14 -0700151 section = &it->second.emplace_back();
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700152 }
153
154 void pumpKV(std::string_view line)
155 {
156 auto epos = line.find('=');
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700157 std::vector<std::string> new_warnings;
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700158 if (epos == line.npos)
159 {
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700160 new_warnings.emplace_back(fmt::format(
161 "{}:{}: KV missing `=`", filename.get().native(), lineno));
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700162 }
163 auto k = line.substr(0, epos);
164 removePadding(k);
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700165 if (section == nullptr)
166 {
167 new_warnings.emplace_back(
168 fmt::format("{}:{}: Key `{}` missing section",
169 filename.get().native(), lineno, k));
170 }
171 if (!new_warnings.empty())
172 {
173 warnings.insert(warnings.end(),
174 std::make_move_iterator(new_warnings.begin()),
175 std::make_move_iterator(new_warnings.end()));
176 return;
177 }
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700178 auto v = line.substr(epos + 1);
179 removePadding(v);
180
181 auto it = section->find(k);
182 if (it == section->end())
183 {
184 std::tie(it, std::ignore) = section->emplace(Key(k), ValueList{});
185 }
186 it->second.emplace_back(v);
187 }
188
189 void pump(std::string_view line)
190 {
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700191 lineno++;
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700192 for (size_t i = 0; i < line.size(); ++i)
193 {
194 auto c = line[i];
195 if (iscomment(c))
196 {
197 return;
198 }
199 else if (c == '[')
200 {
201 return pumpSection(line.substr(i + 1));
202 }
203 else if (!isspace(c))
204 {
205 return pumpKV(line.substr(i));
206 }
207 }
208 }
209};
210
William A. Kennington III25511a12022-08-04 16:32:28 -0700211void Parser::setFile(const fs::path& filename)
Ratan Guptaed123a32017-06-15 09:07:31 +0530212{
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700213 Parse parse(filename);
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700214
215 try
Ratan Guptaed123a32017-06-15 09:07:31 +0530216 {
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700217 auto fd = stdplus::fd::open(filename.c_str(),
218 stdplus::fd::OpenAccess::ReadOnly);
219 stdplus::fd::LineReader reader(fd);
220 while (true)
Ratan Guptaed123a32017-06-15 09:07:31 +0530221 {
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700222 parse.pump(*reader.readLine());
Ratan Guptaed123a32017-06-15 09:07:31 +0530223 }
224 }
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700225 catch (const stdplus::exception::Eof&)
226 {
227 }
228 catch (const std::exception& e)
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700229 {
230 // TODO: Pass exceptions once callers can handle them
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700231 parse.warnings.emplace_back(
232 fmt::format("{}: Read error: {}", filename.native(), e.what()));
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700233 }
234
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700235 this->filename = filename;
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700236 this->sections = std::move(parse.sections);
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700237 this->warnings = std::move(parse.warnings);
Ratan Guptaed123a32017-06-15 09:07:31 +0530238}
239
Gunnar Mills57d9c502018-09-14 14:42:34 -0500240} // namespace config
241} // namespace network
242} // namespace phosphor