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 
Writer(const std::string & filename)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 
Writer(std::ostream & newout)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 
~Writer()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
write_comment(const std::string & comment)55 Writer::write_comment(const std::string& comment)
56 {
57   *out << "; " << comment << "\n";
58 }
59 
60 void
start_list(const std::string & listname,bool string)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
end_list(const std::string & listname)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
write(const std::string & name,int value)94 Writer::write(const std::string& name, int value)
95 {
96   indent();
97   *out << '(' << name << ' ' << value << ")\n";
98 }
99 
100 void
write(const std::string & name,float value)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
write(const std::string & name,const char * value)111 Writer::write(const std::string& name, const char* value)
112 {
113   write(name, value, false);
114 }
115 
116 void
write(const std::string & name,const std::string & value,bool translatable)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
write(const std::string & name,bool value)134 Writer::write(const std::string& name, bool value)
135 {
136   indent();
137   *out << '(' << name << ' ' << (value ? "#t" : "#f") << ")\n";
138 }
139 
140 void
write(const std::string & name,const std::vector<int> & value)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
write(const std::string & name,const std::vector<unsigned int> & value,int width)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
write(const std::string & name,const std::vector<float> & value)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
write(const std::string & name,const std::vector<std::string> & value)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
write_sexp(const sexp::Value & value,bool fudge)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
write(const std::string & name,const sexp::Value & value)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
write_escaped_string(const std::string & str)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
indent()260 Writer::indent()
261 {
262   for (int i = 0; i<indent_depth; ++i)
263     *out << ' ';
264 }
265 
266 /* EOF */
267