1 /////////////////////////////////////////////////////////////////////////////
2 // Name:          wxlbind.cpp
3 // Purpose:       wxLuaBinding
4 // Author:        Ray Gilbert, John Labenski, J Winwood
5 // Created:       14/11/2001
6 // Copyright:     (c) 2012 John Labenski
7 // Licence:       wxWidgets licence
8 /////////////////////////////////////////////////////////////////////////////
9 
10 #include <wx/wxprec.h>
11 
12 #ifdef __BORLANDC__
13     #pragma hdrstop
14 #endif
15 
16 #ifndef WX_PRECOMP
17     #include <wx/wx.h>
18 #endif
19 
20 #include "wxlua/wxlbind.h"
21 #include "wxlua/wxlstate.h"
22 
23 //#include "wxluadebug/include/wxldebug.h" // for debugging only
24 
25 
26 wxLuaArgType g_wxluaargtypeArray_None[1] = {0};
27 
28 int wxluatype_TUNKNOWN       = WXLUA_TUNKNOWN;
29 int wxluatype_TNONE          = WXLUA_TNONE;
30 int wxluatype_TNIL           = WXLUA_TNIL;
31 int wxluatype_TBOOLEAN       = WXLUA_TBOOLEAN;
32 int wxluatype_TLIGHTUSERDATA = WXLUA_TLIGHTUSERDATA; // raw data
33 int wxluatype_TNUMBER        = WXLUA_TNUMBER;
34 int wxluatype_TSTRING        = WXLUA_TSTRING;
35 int wxluatype_TTABLE         = WXLUA_TTABLE;
36 int wxluatype_TFUNCTION      = WXLUA_TFUNCTION;
37 int wxluatype_TUSERDATA      = WXLUA_TUSERDATA;      // raw data
38 int wxluatype_TTHREAD        = WXLUA_TTHREAD;
39 int wxluatype_TINTEGER       = WXLUA_TINTEGER;
40 int wxluatype_TCFUNCTION     = WXLUA_TCFUNCTION;
41 int wxluatype_TPOINTER       = WXLUA_TPOINTER;
42 int wxluatype_TANY           = WXLUA_TANY;
43 
44 int wxluatype_NULL           = WXLUATYPE_NULL;
45 
46 wxLuaBindClass wxLuaBindClass_NULL =
47     { "NULL", NULL, 0, NULL, &wxluatype_NULL, NULL, NULL, NULL, NULL, NULL, 0, };
48 
49 int* p_wxluatype_wxEvent             = &wxluatype_TUNKNOWN;
50 int* p_wxluatype_wxWindow            = &wxluatype_TUNKNOWN;
51 int* p_wxluatype_wxScrollEvent       = &wxluatype_TUNKNOWN;
52 int* p_wxluatype_wxSpinEvent         = &wxluatype_TUNKNOWN;
53 int* p_wxluatype_wxString            = &wxluatype_TUNKNOWN;
54 int* p_wxluatype_wxArrayString       = &wxluatype_TUNKNOWN;
55 int* p_wxluatype_wxSortedArrayString = &wxluatype_TUNKNOWN;
56 int* p_wxluatype_wxArrayInt          = &wxluatype_TUNKNOWN;
57 int* p_wxluatype_wxArrayDouble       = &wxluatype_TUNKNOWN;
58 int* p_wxluatype_wxMemoryBuffer      = &wxluatype_TUNKNOWN;
59 int* p_wxluatype_wxPoint             = &wxluatype_TUNKNOWN;
60 int* p_wxluatype_wxPoint2DDouble     = &wxluatype_TUNKNOWN;
61 
62 // ----------------------------------------------------------------------------
63 // wxlua_tableErrorHandler
64 // ----------------------------------------------------------------------------
65 
66 /*
67 static int LUACALL wxlua_tableErrorHandler(lua_State *L)
68 {
69     wxlua_error(L, "Cannot modify read-only wxLua table");
70     return 0;
71 }
72 */
73 
74 // ----------------------------------------------------------------------------
75 // Generic delete function for bindings
76 // ----------------------------------------------------------------------------
77 
wxlua_userdata_delete(lua_State * L)78 int LUACALL wxlua_userdata_delete(lua_State *L)
79 {
80     // if removed from tracked mem list, remove the metatable so that __gc is not called on this object.
81     if (wxluaO_deletegcobject(L, 1, WXLUA_DELETE_OBJECT_ALL))
82     {
83         lua_pushnil(L);
84         lua_setmetatable(L, -2);
85     }
86     else
87     {
88         wxString msg;
89         msg.Printf(wxT("wxLua: Unable to call wxuserdata:delete() on object!"));
90 
91         // leave this printf since we really want to know if this happens
92         wxPrintf(wxString(msg + wxT("\n")).c_str());
93         wxlua_argerrormsg(L, msg);
94     }
95 
96     return 0;
97 }
98 
99 // ----------------------------------------------------------------------------
100 // If the class defines a gc function, then call it.
101 // ----------------------------------------------------------------------------
102 
wxlua_wxLuaBindClass__gc(lua_State * L)103 int LUACALL wxlua_wxLuaBindClass__gc(lua_State *L)
104 {
105     wxLuaBindClass *wxlClass = (wxLuaBindClass *)lua_touserdata(L, lua_upvalueindex(1));
106 
107     if ((wxlClass != NULL) && wxlua_iswxuserdata(L, 1) && (wxluaT_type(L, 1) == *wxlClass->wxluatype))
108     {
109         // clean up the rest of this, this won't error if the key doesn't exist
110         wxluaO_deletegcobject(L, 1, WXLUA_DELETE_OBJECT_LAST);
111     }
112 
113     return 0;
114 }
115 
116 // ----------------------------------------------------------------------------
117 // Called by LUA to find the method that corresponds to a __index method name.
118 // ----------------------------------------------------------------------------
119 
wxlua_wxLuaBindClass__index(lua_State * L)120 int LUACALL wxlua_wxLuaBindClass__index(lua_State *L)
121 {
122     // This function is called for the __index metatable of the wxLua userdata
123     // for class instances.
124 
125     // Lua stack : 1 = userdata, 2 = key; userdata:key()
126     // You cannot seem to get the calling convention (. or :) or if it was
127     // called as a function() or a .member?
128 
129     // See below, if _XXX is called then we set this flag so that
130     //  the called function knows to call the base class instead of recalling
131     //  the Lua function and recursing.
132     wxlua_setcallbaseclassfunction(L, false);
133 
134     bool found    = false;
135     int  result   = 0;
136     wxLuaBindClass *wxlClass = (wxLuaBindClass *)lua_touserdata(L, lua_upvalueindex(1));
137     wxCHECK_MSG(wxlClass, 0, wxT("Invalid wxLuaBindClass")); // fail hard
138 
139     void *obj_ptr = wxlua_touserdata(L, 1, false);
140     const char *name = lua_tostring(L, 2); // name of the __index method called in Lua
141 
142     if (!name)
143     {
144         // name is NULL if it's not a string
145         wxlua_error(L, wxString::Format(_("wxLua: Attempt to call a class method using '%s' on a '%s' wxLua type."),
146             wxlua_luaL_typename(L, 2).c_str(), lua2wx(wxlClass->name).c_str()).c_str());
147     }
148     else if (wxluaT_type(L, 1) == *wxlClass->wxluatype)
149     {
150         // check if we're to call the baseclass function or if it's a Lua derived function
151         bool callbase = (name[0] == '_');
152 
153         if (callbase)
154             name++; // skip past "_"[FunctionName]
155         else
156         {
157             // if there's a derived method in Lua, push it onto the stack to be run
158             if (wxlua_hasderivedmethod(L, obj_ptr, name, true))
159             {
160                 found = true;
161                 result = 1; // the function for Lua to call is on the stack
162             }
163         }
164 
165         // Search through the bindings for the function to call
166         if (!found)
167         {
168             wxLuaBindMethod* wxlMethod = wxLuaBinding::GetClassMethod(wxlClass, name, WXLUAMETHOD_METHOD|WXLUAMETHOD_GETPROP, true);
169 
170             if ((wxlMethod != NULL) && (wxlMethod->wxluacfuncs != NULL))
171             {
172                 if (WXLUA_HASBIT(wxlMethod->method_type, WXLUAMETHOD_GETPROP))
173                 {
174                     // The user wants to call the C++ function as a property
175                     // which is treated as though it were a member variable.
176                     // It shouldn't have been called as a function with ()
177                     // and so we call the function here and leave the value on the stack.
178                     found = true;
179                     if (WXLUA_HASBIT(wxlMethod->method_type, WXLUAMETHOD_STATIC))
180                         lua_pop(L, 2); // remove the userdata and func name
181                     else
182                         lua_pop(L, 1); // remove the name of the function
183 
184                     result = (*wxlMethod->wxluacfuncs[0].lua_cfunc)(L);
185                 }
186                 else
187                 {
188                     // The user has called a real C++ function and if it's
189                     // overloaded we call wxlua_callOverloadedFunction() to
190                     // find the correct one to call.
191                     found = true;
192                     result = 1;
193 
194                     lua_pushlightuserdata(L, wxlMethod);
195 
196                     if ((wxlMethod->wxluacfuncs_n > 1) || (wxlMethod->basemethod))
197                         lua_pushcclosure(L, wxlua_callOverloadedFunction, 1);
198                     else
199                         lua_pushcclosure(L, wxlMethod->wxluacfuncs[0].lua_cfunc, 1);
200                 }
201             }
202 
203             // Maybe this is an undeclared property? Prepend 'Get' and try again.
204             if (!found)
205             {
206                 int len = strlen(name);
207                 wxCharBuffer buf(len + 4);
208                 char* str = buf.data();
209                 str[0] = 'G'; str[1] = 'e'; str[2] = 't';
210                 memcpy(str+3, name, len+1); // include terminating NULL
211 
212                 wxlMethod = wxLuaBinding::GetClassMethod(wxlClass, str, WXLUAMETHOD_METHOD, true);
213 
214                 if ((wxlMethod != NULL) && WXLUA_HASBIT(wxlMethod->method_type, WXLUAMETHOD_METHOD))
215                     //wxlMethod->funcs && (wxlMethod->funcs->minargs == 0) && // let it error out
216                     //(wxlMethod->funcs->maxargs == 0))
217                 {
218                     found = true;
219                     if (WXLUA_HASBIT(wxlMethod->method_type, WXLUAMETHOD_STATIC))
220                         lua_pop(L, 2); // remove the userdata and func name
221                     else
222                         lua_pop(L, 1); // remove the name of the function
223 
224                     result = (*wxlMethod->wxluacfuncs[0].lua_cfunc)(L);
225                 }
226             }
227 
228             // This MUST be reset to false in the base class function
229             if (found && callbase) wxlua_setcallbaseclassfunction(L, true);
230         }
231     }
232 
233     return result;
234 }
235 
236 // ----------------------------------------------------------------------------
237 // Called by LUA to find the method that corresponds to a __newindex method name.
238 // ----------------------------------------------------------------------------
239 
wxlua_wxLuaBindClass__newindex(lua_State * L)240 int LUACALL wxlua_wxLuaBindClass__newindex(lua_State *L)
241 {
242     wxLuaBindClass *wxlClass = (wxLuaBindClass *)lua_touserdata(L, lua_upvalueindex(1));
243     wxCHECK_MSG(wxlClass, 0, wxT("Invalid wxLuaBindClass")); // fail hard
244 
245     // Lua Stack: 1 = userdata, 2 = key, 3 = value; userdata.key = value
246 
247     const char *name = lua_tostring(L, 2);
248     bool found = false;
249 
250     if (!name)
251     {
252         // name is NULL if it's not a string
253         wxlua_error(L, wxString::Format(_("wxLua: Attempt to call or add a class method using '%s' on a '%s' type."),
254             wxlua_luaL_typename(L, 2).c_str(), lua2wx(wxlClass->name).c_str()).c_str());
255     }
256     else if (wxluaT_type(L, 1) == *wxlClass->wxluatype)
257     {
258         // See if there is a WXLUAMETHOD_SETPROP in the wxLuaBindClass's wxLuaBindMethods
259         wxLuaBindMethod *wxlMethod = wxLuaBinding::GetClassMethod(wxlClass, name, WXLUAMETHOD_SETPROP, true);
260 
261         if (wxlMethod != NULL)
262         {
263             found = true;
264             lua_remove(L, 2); // remove the function name
265             if (WXLUA_HASBIT(wxlMethod->method_type, WXLUAMETHOD_STATIC))
266                 lua_remove(L, 1); // remove the userdata too, leaving the value
267 
268             (*wxlMethod->wxluacfuncs[0].lua_cfunc)(L);
269         }
270         else
271         {
272             // Maybe this is an undeclared property? Prepend 'Set' and try again.
273             int len = strlen(name);
274             wxCharBuffer buf(len + 4);
275             char* str = buf.data();
276             str[0] = 'S'; str[1] = 'e'; str[2] = 't';
277             memcpy(str+3, name, len+1); // include terminating NULL
278 
279             wxlMethod = wxLuaBinding::GetClassMethod(wxlClass, str, WXLUAMETHOD_METHOD, true);
280             if ((wxlMethod != NULL) && WXLUA_HASBIT(wxlMethod->method_type, WXLUAMETHOD_METHOD))
281             {
282                 found = true;
283                 lua_remove(L, 2); // remove the function name
284                 if (WXLUA_HASBIT(wxlMethod->method_type, WXLUAMETHOD_STATIC))
285                     lua_remove(L, 1); // remove the userdata too, leaving the value
286 
287                 (*wxlMethod->wxluacfuncs[0].lua_cfunc)(L);
288             }
289         }
290 
291         // They want to add this to the class so store it in the derived method table
292         if (!found)
293         {
294             found = true;
295 
296             void *obj_ptr = wxlua_touserdata(L, 1, false);
297             wxLuaObject* wxlObj = new wxLuaObject(L, 3);
298             wxlua_setderivedmethod(L, obj_ptr, name, wxlObj);
299         }
300     }
301 
302     if (!found)
303     {
304         wxlua_error(L, wxString::Format(_("wxLua: Unable to call or add an unknown method '%s' on a '%s' type."),
305             lua2wx(name).c_str(), lua2wx(wxlClass ? wxlClass->name : "").c_str()).c_str());
306     }
307 
308     return 0;
309 }
310 
311 // ----------------------------------------------------------------------------
312 // wxlua_wxLuaBindClass__tostring
313 // ----------------------------------------------------------------------------
314 
wxlua_wxLuaBindClass__tostring(lua_State * L)315 int LUACALL wxlua_wxLuaBindClass__tostring(lua_State *L)
316 {
317     // this should be identical to Lua's tostring for a userdata
318     wxString str = wxString::Format(wxT("userdata: %p"), lua_touserdata(L, 1));
319 
320     int wxl_type = wxluaT_type(L, 1);
321     if (wxlua_iswxuserdatatype(wxl_type))
322     {
323         wxString name = wxluaT_typename(L, wxl_type);
324         if (!name.IsEmpty())
325         {
326             // GCC prints '(' for NULL %p for some reason.
327             void* p = wxlua_touserdata(L, 1, false);
328             if (p)
329                 str += wxString::Format(wxT(" [%s(%p, %d)]"), name.c_str(), p, wxl_type);
330             else
331                 str += wxString::Format(wxT(" [%s(0x0, %d)]"), name.c_str(), wxl_type);
332         }
333     }
334     else
335         str += wxT(" [??? Unknown wxLua class type!]"); // get people's attention
336 
337     lua_pushstring(L, wx2lua(str));
338     return 1;
339 }
340 
341 // ----------------------------------------------------------------------------
342 // The __call metatable function to allow the class tables to be called as functions
343 // ----------------------------------------------------------------------------
344 
wxlua_wxLuaBindMethod_table__call(lua_State * L)345 int LUACALL wxlua_wxLuaBindMethod_table__call(lua_State *L)
346 {
347     lua_remove(L, 1); // remove the table
348 
349     return wxlua_callOverloadedFunction(L);
350 }
351 
wxlua_wxLuaBindMethod_table__index(lua_State * L)352 int LUACALL wxlua_wxLuaBindMethod_table__index(lua_State *L)
353 {
354     // Lua stack: 1 = table, 2 = key
355 
356     wxLuaBindClass *wxlClass = (wxLuaBindClass *)lua_touserdata(L, lua_upvalueindex(1));
357     wxCHECK_MSG(wxlClass, 0, wxT("Invalid wxLuaBindClass")); // fail hard
358 
359     int result = 0;
360 
361     const char* name = lua_tostring(L, 2);
362     if (!name)
363     {
364         // name is NULL if it's not a string
365         wxlua_error(L, wxString::Format(_("wxLua: Attempt to call a static class method using '%s' on a '%s' type."),
366             wxlua_luaL_typename(L, 2).c_str(), lua2wx(wxlClass->name).c_str()).c_str());
367         return 0;
368     }
369 
370     wxLuaBindMethod* wxlMethod = wxLuaBinding::GetClassMethod(wxlClass, name, WXLUAMETHOD_GETPROP, true);
371 
372     if (wxlMethod && WXLUA_HASBIT(wxlMethod->method_type, WXLUAMETHOD_STATIC))
373     {
374         lua_pop(L, 2); // remove the table and the name of the function
375         result = (*wxlMethod->wxluacfuncs[0].lua_cfunc)(L);
376     }
377     else
378     {
379         lua_pushvalue(L, -1);  // copy key
380         lua_rawget(L, -3);     // get t[key] = value, pops key pushes value
381         result = 1;            // ok if nil
382     }
383 
384     return result;
385 }
386 
wxlua_wxLuaBindMethod_table__newindex(lua_State * L)387 int LUACALL wxlua_wxLuaBindMethod_table__newindex(lua_State *L)
388 {
389     // 1 = table, 2 = key, 3 = value
390 
391     wxLuaBindClass *wxlClass = (wxLuaBindClass *)lua_touserdata(L, lua_upvalueindex(1));
392     wxCHECK_MSG(wxlClass, 0, wxT("Invalid wxLuaBindClass"));
393 
394     const char* name = lua_tostring(L, 2);
395     if (!name)
396     {
397         // name is NULL if it's not a string
398         wxlua_error(L, wxString::Format(_("wxLua: Attempt to call a static class method using '%s' on a '%s' type."),
399             wxlua_luaL_typename(L, 2).c_str(), lua2wx(wxlClass->name).c_str()).c_str());
400         return 0;
401     }
402 
403     wxLuaBindMethod* wxlMethod = wxLuaBinding::GetClassMethod(wxlClass, name, WXLUAMETHOD_SETPROP, true);
404 
405     if (wxlMethod && WXLUA_HASBIT(wxlMethod->method_type, WXLUAMETHOD_STATIC))
406     {
407         lua_remove(L, 2); // remove the key
408         lua_remove(L, 1); // remove the table
409         (*wxlMethod->wxluacfuncs[0].lua_cfunc)(L);
410     }
411     else
412     {
413         lua_pushvalue(L, -2); // copy key
414         lua_pushvalue(L, -2); // copy value
415         lua_rawset(L, -5);    // set t[key] = value, pops key and value
416     }
417 
418     return 0;
419 }
420 
421 // ----------------------------------------------------------------------------
422 // Central function to call for overloaded functions
423 // ----------------------------------------------------------------------------
424 
wxlua_callOverloadedFunction(lua_State * L)425 int LUACALL wxlua_callOverloadedFunction(lua_State* L)
426 {
427     wxLuaBindMethod* wxlMethod = (wxLuaBindMethod *)lua_touserdata(L, lua_upvalueindex(1)); // lightuserdata
428     wxCHECK_MSG(wxlMethod, 0, wxT("Invalid wxLuaBindMethod"));
429 
430     if ((wxlMethod->wxluacfuncs_n > 1) || (wxlMethod->basemethod))
431         return wxlua_callOverloadedFunction(L, wxlMethod);
432     else
433         return (*wxlMethod->wxluacfuncs[0].lua_cfunc)(L);
434 }
435 
wxlua_callOverloadedFunction(lua_State * L,struct wxLuaBindMethod * wxlMethod)436 int LUACALL wxlua_callOverloadedFunction(lua_State* L, struct wxLuaBindMethod* wxlMethod)
437 {
438     // get number of arguments called from Lua
439     int i, arg, arg_lua_count = lua_gettop(L);
440 
441     // only look at the methods that could possibly work and traverse base classes
442     wxArrayPtrVoid cfuncArray;
443     wxLuaBindMethod* method = wxlMethod;
444     while (method)
445     {
446         wxLuaBindCFunc* wxlCFunc = method->wxluacfuncs;
447 
448         for (i = 0; i < method->wxluacfuncs_n; ++i, ++wxlCFunc)
449         {
450             if ((arg_lua_count >= wxlCFunc->minargs) &&
451                 (arg_lua_count <= wxlCFunc->maxargs))
452             {
453                 cfuncArray.Add(wxlCFunc);
454             }
455         }
456 
457         method = method->basemethod;
458     }
459 
460     wxLuaBindCFunc* bestCFunc = NULL; // stores the last function that worked.
461     int invalid_lua_arg = 1; // arg that failed
462     int cfunc_count = cfuncArray.GetCount();
463 
464     // Look at the available functions in parallel, per arg
465     for (arg = 0; (arg < arg_lua_count) && (cfunc_count != 0); ++arg)
466     {
467         int arg_lua = arg+1; // arg N on the Lua stack
468         int ltype = lua_type(L, arg_lua);
469 
470         for (i = 0; i < cfunc_count; ++i)
471         {
472             wxLuaBindCFunc* wxlCFunc = (wxLuaBindCFunc*)cfuncArray[i];
473             bestCFunc = wxlCFunc;
474             invalid_lua_arg = arg_lua;
475 
476             // does this method have any more arguments?
477             if (!wxlCFunc->argtypes[arg])
478             {
479                 cfuncArray.RemoveAt(i);
480                 cfunc_count--;
481                 i--;
482                 continue;
483             }
484 
485             // get argument wxLua type
486             int wxl_type = (int)*(wxlCFunc->argtypes[arg]);
487 
488             // Does the Lua type match the wxLua type
489             int is_ok = wxlua_iswxluatype(ltype, wxl_type, L);
490 
491             // unknown/invalid standard wxLua type, check binding wxLua type
492             if ((is_ok == -1) || ((is_ok == 0) && (wxl_type == WXLUA_TSTRING)))
493             {
494                 is_ok = (wxluaT_isuserdatatype(L, arg_lua, wxl_type) ||
495                         (wxl_type == wxluatype_NULL)) ? 1 : 0;
496             }
497 
498             // this arg is not a match, remove this function as a possibility
499             if (is_ok == 0)
500             {
501                 cfuncArray.RemoveAt(i);
502                 cfunc_count--;
503                 i--;
504                 continue;
505             }
506         }
507     }
508 
509     // Note that the top function is the one that is highest in the
510     // derived functions from any baseclasses and should be the best choice.
511     // Example is wxBookCtrlBaseEvent::GetSelection() and wxCommandEvent::GetSelection()
512     if (cfunc_count > 0)
513     {
514         lua_CFunction lua_cfunc = ((wxLuaBindCFunc*)cfuncArray[0])->lua_cfunc;
515 
516         // successfully found overloaded function to handle wxLua call
517         return (*lua_cfunc)(L);
518     }
519 
520     // ----------------------------------------------------------------------
521     // Did not find a suitable function to call, post error
522 
523     wxString fnCall = wxlua_getLuaArgsMsg(L, 1, arg_lua_count);
524 
525     wxString fnOverloadList = wxString::Format(wxT("Function called: '%s'\n"), fnCall.c_str());
526     fnOverloadList += wxlua_getBindMethodArgsMsg(L, wxlMethod);
527 
528     wxString errmsg;
529 
530     if (cfunc_count > 1) // Note: we actually allow this.. for now
531     {
532         errmsg = wxT("wxLua: Function call is ambiguous.\nTry coercing values to proper types using tostring/number as appropriate.\n");
533     }
534 
535     if (bestCFunc == NULL)
536         errmsg += wxT("wxLua: Function call has invalid arguments.");
537     else
538     {
539         // We have to count the methods that are displayed to find the one that failed
540         // since we've skipped the ones with wrong number of args.
541         method = wxlMethod;
542         int i_cfunc = 0;
543         bool found = false;
544         while (method && !found)
545         {
546             for (i = 0; i < method->wxluacfuncs_n; ++i)
547             {
548                 i_cfunc++;
549                 if (&method->wxluacfuncs[i] == bestCFunc)
550                 {
551                     found = true;
552                     break;
553                 }
554             }
555 
556             method = method->basemethod;
557         }
558 
559         errmsg += wxString::Format(wxT("wxLua: Function call has invalid argument %d on method %02d.\n"), invalid_lua_arg, i_cfunc);
560     }
561 
562     errmsg += wxT("\n") + fnOverloadList;
563 
564     wxlua_error(L, errmsg.c_str());
565 
566     return 0;
567 }
568 
wxlua_getLuaArgsMsg(lua_State * L,int start_stack_idx,int end_stack_idx)569 wxString wxlua_getLuaArgsMsg(lua_State* L, int start_stack_idx, int end_stack_idx)
570 {
571     lua_Debug ar = {0};
572 
573     // NOTE: We'd like to be able to give some info, however if we are not
574     // running a Lua function the lua_Debug is empty and lua_getinfo() will panic.
575     if (lua_getstack(L, 0, &ar) == 0) // returns 0 when called on a level greater than stack depth
576         return wxT("?");
577 
578     lua_getinfo(L, "n", &ar);
579     wxString funcName = lua2wx(ar.name);
580 
581     wxString funcCall = funcName + wxT("(");
582 
583     for (int arg = start_stack_idx; arg <= end_stack_idx; ++arg)
584     {
585         if (arg > start_stack_idx) funcCall += wxT(", ");
586 
587         funcCall += wxluaT_gettypename(L, arg);
588     }
589     funcCall += wxT(")");
590 
591     return funcCall;
592 }
593 
wxlua_getBindMethodArgsMsg(lua_State * L,struct wxLuaBindMethod * wxlMethod)594 wxString wxlua_getBindMethodArgsMsg(lua_State* L, struct wxLuaBindMethod* wxlMethod)
595 {
596     wxCHECK_MSG(wxlMethod, wxEmptyString, wxT("Invalid method table"));
597 
598     wxString overloadMethods;
599 
600     int i_cfunc = 0; // count total number of overloads
601     wxLuaBindMethod* method = wxlMethod;
602 
603     // traverse the methods down the baseclass methods if any
604     while (method)
605     {
606         wxLuaBindCFunc* wxluacfuncs = method->wxluacfuncs;
607         int i, arg, cfuncs_count = method->wxluacfuncs_n;
608 
609         const wxLuaBindClass* wxlClass = wxLuaBinding::FindBindClass(method);
610         for (i = 0; i < cfuncs_count; ++i)
611         {
612             i_cfunc++;
613 
614             wxString className;
615             if (wxlClass && !WXLUA_HASBIT(wxluacfuncs[i].method_type, WXLUAMETHOD_CONSTRUCTOR))
616                 className = lua2wx(wxlClass->name) + wxT(".");
617 
618             wxString funcStr = wxString::Format(wxT("%02d. %s%s("), i_cfunc, className.c_str(), lua2wx(method->name).c_str());
619 
620             for (arg = 0; arg < wxluacfuncs[i].maxargs; ++arg)
621             {
622                 // optional args?
623                 if ((wxluacfuncs[i].minargs < wxluacfuncs[i].maxargs) && (arg == wxluacfuncs[i].minargs))
624                 {
625                     if (arg > 0) funcStr += wxT(" ");
626                     funcStr += wxT("[");
627                 }
628 
629                 if (arg > 0)
630                     funcStr += wxT(", ");
631 
632                 int wxl_type = (int)*(wxluacfuncs[i].argtypes[arg]);
633                 funcStr += wxluaT_typename(L, wxl_type);
634 
635                 if ((arg == 0) &&
636                     !WXLUA_HASBIT(wxluacfuncs[i].method_type, WXLUAMETHOD_STATIC) &&
637                     !WXLUA_HASBIT(wxluacfuncs[i].method_type, WXLUAMETHOD_CONSTRUCTOR) &&
638                     !WXLUA_HASBIT(wxluacfuncs[i].method_type, WXLUAMETHOD_CFUNCTION))
639                     funcStr += wxT("(self)");
640             }
641 
642             // close optional args
643             if (wxluacfuncs[i].minargs < wxluacfuncs[i].maxargs)
644                 funcStr += wxT("]");
645 
646             funcStr += wxT(")");
647 
648             if (WXLUA_HASBIT(wxluacfuncs[i].method_type, WXLUAMETHOD_STATIC))
649                 funcStr += wxT(" - static");
650 
651             if (overloadMethods.Length() > 0)
652                 overloadMethods += wxT("\n") + funcStr;
653             else
654                 overloadMethods += funcStr;
655         }
656 
657         method = method->basemethod;
658     }
659 
660     return overloadMethods;
661 }
662 
663 // ----------------------------------------------------------------------------
664 // Functions to compare binding structs using qsort and bsearch
665 // ----------------------------------------------------------------------------
666 
667 // Function to compare to wxLuaBindEvents by eventType
wxLuaBindEvent_CompareByEventTypeFn(const void * p1,const void * p2)668 int wxLuaBindEvent_CompareByEventTypeFn(const void *p1, const void *p2)
669 {
670     return (*((const wxLuaBindEvent*)p1)->eventType) - (*((const wxLuaBindEvent*)p2)->eventType);
671 }
672 // Function to compare to wxLuaBindNumber by name
wxLuaBindNumber_CompareByNameFn(const void * p1,const void * p2)673 int wxLuaBindNumber_CompareByNameFn(const void *p1, const void *p2)
674 {
675     return strcmp(((const wxLuaBindNumber*)p1)->name, ((const wxLuaBindNumber*)p2)->name);
676 }
677 // Function to compare to wxLuaBindStrings by name
wxLuaBindString_CompareByNameFn(const void * p1,const void * p2)678 int wxLuaBindString_CompareByNameFn(const void *p1, const void *p2)
679 {
680     return strcmp(((const wxLuaBindString*)p1)->name, ((const wxLuaBindString*)p2)->name);
681 }
682 // Function to compare to wxLuaBindObjects by name
wxLuaBindObject_CompareByNameFn(const void * p1,const void * p2)683 int wxLuaBindObject_CompareByNameFn(const void *p1, const void *p2)
684 {
685     return strcmp(((const wxLuaBindObject*)p1)->name, ((const wxLuaBindObject*)p2)->name);
686 }
687 // Function to compare to wxLuaBindMethods by name
wxLuaBindMethod_CompareByNameFnInit(const void * p1,const void * p2)688 int wxLuaBindMethod_CompareByNameFnInit(const void *p1, const void *p2)
689 {
690     int v = strcmp(((const wxLuaBindMethod*)p1)->name, ((const wxLuaBindMethod*)p2)->name);
691     if (v == 0)
692     {
693         int t1 = ((const wxLuaBindMethod*)p1)->method_type;
694         int t2 = ((const wxLuaBindMethod*)p2)->method_type;
695         v = t1 - t2;
696     }
697 
698     wxCHECK_MSG(v != 0, 0, wxT("Duplicate wxLuaBindMethod names and method_types"));
699 
700     return v;
701 }
702 // Function for wxLuaBinding::GetClassMethod()
wxLuaBindMethod_CompareByNameFnGet(const void * p1,const void * p2)703 int wxLuaBindMethod_CompareByNameFnGet(const void *p1, const void *p2)
704 {
705     int v = strcmp(((const wxLuaBindMethod*)p1)->name, ((const wxLuaBindMethod*)p2)->name);
706     if (v == 0)
707     {
708         int t1 = ((const wxLuaBindMethod*)p1)->method_type;
709         int t2 = ((const wxLuaBindMethod*)p2)->method_type;
710 
711         if ((t1 & t2) != 0) return 0; // any matched bits will work
712 
713         v = t1 - t2;
714     }
715 
716     return v;
717 }
718 // Function to compare the wxLuaBindClasses by name
wxLuaBindClass_CompareByNameFn(const void * p1,const void * p2)719 int wxLuaBindClass_CompareByNameFn(const void *p1, const void *p2)
720 {
721     return strcmp(((const wxLuaBindClass*)p1)->name, ((const wxLuaBindClass*)p2)->name);
722 }
723 // Function to compare the wxLuaBindClasses by wxluatype
wxLuaBindClass_CompareBywxLuaTypeFn(const void * p1,const void * p2)724 int wxLuaBindClass_CompareBywxLuaTypeFn(const void *p1, const void *p2)
725 {
726     return (*((const wxLuaBindClass*)p1)->wxluatype) - (*((const wxLuaBindClass*)p2)->wxluatype);
727 }
728 
729 // ----------------------------------------------------------------------------
730 // wxLuaBinding
731 // ----------------------------------------------------------------------------
732 
733 IMPLEMENT_ABSTRACT_CLASS(wxLuaBinding, wxObject)
734 
735 wxLuaBindingArray wxLuaBinding::sm_bindingArray;
736 int wxLuaBinding::sm_bindingArray_initialized = 0;
737 int wxLuaBinding::sm_wxluatype_max = WXLUA_T_MAX+1; // highest wxLua type initially
738 
wxLuaBinding()739 wxLuaBinding::wxLuaBinding()
740              :m_classCount(0),    m_classArray(NULL),
741               m_numberCount(0),   m_numberArray(NULL),
742               m_stringCount(0),   m_stringArray(NULL),
743               m_eventCount(0),    m_eventArray(NULL),
744               m_objectCount(0),   m_objectArray(NULL),
745               m_functionCount(0), m_functionArray(NULL),
746               m_first_wxluatype(WXLUA_TUNKNOWN),
747               m_last_wxluatype(WXLUA_TUNKNOWN)
748 {
749 }
750 
InitBinding()751 void wxLuaBinding::InitBinding()
752 {
753     // Sort all the bindings by something useful for faster lookup later
754 
755     if (m_classArray && (m_classCount > 0))
756     {
757         // initialize types only once, we don't need to resort them either
758         if (*m_classArray[0].wxluatype != WXLUA_TUNKNOWN)
759             return;
760 
761         qsort(m_classArray, m_classCount, sizeof(wxLuaBindClass), wxLuaBindClass_CompareByNameFn);
762 
763         wxLuaBindClass* wxlClass = m_classArray;
764         for (size_t i = 0; i < m_classCount; ++i, ++wxlClass)
765         {
766             *wxlClass->wxluatype = ++wxLuaBinding::sm_wxluatype_max;
767 
768             // Also sort the member functions for each class
769             if (wxlClass->wxluamethods && (wxlClass->wxluamethods_n > 0))
770                 qsort(wxlClass->wxluamethods, wxlClass->wxluamethods_n, sizeof(wxLuaBindMethod), wxLuaBindMethod_CompareByNameFnInit);
771             // And their enums
772             if (wxlClass->enums && (wxlClass->enums_n > 0))
773                 qsort(wxlClass->enums, wxlClass->enums_n, sizeof(wxLuaBindNumber), wxLuaBindNumber_CompareByNameFn);
774         }
775 
776         // these mark what types numbers are declared in this binding
777         m_first_wxluatype = *m_classArray[0].wxluatype;
778         m_last_wxluatype  = *m_classArray[m_classCount-1].wxluatype;
779     }
780 
781     if (m_numberArray && (m_numberCount > 0))
782         qsort(m_numberArray, m_numberCount, sizeof(wxLuaBindNumber), wxLuaBindNumber_CompareByNameFn);
783 
784     if (m_stringArray && (m_stringCount > 0))
785         qsort(m_stringArray, m_stringCount, sizeof(wxLuaBindString), wxLuaBindString_CompareByNameFn);
786 
787     // sort by event type for fastest lookup
788     if (m_eventArray && (m_eventCount > 0))
789         qsort(m_eventArray, m_eventCount, sizeof(wxLuaBindEvent), wxLuaBindEvent_CompareByEventTypeFn);
790 
791     if (m_objectArray && (m_objectCount > 0))
792         qsort(m_objectArray, m_objectCount, sizeof(wxLuaBindObject), wxLuaBindObject_CompareByNameFn);
793 }
794 
795 // static
RegisterBindings(const wxLuaState & wxlState)796 bool wxLuaBinding::RegisterBindings(const wxLuaState& wxlState)
797 {
798     wxCHECK_MSG(wxlState.Ok(), false, wxT("Invalid wxLuaState"));
799 
800     lua_State *L = wxlState.GetLuaState();
801     size_t n, binding_count = sm_bindingArray.GetCount();
802 
803     wxLuaBinding::InitAllBindings(); // only runs the first time through
804 
805     for (n = 0; n < binding_count; ++n)
806     {
807         sm_bindingArray[n]->RegisterBinding(wxlState);
808         lua_pop(L, 1); // pop the Lua table the binding was installed into
809     }
810 
811     return true;
812 }
813 
RegisterBinding(const wxLuaState & wxlState)814 bool wxLuaBinding::RegisterBinding(const wxLuaState& wxlState)
815 {
816     wxCHECK_MSG(wxlState.Ok(), false, wxT("Invalid wxLuaState"));
817     lua_State *L = wxlState.GetLuaState();
818 
819     // Let Lua create a new table for us and add it to these places.
820     // We use an empty luaL_Reg since we just want luaL_register to create the
821     // tables for us, but we want to install the elements ourselves since
822     // wxLua is too large to follow the luaL_register method without being
823     // wasteful of memory and slow down the initialization.
824     //    LUA_REGISTRYINDEX["_LOADED"][m_nameSpace] = table
825     //    LUA_GLOBALSINDEX[m_nameSpace] = table
826     //    LUA_GLOBALSINDEX["package"]["loaded"][m_nameSpace] = table
827     static const luaL_Reg wxlualib[] = { {NULL, NULL} };
828 
829     wxLuaState::luaL_Register(L, wx2lua(m_nameSpace), wxlualib);
830 
831     // luaL_register should have given an error message about why it couldn't
832     // create the table for us
833     if (!lua_istable(L, -1))
834     {
835         lua_pop(L, 1); // pop the nil value
836         return false;
837     }
838 
839     // Find a registered binding with the same namespace, if any,
840     // and share the table with that of the previously loaded binding
841     int luaTable_ref = -1;
842 
843     lua_pushlightuserdata(L, &wxlua_lreg_wxluabindings_key); // push key
844     lua_rawget(L, LUA_REGISTRYINDEX);   // pop key, push value (the bindings table)
845 
846     lua_pushnil(L);
847     while (lua_next(L, -2) != 0)
848     {
849         // value = -1, key = -2, table = -3
850         wxLuaBinding* binding = (wxLuaBinding*)lua_touserdata(L, -2);
851 
852         if (binding->GetLuaNamespace() == m_nameSpace)
853         {
854             luaTable_ref = (int)lua_tonumber(L, -1);
855             lua_pop(L, 2); // pop key and value
856             break;
857         }
858 
859         lua_pop(L, 1); // pop value, lua_next will pop key at end
860     }
861 
862     lua_pop(L, 1); // pop table
863 
864 
865     // first time adding this namespace table
866     if (luaTable_ref < 1)
867     {
868         // create a ref for the wxLua table we're filling
869         luaTable_ref = wxluaR_ref(L, -1, &wxlua_lreg_refs_key);
870     }
871 
872     // Add us to the LUA_REGISTRYINDEX table of bindings
873     lua_pushlightuserdata(L, &wxlua_lreg_wxluabindings_key); // push key
874     lua_rawget(L, LUA_REGISTRYINDEX); // pop key, push value (the bindings table)
875 
876     lua_pushlightuserdata(L, this);  // push key
877     lua_pushnumber(L, luaTable_ref); // push value
878     lua_rawset(L, -3);               // set t[key] = value; pop key and value
879     lua_pop(L, 1);                   // pop table
880 
881     // register all our classes etc. in the wxLua table
882     DoRegisterBinding(wxlState);
883 
884     return true;
885 }
886 
DoRegisterBinding(const wxLuaState & wxlState) const887 void wxLuaBinding::DoRegisterBinding(const wxLuaState& wxlState) const
888 {
889     wxCHECK_RET(wxlState.Ok(), wxT("Invalid wxLuaState"));
890     lua_State *L = wxlState.GetLuaState();
891 
892     size_t n;
893 
894     // install the classes, functions and methods, creating new wxLua types
895     // if this is the first time we're registering them
896     const wxLuaBindClass *wxlClass = m_classArray;
897     for (n = 0; n < m_classCount; ++n, ++wxlClass)
898     {
899         InstallClassMetatable(L, wxlClass);
900         InstallClass(L, wxlClass);
901     }
902 
903     // register the global C style functions
904     const wxLuaBindMethod* wxlMethod = m_functionArray;
905     for (n = 0; n < m_functionCount; ++n, ++wxlMethod)
906     {
907         lua_pushstring(L, wxlMethod->name);
908         lua_pushlightuserdata(L, (void*)wxlMethod);
909         lua_pushcclosure(L, wxlMethod->wxluacfuncs[0].lua_cfunc, 1);
910         lua_rawset(L, -3);
911     }
912 
913     // install the numerical definitions
914     const wxLuaBindNumber* wxlNumber = m_numberArray;
915     for (n = 0; n < m_numberCount; ++n, ++wxlNumber)
916     {
917         lua_pushstring(L, wxlNumber->name);
918         lua_pushnumber(L, wxlNumber->value);
919         lua_rawset(L, -3);
920     }
921 
922     // install the strings
923     const wxLuaBindString *wxlString = m_stringArray;
924     for (n = 0; n < m_stringCount; ++n, ++wxlString)
925     {
926         lua_pushstring(L, wxlString->name);
927         if (wxlString->wxchar_string != NULL)
928             lua_pushstring(L, wx2lua(wxlString->wxchar_string));
929         else
930             lua_pushstring(L, wxlString->c_string);
931         lua_rawset(L, -3);
932     }
933 
934     // install the objects and pointers
935     const wxLuaBindObject *wxlObject = m_objectArray;
936     for (n = 0; n < m_objectCount; ++n, ++wxlObject)
937     {
938         lua_pushstring(L, wxlObject->name);
939 
940         if (wxlObject->objPtr != 0)
941             wxluaT_pushuserdatatype(L, wxlObject->objPtr, *wxlObject->wxluatype, true);
942         else
943             wxluaT_pushuserdatatype(L, *wxlObject->pObjPtr, *wxlObject->wxluatype, true);
944 
945         lua_rawset(L, -3);
946     }
947 
948     // register the wxEvent types
949     const wxLuaBindEvent *wxlEvent = m_eventArray;
950     for (n = 0; n < m_eventCount; ++n, ++wxlEvent)
951     {
952         lua_pushstring(L, wxlEvent->name);
953         lua_pushnumber(L, *wxlEvent->eventType);
954         lua_rawset(L, -3);
955     }
956 }
957 
958 /* static */
InstallClassMetatable(lua_State * L,const wxLuaBindClass * wxlClass)959 bool wxLuaBinding::InstallClassMetatable(lua_State* L, const wxLuaBindClass* wxlClass)
960 {
961     // Replace the metatable functions for the classes we push into Lua
962     static const luaL_Reg s_funcTable[] =
963     {
964         {"__gc",       wxlua_wxLuaBindClass__gc },
965         {"__index",    wxlua_wxLuaBindClass__index },
966         {"__newindex", wxlua_wxLuaBindClass__newindex },
967         {"__tostring", wxlua_wxLuaBindClass__tostring }
968     };
969     static const size_t s_funcCount = sizeof(s_funcTable)/sizeof(s_funcTable[0]);
970 
971     // ------------------------------------------------------------------
972     // Add to the lookup table for "class name" to wxLuaBindClass struct
973     lua_pushlightuserdata(L, &wxlua_lreg_classes_key);
974     lua_rawget(L, LUA_REGISTRYINDEX);           // pop key, push result (the classes table)
975     lua_pushstring(L, wxlClass->name);          // push key
976     lua_pushlightuserdata(L, (void *)wxlClass); // push value
977     lua_rawset(L, -3);                          // set t[key] = value, pops key and value
978     lua_pop(L, 1);                              // pop wxlua_lreg_classes_key table
979 
980     // ------------------------------------------------------------------
981     // Create a new metatable for this class with a numerical wxLua type index
982 
983     int wxl_type = *wxlClass->wxluatype;
984 
985     // we may be reregistering this binding, get the old metatable, we'll rewrite it
986     if (!wxluaT_getmetatable(L, wxl_type))
987         wxluaT_newmetatable(L, wxl_type); // create metatable, is on top of stack
988 
989     // store a lookup in the class metatable to the wxLuaBindClass struct
990     lua_pushlightuserdata(L, &wxlua_metatable_wxluabindclass_key); // push key
991     lua_pushlightuserdata(L, (void *)wxlClass);                    // push value
992     lua_rawset(L, -3); // set t[key] = value, pops key and value
993 
994     // set the functions for the class in the metatable
995     for (size_t i_func = 0; i_func < s_funcCount; ++i_func)
996     {
997         lua_pushstring(L, s_funcTable[i_func].name);      // push method name
998         lua_pushlightuserdata(L, (void *)wxlClass);       // push the userdata
999         lua_pushcclosure(L, s_funcTable[i_func].func, 1); // push func with wxlClass as upvalue
1000         lua_rawset(L, -3);  // t["method_name"] = closure of func and upvalues
1001     }
1002 
1003     lua_pop(L, 1); // pop metatable from wxluaT_newmetatable()
1004 
1005     return true;
1006 }
1007 
1008 /* static */
InstallClass(lua_State * L,const wxLuaBindClass * wxlClass)1009 bool wxLuaBinding::InstallClass(lua_State* L, const wxLuaBindClass* wxlClass)
1010 {
1011     // ------------------------------------------------------------------
1012     // Create and install the table for the class
1013 
1014     lua_pushstring(L, wxlClass->name); // push key
1015     lua_newtable(L);                   // push value, the table we use as the class
1016 
1017     // Install the member enums for the classname table
1018     for (int i_enum = 0; i_enum < wxlClass->enums_n; ++i_enum)
1019     {
1020         lua_pushstring(L, wxlClass->enums[i_enum].name);
1021         lua_pushnumber(L, wxlClass->enums[i_enum].value);
1022         lua_rawset(L, -3);
1023     }
1024 
1025     int method_count = wxlClass->wxluamethods_n;
1026 
1027     // Install the static functions for the classname table
1028     wxLuaBindMethod *wxlMethod = wxlClass->wxluamethods;
1029     for (int i_static_method = 0; i_static_method < method_count; ++i_static_method, ++wxlMethod)
1030     {
1031         // we will handle the WXLUAMETHOD_GET/SETPROP|WXLUAMETHOD_STATIC using __index and __newindex
1032         if (((wxlMethod->method_type & (WXLUAMETHOD_METHOD|WXLUAMETHOD_STATIC)) == (WXLUAMETHOD_METHOD|WXLUAMETHOD_STATIC)) &&
1033             (wxlMethod->wxluacfuncs_n > 0))
1034         {
1035             lua_pushstring(L, wxlMethod->name);
1036             lua_pushlightuserdata(L, wxlMethod);
1037             if (wxlMethod->wxluacfuncs_n > 1)
1038                 lua_pushcclosure(L, wxlua_callOverloadedFunction, 1);
1039             else
1040                 lua_pushcclosure(L, wxlMethod->wxluacfuncs[0].lua_cfunc, 1);
1041 
1042             lua_rawset(L, -3);
1043         }
1044     }
1045 
1046     // Create a metatable for the "class" table
1047     lua_newtable(L);
1048         lua_pushlstring(L, "__index", 7);
1049         lua_pushlightuserdata(L, (void*)wxlClass);
1050         lua_pushcclosure(L, wxlua_wxLuaBindMethod_table__index, 1);
1051         lua_rawset(L, -3);
1052 
1053         lua_pushlstring(L, "__newindex", 10);
1054         lua_pushlightuserdata(L, (void*)wxlClass);
1055         lua_pushcclosure(L, wxlua_wxLuaBindMethod_table__newindex, 1);
1056         lua_rawset(L, -3);
1057 
1058         //lua_pushstring(L, "__metatable");
1059         //lua_pushstring(L, "Metatable is not accessible");
1060         //lua_rawset(L, -3);
1061     lua_setmetatable(L, -2); // pops the metatable
1062 
1063     // Finalize the class table since we may not have a constructor
1064     // or have multiple constructors.
1065     lua_rawset(L, -3); // set t[key] = value, pops key and value
1066 
1067     // ------------------------------------------------------------------
1068     // Install public functions like constructors or global functions
1069     wxlMethod = wxlClass->wxluamethods;
1070     for (int i_method = 0; i_method < method_count; ++i_method, ++wxlMethod)
1071     {
1072         if (WXLUA_HASBIT(wxlMethod->method_type, WXLUAMETHOD_CONSTRUCTOR | WXLUAMETHOD_CFUNCTION) && wxlMethod->wxluacfuncs_n)
1073         {
1074             // push name of nested table and create the table or use existing
1075             // we do it this way since we can have multiple constructors (renamed)
1076             // that are of the same class and so they share the same wxLua type.
1077             lua_pushstring(L, wxlMethod->name);
1078 
1079             if (strcmp(wxlMethod->name, wxlClass->name) != 0)
1080                 lua_newtable(L);
1081             else
1082                 lua_getfield(L, -2, wxlMethod->name);
1083 
1084             // add the items to the table as t[first pushed] = second pushed
1085             lua_pushlstring(L, "new", 3);
1086             lua_pushlightuserdata(L, wxlMethod);
1087             lua_pushcclosure(L, wxlua_callOverloadedFunction, 1);
1088             lua_rawset(L, -3);
1089 
1090             // Add __call to the metatable for this table
1091             bool has_meta = (lua_getmetatable(L, -1) != 0);
1092             if (!has_meta) lua_newtable(L);
1093 
1094                 lua_pushlstring(L, "__call", 6);
1095                 lua_pushlightuserdata(L, wxlMethod);
1096                 lua_pushcclosure(L, wxlua_wxLuaBindMethod_table__call, 1);
1097                 lua_rawset(L, -3);
1098 
1099                 //lua_pushstring(L, "__metatable");
1100                 //lua_pushstring(L, "Metatable is not accessible");
1101                 //lua_rawset(L, -3);
1102 
1103             if (!has_meta)
1104                 lua_setmetatable(L, -2);
1105             else
1106                 lua_pop(L, 1);
1107 
1108             // add table to the binding table t[wxlMethod->name] = { this table }
1109             lua_rawset(L, -3); // set t[key] = value, pops key and value
1110         }
1111     }
1112 
1113     return true;
1114 }
1115 
1116 // ---------------------------------------------------------------------------
1117 
GetBindEvent(wxEventType eventType_) const1118 const wxLuaBindEvent* wxLuaBinding::GetBindEvent(wxEventType eventType_) const
1119 {
1120     const wxEventType eventType = eventType_;
1121     wxLuaBindEvent eventItem = { "", &eventType, NULL };
1122 
1123     const wxLuaBindEvent *pLuaEvent = (wxLuaBindEvent *)bsearch(&eventItem,
1124                                                     m_eventArray,
1125                                                     m_eventCount,
1126                                                     sizeof(wxLuaBindEvent),
1127                                                     wxLuaBindEvent_CompareByEventTypeFn);
1128     return pLuaEvent;
1129 }
1130 
GetEventTypeName(wxEventType eventType) const1131 wxString wxLuaBinding::GetEventTypeName(wxEventType eventType) const
1132 {
1133     const wxLuaBindEvent* wxlEvent = GetBindEvent(eventType);
1134     return (wxlEvent != NULL) ? lua2wx(wxlEvent->name) : wxString();
1135 }
1136 
GetBindClass(int wxluatype_) const1137 const wxLuaBindClass* wxLuaBinding::GetBindClass(int wxluatype_) const
1138 {
1139     int wxluatype = wxluatype_; // create a local var to get the address of
1140     wxLuaBindClass classItem = { 0, 0, 0, 0, &wxluatype, 0, 0, 0, 0 };
1141 
1142     // this relies on LUA allocating the wxLua types in ascending order of definition
1143     // if LUA stops doing this, then the search may break. Note that we initially
1144     // sort the classes by name then allocate types in acending order.
1145     const wxLuaBindClass *wxlClass = (wxLuaBindClass *)bsearch(&classItem,
1146                                                        m_classArray,
1147                                                        m_classCount,
1148                                                        sizeof(wxLuaBindClass),
1149                                                        wxLuaBindClass_CompareBywxLuaTypeFn);
1150 
1151     return wxlClass;
1152 }
1153 
GetBindClass(const char * className) const1154 const wxLuaBindClass* wxLuaBinding::GetBindClass(const char* className) const
1155 {
1156     wxLuaBindClass classItem = { className, 0, 0, 0, 0, 0, 0, 0, 0 };
1157 
1158     const wxLuaBindClass *wxlClass = (wxLuaBindClass *)bsearch(&classItem,
1159                                                        m_classArray,
1160                                                        m_classCount,
1161                                                        sizeof(wxLuaBindClass),
1162                                                        wxLuaBindClass_CompareByNameFn);
1163 
1164     return wxlClass;
1165 }
1166 
GetBindClass(const wxLuaBindMethod * wxlMethod_tofind) const1167 const wxLuaBindClass* wxLuaBinding::GetBindClass(const wxLuaBindMethod* wxlMethod_tofind) const
1168 {
1169     size_t c, m, methods_n;
1170     wxLuaBindClass*  wxlClass  = m_classArray;
1171     wxLuaBindMethod* wxlMethod = NULL;
1172 
1173     for (c = 0; c < m_classCount; ++c, ++wxlClass)
1174     {
1175         wxlMethod = wxlClass->wxluamethods;
1176         methods_n = wxlClass->wxluamethods_n;
1177 
1178         for (m = 0; m < methods_n; ++m, ++wxlMethod)
1179         {
1180             if (wxlMethod == wxlMethod_tofind)
1181                 return wxlClass;
1182         }
1183     }
1184 
1185     return NULL;
1186 }
1187 
GetBindClass(const wxLuaBindCFunc * wxlCFunc_tofind) const1188 const wxLuaBindClass* wxLuaBinding::GetBindClass(const wxLuaBindCFunc* wxlCFunc_tofind) const
1189 {
1190     size_t c, m, f, methods_n, funcs_n;
1191     wxLuaBindClass*  wxlClass  = m_classArray;
1192     wxLuaBindMethod* wxlMethod = NULL;
1193     wxLuaBindCFunc*  wxlCFunc  = NULL;
1194 
1195     for (c = 0; c < m_classCount; ++c, ++wxlClass)
1196     {
1197         wxlMethod = wxlClass->wxluamethods;
1198         methods_n = wxlClass->wxluamethods_n;
1199 
1200         for (m = 0; m < methods_n; ++m, ++wxlMethod)
1201         {
1202             wxlCFunc = wxlMethod->wxluacfuncs;
1203             funcs_n  = wxlMethod->wxluacfuncs_n;
1204 
1205             for (f = 0; f < funcs_n; ++f, ++wxlCFunc)
1206             {
1207                 if (wxlCFunc == wxlCFunc_tofind)
1208                     return wxlClass;
1209             }
1210         }
1211     }
1212 
1213     return NULL;
1214 }
1215 
1216 // --------------------------------------------------------------------------
1217 
1218 // static
GetLuaBinding(const wxString & bindingName)1219 wxLuaBinding* wxLuaBinding::GetLuaBinding(const wxString& bindingName)
1220 {
1221     size_t i, binding_count = sm_bindingArray.GetCount();
1222 
1223     for (i = 0; i < binding_count; ++i)
1224     {
1225         if (sm_bindingArray[i]->GetBindingName() == bindingName)
1226             return sm_bindingArray[i];
1227     }
1228 
1229     return NULL;
1230 }
1231 
1232 // static
FindBindClass(const char * className)1233 const wxLuaBindClass* wxLuaBinding::FindBindClass(const char* className)
1234 {
1235     size_t i, binding_count = sm_bindingArray.GetCount();
1236 
1237     for (i = 0; i < binding_count; ++i)
1238     {
1239         const wxLuaBindClass* wxlClass = sm_bindingArray[i]->GetBindClass(className);
1240 
1241         if (wxlClass)
1242             return wxlClass;
1243     }
1244 
1245     return NULL;
1246 }
1247 
1248 // static
FindBindClass(int wxluatype)1249 const wxLuaBindClass* wxLuaBinding::FindBindClass(int wxluatype)
1250 {
1251     size_t i, binding_count = sm_bindingArray.GetCount();
1252 
1253     for (i = 0; i < binding_count; ++i)
1254     {
1255         const wxLuaBindClass* wxlClass = sm_bindingArray[i]->GetBindClass(wxluatype);
1256 
1257         if (wxlClass)
1258             return wxlClass;
1259     }
1260 
1261     return NULL;
1262 }
1263 
1264 // static
FindBindClass(const wxLuaBindMethod * wxlMethod)1265 const wxLuaBindClass* wxLuaBinding::FindBindClass(const wxLuaBindMethod* wxlMethod)
1266 {
1267     size_t i, binding_count = sm_bindingArray.GetCount();
1268 
1269     for (i = 0; i < binding_count; ++i)
1270     {
1271         const wxLuaBindClass* wxlClass = sm_bindingArray[i]->GetBindClass(wxlMethod);
1272 
1273         if (wxlClass)
1274             return wxlClass;
1275     }
1276 
1277     return NULL;
1278 }
1279 
1280 // static
FindBindClass(const wxLuaBindCFunc * wxlCFunc)1281 const wxLuaBindClass* wxLuaBinding::FindBindClass(const wxLuaBindCFunc* wxlCFunc)
1282 {
1283     size_t i, binding_count = sm_bindingArray.GetCount();
1284 
1285     for (i = 0; i < binding_count; ++i)
1286     {
1287         const wxLuaBindClass* wxlClass = sm_bindingArray[i]->GetBindClass(wxlCFunc);
1288 
1289         if (wxlClass)
1290             return wxlClass;
1291     }
1292 
1293     return NULL;
1294 }
1295 
1296 // static
FindBindEvent(wxEventType eventType)1297 const wxLuaBindEvent* wxLuaBinding::FindBindEvent(wxEventType eventType)
1298 {
1299     size_t i, binding_count = sm_bindingArray.GetCount();
1300 
1301     for (i = 0; i < binding_count; ++i)
1302     {
1303         const wxLuaBindEvent* wxlEvent = sm_bindingArray[i]->GetBindEvent(eventType);
1304 
1305         if (wxlEvent)
1306             return wxlEvent;
1307     }
1308 
1309     return NULL;
1310 }
1311 
1312 // static
FindMethodBinding(const wxLuaBindMethod * wxlMethod)1313 wxLuaBinding* wxLuaBinding::FindMethodBinding(const wxLuaBindMethod* wxlMethod)
1314 {
1315     size_t i, binding_count = sm_bindingArray.GetCount();
1316 
1317     for (i = 0; i < binding_count; ++i)
1318     {
1319         size_t j, fn_count = sm_bindingArray[i]->GetFunctionCount();
1320         wxLuaBindMethod* m = sm_bindingArray[i]->GetFunctionArray();
1321 
1322         for (j = 0; j < fn_count; ++j, ++m)
1323         {
1324             if (m == wxlMethod)
1325                 return sm_bindingArray[i];
1326         }
1327     }
1328 
1329     return NULL;
1330 }
1331 
1332 
1333 // --------------------------------------------------------------------------
1334 
1335 // static
GetClassMethod(const wxLuaBindClass * wxlClass,const char * methodName,int method_type,bool search_baseclasses)1336 wxLuaBindMethod* wxLuaBinding::GetClassMethod(const wxLuaBindClass *wxlClass, const char *methodName, int method_type, bool search_baseclasses)
1337 {
1338     wxCHECK_MSG(wxlClass, NULL, wxT("Invalid wxLuaBindClass to find method from."));
1339 
1340     wxLuaBindMethod methodItem = { methodName, method_type, 0, 0, 0 };
1341 
1342     wxLuaBindMethod *wxlMethod = (wxLuaBindMethod *)bsearch(&methodItem,
1343                                                        wxlClass->wxluamethods,
1344                                                        wxlClass->wxluamethods_n,
1345                                                        sizeof(wxLuaBindMethod),
1346                                                        wxLuaBindMethod_CompareByNameFnGet);
1347 
1348     if ((wxlMethod == NULL) && search_baseclasses && wxlClass->baseclassNames)
1349     {
1350         for (size_t i = 0; wxlClass->baseclassNames[i]; ++i)
1351         {
1352             // The class may not have been installed
1353             if (wxlClass->baseBindClasses[i])
1354             {
1355                 wxlMethod = GetClassMethod(wxlClass->baseBindClasses[i], methodName, method_type, search_baseclasses);
1356                 if (wxlMethod != NULL)
1357                     return wxlMethod;
1358             }
1359         }
1360     }
1361 
1362     return wxlMethod;
1363 }
1364 
1365 // --------------------------------------------------------------------------
1366 
1367 // static
InitAllBindings(bool force_update)1368 void wxLuaBinding::InitAllBindings(bool force_update)
1369 {
1370     size_t n, i, j, k, binding_count = sm_bindingArray.GetCount();
1371 
1372     // update if a binding was added or removed
1373     if (((size_t)sm_bindingArray_initialized == binding_count) && !force_update)
1374         return;
1375 
1376     // set the base class wxLuaBindClass* using the base class names of the parent wxLuaBindClass
1377     for (n = 0; n < binding_count; ++n)
1378     {
1379         wxLuaBindClass* wxlClass = sm_bindingArray[n]->GetClassArray();
1380         size_t class_count       = sm_bindingArray[n]->GetClassCount();
1381 
1382         for (i = 0; i < class_count; ++i, ++wxlClass)
1383         {
1384             if (wxlClass->baseclassNames) // does it have any base classes at all?
1385             {
1386                 // find the base class using their names in the bindings
1387                 for (j = 0; wxlClass->baseclassNames[j]; ++j)
1388                 {
1389                     wxLuaBindClass* wxlBaseClass = (wxLuaBindClass*)wxLuaBinding::FindBindClass(wxlClass->baseclassNames[j]);
1390                     if (wxlBaseClass)
1391                         wxlClass->baseBindClasses[j] = wxlBaseClass;
1392                 }
1393             }
1394         }
1395     }
1396 
1397     // Link together all of the class member functions with base class functions
1398     // with the same name so the overloads work for them too.
1399     for (n = 0; n < binding_count; ++n)
1400     {
1401         wxLuaBindClass* wxlClass = sm_bindingArray[n]->GetClassArray();
1402         size_t i, class_count    = sm_bindingArray[n]->GetClassCount();
1403 
1404         for (i = 0; i < class_count; ++i, ++wxlClass)
1405         {
1406             if (wxlClass->baseclassNames) // does it have any base classes at all?
1407             {
1408                 wxLuaBindMethod *wxlMethod = wxlClass->wxluamethods;
1409                 size_t method_count        = wxlClass->wxluamethods_n;
1410 
1411                 for (j = 0; j < method_count; ++j, ++wxlMethod)
1412                 {
1413                     if (wxlClass->baseclassNames && !WXLUA_HASBIT(wxlMethod->method_type, WXLUAMETHOD_DELETE))
1414                     {
1415                         // Use the baseclassNames to check for terminating NULL
1416                         for (k = 0; wxlClass->baseclassNames[k]; ++k)
1417                         {
1418                             // Note that these may be NULL if the lib/module containing them wasn't loaded
1419                             wxLuaBindClass *baseClass = wxlClass->baseBindClasses[k];
1420                             if (baseClass != NULL)
1421                             {
1422                                 wxLuaBindMethod* baseMethod = wxLuaBinding::GetClassMethod(baseClass, wxlMethod->name, WXLUAMETHOD_MASK, true);
1423                                 if (baseMethod)
1424                                 {
1425                                     // don't link to base class delete functions
1426                                     if (!WXLUA_HASBIT(baseMethod->method_type, WXLUAMETHOD_DELETE))
1427                                         wxlMethod->basemethod = baseMethod;
1428                                 }
1429                             }
1430                         }
1431                     }
1432                 }
1433             }
1434         }
1435     }
1436 
1437     sm_bindingArray_initialized = binding_count;
1438 }
1439