1 #include "pch.h"
2 #include "ScriptLoader.hpp"
3 
4 #include <iostream>
5 #include <vector>
6 #include <map>
7 #include <exception>
8 #include <fstream>
9 
10 #include <boost/filesystem.hpp>
11 
12 namespace sh
13 {
loadAllFiles(ScriptLoader * c,const std::string & path)14 	void ScriptLoader::loadAllFiles(ScriptLoader* c, const std::string& path)
15 	{
16 		for ( boost::filesystem::recursive_directory_iterator end, dir(path); dir != end; ++dir )
17 		{
18 			boost::filesystem::path p(*dir);
19 			if(p.extension() == c->mFileEnding)
20 			{
21 				c->mCurrentFileName = (*dir).path().string();
22 				std::ifstream in((*dir).path().string().c_str(), std::ios::binary);
23 				c->parseScript(in);
24 			}
25 		}
26 	}
27 
ScriptLoader(const std::string & fileEnding)28 	ScriptLoader::ScriptLoader(const std::string& fileEnding)
29 		: mLoadOrder(0)
30 		, mToken(TOKEN_NewLine)
31 		, mLastToken(TOKEN_NewLine)
32 
33 	{
34 		mFileEnding = fileEnding;
35 	}
36 
~ScriptLoader()37 	ScriptLoader::~ScriptLoader()
38 	{
39 		clearScriptList();
40 	}
41 
clearScriptList()42 	void ScriptLoader::clearScriptList()
43 	{
44 		std::map <std::string, ScriptNode *>::iterator i;
45 		for (i = m_scriptList.begin(); i != m_scriptList.end(); ++i)
46 		{
47 			delete i->second;
48 		}
49 		m_scriptList.clear();
50 	}
51 
getConfigScript(const std::string & name)52 	ScriptNode *ScriptLoader::getConfigScript(const std::string &name)
53 	{
54 		std::map <std::string, ScriptNode*>::iterator i;
55 
56 		std::string key = name;
57 		i = m_scriptList.find(key);
58 
59 		//If found..
60 		if (i != m_scriptList.end())
61 		{
62 			return i->second;
63 		}
64 		else
65 		{
66 			return NULL;
67 		}
68 	}
69 
getAllConfigScripts()70 	std::map <std::string, ScriptNode*> ScriptLoader::getAllConfigScripts ()
71 	{
72 		return m_scriptList;
73 	}
74 
parseScript(std::ifstream & stream)75 	void ScriptLoader::parseScript(std::ifstream &stream)
76 	{
77 		//Get first token
78 		_nextToken(stream);
79 		if (mToken == TOKEN_EOF)
80 		{
81 			stream.close();
82 			return;
83 		}
84 
85 		//Parse the script
86 		_parseNodes(stream, 0);
87 
88 		stream.close();
89 	}
90 
_nextToken(std::ifstream & stream)91 	void ScriptLoader::_nextToken(std::ifstream &stream)
92 	{
93 		//EOF token
94 		if (!stream.good())
95 		{
96 			mToken = TOKEN_EOF;
97 			return;
98 		}
99 
100 		//(Get next character)
101 		int ch = stream.get();
102 
103 		while ((ch == ' ' || ch == 9) && !stream.eof())
104 		{    //Skip leading spaces / tabs
105 			ch = stream.get();
106 		}
107 
108 		if (!stream.good())
109 		{
110 			mToken = TOKEN_EOF;
111 			return;
112 		}
113 
114 		//Newline token
115 		if (ch == '\r' || ch == '\n')
116 		{
117 			do
118 			{
119 				ch = stream.get();
120 			} while ((ch == '\r' || ch == '\n') && !stream.eof());
121 
122 			stream.unget();
123 
124 			mToken = TOKEN_NewLine;
125 			return;
126 		}
127 
128 		//Open brace token
129 		else if (ch == '{')
130 		{
131 			mToken = TOKEN_OpenBrace;
132 			return;
133 		}
134 
135 		//Close brace token
136 		else if (ch == '}')
137 		{
138 			mToken = TOKEN_CloseBrace;
139 			return;
140 		}
141 
142 		//Text token
143 		if (ch < 32 || ch > 122)    //Verify valid char
144 		{
145 			throw std::runtime_error("Parse Error: Invalid character, ConfigLoader::load()");
146 		}
147 
148 		mTokenValue = "";
149 		mToken = TOKEN_Text;
150 		do
151 		{
152 			//Skip comments
153 			if (ch == '/')
154 			{
155 				int ch2 = stream.peek();
156 
157 				//C++ style comment (//)
158 				if (ch2 == '/')
159 				{
160 					stream.get();
161 					do
162 					{
163 						ch = stream.get();
164 					} while (ch != '\r' && ch != '\n' && !stream.eof());
165 
166 					mToken = TOKEN_NewLine;
167 					return;
168 				}
169 			}
170 
171 			//Add valid char to tokVal
172 			mTokenValue += (char)ch;
173 
174 			//Next char
175 			ch = stream.get();
176 
177 		} while (ch > 32 && ch <= 122 && !stream.eof());
178 
179 		stream.unget();
180 
181 		return;
182 	}
183 
_skipNewLines(std::ifstream & stream)184 	void ScriptLoader::_skipNewLines(std::ifstream &stream)
185 	{
186 		while (mToken == TOKEN_NewLine)
187 		{
188 			_nextToken(stream);
189 		}
190 	}
191 
_parseNodes(std::ifstream & stream,ScriptNode * parent)192 	void ScriptLoader::_parseNodes(std::ifstream &stream, ScriptNode *parent)
193 	{
194 		typedef std::pair<std::string, ScriptNode*> ScriptItem;
195 
196 		while (true)
197 		{
198 			switch (mToken)
199 			{
200 				//Node
201 				case TOKEN_Text:
202 				{
203 					//Add the new node
204 					ScriptNode *newNode;
205 					if (parent)
206 					{
207 						newNode = parent->addChild(mTokenValue);
208 					}
209 					else
210 					{
211 						newNode = new ScriptNode(0, mTokenValue);
212 					}
213 
214 					//Get values
215 					_nextToken(stream);
216 					std::string valueStr;
217 					int i=0;
218 					while (mToken == TOKEN_Text)
219 					{
220 						if (i == 0)
221 							valueStr += mTokenValue;
222 						else
223 							valueStr += " " + mTokenValue;
224 						_nextToken(stream);
225 						++i;
226 					}
227 					newNode->setValue(valueStr);
228 
229 					_skipNewLines(stream);
230 
231 					//Add any sub-nodes
232 					if (mToken == TOKEN_OpenBrace)
233 					{
234 						//Parse nodes
235 						_nextToken(stream);
236 						_parseNodes(stream, newNode);
237 						//Check for matching closing brace
238 						if (mToken != TOKEN_CloseBrace)
239 						{
240 							throw std::runtime_error("Parse Error: Expecting closing brace");
241 						}
242 						_nextToken(stream);
243 						_skipNewLines(stream);
244 					}
245 
246 					newNode->mFileName = mCurrentFileName;
247 
248 					//Add root nodes to scriptList
249 					if (!parent)
250 					{
251 						std::string key;
252 
253 						if (newNode->getValue() == "")
254 								throw std::runtime_error("Root node must have a name (\"" + newNode->getName() + "\")");
255 						key = newNode->getValue();
256 
257 						if (!m_scriptList.insert(ScriptItem(key, newNode)).second)
258 						{
259 							std::cout << "Script node '" << key << "' already exists" << std::endl;
260 							delete newNode;
261 							newNode = NULL;
262 						}
263 					}
264 
265 					break;
266 				}
267 
268 				//Out of place brace
269 				case TOKEN_OpenBrace:
270 					throw std::runtime_error("Parse Error: Opening brace out of plane");
271 					break;
272 
273 				//Return if end of nodes have been reached
274 				case TOKEN_CloseBrace:
275 					return;
276 
277 				//Return if reached end of file
278 				case TOKEN_EOF:
279 					return;
280 
281 				case TOKEN_NewLine:
282 					_nextToken(stream);
283 					break;
284 			}
285 		};
286 	}
287 
ScriptNode(ScriptNode * parent,const std::string & name)288 	ScriptNode::ScriptNode(ScriptNode *parent, const std::string &name)
289 	{
290 		mName = name;
291 		mParent = parent;
292 	}
293 
~ScriptNode()294 	ScriptNode::~ScriptNode()
295 	{
296 		//Delete all children
297 		std::vector<ScriptNode*>::iterator i;
298 		for (i = mChildren.begin(); i != mChildren.end(); ++i)
299 		{
300 			ScriptNode *node = *i;
301 			delete node;
302 		}
303 		mChildren.clear();
304 	}
305 
addChild(const std::string & name)306 	ScriptNode *ScriptNode::addChild(const std::string &name)
307 	{
308 		ScriptNode* node = new ScriptNode(this, name);
309 		mChildren.push_back(node);
310 		return node;
311 	}
312 
findChild(const std::string & name)313 	ScriptNode *ScriptNode::findChild(const std::string &name)
314 	{
315 		int childCount = (int)mChildren.size();
316 
317 		//Search for the node from start to finish
318 		for (int indx = 0; indx < childCount; ++indx){
319 			ScriptNode *node = mChildren[indx];
320 			if (node->mName == name)
321 				return node;
322 		}
323 
324 		//Not found anywhere
325 		return NULL;
326 	}
327 }
328