wxldebug.cpp

Go to the documentation of this file.
00001 /////////////////////////////////////////////////////////////////////////////
00002 // Name:        wxLuaDebug.cpp
00003 // Purpose:     Debugging I/O functions for wxLua
00004 // Author:      J. Winwood, Ray Gilbert, John Labenski
00005 // Created:     May 2002
00006 // Copyright:   (c) 2002 Lomtick Software. All rights reserved.
00007 // Licence:     wxWidgets licence
00008 /////////////////////////////////////////////////////////////////////////////
00009 
00010 #include "wx/wxprec.h"
00011 
00012 #ifdef __BORLANDC__
00013     #pragma hdrstop
00014 #endif
00015 
00016 #ifndef WX_PRECOMP
00017     #include "wx/wx.h"
00018 #endif
00019 
00020 #include "wxluadebug/include/wxldebug.h"
00021 #include "wxlua/include/wxlcallb.h"
00022 
00023 wxLuaDebugData wxNullLuaDebugData(false);
00024 
00025 // ----------------------------------------------------------------------------
00026 // wxLuaDebugItem
00027 // ----------------------------------------------------------------------------
00028 wxLuaDebugItem::wxLuaDebugItem(const wxString &itemKey, int itemKeyType,
00029                                const wxString &itemValue, int itemValueType,
00030                                const wxString &itemSource,
00031                                int lua_ref, int idx, int flag)
00032                    :m_itemKey(itemKey), m_itemKeyType(itemKeyType),
00033                     m_itemValue(itemValue), m_itemValueType(itemValueType),
00034                     m_itemSource(itemSource),
00035                     m_lua_ref(lua_ref), m_index(idx), m_flag(flag)
00036 {
00037 }
00038 
00039 wxLuaDebugItem::wxLuaDebugItem(const wxLuaDebugItem &dataItem)
00040                :m_itemKey(dataItem.m_itemKey), m_itemKeyType(dataItem.m_itemKeyType),
00041                 m_itemValue(dataItem.m_itemValue), m_itemValueType(dataItem.m_itemValueType),
00042                 m_itemSource(dataItem.m_itemSource),
00043                 m_lua_ref(dataItem.m_lua_ref), m_index(dataItem.m_index),
00044                 m_flag(dataItem.m_flag)
00045 {
00046 }
00047 
00048 bool wxLuaDebugItem::GetRefPtr(long& ptr) const
00049 {
00050     bool key_ref = GetFlagBit(WXLUA_DEBUGITEM_KEY_REF);
00051     bool val_ref = GetFlagBit(WXLUA_DEBUGITEM_VALUE_REF);
00052 
00053     // sanity checks
00054     wxCHECK_MSG((key_ref || val_ref), false, wxT("wxLuaDebugItem has neither key or value reference"));
00055     wxCHECK_MSG(!(key_ref && val_ref), false, wxT("wxLuaDebugItem has both key and value reference"));
00056 
00057     return wxString(key_ref ? m_itemKey: m_itemValue).BeforeFirst(wxT(' ')).ToLong(&ptr, 16);
00058 }
00059 
00060 // ----------------------------------------------------------------------------
00061 // wxLuaDebugData - Debug Info sent via socket to debugger client
00062 // ----------------------------------------------------------------------------
00063 
00064 class wxLuaDebugDataRefData : public wxObjectRefData
00065 {
00066 public:
00067     wxLuaDebugDataRefData() : m_dataArray(wxLuaDebugData::SortFunction) {}
00068 
00069     virtual ~wxLuaDebugDataRefData()
00070     {
00071         size_t idx, count = m_dataArray.GetCount();
00072         for (idx = 0; idx < count; ++idx)
00073         {
00074             const wxLuaDebugItem *pData = m_dataArray.Item(idx);
00075             delete pData;
00076         }
00077     }
00078 
00079     wxLuaDebugItemArray m_dataArray;
00080 };
00081 
00082 #define M_DEBUGREFDATA ((wxLuaDebugDataRefData*)m_refData)
00083 
00084 wxLuaDebugData::wxLuaDebugData(bool create) : wxObject()
00085 {
00086     if (create)
00087         m_refData = new wxLuaDebugDataRefData;
00088 }
00089 
00090 wxLuaDebugItemArray* wxLuaDebugData::GetArray()
00091 {
00092     wxCHECK_MSG(M_DEBUGREFDATA != NULL, NULL, wxT("Invalid ref data"));
00093     return &(M_DEBUGREFDATA->m_dataArray);
00094 }
00095 const wxLuaDebugItemArray* wxLuaDebugData::GetArray() const
00096 {
00097     wxCHECK_MSG(M_DEBUGREFDATA != NULL, NULL, wxT("Invalid ref data"));
00098     return &(M_DEBUGREFDATA->m_dataArray);
00099 }
00100 
00101 size_t wxLuaDebugData::GetCount() const
00102 {
00103     wxCHECK_MSG(M_DEBUGREFDATA != NULL, 0, wxT("Invalid ref data"));
00104     return M_DEBUGREFDATA->m_dataArray.GetCount();
00105 }
00106 wxLuaDebugItem* wxLuaDebugData::Item(size_t index) const
00107 {
00108     wxCHECK_MSG(M_DEBUGREFDATA != NULL, NULL, wxT("Invalid ref data"));
00109     return M_DEBUGREFDATA->m_dataArray.Item(index);
00110 }
00111 void wxLuaDebugData::Add(wxLuaDebugItem* item)
00112 {
00113     wxCHECK_RET(M_DEBUGREFDATA != NULL, wxT("Invalid ref data"));
00114     wxCHECK_RET(item != NULL, wxT("Invalid wxLuaDebugItem"));
00115     M_DEBUGREFDATA->m_dataArray.Add(item);
00116 }
00117 
00118 wxLuaDebugData wxLuaDebugData::Copy() const
00119 {
00120     wxCHECK_MSG(M_DEBUGREFDATA != NULL, wxNullLuaDebugData, wxT("Invalid ref data"));
00121 
00122     wxLuaDebugData copyData(true);
00123 
00124     size_t idx, count = GetCount();
00125     for (idx = 0; idx < count; ++idx)
00126     {
00127         const wxLuaDebugItem *pOldData = M_DEBUGREFDATA->m_dataArray.Item(idx);
00128         if (pOldData != NULL)
00129             copyData.Add(new wxLuaDebugItem(*pOldData));
00130     }
00131 
00132     return copyData;
00133 }
00134 
00135 int wxLuaDebugData::SortFunction(wxLuaDebugItem *elem1, wxLuaDebugItem *elem2 )
00136 {
00137     int ret = 0;
00138 
00139     long l1 = 0, l2 = 0;
00140 
00141     if ((elem1->m_itemKeyType == WXLUA_TNUMBER) &&
00142         (elem2->m_itemKeyType == WXLUA_TNUMBER) &&
00143         elem1->m_itemKey.BeforeFirst(wxT(' ')).ToLong(&l1) &&
00144         elem2->m_itemKey.BeforeFirst(wxT(' ')).ToLong(&l2))
00145         ret = l1 - l2;
00146     else
00147         ret = elem1->m_itemKey.Cmp(elem2->m_itemKey);
00148 
00149     if (ret == 0) // can be true for unnamed "(*temporary)" vars
00150     {
00151         ret = elem1->m_itemKeyType - elem2->m_itemKeyType;
00152 
00153         if (ret == 0)
00154         {
00155             ret = elem1->m_itemValueType - elem2->m_itemValueType;
00156 
00157             if (ret == 0)
00158             {
00159                 ret = elem1->m_itemValue.Cmp(elem2->m_itemValue);
00160 
00161                 if (ret == 0)
00162                     ret = int(elem2->GetFlagBit(WXLUA_DEBUGITEM_KEY_REF)) -
00163                           int(elem1->GetFlagBit(WXLUA_DEBUGITEM_KEY_REF));
00164             }
00165         }
00166     }
00167 
00168     return ret;
00169 }
00170 
00171 int wxLuaDebugData::EnumerateStack(const wxLuaState& wxlState_)
00172 {
00173     wxCHECK_MSG(wxlState_.Ok(), 0, wxT("Invalid wxLuaState"));
00174     wxCHECK_MSG(M_DEBUGREFDATA != NULL, 0, wxT("Invalid ref data"));
00175 
00176     wxLuaState wxlState(wxlState_); // unconst the state
00177     lua_State* L = wxlState.GetLuaState();
00178     lua_Debug luaDebug = INIT_LUA_DEBUG;
00179     int       stack_frame = 0;
00180     int       count = 0;
00181 
00182     while (lua_getstack(L, stack_frame, &luaDebug) != 0)
00183     {
00184         if (lua_getinfo(L, "Sln", &luaDebug))
00185         {
00186             //wxPrintf(wxString(lua_Debug_to_wxString(luaDebug) + wxT("\n")).c_str());
00187 
00188             // skip stack frames that do not have line number, always add first
00189             int  currentLine = luaDebug.currentline;
00190             if ((count == 0) || (currentLine != -1))
00191             {
00192                 wxString name;
00193                 wxString source(lua2wx(luaDebug.source));
00194 
00195                 if (currentLine == -1)
00196                     currentLine = 0;
00197 
00198                 if (luaDebug.name != NULL)
00199                     name = wxString::Format(_("function %s line %d"), lua2wx(luaDebug.name).c_str(), currentLine);
00200                 else
00201                     name = wxString::Format(_("line %d"), currentLine);
00202 
00203                 Add(new wxLuaDebugItem(name, WXLUA_TNONE, wxT(""), WXLUA_TNONE, source, LUA_NOREF, stack_frame, WXLUA_DEBUGITEM_LOCALS));
00204                 ++count;
00205             }
00206         }
00207 
00208         ++stack_frame;
00209     }
00210 
00211     return count;
00212 }
00213 
00214 int wxLuaDebugData::EnumerateStackEntry(const wxLuaState& wxlState_, int stack_frame, wxArrayInt& references)
00215 {
00216     wxCHECK_MSG(wxlState_.Ok(), 0, wxT("Invalid wxLuaState"));
00217     wxCHECK_MSG(M_DEBUGREFDATA != NULL, 0, wxT("Invalid ref data"));
00218 
00219     wxLuaState wxlState(wxlState_); // unconst the state
00220     lua_State* L = wxlState.GetLuaState();
00221     lua_Debug luaDebug = INIT_LUA_DEBUG;
00222     int count = 0;
00223 
00224     if (lua_getstack(L, stack_frame, &luaDebug) != 0)
00225     {
00226         int stack_idx  = 1;
00227         wxString name(lua2wx(lua_getlocal(L, &luaDebug, stack_idx)));
00228         while (!name.IsEmpty())
00229         {
00230             //wxPrintf(wxString(lua_Debug_to_wxString(luaDebug) + wxT(" lua_getlocal :") + name + wxT("\n")).c_str());
00231 
00232             int wxl_valuetype = WXLUA_TNONE;
00233             wxString value;
00234             wxString source(lua2wx(luaDebug.source));
00235 
00236             GetTypeValue(wxlState, -1, &wxl_valuetype, value);
00237 
00238             // FIXME! local tables get the right values for GetTypeValue(...)
00239             // but when you run wxluaR_ref() to store them they disappear
00240             // so that the next time wxluaR_ref() is run it reuses the same
00241             // index as your local table.
00242             // When using the stack dialog the next wxluaR_ref() is the
00243             // global table which is very confusing.
00244 
00245             int flag_type = 0;
00246             int nRef = LUA_NOREF; //RefTable(L, -1, &flag_type, references);
00247 
00248             lua_pop(L, 1); // remove variable value
00249 
00250             Add(new wxLuaDebugItem(name, WXLUA_TNONE, value, wxl_valuetype, source, nRef, 0, flag_type));
00251             ++count;
00252 
00253             name = lua2wx(lua_getlocal(L, &luaDebug, ++stack_idx));
00254         }
00255     }
00256 
00257     return count;
00258 }
00259 
00260 wxString wxLuaBindClassString(wxLuaBindClass* wxlClass)
00261 {
00262     wxCHECK_MSG(wxlClass, wxEmptyString, wxT("Invalid wxLuaBindClass"));
00263     wxString baseClasses;
00264     if (wxlClass->baseclassNames)
00265     {
00266         for (size_t i = 0; wxlClass->baseclassNames[i]; ++i)
00267             baseClasses += lua2wx(wxlClass->baseclassNames[i]) + wxT(",");
00268     }
00269 
00270     return wxString::Format(wxT(" (%s, wxluatype=%d, classinfo=%s, baseclass=%s, methods=%d, enums=%d)"),
00271                             lua2wx(wxlClass->name).c_str(), *wxlClass->wxluatype,
00272                             wxString(wxlClass->classInfo ? wxlClass->classInfo->GetClassName() : wxEmptyString).c_str(),
00273                             baseClasses.c_str(),
00274                             wxlClass->wxluamethods_n, wxlClass->enums_n);
00275 }
00276 
00277 int wxLuaDebugData::EnumerateTable(const wxLuaState& wxlState_, int tableRef, int nIndex, wxArrayInt& references)
00278 {
00279     wxCHECK_MSG(wxlState_.Ok(), 0, wxT("Invalid wxLuaState"));
00280     wxCHECK_MSG(M_DEBUGREFDATA != NULL, 0, wxT("Invalid ref data"));
00281 
00282     wxLuaState wxlState(wxlState_); // unconst the state
00283     lua_State* L = wxlState.GetLuaState();
00284     int count = 0;
00285 
00286     int wxl_keytype   = WXLUA_TNONE;
00287     int wxl_valuetype = WXLUA_TNONE;
00288     wxString value;
00289     wxString name;
00290 
00291     if ((tableRef == -1) || (tableRef == LUA_GLOBALSINDEX))
00292     {
00293         lua_pushvalue(L, LUA_GLOBALSINDEX);
00294         GetTypeValue(wxlState, -1, &wxl_valuetype, value);
00295 
00296         int flag_type = 0;
00297         int val_ref = RefTable(L, -1, &flag_type, WXLUA_DEBUGITEM_VALUE_REF, references);
00298         lua_pop(L, 1); // pop globals table
00299 
00300         Add(new wxLuaDebugItem(wxT("Globals"), WXLUA_TNONE, value, WXLUA_TTABLE, wxT(""), val_ref, 0, flag_type));
00301     }
00302     else if (tableRef == LUA_REGISTRYINDEX)
00303     {
00304         lua_pushvalue(L, LUA_REGISTRYINDEX);
00305         GetTypeValue(wxlState, -1, &wxl_valuetype, value);
00306 
00307         int flag_type = 0;
00308         int val_ref = RefTable(L, -1, &flag_type, WXLUA_DEBUGITEM_VALUE_REF, references);
00309         lua_pop(L, 1); // pop registry table
00310 
00311         Add(new wxLuaDebugItem(wxT("Registry"), WXLUA_TNONE, value, WXLUA_TTABLE, wxT(""), val_ref, 0, flag_type));
00312     }
00313     else
00314     {
00315         // push the table onto the stack to iterate through
00316         if (wxluaR_getref(L, tableRef, &wxlua_lreg_debug_refs_key))
00317         {
00318             if (lua_isnil(L, -1))
00319             {
00320                 // assert so we don't crash mysteriously inside Lua on nil
00321                 lua_pop(L, 1); // pop nil
00322                 wxFAIL_MSG(wxT("Invalid wxLua debug reference"));
00323                 return count;
00324             }
00325 
00326             // Check to see if this is a wxLua LUA_REGISTRYINDEX table
00327             void *lightuserdata_reg_key = NULL;
00328             lua_pushlightuserdata(L, &wxlua_lreg_regtable_key); // push key
00329             lua_rawget(L, LUA_REGISTRYINDEX);
00330             lua_pushvalue(L, -2); // push value (table we're iterating)
00331             lua_rawget(L, -2);
00332             lightuserdata_reg_key = lua_touserdata(L, -1);
00333             lua_pop(L, 2); // pop wxlua_lreg_regtable_key table and (nil or lightuserdata)
00334 
00335             // Check if the table/userdata has a metatable
00336             if (lua_getmetatable(L, -1)) // if no metatable then nothing is pushed
00337             {
00338                 // get the type and value
00339                 GetTypeValue(wxlState, -1, &wxl_valuetype, value);
00340 
00341                 int flag_type = 0;
00342                 int val_ref = RefTable(L, -1, &flag_type, WXLUA_DEBUGITEM_VALUE_REF, references);
00343 
00344                 // leading space so it's first when sorted
00345                 Add(new wxLuaDebugItem(wxT(" __metatable"), WXLUA_TTABLE, value, wxl_valuetype, wxT(""), val_ref, nIndex, flag_type));
00346                 ++count;
00347 
00348                 lua_pop(L, 1); // pop metatable
00349             }
00350 
00351             // start iterating
00352             if (lua_istable(L, -1))
00353             {
00354             lua_pushnil(L);
00355             while (lua_next(L, -2) != 0)
00356             {
00357                 // value at -1, key at -2, table at -3
00358 
00359                 // get the key type and value
00360                 int lua_key_type = GetTypeValue(wxlState, -2, &wxl_keytype, name);
00361                 // get the value type and value
00362                 int lua_value_type = GetTypeValue(wxlState, -1, &wxl_valuetype, value);
00363 
00364                 // Handle wxLua LUA_REGISTRYINDEX tables to give more information
00365                 if (lightuserdata_reg_key != NULL)
00366                 {
00367                     if (lightuserdata_reg_key == &wxlua_lreg_types_key)
00368                     {
00369                         value += wxT(" (") + wxluaT_typename(L, (int)lua_tonumber(L, -2)) + wxT(")");
00370                     }
00371                     else if (lightuserdata_reg_key == &wxlua_lreg_classes_key)
00372                     {
00373                         wxLuaBindClass* wxlClass = (wxLuaBindClass*)lua_touserdata(L, -1);
00374                         value += wxLuaBindClassString(wxlClass);
00375                     }
00376                     else if (lightuserdata_reg_key == &wxlua_lreg_wxluabindings_key)
00377                     {
00378                         wxLuaBinding* binding = (wxLuaBinding*)lua_touserdata(L, -2);
00379                         name = wxT("wxLuaBinding(")+name+wxT(") -> ")+binding->GetBindingName();
00380                         value += wxT(" = ") + binding->GetLuaNamespace();
00381                     }
00382                     else if (lightuserdata_reg_key == &wxlua_lreg_evtcallbacks_key)
00383                     {
00384                         wxLuaEventCallback* wxlCallback = (wxLuaEventCallback*)lua_touserdata(L, -2);
00385                         wxCHECK_MSG(wxlCallback, count, wxT("Invalid wxLuaEventCallback"));
00386 
00387                         wxString s(wxlCallback->GetInfo());
00388                         name  = s.BeforeFirst(wxT('|'));
00389                         value = s.AfterFirst(wxT('|'));
00390                     }
00391                     else if (lightuserdata_reg_key == &wxlua_lreg_windestroycallbacks_key)
00392                     {
00393                         // only handle t[wxWindow*] = wxLuaWinDestroyCallback*
00394                         wxLuaWinDestroyCallback* wxlDestroyCallBack = (wxLuaWinDestroyCallback*)lua_touserdata(L, -1);
00395                         wxCHECK_MSG(wxlDestroyCallBack, count, wxT("Invalid wxLuaWinDestroyCallback"));
00396 
00397                         wxString s(wxlDestroyCallBack->GetInfo());
00398                         name  = s.BeforeFirst(wxT('|'));
00399                         value = s.AfterFirst(wxT('|'));
00400                     }
00401                     else if (lightuserdata_reg_key == &wxlua_lreg_topwindows_key)
00402                     {
00403                         wxWindow* win = (wxWindow*)lua_touserdata(L, -2);
00404                         name += wxT(" ") + wxString(win->GetClassInfo()->GetClassName());
00405                     }
00406                     else if (lightuserdata_reg_key == &wxlua_lreg_gcobjects_key)
00407                     {
00408                         wxObject* obj = (wxObject*)lua_touserdata(L, -1);
00409                         name = wxString(obj->GetClassInfo()->GetClassName()) + wxT("(") + name + wxT(")");
00410                     }
00411                 }
00412 
00413                 // For these keys we know what is in the value to give more information
00414                 if (lua_key_type == LUA_TLIGHTUSERDATA)
00415                 {
00416                     void* key = lua_touserdata(L, -2);
00417 
00418                     if (key == &wxlua_metatable_type_key)
00419                     {
00420                         value += wxT(" (") + wxluaT_typename(L, (int)lua_tonumber(L, -1)) + wxT(")");
00421                     }
00422                     else if (key == &wxlua_metatable_wxluabindclass_key)
00423                     {
00424                         wxLuaBindClass* wxlClass = (wxLuaBindClass*)lua_touserdata(L, -1);
00425                         value += wxLuaBindClassString(wxlClass);
00426                     }
00427                     else if (key == &wxlua_lreg_debug_refs_key)
00428                     {
00429                         value += wxT(" Note: You cannot traverse refed tables");
00430                     }
00431                 }
00432 
00433                 // ----------------------------------------------------------
00434                 // Handle the key
00435 
00436                 int key_flag_type = 0;
00437                 int key_ref = LUA_NOREF;
00438 
00439                 // don't ref anything in this table since it's already refed
00440                 if ((lua_key_type == LUA_TTABLE) && (lightuserdata_reg_key != &wxlua_lreg_debug_refs_key))
00441                     key_ref = RefTable(L, -2, &key_flag_type, WXLUA_DEBUGITEM_KEY_REF, references);
00442                 else if (lua_key_type == LUA_TUSERDATA)
00443                 {
00444                     if (lua_getmetatable(L, -2)) // doesn't push anything if nil
00445                     {
00446                         key_ref = RefTable(L, -2, &key_flag_type, WXLUA_DEBUGITEM_KEY_REF, references);
00447                         lua_pop(L, 1);
00448                     }
00449                 }
00450 
00451                 // only add the key if we refed it so it can be viewed in the stack dialog
00452                 if (key_flag_type != 0)
00453                 {
00454                     Add(new wxLuaDebugItem(name, wxl_keytype, value, wxl_valuetype, wxT(""), key_ref, nIndex, key_flag_type));
00455                     ++count;
00456                 }
00457 
00458                 // ----------------------------------------------------------
00459                 // Handle the value
00460 
00461                 int val_flag_type = 0;
00462                 int val_ref = LUA_NOREF;
00463 
00464                 // don't ref anything in this table since it's already refed
00465                 if ((lua_value_type == LUA_TTABLE) && (lightuserdata_reg_key != &wxlua_lreg_debug_refs_key))
00466                     val_ref = RefTable(L, -1, &val_flag_type, WXLUA_DEBUGITEM_VALUE_REF, references);
00467                 else if (lua_value_type == LUA_TUSERDATA)
00468                 {
00469                     if (lua_getmetatable(L, -1)) // doesn't push anything if nil
00470                     {
00471                         val_ref = RefTable(L, -1, &val_flag_type, WXLUA_DEBUGITEM_VALUE_REF, references);
00472                         lua_pop(L, 1);
00473                     }
00474                 }
00475 
00476                 if ((key_flag_type == 0) || ((key_flag_type != 0) && (val_flag_type != 0)))
00477                 {
00478                     Add(new wxLuaDebugItem(name, wxl_keytype, value, wxl_valuetype, wxT(""), val_ref, nIndex, val_flag_type));
00479                     ++count;
00480                 }
00481 
00482                 lua_pop(L, 1); // pop value, leave key
00483             }
00484             }
00485 
00486             lua_pop(L, 1); // remove reference
00487         }
00488     }
00489 
00490     return count;
00491 }
00492 
00493 int wxLuaDebugData::RefTable(lua_State* L, int stack_idx, int* flag_type, int extra_flag, wxArrayInt& references)
00494 {
00495     wxCHECK_MSG(L, LUA_NOREF, wxT("Invalid lua_State"));
00496 
00497     int lua_ref = LUA_NOREF;
00498     //if (lua_istable(L, stack_idx))
00499     {
00500         //nRef = wxluaR_isrefed(L, stack_idx, &wxlua_lreg_debug_refs_key); // don't duplicate refs
00501 
00502         if (lua_ref == LUA_NOREF)
00503         {
00504             if (flag_type) *flag_type |= (WXLUA_DEBUGITEM_IS_REFED | extra_flag);
00505             lua_ref = wxluaR_ref(L, stack_idx, &wxlua_lreg_debug_refs_key);
00506             references.Add(lua_ref);
00507         }
00508     }
00509 
00510     return lua_ref;
00511 }
00512 
00513 int wxLuaDebugData::GetTypeValue(const wxLuaState& wxlState, int stack_idx, int* wxl_type_, wxString& value)
00514 {
00515     wxCHECK_MSG(wxlState.Ok(), 0, wxT("Invalid wxLuaState"));
00516 
00517     lua_State* L  = wxlState.GetLuaState();
00518     int l_type    = lua_type(L, stack_idx);
00519     int wxl_type  = wxlua_luatowxluatype(l_type);
00520 
00521     if (wxl_type_) *wxl_type_ = wxl_type;
00522 
00523     switch (l_type)
00524     {
00525         case LUA_TNONE:
00526         {
00527             value = wxEmptyString;
00528             break;
00529         }
00530         case LUA_TNIL:
00531         {
00532             value = wxT("nil");
00533             break;
00534         }
00535         case LUA_TBOOLEAN:
00536         {
00537             value = (lua_toboolean(L, stack_idx) != 0) ? wxT("true") : wxT("false");
00538             break;
00539         }
00540         case LUA_TLIGHTUSERDATA:
00541         {
00542             value = GetUserDataInfo(wxlState, stack_idx, false);
00543             break;
00544         }
00545         case LUA_TNUMBER:
00546         {
00547             double num = lua_tonumber(L, stack_idx);
00548 
00549             if ((long)num == num)
00550                 value = wxString::Format(wxT("%ld (0x%lx)"), (long)num, (unsigned long)num);
00551             else
00552                 value = wxString::Format(wxT("%g"), num);
00553 
00554             break;
00555         }
00556         case LUA_TSTRING:
00557         {
00558             value = lua2wx(lua_tostring(L, stack_idx));
00559             break;
00560         }
00561         case LUA_TTABLE:
00562         {
00563             value = GetTableInfo(wxlState, stack_idx);
00564             break;
00565         }
00566         case LUA_TFUNCTION:
00567         {
00568             value.Printf(wxT("%p"), lua_topointer(L, stack_idx));
00569 
00570             if (lua_iscfunction(L, stack_idx))
00571                 wxl_type = WXLUA_TCFUNCTION;
00572 
00573             break;
00574         }
00575         case LUA_TUSERDATA:
00576         {
00577             value = GetUserDataInfo(wxlState, stack_idx, true);
00578             break;
00579         }
00580         case LUA_TTHREAD:
00581         {
00582             value.Printf(wxT("%p"), lua_topointer(L, stack_idx));
00583             break;
00584         }
00585         default :
00586         {
00587             value = wxEmptyString;
00588             break;
00589         }
00590     }
00591 
00592     return l_type;
00593 }
00594 
00595 wxString wxLuaDebugData::GetTableInfo(const wxLuaState& wxlState, int stack_idx)
00596 {
00597     wxCHECK_MSG(wxlState.Ok(), wxEmptyString, wxT("Invalid wxLuaState"));
00598     lua_State* L = wxlState.GetLuaState();
00599 
00600     int         wxl_type = wxluaT_type(L, stack_idx);
00601     int         nItems   = luaL_getn(L, stack_idx);
00602     const void *pItem    = lua_topointer(L, stack_idx);
00603 
00604     wxString s(wxString::Format(wxT("%p"), pItem));
00605 
00606     if (nItems > 0)
00607         s += wxString::Format(wxT(" (approx %d items)"), nItems);
00608 
00609     if (wxlua_iswxuserdatatype(wxl_type))
00610         s += wxString::Format(wxT(" (wxltype %d)"), wxl_type);
00611 
00612     return s;
00613 }
00614 
00615 wxString wxLuaDebugData::GetUserDataInfo(const wxLuaState& wxlState, int stack_idx, bool full_userdata)
00616 {
00617     wxCHECK_MSG(wxlState.Ok(), wxEmptyString, wxT("Invalid wxLuaState"));
00618     lua_State* L = wxlState.GetLuaState();
00619 
00620     void* udata = lua_touserdata(L, stack_idx);
00621 
00622     wxString s(wxString::Format(wxT("%p"), udata));
00623 
00624     if (!full_userdata)
00625     {
00626         // Convert our known keys to something more readable
00627         if ((udata == &wxlua_lreg_types_key) ||
00628             (udata == &wxlua_lreg_refs_key) ||
00629             (udata == &wxlua_lreg_debug_refs_key) ||
00630             (udata == &wxlua_lreg_classes_key) ||
00631             (udata == &wxlua_lreg_derivedmethods_key) ||
00632             (udata == &wxlua_lreg_wxluastate_key) ||
00633             (udata == &wxlua_lreg_wxluabindings_key) ||
00634             (udata == &wxlua_lreg_weakobjects_key) ||
00635             (udata == &wxlua_lreg_gcobjects_key) ||
00636             (udata == &wxlua_lreg_evtcallbacks_key) ||
00637             (udata == &wxlua_lreg_windestroycallbacks_key) ||
00638             (udata == &wxlua_lreg_callbaseclassfunc_key) ||
00639             (udata == &wxlua_lreg_wxeventtype_key) ||
00640             (udata == &wxlua_lreg_wxluastatedata_key) ||
00641             (udata == &wxlua_lreg_regtable_key) ||
00642 
00643             (udata == &wxlua_metatable_type_key) ||
00644             (udata == &wxlua_lreg_topwindows_key) ||
00645             (udata == &wxlua_metatable_wxluabindclass_key))
00646         {
00647             const char* ss = *(const char**)udata;
00648             s += wxT(" (") + lua2wx(ss) + wxT(")");
00649         }
00650     }
00651     else // is full userdata
00652     {
00653         int wxl_type = wxluaT_type(L, stack_idx);
00654 
00655         if (wxlua_iswxuserdatatype(wxl_type))
00656         {
00657             s += wxString::Format(wxT(" (wxltype %d)"), wxl_type);
00658 
00659             wxString wxltypeName(wxluaT_typename(L, wxl_type));
00660             if (!wxltypeName.IsEmpty())
00661                 s += wxString::Format(wxT(" '%s'"), wxltypeName.c_str());
00662         }
00663     }
00664 
00665     return s;
00666 }
00667 
00668 // ----------------------------------------------------------------------------
00669 // wxLuaCheckStack - dumps the contents of the lua_State
00670 // ----------------------------------------------------------------------------
00671 
00672 wxLuaCheckStack::wxLuaCheckStack(lua_State *L, const wxString &msg, bool print_to_console)
00673 {
00674     m_luaState = L;
00675     m_msg      = msg;
00676     m_top      = lua_gettop(m_luaState);
00677     m_print_to_console = print_to_console;
00678 }
00679 
00680 wxLuaCheckStack::~wxLuaCheckStack()
00681 {
00682     if (m_print_to_console)
00683         TestStack(wxT("~wxLuaCheckStack"));
00684 }
00685 
00686 wxString wxLuaCheckStack::TestStack(const wxString &msg)
00687 {
00688     wxString s;
00689     s.Printf(wxT("wxLuaCheckStack::TestStack(L=%p) '%s':'%s': starting top %d ending top %d\n"),
00690                     m_luaState, m_msg.c_str(), msg.c_str(), m_top, lua_gettop(m_luaState));
00691 
00692     if (m_top != lua_gettop(m_luaState)) s += wxT(" **********"); // easy to find
00693 
00694     OutputMsg(s);
00695 
00696     return s;
00697 }
00698 
00699 wxString wxLuaCheckStack::DumpStack(const wxString& msg)
00700 {
00701     wxCHECK_MSG(m_luaState, wxEmptyString, wxT("Invalid lua_State"));
00702 
00703     lua_State* L = m_luaState;
00704     int i, count = lua_gettop(L);
00705     wxString str;
00706     wxString retStr;
00707 
00708     str.Printf(wxT("wxLuaCheckStack::DumpStack(L=%p), '%s':'%s', items %d, starting top %d\n"), L, m_msg.c_str(), msg.c_str(), count, m_top);
00709     retStr += str;
00710     OutputMsg(str);
00711 
00712     wxLuaState wxlState(L);
00713 
00714     for (i = 1; i <= count; i++)
00715     {
00716         int wxl_type = 0;
00717         wxString value;
00718         int l_type = wxLuaDebugData::GetTypeValue(wxlState, i, &wxl_type, value);
00719 
00720         str.Printf(wxT("  idx %d: l_type = %d, wxl_type = %d : '%s'='%s'\n"),
00721                 i, l_type, wxl_type, wxluaT_typename(L, wxl_type).c_str(), value.c_str());
00722         retStr += str;
00723         OutputMsg(str);
00724     }
00725 
00726     return retStr;
00727 }
00728 
00729 wxString wxLuaCheckStack::DumpGlobals(const wxString& msg)
00730 {
00731     wxCHECK_MSG(m_luaState, wxEmptyString, wxT("Invalid lua_State"));
00732 
00733     wxSortedArrayString tableArray;
00734 
00735     return DumpTable(LUA_GLOBALSINDEX, wxT("Globals"), msg, tableArray, 0);
00736 }
00737 
00738 wxString wxLuaCheckStack::DumpTable(const wxString &tablename, const wxString& msg)
00739 {
00740     wxCHECK_MSG(m_luaState, wxEmptyString, wxT("Invalid lua_State"));
00741 
00742     lua_State* L = m_luaState;
00743     wxSortedArrayString tableArray;
00744     wxString s;
00745 
00746     // Allow iteration through table1.table2.table3...
00747     wxString tname(tablename);
00748     lua_pushvalue(L, LUA_GLOBALSINDEX);
00749 
00750     do {
00751         lua_pushstring(L, wx2lua(tname.BeforeFirst(wxT('.'))));
00752         lua_rawget(L, -2);
00753 
00754         if (lua_isnil(L, -1) || !lua_istable(L, -1))
00755         {
00756             lua_pop(L, 2);  // remove table and value
00757 
00758             s.Printf(wxT("wxLuaCheckStack::DumpTable(L=%p) Table: '%s' cannot be found!\n"), L, tablename.c_str());
00759             OutputMsg(s);
00760             return s;
00761         }
00762 
00763         lua_remove(L, -2);  // remove previous table
00764         tname = tname.AfterFirst(wxT('.'));
00765     } while (tname.Len() > 0);
00766 
00767     s = DumpTable(lua_gettop(L), tablename, msg, tableArray, 0);
00768     lua_pop(L, 1);
00769 
00770     return s;
00771 }
00772 
00773 wxString wxLuaCheckStack::DumpTable(int stack_idx, const wxString& msg)
00774 {
00775     wxCHECK_MSG(m_luaState, wxEmptyString, wxT("Invalid lua_State"));
00776 
00777     wxSortedArrayString tableArray;
00778 
00779     return DumpTable(stack_idx, wxString::Format(wxT("StackIdx=%d"), stack_idx), msg, tableArray, 0);
00780 }
00781 
00782 wxString wxLuaCheckStack::DumpTable(int stack_idx, const wxString& tablename, const wxString& msg, wxSortedArrayString& tableArray, int indent)
00783 {
00784     wxCHECK_MSG(m_luaState, wxEmptyString, wxT("Invalid lua_State"));
00785 
00786     lua_State* L = m_luaState;
00787     wxLuaState wxlState(L);
00788     wxString indentStr;
00789     wxString s;
00790 
00791     // We only do tables, return error message
00792     if (!lua_istable(L, stack_idx))
00793     {
00794         s.Printf(wxT("wxLuaCheckStack::DumpTable(L=%p) stack idx %d is not a table.\n"), L, stack_idx);
00795         OutputMsg(s);
00796         return s;
00797     }
00798 
00799     if (indent == 0)
00800     {
00801         // First time through print header
00802         s.Printf(wxT("wxLuaCheckStack::DumpTable(L=%p) Table: '%s'\n"), L, tablename.c_str());
00803         OutputMsg(s);
00804     }
00805     else if (indent > 10)
00806     {
00807         // Don't let things get out of hand...
00808         s.Printf(wxT("wxLuaCheckStack::DumpTable(L=%p) Table depth > 10! Truncating: '%s'\n"), L, tablename.c_str());
00809         OutputMsg(s);
00810         return s;
00811     }
00812     else
00813     {
00814         indentStr = wxString(wxT(' '), indent*2) + wxT(">");
00815     }
00816 
00817     wxString title = wxString::Format(wxT("%sTable Level %d : name '%s'\n"), indentStr.c_str(), indent, tablename.c_str());
00818     s += title;
00819     OutputMsg(title);
00820 
00821     lua_pushvalue(L, stack_idx); // push the table to read the top of the stack
00822 
00823     lua_pushnil(L);
00824     while (lua_next(L, -2) != 0)
00825     {
00826         int keyType = 0, valueType = 0;
00827         wxString key, value;
00828 
00829         wxLuaDebugData::GetTypeValue(wxlState, -2, &keyType,   key);
00830         wxLuaDebugData::GetTypeValue(wxlState, -1, &valueType, value);
00831 
00832         wxString info = wxString::Format(wxT("%s%-32s\t%-16s\t%-20s\t%-16s\n"),
00833                 indentStr.c_str(), key.c_str(), wxluaT_typename(L, keyType).c_str(), value.c_str(), wxluaT_typename(L, valueType).c_str());
00834         s += info;
00835         OutputMsg(info);
00836 
00837         if (tableArray.Index(value) == wxNOT_FOUND)
00838         {
00839             if (valueType == WXLUA_TTABLE)
00840             {
00841                 tableArray.Add(value);
00842                 s += DumpTable(lua_gettop(L), tablename + wxT(".") + key, msg, tableArray, indent+1);
00843             }
00844             else
00845             {
00846                 tableArray.Add(value);
00847             }
00848         }
00849 
00850         lua_pop(L, 1); // pop value
00851     }
00852 
00853     lua_pop(L, 1); // pop pushed table
00854 
00855     return s;
00856 }
00857 
00858 void wxLuaCheckStack::OutputMsg(const wxString& msg) const
00859 {
00860     if (m_print_to_console)
00861     {
00862 #if  defined(__WXMSW__)
00863     //OutputDebugString(msg.c_str());
00864     wxPrintf(wxT("%s"), msg.c_str()); fflush(stdout);
00865 #else //if defined(__WXGTK__) || defined(__WXMAC__)
00866     wxPrintf(wxT("%s"), msg.c_str());
00867 #endif
00868     }
00869 }
Generated on Tue Jul 13 10:30:39 2010 for wxLua by  doxygen 1.6.3