blob: 27a7b15e84889befcbd91b032a28ac413e92bfd7 [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>
11#include <utility>
Ratan Guptaed123a32017-06-15 09:07:31 +053012
13namespace phosphor
14{
15namespace network
16{
17namespace config
18{
19
William A. Kennington III150753f2022-08-05 15:20:54 -070020using std::literals::string_view_literals::operator""sv;
21
22bool icaseeq(std::string_view in, std::string_view expected) noexcept
23{
24 return std::equal(in.begin(), in.end(), expected.begin(), expected.end(),
25 [](auto a, auto b) { return tolower(a) == b; });
26}
27
28std::optional<bool> parseBool(std::string_view in) noexcept
29{
30 if (in == "1"sv || icaseeq(in, "yes"sv) || icaseeq(in, "y"sv) ||
31 icaseeq(in, "true"sv) || icaseeq(in, "t"sv) || icaseeq(in, "on"sv))
32 {
33 return true;
34 }
35 if (in == "0"sv || icaseeq(in, "no"sv) || icaseeq(in, "n"sv) ||
36 icaseeq(in, "false"sv) || icaseeq(in, "f"sv) || icaseeq(in, "off"sv))
37 {
38 return false;
39 }
40 return std::nullopt;
41}
42
William A. Kennington IIIa520a392022-08-08 12:17:34 -070043fs::path pathForIntfConf(const fs::path& dir, std::string_view intf)
44{
45 return dir / fmt::format(FMT_COMPILE("00-bmc-{}.network"), intf);
46}
47
48fs::path pathForIntfDev(const fs::path& dir, std::string_view intf)
49{
50 return dir / fmt::format(FMT_COMPILE("{}.netdev"), intf);
51}
52
William A. Kennington III25511a12022-08-04 16:32:28 -070053Parser::Parser(const fs::path& filename)
Ratan Guptaed123a32017-06-15 09:07:31 +053054{
William A. Kennington III25511a12022-08-04 16:32:28 -070055 setFile(filename);
Ratan Guptaed123a32017-06-15 09:07:31 +053056}
57
William A. Kennington III25511a12022-08-04 16:32:28 -070058const ValueList& Parser::getValues(std::string_view section,
59 std::string_view key) const noexcept
Ratan Guptaed123a32017-06-15 09:07:31 +053060{
William A. Kennington III25511a12022-08-04 16:32:28 -070061 static const ValueList empty;
62 auto sit = sections.find(section);
63 if (sit == sections.end())
Ratan Guptaed123a32017-06-15 09:07:31 +053064 {
William A. Kennington III25511a12022-08-04 16:32:28 -070065 return empty;
Ratan Guptaed123a32017-06-15 09:07:31 +053066 }
Ratan Guptac27170a2017-11-22 15:44:42 +053067
William A. Kennington III25511a12022-08-04 16:32:28 -070068 auto kit = sit->second.find(key);
69 if (kit == sit->second.end())
Ratan Guptac27170a2017-11-22 15:44:42 +053070 {
William A. Kennington III25511a12022-08-04 16:32:28 -070071 return empty;
Ratan Guptac27170a2017-11-22 15:44:42 +053072 }
73
William A. Kennington III25511a12022-08-04 16:32:28 -070074 return kit->second;
Ratan Guptaed123a32017-06-15 09:07:31 +053075}
76
William A. Kennington III61ef4f22022-08-18 16:29:09 -070077inline bool isspace(char c) noexcept
Ratan Guptaed123a32017-06-15 09:07:31 +053078{
William A. Kennington III61ef4f22022-08-18 16:29:09 -070079 return c == ' ' || c == '\t';
Ratan Guptaed123a32017-06-15 09:07:31 +053080}
81
William A. Kennington III61ef4f22022-08-18 16:29:09 -070082inline bool iscomment(char c) noexcept
83{
84 return c == '#' || c == ';';
85}
86
87static void removePadding(std::string_view& str) noexcept
88{
89 size_t idx = str.size();
90 for (; idx > 0 && isspace(str[idx - 1]); idx--)
91 ;
92 str.remove_suffix(str.size() - idx);
93
94 idx = 0;
95 for (; idx < str.size() && isspace(str[idx]); idx++)
96 ;
97 str.remove_prefix(idx);
98}
99
100struct Parse
101{
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700102 std::reference_wrapper<const fs::path> filename;
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700103 SectionMap sections;
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700104 KeyValuesMap* section;
105 std::vector<std::string> warnings;
106 size_t lineno;
107
108 inline Parse(const fs::path& filename) :
109 filename(filename), section(nullptr), lineno(0)
110 {
111 }
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700112
113 void pumpSection(std::string_view line)
114 {
115 auto cpos = line.find(']');
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700116 if (cpos == line.npos)
117 {
118 warnings.emplace_back(fmt::format("{}:{}: Section missing ]",
119 filename.get().native(), lineno));
120 }
121 else
122 {
123 for (auto c : line.substr(cpos + 1))
124 {
125 if (!isspace(c))
126 {
127 warnings.emplace_back(
128 fmt::format("{}:{}: Characters outside section name",
129 filename.get().native(), lineno));
130 break;
131 }
132 }
133 }
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700134 auto s = line.substr(0, cpos);
135 auto it = sections.find(s);
136 if (it == sections.end())
137 {
138 std::tie(it, std::ignore) =
139 sections.emplace(Section(s), KeyValuesMap{});
140 }
141 section = &it->second;
142 }
143
144 void pumpKV(std::string_view line)
145 {
146 auto epos = line.find('=');
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700147 std::vector<std::string> new_warnings;
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700148 if (epos == line.npos)
149 {
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700150 new_warnings.emplace_back(fmt::format(
151 "{}:{}: KV missing `=`", filename.get().native(), lineno));
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700152 }
153 auto k = line.substr(0, epos);
154 removePadding(k);
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700155 if (section == nullptr)
156 {
157 new_warnings.emplace_back(
158 fmt::format("{}:{}: Key `{}` missing section",
159 filename.get().native(), lineno, k));
160 }
161 if (!new_warnings.empty())
162 {
163 warnings.insert(warnings.end(),
164 std::make_move_iterator(new_warnings.begin()),
165 std::make_move_iterator(new_warnings.end()));
166 return;
167 }
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700168 auto v = line.substr(epos + 1);
169 removePadding(v);
170
171 auto it = section->find(k);
172 if (it == section->end())
173 {
174 std::tie(it, std::ignore) = section->emplace(Key(k), ValueList{});
175 }
176 it->second.emplace_back(v);
177 }
178
179 void pump(std::string_view line)
180 {
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700181 lineno++;
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700182 for (size_t i = 0; i < line.size(); ++i)
183 {
184 auto c = line[i];
185 if (iscomment(c))
186 {
187 return;
188 }
189 else if (c == '[')
190 {
191 return pumpSection(line.substr(i + 1));
192 }
193 else if (!isspace(c))
194 {
195 return pumpKV(line.substr(i));
196 }
197 }
198 }
199};
200
William A. Kennington III25511a12022-08-04 16:32:28 -0700201void Parser::setFile(const fs::path& filename)
Ratan Guptaed123a32017-06-15 09:07:31 +0530202{
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700203 Parse parse(filename);
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700204
205 try
Ratan Guptaed123a32017-06-15 09:07:31 +0530206 {
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700207 auto fd = stdplus::fd::open(filename.c_str(),
208 stdplus::fd::OpenAccess::ReadOnly);
209 stdplus::fd::LineReader reader(fd);
210 while (true)
Ratan Guptaed123a32017-06-15 09:07:31 +0530211 {
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700212 parse.pump(*reader.readLine());
Ratan Guptaed123a32017-06-15 09:07:31 +0530213 }
214 }
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700215 catch (const stdplus::exception::Eof&)
216 {
217 }
218 catch (const std::exception& e)
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700219 {
220 // TODO: Pass exceptions once callers can handle them
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700221 parse.warnings.emplace_back(
222 fmt::format("{}: Read error: {}", filename.native(), e.what()));
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700223 }
224
William A. Kennington IIIa520a392022-08-08 12:17:34 -0700225 this->filename = filename;
William A. Kennington III61ef4f22022-08-18 16:29:09 -0700226 this->sections = std::move(parse.sections);
William A. Kennington IIIbc52d932022-08-18 16:34:02 -0700227 this->warnings = std::move(parse.warnings);
Ratan Guptaed123a32017-06-15 09:07:31 +0530228}
229
Gunnar Mills57d9c502018-09-14 14:42:34 -0500230} // namespace config
231} // namespace network
232} // namespace phosphor