如何替换Lua默认错误打印?

时间:2013-12-08 14:50:55

标签: c++ lua win32gui

我正在将Lua作为脚本语言实现到Windows应用程序中。由于应用程序的结构,打印输出不使用流式传输io,例如stdoutstderror

我已设法覆盖Lua print以适应我的结构......

lua_register(L,"print", cs_print);

...但是如何在不使用流的情况下覆盖调试打印输出的所有错误?我需要在一个函数中处理它(类似于print)。

2 个答案:

答案 0 :(得分:6)

Lua写入stderr的唯一地方是luaL_newstate安装的恐慌功能。如果您将Lua嵌入到您的应用程序中,请确保从受保护的呼叫启动Lua并且不会发生任何恐慌。有关提示,请参阅http://www.lua.org/source/5.2/lua.c.html#main

答案 1 :(得分:1)

在很多Google之后,我想出了这个解决方案来获取编译器和运行时错误消息以及重定向标准Lua打印功能。

我使用的是C ++ Builder,但我认为它对于寻找相同答案的人来说非常有用。 该脚本在TScriptLua对象实例中运行,并将Lua状态映射到正确的脚本实例,我使用std :: map列表来查找对象指针。

// list for mapping Lua state with object pointers.
static std::map<lua_State*,TScriptLua*> LuaObjMap;

接下来是一个内联函数,用于从Lua状态指针获取对象指针。

extern "C" {

   // Inline to map Lua state pointer to object pointer
   static inline TScriptLua* GetScriptObject(lua_State* L) {
     return LuaObjMap.find(L)->second;
   }

此功能将取代标准的Lua打印功能。对象指针(f)在其基类中有一个名为Out()的成员函数,它将在相关的窗口控件中输出一个char缓冲区。

   // New Lua print function
   static int cs_print (lua_State *L) {

     // Map Lua state to object
     TScriptLua* f = GetScriptObject(L);

     if (f) {
       int count = lua_gettop(L);
       for (int i=1; i <= count; ++i) {
         const char *str = lua_tostring(L, i); // Get string
         size_t len = lua_rawlen(L,i);         // Get string length

         // Output string.
         f->Out(str,len);
       }
     }

     return 0;
   }

这是我的错误打印例程,它将显示编译器/运行时错误。对于Lua打印功能,再次使用f-> Out来打印错误消息。

   // Error print routine
   static int cs_error(lua_State *L, char *msg) {

     // Map Lua state to object
     TScriptLua* f = GetScriptObject(L);

     // Get error message
     AnsiString m = String(msg) + " " + String(lua_tostring(L, -1));

     // "print" error message
     f->Out(m.c_str(),m.Length());

     // Clenaup Lua stack
     lua_pop(L, 1);

     return 0;
   }

 } // <--- End extern C

这是实际的加载和运行成员。在创建新的Lua状态之后,它与映射列表中的此对象相关联。然后它使用luaL_loadbuffer()从Rich编辑控件加载脚本,检查编译器错误并使用lua_pcall()运行编译的脚本。

void __fastcall TScriptLua::Compile(void) {

   // Create new Lua state
   lua_State *L = luaL_newstate();

   // Store mapping Lua state --> object
   LuaObjMap.insert( std::pair<lua_State*,TScriptLua*>(L,this) );

   // Override Lua Print
   lua_register(L,"print",  cs_print);

   // Load and compile script
   AnsiString script(Frame->Script_RichEdit->Text);
   if (luaL_loadbuffer(L,script.c_str(),script.Length(),AnsiString(Name).c_str()) == 0) {
     if (lua_pcall(L, 0, 0, 0))        // Run loaded Lua script
       cs_error(L, "Runtime error: "); // Print runtime error
   } else {
     cs_error(L, "Compiler error: ");  // Print compiler error
   }

   // Close Lua state
   lua_close(L);

   // Remove Lua --> object mapping
   LuaObjMap.erase( LuaObjMap.find(L) );

 }

这不是我的最终解决方案,但到目前为止它已经成功了。我认为最好的办法是将流处理写入TScriptLua对象,这样我就可以直接将它注册到Lua中。