1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
3 #include "base/configwriter.hpp"
4 #include "base/exception.hpp"
5 #include <boost/regex.hpp>
6 #include <boost/algorithm/string/replace.hpp>
10 using namespace icinga;
12 void ConfigWriter::EmitBoolean(std::ostream& fp, bool val)
14 fp << (val ? "true" : "false");
17 void ConfigWriter::EmitNumber(std::ostream& fp, double val)
19 fp << std::fixed << val;
22 void ConfigWriter::EmitString(std::ostream& fp, const String& val)
24 fp << "\"" << EscapeIcingaString(val) << "\"";
27 void ConfigWriter::EmitEmpty(std::ostream& fp)
32 void ConfigWriter::EmitArray(std::ostream& fp, int indentLevel, const Array::Ptr& val)
35 EmitArrayItems(fp, indentLevel, val);
36 if (val->GetLength() > 0)
41 void ConfigWriter::EmitArrayItems(std::ostream& fp, int indentLevel, const Array::Ptr& val)
45 ObjectLock olock(val);
46 for (const Value& item : val) {
52 EmitValue(fp, indentLevel, item);
56 void ConfigWriter::EmitScope(std::ostream& fp, int indentLevel, const Dictionary::Ptr& val,
57 const Array::Ptr& imports, bool splitDot)
61 if (imports && imports->GetLength() > 0) {
62 ObjectLock xlock(imports);
63 for (const Value& import : imports) {
65 EmitIndent(fp, indentLevel);
66 fp << "import \"" << import << "\"";
73 ObjectLock olock(val);
74 for (const Dictionary::Pair& kv : val) {
76 EmitIndent(fp, indentLevel);
79 std::vector<String> tokens = kv.first.Split(".");
81 EmitIdentifier(fp, tokens[0], true);
83 for (std::vector<String>::size_type i = 1; i < tokens.size(); i++) {
85 EmitString(fp, tokens[i]);
89 EmitIdentifier(fp, kv.first, true);
92 EmitValue(fp, indentLevel + 1, kv.second);
97 EmitIndent(fp, indentLevel - 1);
101 void ConfigWriter::EmitValue(std::ostream& fp, int indentLevel, const Value& val)
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())
111 else if (val.IsNumber())
113 else if (val.IsBoolean())
114 EmitBoolean(fp, val);
115 else if (val.IsEmpty())
119 void ConfigWriter::EmitRaw(std::ostream& fp, const String& val)
124 void ConfigWriter::EmitIndent(std::ostream& fp, int indentLevel)
126 for (int i = 0; i < indentLevel; i++)
130 void ConfigWriter::EmitIdentifier(std::ostream& fp, const String& identifier, bool inAssignment)
132 static std::set<String> keywords;
133 static boost::mutex mutex;
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()));
143 if (keywords.find(identifier) != keywords.end()) {
144 fp << "@" << identifier;
148 boost::regex expr("^[a-zA-Z_][a-zA-Z0-9\\_]*$");
150 if (boost::regex_search(identifier.GetData(), what, expr))
152 else if (inAssignment)
153 EmitString(fp, identifier);
155 BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid identifier"));
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)
166 EmitIdentifier(fp, type, false);
168 EmitString(fp, name);
171 fp << " ignore_on_error";
174 EmitScope(fp, 1, attrs, imports, true);
177 void ConfigWriter::EmitComment(std::ostream& fp, const String& text)
179 fp << "/* " << text << " */\n";
182 void ConfigWriter::EmitFunctionCall(std::ostream& fp, const String& name, const Array::Ptr& arguments)
184 EmitIdentifier(fp, name, false);
186 EmitArrayItems(fp, 0, arguments);
190 String ConfigWriter::EscapeIcingaString(const String& 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, "\"", "\\\"");
203 const std::vector<String>& ConfigWriter::GetKeywords()
205 static std::vector<String> keywords;
206 static boost::mutex mutex;
207 boost::mutex::scoped_lock lock(mutex);
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");
253 ConfigIdentifier::ConfigIdentifier(String identifier)
254 : m_Name(std::move(identifier))
257 String ConfigIdentifier::GetName() const