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