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