1 | // SuperTux |
2 | // Copyright (C) 2006 Matthias Braun <matze@braunis.de> |
3 | // |
4 | // This program is free software: you can redistribute it and/or modify |
5 | // it under the terms of the GNU General Public License as published by |
6 | // the Free Software Foundation, either version 3 of the License, or |
7 | // (at your option) any later version. |
8 | // |
9 | // This program is distributed in the hope that it will be useful, |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | // GNU General Public License for more details. |
13 | // |
14 | // You should have received a copy of the GNU General Public License |
15 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | |
17 | #include "util/writer.hpp" |
18 | |
19 | #include <sexp/value.hpp> |
20 | #include <sexp/io.hpp> |
21 | |
22 | #include "physfs/ofile_stream.hpp" |
23 | #include "util/log.hpp" |
24 | |
25 | Writer::Writer(const std::string& filename) : |
26 | m_filename(filename), |
27 | out(new OFileStream(filename)), |
28 | out_owned(true), |
29 | indent_depth(0), |
30 | lists() |
31 | { |
32 | out->precision(7); |
33 | } |
34 | |
35 | Writer::Writer(std::ostream& newout) : |
36 | m_filename("<stream>" ), |
37 | out(&newout), |
38 | out_owned(false), |
39 | indent_depth(0), |
40 | lists() |
41 | { |
42 | out->precision(7); |
43 | } |
44 | |
45 | Writer::~Writer() |
46 | { |
47 | if (lists.size() > 0) { |
48 | log_warning << m_filename << ": Not all sections closed in Writer" << std::endl; |
49 | } |
50 | if (out_owned) |
51 | delete out; |
52 | } |
53 | |
54 | void |
55 | Writer::(const std::string& ) |
56 | { |
57 | *out << "; " << comment << "\n" ; |
58 | } |
59 | |
60 | void |
61 | Writer::start_list(const std::string& listname, bool string) |
62 | { |
63 | indent(); |
64 | *out << '('; |
65 | if (string) |
66 | write_escaped_string(listname); |
67 | else |
68 | *out << listname; |
69 | *out << '\n'; |
70 | indent_depth += 2; |
71 | |
72 | lists.push_back(listname); |
73 | } |
74 | |
75 | void |
76 | Writer::end_list(const std::string& listname) |
77 | { |
78 | if (lists.size() == 0) { |
79 | log_warning << m_filename << ": Trying to close list '" << listname << "', which is not open" << std::endl; |
80 | return; |
81 | } |
82 | if (lists.back() != listname) { |
83 | log_warning << m_filename << ": trying to close list '" << listname << "' while list '" << lists.back() << "' is open" << std::endl; |
84 | return; |
85 | } |
86 | lists.pop_back(); |
87 | |
88 | indent_depth -= 2; |
89 | indent(); |
90 | *out << ")\n" ; |
91 | } |
92 | |
93 | void |
94 | Writer::write(const std::string& name, int value) |
95 | { |
96 | indent(); |
97 | *out << '(' << name << ' ' << value << ")\n" ; |
98 | } |
99 | |
100 | void |
101 | Writer::write(const std::string& name, float value) |
102 | { |
103 | indent(); |
104 | *out << '(' << name << ' ' << value << ")\n" ; |
105 | } |
106 | |
107 | /** This function is needed to properly resolve the overloaded write() |
108 | function, without it the call write("foo", "bar") would call |
109 | write(name, bool), not write(name, string, bool) */ |
110 | void |
111 | Writer::write(const std::string& name, const char* value) |
112 | { |
113 | write(name, value, false); |
114 | } |
115 | |
116 | void |
117 | Writer::write(const std::string& name, const std::string& value, |
118 | bool translatable) |
119 | { |
120 | indent(); |
121 | *out << '(' << name; |
122 | if (translatable) { |
123 | *out << " (_ " ; |
124 | write_escaped_string(value); |
125 | *out << "))\n" ; |
126 | } else { |
127 | *out << " " ; |
128 | write_escaped_string(value); |
129 | *out << ")\n" ; |
130 | } |
131 | } |
132 | |
133 | void |
134 | Writer::write(const std::string& name, bool value) |
135 | { |
136 | indent(); |
137 | *out << '(' << name << ' ' << (value ? "#t" : "#f" ) << ")\n" ; |
138 | } |
139 | |
140 | void |
141 | Writer::write(const std::string& name, |
142 | const std::vector<int>& value) |
143 | { |
144 | indent(); |
145 | *out << '(' << name; |
146 | for (const auto& i : value) |
147 | *out << " " << i; |
148 | *out << ")\n" ; |
149 | } |
150 | |
151 | void |
152 | Writer::write(const std::string& name, |
153 | const std::vector<unsigned int>& value, |
154 | int width) |
155 | { |
156 | indent(); |
157 | *out << '(' << name; |
158 | if (!width) |
159 | { |
160 | for (const auto& i : value) |
161 | *out << " " << i; |
162 | } |
163 | else |
164 | { |
165 | *out << "\n" ; |
166 | indent(); |
167 | int count = 0; |
168 | for (const auto& i : value) { |
169 | *out << i; |
170 | count += 1; |
171 | if (count >= width) { |
172 | *out << "\n" ; |
173 | indent(); |
174 | count = 0; |
175 | } else { |
176 | *out << " " ; |
177 | } |
178 | } |
179 | } |
180 | *out << ")\n" ; |
181 | } |
182 | |
183 | void |
184 | Writer::write(const std::string& name, |
185 | const std::vector<float>& value) |
186 | { |
187 | indent(); |
188 | *out << '(' << name; |
189 | for (const auto& i : value) |
190 | *out << " " << i; |
191 | *out << ")\n" ; |
192 | } |
193 | |
194 | void |
195 | Writer::write(const std::string& name, |
196 | const std::vector<std::string>& value) |
197 | { |
198 | indent(); |
199 | *out << '(' << name; |
200 | for (const auto& i : value) { |
201 | *out << " " ; |
202 | write_escaped_string(i); |
203 | } |
204 | *out << ")\n" ; |
205 | } |
206 | |
207 | void |
208 | Writer::write_sexp(const sexp::Value& value, bool fudge) |
209 | { |
210 | if (value.is_array()) { |
211 | if (fudge) { |
212 | indent_depth -= 1; |
213 | indent(); |
214 | indent_depth += 1; |
215 | } else { |
216 | indent(); |
217 | } |
218 | *out << "(" ; |
219 | auto& arr = value.as_array(); |
220 | for(size_t i = 0; i < arr.size(); ++i) { |
221 | write_sexp(arr[i], false); |
222 | if (i != arr.size() - 1) { |
223 | *out << " " ; |
224 | } |
225 | } |
226 | *out << ")\n" ; |
227 | } else { |
228 | *out << value; |
229 | } |
230 | } |
231 | |
232 | void |
233 | Writer::write(const std::string& name, const sexp::Value& value) |
234 | { |
235 | indent(); |
236 | *out << '(' << name << "\n" ; |
237 | indent_depth += 4; |
238 | write_sexp(value, true); |
239 | indent_depth -= 4; |
240 | indent(); |
241 | *out << ")\n" ; |
242 | } |
243 | |
244 | void |
245 | Writer::write_escaped_string(const std::string& str) |
246 | { |
247 | *out << '"'; |
248 | for (const char* c = str.c_str(); *c != 0; ++c) { |
249 | if (*c == '\"') |
250 | *out << "\\\"" ; |
251 | else if (*c == '\\') |
252 | *out << "\\\\" ; |
253 | else |
254 | *out << *c; |
255 | } |
256 | *out << '"'; |
257 | } |
258 | |
259 | void |
260 | Writer::indent() |
261 | { |
262 | for (int i = 0; i<indent_depth; ++i) |
263 | *out << ' '; |
264 | } |
265 | |
266 | /* EOF */ |
267 | |