script_modify.cpp

Go to the documentation of this file.
00001 
00002 //            Copyright (C) 2004-2007 by The Allacrost Project
00003 //                         All Rights Reserved
00004 //
00005 // This code is licensed under the GNU GPL version 2. It is free software
00006 // and you may modify it and/or redistribute it under the terms of this license.
00007 // See http://www.gnu.org/copyleft/gpl.html for details.
00009 
00017 #include "script.h"
00018 #include "script_modify.h"
00019 #include "script_read.h"
00020 #include "script_write.h"
00021 
00022 using namespace std;
00023 using namespace luabind;
00024 
00025 using namespace hoa_utils;
00026 
00027 namespace hoa_script {
00028 
00029 ModifyScriptDescriptor::~ModifyScriptDescriptor() {
00030   if (IsFileOpen()) {
00031     if (SCRIPT_DEBUG)
00032       cerr << "SCRIPT WARNING: ModifyScriptDescriptor destructor was called when file was still open: "
00033         << _filename << endl;
00034     CloseFile();
00035   }
00036   
00037   _filename = "";
00038   _access_mode = SCRIPT_CLOSED;
00039   _error_messages.clear();
00040   _open_tables.clear();
00041 }
00042 
00043 //-----------------------------------------------------------------------------
00044 // File Access Functions
00045 //-----------------------------------------------------------------------------
00046 
00047 bool ModifyScriptDescriptor::OpenFile(const std::string& file_name) {
00048   if (ScriptManager->IsFileOpen(file_name) == true) {
00049     if (SCRIPT_DEBUG)
00050       cerr << "SCRIPT WARNING: ModifyScriptDescriptor::OpenFile() attempted to open file that is already opened: "
00051         << file_name << endl;
00052     return false;
00053   }
00054 
00055   // Increases the global stack size by 1 element. That is needed because the new thread will be pushed in the
00056   // stack and we have to be sure there is enough space there.
00057   lua_checkstack(ScriptManager->GetGlobalState(),1);
00058   _lstack = lua_newthread(ScriptManager->GetGlobalState());
00059 
00060   // Attempt to load the Lua file.
00061   if (lua_dofile(_lstack, file_name.c_str()) != 0) {
00062     cerr << "SCRIPT ERROR: ModifyScriptDescriptor::OpenFile() could not open the file " << file_name << endl;
00063     _access_mode = SCRIPT_CLOSED;
00064     return false;
00065   }
00066 
00067   _filename = file_name;
00068   _access_mode = SCRIPT_READ;
00069   ScriptManager->_AddOpenFile(this);
00070   return true;
00071 } // bool ModifyScriptDescriptor::OpenFile(std::string file_name)
00072 
00073 
00074 
00075 bool ModifyScriptDescriptor::OpenFile() {
00076   if (_filename == "") {
00077     if (SCRIPT_DEBUG)
00078       cerr << "SCRIPT ERROR: ModifyScriptDescriptor::OpenFile(), could not open file "
00079         << "because of an invalid file name (empty string)." << endl;
00080     return false;
00081   }
00082 
00083   return OpenFile(_filename);
00084 }
00085 
00086 
00087 
00088 void ModifyScriptDescriptor::CloseFile() {
00089   if (IsFileOpen() == false) {
00090     if (SCRIPT_DEBUG)
00091       cerr << "SCRIPT ERROR: ModifyScriptDescriptor::CloseFile() could not close the "
00092         << "file because it was not open." << endl;
00093     return;
00094   }
00095 
00096   if (SCRIPT_DEBUG && IsErrorDetected()) {
00097     cerr << "SCRIPT WARNING: In ModifyScriptDescriptor::CloseFile(), the file " << _filename
00098       << " had error messages remaining. They are as follows:" << endl;
00099     cerr << _error_messages.str() << endl;
00100   }
00101 
00102   _lstack = NULL;
00103   _error_messages.clear();
00104   _open_tables.clear();
00105   _access_mode = SCRIPT_CLOSED;
00106   ScriptManager->_RemoveOpenFile(this);
00107 }
00108 
00109 //-----------------------------------------------------------------------------
00110 // Commit Function Definitions
00111 //-----------------------------------------------------------------------------
00112 
00113 void ModifyScriptDescriptor::CommitChanges(bool leave_closed) {
00114   WriteScriptDescriptor file; // The file to write the modified Lua state out to
00115   string temp_filename = "TEMP" + _filename;
00116 
00117   if (file.OpenFile(temp_filename) == false) {
00118     if (SCRIPT_DEBUG)
00119       _error_messages << "* ModifyScriptDescriptor::CommitChanges() failed because it could not open "
00120         << "the file to write the modifications to" << endl;
00121     return;
00122   }
00123 
00124   // Write the global tables to the file. This in turn will write all other tables that are members of
00125   // the global tables, or members of those tables, and so on.
00126   object globals(luabind::from_stack(_lstack, LUA_GLOBALSINDEX));
00127   _CommitTable(file, globals);
00128 
00129   file.CloseFile(); // Close the temporary file we were writing to
00130   CloseFile(); // Close this file as well as it is about to be over-written
00131 
00132   // Now overwrite this file with the temporary file written, remove the temporary file, and re-open the new file
00133   
00134   if (MoveFile(temp_filename, _filename) == false) {
00135     _error_messages << "* ModifyScriptDescriptor::CommitChanges() failed because after writing the temporary file "
00136       << temp_filename << ", it could not be moved to overwrite the original filename " << _filename << endl;
00137   }
00138 
00139   if (leave_closed == false)
00140     OpenFile();
00141 } // void ModifyScriptDescriptor::CommitChanges(bool leave_closed)
00142 
00143 
00144 
00145 void ModifyScriptDescriptor::_CommitTable(WriteScriptDescriptor& file, const luabind::object& table) {
00146   bool key_is_numeric;  // Set to true when a variable's key is not a string
00147   int32 num_key = 0;    // Holds the current numeric key
00148   string str_key = "";  // Holds the current string key
00149 
00150   for (luabind::iterator it(table), end; it != end; ++it) {
00151     try {
00152       num_key = object_cast<int32>(it.key());
00153       key_is_numeric = true;
00154     } catch (...) {
00155       str_key = object_cast<string>(it.key());
00156       key_is_numeric = false;
00157     }
00158   
00159     switch (luabind::type(*it)) {
00160       case LUA_TBOOLEAN:
00161         if (key_is_numeric)
00162           file.WriteBool(num_key, object_cast<bool>(*it));
00163         else
00164           file.WriteBool(str_key, object_cast<bool>(*it));
00165         break;
00166       case LUA_TNUMBER:
00167         try {
00168           if (key_is_numeric)
00169             file.WriteInt(num_key, object_cast<int32>(*it));
00170           else
00171             file.WriteInt(str_key, object_cast<int32>(*it));
00172         } catch (...) {
00173           if (key_is_numeric)
00174             file.WriteFloat(num_key, object_cast<float>(*it));
00175           else
00176             file.WriteFloat(str_key, object_cast<float>(*it));
00177         }
00178         break;
00179       case LUA_TSTRING:
00180         if (key_is_numeric)
00181           file.WriteString(num_key, object_cast<string>(*it));
00182         else
00183           file.WriteString(str_key, object_cast<string>(*it));
00184         break;
00185       case LUA_TTABLE:
00186         if (key_is_numeric)
00187           file.BeginTable(num_key);
00188         else
00189           file.BeginTable(str_key);
00190         _CommitTable(file, object(*it));
00191         file.EndTable();
00192         break;
00193       case LUA_TNIL:
00194       case LUA_TFUNCTION:
00195       case LUA_TUSERDATA:
00196       case LUA_TLIGHTUSERDATA:
00197       case LUA_TTHREAD:
00198       default:
00199         if (SCRIPT_DEBUG) {
00200           _error_messages << "* ModifyScriptDescriptor::_CommitTable() detected a ";
00201           if (type(*it) == LUA_TNIL) {
00202             _error_messages << "nil value ";
00203           } else if (type(*it) == LUA_TFUNCTION) {
00204             _error_messages << "function ";
00205           } else if (type(*it) == LUA_TFUNCTION) {
00206             _error_messages << "function ";
00207           } else if (type(*it) == LUA_TUSERDATA) {
00208             _error_messages << "user data ";
00209           } else if (type(*it) == LUA_TLIGHTUSERDATA) {
00210             _error_messages << "light user data ";
00211           } else if (type(*it) == LUA_TTHREAD) {
00212             _error_messages << "thread ";
00213           } else {
00214             _error_messages << "unknown data type ";
00215           }
00216           
00217           if (key_is_numeric)
00218             _error_messages << "key: " << num_key;
00219           else
00220             _error_messages << str_key;
00221           _error_messages << ". It was not written to the modified file." << endl;
00222         }
00223         break;
00224     } // switch (luabind::type(*it))
00225   } // for (luabind::iterator it(table), end; it != end; ++it)
00226 } // void ModifyScriptDescriptor::_CommitTable(WriteScriptDescriptor& file, luabind::object& table)
00227 
00228 } // namespace hoa_script

Generated on Fri Jul 6 23:11:22 2007 for Hero of Allacrost by  doxygen 1.5.1