]> granicus.if.org Git - icinga2/blob - lib/base/configwriter.cpp
Merge pull request #7185 from Icinga/bugfix/gelfwriter-wrong-log-facility
[icinga2] / lib / base / configwriter.cpp
1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "base/configwriter.hpp"
4 #include "base/exception.hpp"
5 #include <boost/regex.hpp>
6 #include <boost/algorithm/string/replace.hpp>
7 #include <set>
8 #include <iterator>
9
10 using namespace icinga;
11
12 void ConfigWriter::EmitBoolean(std::ostream& fp, bool val)
13 {
14         fp << (val ? "true" : "false");
15 }
16
17 void ConfigWriter::EmitNumber(std::ostream& fp, double val)
18 {
19         fp << std::fixed << val;
20 }
21
22 void ConfigWriter::EmitString(std::ostream& fp, const String& val)
23 {
24         fp << "\"" << EscapeIcingaString(val) << "\"";
25 }
26
27 void ConfigWriter::EmitEmpty(std::ostream& fp)
28 {
29         fp << "null";
30 }
31
32 void ConfigWriter::EmitArray(std::ostream& fp, int indentLevel, const Array::Ptr& val)
33 {
34         fp << "[ ";
35         EmitArrayItems(fp, indentLevel, val);
36         if (val->GetLength() > 0)
37                 fp << " ";
38         fp << "]";
39 }
40
41 void ConfigWriter::EmitArrayItems(std::ostream& fp, int indentLevel, const Array::Ptr& val)
42 {
43         bool first = true;
44
45         ObjectLock olock(val);
46         for (const Value& item : val) {
47                 if (first)
48                         first = false;
49                 else
50                         fp << ", ";
51
52                 EmitValue(fp, indentLevel, item);
53         }
54 }
55
56 void ConfigWriter::EmitScope(std::ostream& fp, int indentLevel, const Dictionary::Ptr& val,
57         const Array::Ptr& imports, bool splitDot)
58 {
59         fp << "{";
60
61         if (imports && imports->GetLength() > 0) {
62                 ObjectLock xlock(imports);
63                 for (const Value& import : imports) {
64                         fp << "\n";
65                         EmitIndent(fp, indentLevel);
66                         fp << "import \"" << import << "\"";
67                 }
68
69                 fp << "\n";
70         }
71
72         if (val) {
73                 ObjectLock olock(val);
74                 for (const Dictionary::Pair& kv : val) {
75                         fp << "\n";
76                         EmitIndent(fp, indentLevel);
77
78                         if (splitDot) {
79                                 std::vector<String> tokens = kv.first.Split(".");
80
81                                 EmitIdentifier(fp, tokens[0], true);
82
83                                 for (std::vector<String>::size_type i = 1; i < tokens.size(); i++) {
84                                         fp << "[";
85                                         EmitString(fp, tokens[i]);
86                                         fp << "]";
87                                 }
88                         } else
89                                 EmitIdentifier(fp, kv.first, true);
90
91                         fp << " = ";
92                         EmitValue(fp, indentLevel + 1, kv.second);
93                 }
94         }
95
96         fp << "\n";
97         EmitIndent(fp, indentLevel - 1);
98         fp << "}";
99 }
100
101 void ConfigWriter::EmitValue(std::ostream& fp, int indentLevel, const Value& val)
102 {
103         if (val.IsObjectType<Array>())
104                 EmitArray(fp, indentLevel, val);
105         else if (val.IsObjectType<Dictionary>())
106                 EmitScope(fp, indentLevel, val);
107         else if (val.IsObjectType<ConfigIdentifier>())
108                 EmitIdentifier(fp, static_cast<ConfigIdentifier::Ptr>(val)->GetName(), false);
109         else if (val.IsString())
110                 EmitString(fp, val);
111         else if (val.IsNumber())
112                 EmitNumber(fp, val);
113         else if (val.IsBoolean())
114                 EmitBoolean(fp, val);
115         else if (val.IsEmpty())
116                 EmitEmpty(fp);
117 }
118
119 void ConfigWriter::EmitRaw(std::ostream& fp, const String& val)
120 {
121         fp << val;
122 }
123
124 void ConfigWriter::EmitIndent(std::ostream& fp, int indentLevel)
125 {
126         for (int i = 0; i < indentLevel; i++)
127                 fp << "\t";
128 }
129
130 void ConfigWriter::EmitIdentifier(std::ostream& fp, const String& identifier, bool inAssignment)
131 {
132         static std::set<String> keywords;
133         static boost::mutex mutex;
134
135         {
136                 boost::mutex::scoped_lock lock(mutex);
137                 if (keywords.empty()) {
138                         const std::vector<String>& vkeywords = GetKeywords();
139                         std::copy(vkeywords.begin(), vkeywords.end(), std::inserter(keywords, keywords.begin()));
140                 }
141         }
142
143         if (keywords.find(identifier) != keywords.end()) {
144                 fp << "@" << identifier;
145                 return;
146         }
147
148         boost::regex expr("^[a-zA-Z_][a-zA-Z0-9\\_]*$");
149         boost::smatch what;
150         if (boost::regex_search(identifier.GetData(), what, expr))
151                 fp << identifier;
152         else if (inAssignment)
153                 EmitString(fp, identifier);
154         else
155                 BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid identifier"));
156 }
157
158 void ConfigWriter::EmitConfigItem(std::ostream& fp, const String& type, const String& name, bool isTemplate,
159         bool ignoreOnError, const Array::Ptr& imports, const Dictionary::Ptr& attrs)
160 {
161         if (isTemplate)
162                 fp << "template ";
163         else
164                 fp << "object ";
165
166         EmitIdentifier(fp, type, false);
167         fp << " ";
168         EmitString(fp, name);
169
170         if (ignoreOnError)
171                 fp << " ignore_on_error";
172
173         fp << " ";
174         EmitScope(fp, 1, attrs, imports, true);
175 }
176
177 void ConfigWriter::EmitComment(std::ostream& fp, const String& text)
178 {
179         fp << "/* " << text << " */\n";
180 }
181
182 void ConfigWriter::EmitFunctionCall(std::ostream& fp, const String& name, const Array::Ptr& arguments)
183 {
184         EmitIdentifier(fp, name, false);
185         fp << "(";
186         EmitArrayItems(fp, 0, arguments);
187         fp << ")";
188 }
189
190 String ConfigWriter::EscapeIcingaString(const String& str)
191 {
192         String result = str;
193         boost::algorithm::replace_all(result, "\\", "\\\\");
194         boost::algorithm::replace_all(result, "\n", "\\n");
195         boost::algorithm::replace_all(result, "\t", "\\t");
196         boost::algorithm::replace_all(result, "\r", "\\r");
197         boost::algorithm::replace_all(result, "\b", "\\b");
198         boost::algorithm::replace_all(result, "\f", "\\f");
199         boost::algorithm::replace_all(result, "\"", "\\\"");
200         return result;
201 }
202
203 const std::vector<String>& ConfigWriter::GetKeywords()
204 {
205         static std::vector<String> keywords;
206         static boost::mutex mutex;
207         boost::mutex::scoped_lock lock(mutex);
208
209         if (keywords.empty()) {
210                 keywords.emplace_back("object");
211                 keywords.emplace_back("template");
212                 keywords.emplace_back("include");
213                 keywords.emplace_back("include_recursive");
214                 keywords.emplace_back("include_zones");
215                 keywords.emplace_back("library");
216                 keywords.emplace_back("null");
217                 keywords.emplace_back("true");
218                 keywords.emplace_back("false");
219                 keywords.emplace_back("const");
220                 keywords.emplace_back("var");
221                 keywords.emplace_back("this");
222                 keywords.emplace_back("globals");
223                 keywords.emplace_back("locals");
224                 keywords.emplace_back("use");
225                 keywords.emplace_back("using");
226                 keywords.emplace_back("namespace");
227                 keywords.emplace_back("default");
228                 keywords.emplace_back("ignore_on_error");
229                 keywords.emplace_back("current_filename");
230                 keywords.emplace_back("current_line");
231                 keywords.emplace_back("apply");
232                 keywords.emplace_back("to");
233                 keywords.emplace_back("where");
234                 keywords.emplace_back("import");
235                 keywords.emplace_back("assign");
236                 keywords.emplace_back("ignore");
237                 keywords.emplace_back("function");
238                 keywords.emplace_back("return");
239                 keywords.emplace_back("break");
240                 keywords.emplace_back("continue");
241                 keywords.emplace_back("for");
242                 keywords.emplace_back("if");
243                 keywords.emplace_back("else");
244                 keywords.emplace_back("while");
245                 keywords.emplace_back("throw");
246                 keywords.emplace_back("try");
247                 keywords.emplace_back("except");
248         }
249
250         return keywords;
251 }
252
253 ConfigIdentifier::ConfigIdentifier(String identifier)
254         : m_Name(std::move(identifier))
255 { }
256
257 String ConfigIdentifier::GetName() const
258 {
259         return m_Name;
260 }