blob: 92c344f94c50a20c9ea858161f0d73c1d276cd72 [file] [log] [blame]
Ratan Guptaed123a32017-06-15 09:07:31 +05301#include "config_parser.hpp"
Ratan Guptaed123a32017-06-15 09:07:31 +05302
Ratan Guptaed123a32017-06-15 09:07:31 +05303#include <algorithm>
Patrick Venture189d44e2018-07-09 12:30:59 -07004#include <fstream>
Ratan Guptaed123a32017-06-15 09:07:31 +05305#include <list>
Patrick Venture189d44e2018-07-09 12:30:59 -07006#include <phosphor-logging/log.hpp>
7#include <regex>
8#include <string>
9#include <unordered_map>
Ratan Guptaed123a32017-06-15 09:07:31 +053010
11namespace phosphor
12{
13namespace network
14{
15namespace config
16{
17
18using namespace phosphor::logging;
Ratan Guptaed123a32017-06-15 09:07:31 +053019
20Parser::Parser(const fs::path& filePath)
21{
22 setFile(filePath);
23}
24
25
Ratan Guptac27170a2017-11-22 15:44:42 +053026std::tuple<ReturnCode, KeyValueMap> Parser::getSection(const std::string& section)
Ratan Guptaed123a32017-06-15 09:07:31 +053027{
28 auto it = sections.find(section);
29 if (it == sections.end())
30 {
Ratan Guptac27170a2017-11-22 15:44:42 +053031 KeyValueMap keyValues;
32 return std::make_tuple(ReturnCode::SECTION_NOT_FOUND,
33 std::move(keyValues));
Ratan Guptaed123a32017-06-15 09:07:31 +053034 }
Ratan Guptac27170a2017-11-22 15:44:42 +053035
36 return std::make_tuple(ReturnCode::SUCCESS, it->second);
Ratan Guptaed123a32017-06-15 09:07:31 +053037}
38
Ratan Guptac27170a2017-11-22 15:44:42 +053039std::tuple<ReturnCode, ValueList> Parser::getValues(const std::string& section,
40 const std::string& key)
Ratan Guptaed123a32017-06-15 09:07:31 +053041{
Ratan Guptac27170a2017-11-22 15:44:42 +053042 ValueList values;
43 KeyValueMap keyValues {};
44 auto rc = ReturnCode::SUCCESS;
45
46 std::tie(rc, keyValues) = getSection(section);
47 if (rc != ReturnCode::SUCCESS)
48 {
49 return std::make_tuple(rc, std::move(values));
50 }
51
Ratan Guptaed123a32017-06-15 09:07:31 +053052 auto it = keyValues.find(key);
53 if (it == keyValues.end())
54 {
Ratan Guptac27170a2017-11-22 15:44:42 +053055 return std::make_tuple(ReturnCode::KEY_NOT_FOUND, std::move(values));
Ratan Guptaed123a32017-06-15 09:07:31 +053056 }
Ratan Guptac27170a2017-11-22 15:44:42 +053057
Ratan Guptaed123a32017-06-15 09:07:31 +053058 for (; it != keyValues.end() && key == it->first; it++)
59 {
60 values.push_back(it->second);
61 }
Ratan Guptac27170a2017-11-22 15:44:42 +053062
63 return std::make_tuple(ReturnCode::SUCCESS, std::move(values));
Ratan Guptaed123a32017-06-15 09:07:31 +053064}
65
66
67bool Parser::isValueExist(const std::string& section, const std::string& key,
68 const std::string& value)
69{
Ratan Guptac27170a2017-11-22 15:44:42 +053070 auto rc = ReturnCode::SUCCESS;
71 ValueList values;
72 std::tie(rc, values) = getValues(section, key);
73
74 if (rc != ReturnCode::SUCCESS)
Ratan Guptaed123a32017-06-15 09:07:31 +053075 {
Ratan Guptac27170a2017-11-22 15:44:42 +053076 return false;
Ratan Guptaed123a32017-06-15 09:07:31 +053077 }
Ratan Guptac27170a2017-11-22 15:44:42 +053078 auto it = std::find(values.begin(), values.end(), value);
79 return it != std::end(values) ? true : false;
Ratan Guptaed123a32017-06-15 09:07:31 +053080}
81
82void Parser::setValue(const std::string& section, const std::string& key,
83 const std::string& value)
84{
Ratan Guptac27170a2017-11-22 15:44:42 +053085 KeyValueMap values;
Ratan Guptadea3ead2017-08-02 18:09:25 +053086 auto it = sections.find(section);
87 if (it != sections.end())
Ratan Guptaed123a32017-06-15 09:07:31 +053088 {
Ratan Guptadea3ead2017-08-02 18:09:25 +053089 values = std::move(it->second);
Ratan Guptaed123a32017-06-15 09:07:31 +053090 }
Ratan Guptadea3ead2017-08-02 18:09:25 +053091 values.insert(std::make_pair(key, value));
Ratan Guptaed123a32017-06-15 09:07:31 +053092
Ratan Guptadea3ead2017-08-02 18:09:25 +053093 if (it != sections.end())
94 {
95 it->second = std::move(values);
Ratan Guptaed123a32017-06-15 09:07:31 +053096 }
Ratan Guptadea3ead2017-08-02 18:09:25 +053097 else
98 {
99 sections.insert(std::make_pair(section, std::move(values)));
100 }
Ratan Guptaed123a32017-06-15 09:07:31 +0530101}
102
103#if 0
104void Parser::print()
105{
106 for (auto section : sections)
107 {
108 std::cout << "[" << section.first << "]\n\n";
109 for (auto keyValue : section.second)
110 {
111 std::cout << keyValue.first << "=" << keyValue.second << "\n";
112 }
113 }
114}
115#endif
116
117void Parser::setFile(const fs::path& filePath)
118{
119 this->filePath = filePath;
120 std::fstream stream;
121 stream.open(filePath.string(), std::fstream::in);
122
123 if (!stream.is_open())
124 {
125 return;
126 }
127 //clear all the section data.
128 sections.clear();
129 parse(stream);
130 stream.close();
131 }
132
133void Parser::parse(std::istream& in)
134{
135 static const std::regex commentRegex
136 {
137 R"x(\s*[;#])x"
138 };
139 static const std::regex sectionRegex
140 {
141 R"x(\s*\[([^\]]+)\])x"
142 };
143 static const std::regex valueRegex
144 {
145 R"x(\s*(\S[^ \t=]*)\s*=\s*(\S+)\s*$)x"
146 };
147 std::string section;
148 std::smatch pieces;
149 for (std::string line; std::getline(in, line);)
150 {
151 if (line.empty() || std::regex_match(line, pieces, commentRegex))
152 {
153 // skip comment lines and blank lines
154 }
155 else if (std::regex_match(line, pieces, sectionRegex))
156 {
157 if (pieces.size() == 2)
158 {
159 section = pieces[1].str();
160 }
161 }
162 else if (std::regex_match(line, pieces, valueRegex))
163 {
164 if (pieces.size() == 3)
165 {
166 setValue(section, pieces[1].str(), pieces[2].str());
167 }
168 }
169 }
170}
171
172}//namespace config
173}//namespace network
174}//namespace phosphor