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
25Writer::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
35Writer::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
45Writer::~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
54void
55Writer::write_comment(const std::string& comment)
56{
57 *out << "; " << comment << "\n";
58}
59
60void
61Writer::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
75void
76Writer::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
93void
94Writer::write(const std::string& name, int value)
95{
96 indent();
97 *out << '(' << name << ' ' << value << ")\n";
98}
99
100void
101Writer::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) */
110void
111Writer::write(const std::string& name, const char* value)
112{
113 write(name, value, false);
114}
115
116void
117Writer::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
133void
134Writer::write(const std::string& name, bool value)
135{
136 indent();
137 *out << '(' << name << ' ' << (value ? "#t" : "#f") << ")\n";
138}
139
140void
141Writer::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
151void
152Writer::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
183void
184Writer::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
194void
195Writer::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
207void
208Writer::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
232void
233Writer::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
244void
245Writer::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
259void
260Writer::indent()
261{
262 for (int i = 0; i<indent_depth; ++i)
263 *out << ' ';
264}
265
266/* EOF */
267