1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (C) 2004-2010 by The Allacrost Project
3 // All Rights Reserved
4 //
5 // This code is licensed under the GNU GPL version 2. It is free software
6 // and you may modify it and/or redistribute it under the terms of this license.
7 // See http://www.gnu.org/copyleft/gpl.html for details.
8 ///////////////////////////////////////////////////////////////////////////////
9
10 /** ****************************************************************************
11 *** \file script_write.cpp
12 *** \author Daniel Steuernol - steu@allacrost.org,
13 *** Tyler Olsen - roots@allacrost.org
14 *** \brief Source file for the WriteScriptDescriptor class.
15 *** ***************************************************************************/
16
17 #include <fstream>
18
19 #include "utils.h"
20
21 #include "script.h"
22 #include "script_write.h"
23
24 using namespace std;
25
26 using namespace hoa_utils;
27
28 namespace hoa_script {
29
~WriteScriptDescriptor()30 WriteScriptDescriptor::~WriteScriptDescriptor() {
31 if (IsFileOpen()) {
32 if (SCRIPT_DEBUG)
33 cerr << "SCRIPT WARNING: WriteScriptDescriptor destructor was called when file was still open: "
34 << _filename << endl;
35 CloseFile();
36 }
37
38 _filename = "";
39 _access_mode = SCRIPT_CLOSED;
40 _error_messages.clear();
41 _open_tables.clear();
42 }
43
44 //-----------------------------------------------------------------------------
45 // File Access Functions
46 //-----------------------------------------------------------------------------
47
OpenFile(const string & file_name)48 bool WriteScriptDescriptor::OpenFile(const string& file_name) {
49 if (ScriptManager->IsFileOpen(file_name) == true) {
50 if (SCRIPT_DEBUG)
51 cerr << "SCRIPT WARNING: WriteScriptDescriptor::OpenFile() attempted to open file that is already opened: "
52 << file_name << endl;
53 return false;
54 }
55
56 // In debug mode, first check if the file exists before overwriting it
57 if (SCRIPT_DEBUG) {
58 ifstream temp_file;
59 temp_file.open(file_name.c_str());
60 if (temp_file) {
61 cerr << "SCRIPT WARNING: In WriteScriptDescriptor::OpenFile(), the file to be opened "
62 << "already exists and will be overwritten: " << file_name << endl;
63 }
64 temp_file.close();
65 }
66
67 _outfile.open(file_name.c_str());
68 if (!_outfile) {
69 cerr << "SCRIPT ERROR: WriteScriptDescriptor::OpenFile() failed to open the file "
70 << file_name << " for writing." << endl;
71 _access_mode = SCRIPT_CLOSED;
72 return false;
73 }
74
75 _filename = file_name;
76 _access_mode = SCRIPT_WRITE;
77 ScriptManager->_AddOpenFile(this);
78 return true;
79 } // bool WriteScriptDescriptor::OpenFile(string file_name)
80
81
82
OpenFile()83 bool WriteScriptDescriptor::OpenFile() {
84 if (_filename == "") {
85 if (SCRIPT_DEBUG)
86 cerr << "SCRIPT ERROR: WriteScriptDescriptor::OpenFile() could not open file "
87 << "because of an invalid file name (empty string)." << endl;
88 return false;
89 }
90
91 return OpenFile(_filename);
92 }
93
94
95
CloseFile()96 void WriteScriptDescriptor::CloseFile() {
97 if (IsFileOpen() == false) {
98 if (SCRIPT_DEBUG)
99 cerr << "SCRIPT ERROR: in WriteScriptDescriptor::CloseFile(), could not close the "
100 << "file because it was not open." << endl;
101 return;
102 }
103
104 if (SCRIPT_DEBUG && IsErrorDetected()) {
105 cerr << "SCRIPT WARNING: In WriteScriptDescriptor::CloseFile(), the file " << _filename
106 << " had error messages remaining. They are as follows:" << endl;
107 cerr << _error_messages.str() << endl;
108 }
109
110 _outfile.close();
111 _error_messages.clear();
112 _open_tables.clear();
113 _access_mode = SCRIPT_CLOSED;
114 ScriptManager->_RemoveOpenFile(this);
115 }
116
117
118
SaveFile()119 bool WriteScriptDescriptor::SaveFile() {
120 if (IsFileOpen() == false) {
121 PRINT_ERROR << "could not save the file because it was not open" << endl;
122 return false;
123 }
124
125 if (SCRIPT_DEBUG && IsErrorDetected()) {
126 cerr << "SCRIPT WARNING: In WriteScriptDescriptor::CloseFile(), the file " << _filename
127 << " had error messages remaining. They are as follows:" << endl;
128 cerr << _error_messages.str() << endl;
129 }
130
131 _outfile.flush();
132 return _outfile.bad();
133 }
134
135 //-----------------------------------------------------------------------------
136 // Comment Write Functions
137 //-----------------------------------------------------------------------------
138
InsertNewLine()139 void WriteScriptDescriptor::InsertNewLine() {
140 _outfile << endl;
141 }
142
143
144
WriteComment(const string & comment)145 void WriteScriptDescriptor::WriteComment(const string& comment) {
146 _outfile << "-- " << comment << endl;
147 }
148
149
150
BeginCommentBlock()151 void WriteScriptDescriptor::BeginCommentBlock() {
152 if (_inside_comment_block == true) {
153 _error_messages << "* WriteScriptDescriptor::BeginCommentBlock() was already "
154 << "inside a comment block when it was called" << endl;
155 return;
156 }
157
158 _inside_comment_block = true;
159 _outfile << "--[[" << endl;
160 }
161
162
163
EndCommentBlock()164 void WriteScriptDescriptor::EndCommentBlock() {
165 if (_inside_comment_block == false) {
166 _error_messages << "* WriteScriptDescriptor::EndCommentBlock() was not "
167 << "inside a comment block when it was called" << endl;
168 return;
169 }
170
171 _inside_comment_block = false;
172 _outfile << "--]]" << endl;
173 }
174
175
176
WriteLine(const string & comment,bool new_line)177 void WriteScriptDescriptor::WriteLine(const string& comment, bool new_line) {
178 _outfile << comment;
179 if (new_line)
180 _outfile << endl;
181 }
182
183 //-----------------------------------------------------------------------------
184 // Variable Write Functions
185 //-----------------------------------------------------------------------------
186
187 // WriteBool can not use the _WriteData helper because true/false values must
188 // be explicitly written to the file
WriteBool(const string & key,bool value)189 void WriteScriptDescriptor::WriteBool(const string& key, bool value) {
190 if (_open_tables.size() == 0) {
191 _outfile << key << " = ";
192 if (value)
193 _outfile << "true" << endl;
194 else
195 _outfile << "false" << endl;
196 }
197 else {
198 _WriteTablePath();
199 _outfile << '.' << key << " = ";
200 if (value)
201 _outfile << "true" << endl;
202 else
203 _outfile << "false" << endl;
204 }
205 }
206
207
208
WriteBool(const int32 key,bool value)209 void WriteScriptDescriptor::WriteBool(const int32 key, bool value) {
210 if (_open_tables.empty()) {
211 _error_messages << "* WriteScriptDescriptor::WriteBool() failed because there were no "
212 << "tables open when attempting to write the key/value: " << key << " = " << value << std::endl;
213 return;
214 }
215
216 _WriteTablePath();
217 _outfile << '[' << key << ']' << " = ";
218 if (value)
219 _outfile << "true" << endl;
220 else
221 _outfile << "false" << endl;
222 }
223
224 // WriteString can not use the _WriteData helper because it needs to do additional
225 // checking and add quotation marks around its value.
226 // TODO: Check for bad strings (ie, if it contains puncutation charcters like , or ])
WriteString(const string & key,const string & value)227 void WriteScriptDescriptor::WriteString(const string& key, const string& value) {
228 if (_open_tables.size() == 0) {
229 _outfile << key << " = \"" << value << "\"" << endl;
230 }
231 else {
232 _WriteTablePath();
233 _outfile << '.' << key << " = \"" << value << "\"" << endl;
234 }
235 }
236
237
238
WriteString(const int32 key,const string & value)239 void WriteScriptDescriptor::WriteString(const int32 key, const string& value) {
240 if (_open_tables.empty()) {
241 _error_messages << "* WriteScriptDescriptor::WriteString() failed because there were no "
242 << "tables open when attempting to write the key/value: [" << key << "] = " << value << std::endl;
243 return;
244 }
245
246 _WriteTablePath();
247 _outfile << '[' << key << ']' << " = \"" << value << "\"" << endl;
248 }
249
250 // WriteUString can not use the _WriteData helper because it needs to do additional
251 // checking and add quotation marks around its value.
252 // TODO: Write strings with a call to the gettext library to retrieve translated strings
WriteUString(const string & key,const string & value)253 void WriteScriptDescriptor::WriteUString(const string& key, const string& value) {
254 WriteString(key, value);
255 }
256
257
258
WriteUString(const int32 key,const string & value)259 void WriteScriptDescriptor::WriteUString(const int32 key, const string& value) {
260 WriteString(key, value);
261 }
262
263 //-----------------------------------------------------------------------------
264 // Vector Write Functions
265 //-----------------------------------------------------------------------------
266
267 // WriteBoolVector can not use the _WriteDataVector helper because true/false values must
268 // be explicitly written to the file
WriteBoolVector(const string & key,std::vector<bool> & vect)269 void WriteScriptDescriptor::WriteBoolVector(const string& key, std::vector<bool>& vect) {
270 if (vect.empty()) {
271 _error_messages << "* WriteScriptDescriptor::WriteBoolVector() failed because "
272 << "the vector argument was empty for key name: " << key << endl;
273 return;
274 }
275
276 if (_open_tables.size() == 0) {
277 _outfile << key << " = { ";
278 }
279 else {
280 _WriteTablePath();
281 _outfile << '.' << key << " = { ";
282 }
283
284 if (vect[0])
285 _outfile << "true";
286 else
287 _outfile << "false";
288 for (uint32 i = 1; i < vect.size(); i++) {
289 if (vect[i])
290 _outfile << ", true";
291 else
292 _outfile << ", false";
293 }
294 _outfile << " }" << endl;
295 }
296
297
298
WriteBoolVector(const int32 key,std::vector<bool> & vect)299 void WriteScriptDescriptor::WriteBoolVector(const int32 key, std::vector<bool>& vect) {
300 if (_open_tables.empty()) {
301 _error_messages << "* WriteScriptDescriptor::WriteBoolVector() failed because there were no "
302 << "tables open when attempting for key name: " << key << endl;
303 return;
304 }
305
306 _WriteTablePath();
307 _outfile << '[' << key << "] = { ";
308
309 if (vect[0])
310 _outfile << "true";
311 else
312 _outfile << "false";
313 for (uint32 i = 1; i < vect.size(); i++) {
314 if (vect[i])
315 _outfile << ", true";
316 else
317 _outfile << ", false";
318 }
319 _outfile << " }" << endl;
320 }
321
322 // WriteString can not use the _WriteData helper because it needs to do additional
323 // checking and add quotation marks around its value.
324 // TODO: Check for bad strings (ie, if it contains puncutation charcters like , or ])
WriteStringVector(const string & key,std::vector<string> & vect)325 void WriteScriptDescriptor::WriteStringVector(const string &key, std::vector<string>& vect) {
326 if (vect.empty()) {
327 _error_messages << "* WriteScriptDescriptor::WriteStringVector() failed because there were no "
328 << "tables open when attempting for key name: " << key << endl;
329 return;
330 }
331
332 if (_open_tables.size() == 0) {
333 _outfile << key << " = { ";
334 }
335 else {
336 _WriteTablePath();
337 _outfile << '.' << key << " = { ";
338 }
339
340 _outfile << "\"" << vect[0] << "\"";
341 for (uint32 i = 1; i < vect.size(); i++) {
342 _outfile << ", \"" << vect[i] << "\"";
343 }
344 _outfile << " }" << endl;
345 }
346
347
348
WriteStringVector(const int32 key,std::vector<string> & vect)349 void WriteScriptDescriptor::WriteStringVector(const int32 key, std::vector<string>& vect) {
350 if (vect.empty()) {
351 _error_messages << "* WriteScriptDescriptor::WriteStringVector() failed because there were no "
352 << "tables open when attempting for key name: " << key << endl;
353 return;
354 }
355 if (_open_tables.empty()) {
356 _error_messages << "* WriteScriptDescriptor::WriteSringVector() failed because there were no "
357 << "tables open when attempting for key name: " << key << endl;
358 return;
359 }
360
361 _WriteTablePath();
362 _outfile << '[' << key << "] = { ";
363
364 _outfile << "\"" << vect[0] << "\"";
365 for (uint32 i = 1; i < vect.size(); i++) {
366 _outfile << ", \"" << vect[i] << "\"";
367 }
368 _outfile << " }" << endl;
369 }
370
371
372
373 // WriteUString can not use the _WriteData helper because it needs to do additional
374 // checking and add quotation marks around its value.
375 // TODO: Write strings with a call to the gettext library to retrieve translated strings
WriteUStringVector(const string & key,std::vector<string> & vect)376 void WriteScriptDescriptor::WriteUStringVector(const string& key, std::vector<string>& vect) {
377 WriteStringVector(key, vect);
378 }
379
380
381
WriteUStringVector(const int32 key,std::vector<string> & vect)382 void WriteScriptDescriptor::WriteUStringVector(const int32 key, std::vector<string>& vect) {
383 WriteStringVector(key, vect);
384 }
385
WriteNamespace(const string & ns)386 void WriteScriptDescriptor::WriteNamespace(const string &ns)
387 {
388 _outfile << "local ns = {};" << endl;
389 _outfile << "setmetatable(ns, {__index = _G});" << endl;
390 _outfile << ns << " = ns;" << endl;
391 _outfile << "setfenv(1, ns);" << endl;
392 }
393
394 //-----------------------------------------------------------------------------
395 // Table Write Functions
396 //-----------------------------------------------------------------------------
397
BeginTable(const string & key)398 void WriteScriptDescriptor::BeginTable(const string &key) {
399 if (_open_tables.size() == 0) {
400 _outfile << key << " = {}" << endl;
401 }
402 else {
403 _WriteTablePath();
404 _outfile << '.' << key << " = {}" << endl;
405 }
406
407 _open_tables.push_back(key);
408 }
409
410
411
BeginTable(int32 key)412 void WriteScriptDescriptor::BeginTable(int32 key) {
413 if (_open_tables.size() == 0)
414 _outfile << key << " = {}" << endl;
415 else {
416 _WriteTablePath();
417 _outfile << '[' << key << "] = {}" << endl;
418 }
419
420 _open_tables.push_back(NumberToString<int32>(key));
421 }
422
423
424 // This doesn't actually do any file write operations, but the user still needs to call it.
EndTable()425 void WriteScriptDescriptor::EndTable() {
426 if (_open_tables.empty()) {
427 _error_messages << "* WriteScriptDescriptor::EndTable() failed because no tables were open" << endl;
428 }
429 else {
430 _open_tables.pop_back();
431 }
432 }
433
434 //-----------------------------------------------------------------------------
435 // Miscellaneous Functions
436 //-----------------------------------------------------------------------------
437
438 // Writes the path for all the open tables. For example, "table01[table02][table03]"
_WriteTablePath()439 void WriteScriptDescriptor::_WriteTablePath() {
440 if (_open_tables.empty()) {
441 _error_messages << "* WriteScriptDescriptor::_WriteTablePath() failed because there were no "
442 << "tables open" << endl;
443 return;
444 }
445
446 _outfile << _open_tables[0];
447 for (uint32 i = 1; i < _open_tables.size(); i++) {
448 if (IsStringNumeric(_open_tables[i]))
449 _outfile << '[' << _open_tables[i] << ']';
450 else
451 _outfile << '.' << _open_tables[i];
452 }
453 }
454
455 } // namespace hoa_script
456