Changeset 5654 for code/branches/resource2/src/core/LuaState.cc
- Timestamp:
- Aug 17, 2009, 4:37:10 PM (15 years ago)
- File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
code/branches/resource2/src/core/LuaState.cc
r5645 r5654 22 22 * Author: 23 23 * Benjamin Knecht 24 * Reto Grieder 24 25 * Co-authors: 25 26 * ... … … 27 28 */ 28 29 29 #include "LuaBind.h" 30 31 #include <fstream> 32 #include <map> 30 #include "LuaState.h" 31 32 #include <tolua/tolua++.h> 33 33 extern "C" { 34 #include <lua.h> 34 35 #include <lualib.h> 35 36 } 36 #include <tolua/tolua++.h>37 #include <boost/filesystem.hpp>38 37 39 38 #include "util/Debug.h" 40 #include "util/StringUtils.h"41 39 #include "Core.h" 40 #include "Resource.h" 42 41 43 42 namespace orxonox 44 43 { 45 LuaBind* LuaBind::singletonPtr_s = NULL; 46 47 LuaBind::LuaBind() 48 { 49 this->includePath_ = Core::getDataPathString(); 50 51 luaState_ = lua_open(); 52 luaSource_ = ""; 44 LuaState::ToluaInterfaceMap LuaState::toluaInterfaces_s; 45 std::vector<LuaState*> LuaState::instances_s; 46 47 LuaState::LuaState() 48 : bIsRunning_(false) 49 , includeParseFunction_(NULL) 50 { 51 // Create new lua state and configure it 52 luaState_ = lua_open(); 53 53 #if LUA_VERSION_NUM == 501 54 luaL_openlibs(luaState_);54 luaL_openlibs(luaState_); 55 55 #else 56 luaopen_base(luaState_);57 luaopen_string(luaState_);58 luaopen_table(luaState_);59 luaopen_math(luaState_);60 luaopen_io(luaState_);61 luaopen_debug(luaState_);56 luaopen_base(luaState_); 57 luaopen_string(luaState_); 58 luaopen_table(luaState_); 59 luaopen_math(luaState_); 60 luaopen_io(luaState_); 61 luaopen_debug(luaState_); 62 62 #endif 63 63 64 // Open all available tolua interfaces 65 this->openToluaInterfaces(luaState_); 66 67 output_ = ""; 68 isRunning_ = false; 69 } 70 71 LuaBind::~LuaBind() 72 { 73 this->closeToluaInterfaces(luaState_); 74 }; 75 76 void LuaBind::luaPrint(const std::string& str) 77 { 78 output_ += str; 79 // COUT(4) << "Lua_output!:" << std::endl << str << std::endl << "***" << std::endl; 80 COUT(5) << str; 81 } 82 83 /** 84 @brief Loads the specified file line by line 85 @param filename The filename of the file 86 @param luaTags if true, the loaded file gets stripped off luaTags 87 */ 88 void LuaBind::loadFile(const std::string& filename, bool luaTags) 89 { 90 boost::filesystem::path filepath(filename); 91 92 output_ = ""; 93 std::ifstream file; 94 file.open(filepath.string().c_str(), std::fstream::in); 95 96 if (!file.is_open()) 97 { 98 // some error msg 99 } 100 101 std::string levelString = ""; 102 103 while (file.good() && !file.eof()) 104 { 105 std::string line; 106 std::getline(file, line); 107 levelString += line; 108 levelString += "\n"; 109 } 110 111 file.close(); 112 //std::string output; 113 114 if (luaTags) 115 luaSource_ = replaceLuaTags(levelString); 116 else 117 luaSource_ = levelString; 118 COUT(5) << "ParsedSourceCode: " << luaSource_ << std::endl; 119 } 120 121 void LuaBind::loadString(const std::string& code) 122 { 123 luaSource_ = code; 124 output_ = ""; 125 } 126 64 // Open all available tolua interfaces 65 this->openToluaInterfaces(luaState_); 66 67 // Create dummy file info 68 sourceFileInfo_.reset(new ResourceInfo()); 69 sourceFileInfo_->group = "General"; 70 sourceFileInfo_->size = 0; 71 72 // Push this pointer 73 tolua_pushusertype(luaState_, static_cast<void*>(this), "orxonox::LuaState"); 74 lua_setglobal(luaState_, "luaState"); 75 76 // Parse init script 77 // Note: We have to use a hard coded path because the script is required for the resource loading 78 this->doString("dofile(\"" + Core::getDataPathString() + "lua/LuaStateInit.lua\")"); 79 } 80 81 LuaState::~LuaState() 82 { 83 lua_close(luaState_); 84 } 85 86 shared_ptr<ResourceInfo> LuaState::getFileInfo(const std::string& filename, const std::string& resourceGroup, bool bSearchOtherPaths) 87 { 88 shared_ptr<ResourceInfo> sourceInfo; 89 if (resourceGroup != "NoResourceGroupProvided") 90 sourceInfo = Resource::getInfo(filename, resourceGroup); 91 92 // Continue search if not explicitely forbidden 93 if (bSearchOtherPaths && sourceInfo == NULL) 94 { 95 // Call might be relative to the file currently being processed 96 sourceInfo = Resource::getInfo(sourceFileInfo_->path + filename, sourceFileInfo_->group); 97 if (sourceInfo == NULL) 98 { 99 // Maybe find something in the same group but in the root path 100 sourceInfo = Resource::getInfo(filename, sourceFileInfo_->group); 101 } 102 } 103 return sourceInfo; 104 } 105 106 void LuaState::includeFile(const std::string& filename, const std::string& resourceGroup, bool bSearchOtherPaths) 107 { 108 shared_ptr<ResourceInfo> sourceInfo = this->getFileInfo(filename, resourceGroup, bSearchOtherPaths); 109 if (sourceInfo != NULL) 110 this->includeString(Resource::open(sourceInfo->filename, sourceInfo->group)->getAsString(), sourceInfo); 111 else 112 COUT(2) << "LuaState: Cannot include file '" << filename << "' in resource group '" 113 << (resourceGroup == "NoResourceGroupProvided" ? sourceFileInfo_->group : resourceGroup) << "': group not found." << std::endl; 114 } 115 116 void LuaState::includeString(const std::string& code, shared_ptr<ResourceInfo> sourceFileInfo) 117 { 118 // Parse string with provided include parser (otherwise don't preparse at all) 119 std::string luaInput; 120 if (includeParseFunction_ != NULL) 121 luaInput = (*includeParseFunction_)(code); 122 else 123 luaInput = code; 124 125 this->doString(luaInput, sourceFileInfo); 126 } 127 128 void LuaState::doFile(const std::string& filename, const std::string& resourceGroup, bool bSearchOtherPaths) 129 { 130 shared_ptr<ResourceInfo> sourceInfo = this->getFileInfo(filename, resourceGroup, bSearchOtherPaths); 131 if (sourceInfo != NULL) 132 this->doString(Resource::open(sourceInfo->filename, sourceInfo->group)->getAsString(), sourceInfo); 133 else 134 COUT(2) << "LuaState: Cannot do file '" << filename << "' in resource group '" 135 << (resourceGroup == "NoResourceGroupProvided" ? sourceFileInfo_->group : resourceGroup) << "': group not found." << std::endl; 136 } 137 138 void LuaState::doString(const std::string& code, shared_ptr<ResourceInfo> sourceFileInfo) 139 { 140 // Save the oold source file info 141 shared_ptr<ResourceInfo> oldSourceFileInfo = sourceFileInfo_; 142 // Only override if sourceFileInfo provides useful information 143 if (sourceFileInfo != NULL) 144 sourceFileInfo_ = sourceFileInfo; 145 146 //if (!bIsRunning_) 147 //{ 148 // bIsRunning_ = true; 149 150 int error = 0; 127 151 #if LUA_VERSION_NUM != 501 128 const char * LuaBind::lua_Chunkreader(lua_State *L, void *data, size_t *size) 129 { 130 LoadS* ls = static_cast<LoadS*>(data); 131 if (ls->size == 0) return NULL; 132 *size = ls->size; 133 ls->size = 0; 134 return ls->s; 135 } 152 LoadS ls; 153 ls.s = code.c_str(); 154 ls.size = code.size(); 155 error = lua_load(luaState_, &orxonox::LuaState::lua_Chunkreader, &ls, code.c_str()); 156 #else 157 error = luaL_loadstring(luaState_, code.c_str()); 136 158 #endif 137 void LuaBind::run() 138 { 139 if (!isRunning_) 140 { 141 isRunning_ = true; 142 int error = 0; 143 std::string init = 144 "local scr = orxonox.LuaBind:getInstance()\n \ 145 local debug = print\n \ 146 print = function(s)\n \ 147 scr:luaPrint(s)\n \ 148 end\n \ 149 include = function(f)\n \ 150 file = assert(io.open(\"" + this->includePath_ + "\"..\"/\"..f))\n \ 151 content = file:read(\"*a\")\n \ 152 file:close()\n \ 153 source = scr:replaceLuaTags(content)\n \ 154 assert(loadstring(source))()\n \ 155 end\n"; 156 init += luaSource_; 157 #if LUA_VERSION_NUM == 501 158 error = luaL_loadstring(luaState_, init.c_str()); 159 #else 160 LoadS ls; 161 ls.s = init.c_str(); 162 ls.size = init.size(); 163 error = lua_load(luaState_, &orxonox::LuaBind::lua_Chunkreader, &ls, init.c_str()); 164 #endif 165 if (error == 0) 166 { 167 error = lua_pcall(luaState_, 0, 0, 0); 168 } 169 if (error != 0) 170 { 171 COUT(2) << "Error in Lua-script: " << lua_tostring(luaState_, -1) << std::endl; 172 } 173 isRunning_ = false; 174 } 175 else 176 { 177 COUT(2) << "Warning: Lua's run is called while running!" << std::endl; 178 } 179 } 180 181 std::string LuaBind::replaceLuaTags(const std::string& text) 182 { 183 // chreate map with all Lua tags 184 std::map<size_t, bool> luaTags; 185 { 186 size_t pos = 0; 187 while ((pos = text.find("<?lua", pos)) != std::string::npos) 188 luaTags[pos++] = true; 189 } 190 { 191 size_t pos = 0; 192 while ((pos = text.find("?>", pos)) != std::string::npos) 193 luaTags[pos++] = false; 194 } 195 196 // erase all tags from the map that are between two quotes 197 { 198 std::map<size_t, bool>::iterator it = luaTags.begin(); 199 std::map<size_t, bool>::iterator it2 = it; 200 bool bBetweenQuotes = false; 201 size_t pos = 0; 202 while ((pos = getNextQuote(text, pos)) != std::string::npos) 203 { 204 while ((it != luaTags.end()) && (it->first < pos)) 205 { 206 if (bBetweenQuotes) { 207 it2++; 208 if(it->second && !(it2->second) && it2->first < pos) 209 it = ++it2; 210 else 211 luaTags.erase(it++); 212 } 213 else 214 ++it; 215 } 216 bBetweenQuotes = !bBetweenQuotes; 217 pos++; 218 } 219 } 220 221 // check whether on every opening <?lua tag a closing ?> tag follows 222 { 223 bool expectedValue = true; 224 for (std::map<size_t, bool>::iterator it = luaTags.begin(); it != luaTags.end(); ++it) 225 { 226 if (it->second == expectedValue) 227 expectedValue = !expectedValue; 228 else 229 { 230 expectedValue = false; 231 break; 232 } 233 } 234 if (!expectedValue) { 235 COUT(2) << "Warning: Error in level file" << std::endl; 236 // todo: errorhandling 237 return ""; 238 } 239 } 240 241 // cut the original string into pieces and put them together with print() instead of lua tags 242 std::string output; 243 { 244 std::map<size_t, bool>::iterator it = luaTags.begin(); 245 bool bInPrintFunction = true; 246 size_t start = 0; 247 size_t end = 0; 248 249 do 250 { 251 if (it != luaTags.end()) 252 end = (*(it++)).first; 253 else 254 end = std::string::npos; 255 256 unsigned int equalSignCounter = 0; 257 258 if (bInPrintFunction) 259 { 260 // count ['='[ and ]'='] and replace tags with print([[ and ]]) 261 std::string temp = text.substr(start, end - start); 262 { 263 size_t pos = 0; 264 while ((pos = temp.find('[', pos)) != std::string::npos) 159 160 // execute the chunk 161 if (error == 0) 162 error = lua_pcall(luaState_, 0, 0, 0); 163 if (error != 0) 164 { 165 std::string origin; 166 if (sourceFileInfo != NULL) 167 origin = " originating from " + sourceFileInfo_->filename; 168 COUT(2) << "Error in Lua-script" << origin << ": " << lua_tostring(luaState_, -1) << std::endl; 169 } 170 171 // bIsRunning_ = false; 172 //} 173 //else 174 //{ 175 // COUT(2) << "Warning: LuaState do function called while running!" << std::endl; 176 //} 177 178 // Load the old info again 179 sourceFileInfo_ = oldSourceFileInfo; 180 } 181 182 void LuaState::luaPrint(const std::string& str) 183 { 184 output_ << str; 185 } 186 187 void LuaState::luaLog(unsigned int level, const std::string& message) 188 { 189 OutputHandler::getOutStream().setOutputLevel(level) << message << std::endl; 190 } 191 192 #if LUA_VERSION_NUM != 501 193 const char * LuaState::lua_Chunkreader(lua_State *L, void *data, size_t *size) 194 { 195 LoadS* ls = static_cast<LoadS*>(data); 196 if (ls->size == 0) 197 return NULL; 198 *size = ls->size; 199 ls->size = 0; 200 return ls->s; 201 } 202 #endif 203 204 /*static*/ bool LuaState::addToluaInterface(int (*function)(lua_State*), const std::string& name) 205 { 206 for (ToluaInterfaceMap::const_iterator it = toluaInterfaces_s.begin(); it != toluaInterfaces_s.end(); ++it) 207 { 208 if (it->first == name || it->second == function) 265 209 { 266 unsigned int tempCounter = 1; 267 size_t tempPos = pos++; 268 while(temp[++tempPos] == '=') { 269 tempCounter++; 270 } 271 if(temp[tempPos] != '[') { 272 tempCounter = 0; 273 } 274 else if(tempCounter == 0) { 275 tempCounter = 1; 276 } 277 if (tempCounter > equalSignCounter) 278 equalSignCounter = tempCounter; 210 COUT(2) << "Warning: Trying to add a Tolua interface with the same name or function." << std::endl; 211 return true; 279 212 } 280 } 281 { 282 size_t pos = 0; 283 while ((pos = temp.find(']', pos)) != std::string::npos) 284 { 285 unsigned int tempCounter = 1; 286 size_t tempPos = pos++; 287 while(temp[++tempPos] == '=') { 288 tempCounter++; 289 } 290 if(temp[tempPos] != ']') { 291 tempCounter = 0; 292 } 293 else if(tempCounter == 0) { 294 tempCounter = 1; 295 } 296 if (tempCounter > equalSignCounter) 297 equalSignCounter = tempCounter; 298 } 299 } 300 std::string equalSigns = ""; 301 for(unsigned int i = 0; i < equalSignCounter; i++) { 302 equalSigns += "="; 303 } 304 output += "print([" + equalSigns + "[" + temp + "]" + equalSigns +"])"; 305 start = end + 5; 306 } 307 else 308 { 309 output += text.substr(start, end - start); 310 start = end + 2; 311 } 312 313 bInPrintFunction = !bInPrintFunction; 314 } 315 while (end != std::string::npos); 316 } 317 318 return output; 319 } 320 321 void LuaBind::addToluaInterface(int (*function)(lua_State*), const std::string& name) 322 { 323 toluaInterfaces_.push_back(std::make_pair(name, function)); 324 // Apply changes to our own lua state as well 325 (*function)(luaState_); 326 } 327 328 void LuaBind::openToluaInterfaces(lua_State* state) 329 { 330 for (unsigned int i = 0; i < toluaInterfaces_.size(); ++i) 331 (*toluaInterfaces_[i].second)(state); 332 } 333 334 void LuaBind::closeToluaInterfaces(lua_State* state) 335 { 336 for (unsigned int i = 0; i < toluaInterfaces_.size(); ++i) 337 { 338 lua_pushnil(state); 339 lua_setglobal(state, toluaInterfaces_[i].first.c_str()); 340 } 341 } 342 213 } 214 toluaInterfaces_s[name] = function; 215 216 // Open interface in all LuaStates 217 for (std::vector<LuaState*>::const_iterator it = instances_s.begin(); it != instances_s.end(); ++it) 218 (*function)((*it)->luaState_); 219 220 // Return dummy bool 221 return true; 222 } 223 224 /*static*/ bool LuaState::removeToluaInterface(const std::string& name) 225 { 226 ToluaInterfaceMap::iterator it = toluaInterfaces_s.find(name); 227 if (it == toluaInterfaces_s.end()) 228 { 229 COUT(2) << "Warning: Cannot remove Tolua interface '" << name << "': Not found" << std::endl; 230 return true; 231 } 232 233 // Close interface in all LuaStates 234 for (std::vector<LuaState*>::const_iterator itState = instances_s.begin(); itState != instances_s.end(); ++itState) 235 { 236 lua_pushnil((*itState)->luaState_); 237 lua_setglobal((*itState)->luaState_, it->first.c_str()); 238 } 239 240 // Remove entry 241 toluaInterfaces_s.erase(it); 242 243 // Return dummy bool 244 return true; 245 } 246 247 /*static*/ void LuaState::openToluaInterfaces(lua_State* state) 248 { 249 for (ToluaInterfaceMap::const_iterator it = toluaInterfaces_s.begin(); it != toluaInterfaces_s.end(); ++it) 250 (*it->second)(state); 251 } 252 253 /*static*/ void LuaState::closeToluaInterfaces(lua_State* state) 254 { 255 for (ToluaInterfaceMap::const_iterator it = toluaInterfaces_s.begin(); it != toluaInterfaces_s.end(); ++it) 256 { 257 lua_pushnil(state); 258 lua_setglobal(state, it->first.c_str()); 259 } 260 } 343 261 }
Note: See TracChangeset
for help on using the changeset viewer.