1 /*
2    This file is part of darktable,
3    Copyright (C) 2013-2020 darktable developers.
4 
5    darktable is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9 
10    darktable is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with darktable.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 #include "lua/types.h"
19 #include "common/darktable.h"
20 #include "common/file_location.h"
21 #include "control/control.h"
22 #include "lua/call.h"
23 #include <math.h>
24 #include <stdarg.h>
25 #include <string.h>
26 
27 /*************/
28 /*   TYPES   */
29 /*************/
30 
to_char_array(lua_State * L,luaA_Type type_id,void * c_out,int index,int size)31 static void to_char_array(lua_State *L, luaA_Type type_id, void *c_out, int index, int size)
32 {
33   size_t tgt_size;
34   const char *value = luaL_checklstring(L, index, &tgt_size);
35   if(tgt_size > size)
36   {
37     luaL_error(L, "string '%s' too long (max is %d)", value, size);
38   }
39   strncpy(c_out, value, size);
40 }
41 
push_char_array(lua_State * L,luaA_Type type_id,const void * c_in)42 static int push_char_array(lua_State *L, luaA_Type type_id, const void *c_in)
43 {
44   lua_pushstring(L, c_in);
45   return 1;
46 }
47 
to_char20(lua_State * L,luaA_Type type_id,void * c_out,int index)48 static void to_char20(lua_State *L, luaA_Type type_id, void *c_out, int index)
49 {
50   to_char_array(L, type_id, c_out, index, 20);
51 }
to_char32(lua_State * L,luaA_Type type_id,void * c_out,int index)52 static void to_char32(lua_State *L, luaA_Type type_id, void *c_out, int index)
53 {
54   to_char_array(L, type_id, c_out, index, 32);
55 }
to_char52(lua_State * L,luaA_Type type_id,void * c_out,int index)56 static void to_char52(lua_State *L, luaA_Type type_id, void *c_out, int index)
57 {
58   to_char_array(L, type_id, c_out, index, 52);
59 }
to_char64(lua_State * L,luaA_Type type_id,void * c_out,int index)60 static void to_char64(lua_State *L, luaA_Type type_id, void *c_out, int index)
61 {
62   to_char_array(L, type_id, c_out, index, 64);
63 }
to_char128(lua_State * L,luaA_Type type_id,void * c_out,int index)64 static void to_char128(lua_State *L, luaA_Type type_id, void *c_out, int index)
65 {
66   to_char_array(L, type_id, c_out, index, 128);
67 }
to_char256(lua_State * L,luaA_Type type_id,void * c_out,int index)68 static void to_char256(lua_State *L, luaA_Type type_id, void *c_out, int index)
69 {
70   to_char_array(L, type_id, c_out, index, 256);
71 }
to_char512(lua_State * L,luaA_Type type_id,void * c_out,int index)72 static void to_char512(lua_State *L, luaA_Type type_id, void *c_out, int index)
73 {
74   to_char_array(L, type_id, c_out, index, 512);
75 }
to_char1024(lua_State * L,luaA_Type type_id,void * c_out,int index)76 static void to_char1024(lua_State *L, luaA_Type type_id, void *c_out, int index)
77 {
78   to_char_array(L, type_id, c_out, index, 1024);
79 }
to_charfilename_length(lua_State * L,luaA_Type type_id,void * c_out,int index)80 static void to_charfilename_length(lua_State *L, luaA_Type type_id, void *c_out, int index)
81 {
82   to_char_array(L, type_id, c_out, index, DT_MAX_FILENAME_LEN);
83 }
to_charpath_length(lua_State * L,luaA_Type type_id,void * c_out,int index)84 static void to_charpath_length(lua_State *L, luaA_Type type_id, void *c_out, int index)
85 {
86   to_char_array(L, type_id, c_out, index, PATH_MAX);
87 }
push_protected_double(lua_State * L,luaA_Type type_id,const void * c_in)88 static int push_protected_double(lua_State *L, luaA_Type type_id, const void *c_in)
89 {
90   double value = *(double *)c_in;
91   if(!isnormal(value))
92   {
93     lua_pushnil(L);
94   }
95   else
96   {
97     lua_pushnumber(L, value);
98   }
99   return 1;
100 }
101 
push_progress_double(lua_State * L,luaA_Type type_id,const void * c_in)102 static int push_progress_double(lua_State *L, luaA_Type type_id, const void *c_in)
103 {
104   double value = *(double *)c_in;
105   if(value < 0.0) value = 0.0;
106   if(value > 1.0) value = 1.0;
107   lua_pushnumber(L, value);
108   return 1;
109 }
110 
to_progress_double(lua_State * L,luaA_Type type_id,void * c_out,int index)111 static void to_progress_double(lua_State *L, luaA_Type type_id, void *c_out, int index)
112 {
113   luaA_to_double(L, type_id, c_out, index);
114   if(*(double *)c_out < 0.0) *(double *)c_out = 0.0;
115   if(*(double *)c_out > 1.0) *(double *)c_out = 1.0;
116 }
117 
118 /************************************/
119 /* METATBLE CALLBACKS FOR AUTOTYPES */
120 /************************************/
autotype_next(lua_State * L)121 static int autotype_next(lua_State *L)
122 {
123   /* CONVENTION
124      each block has the following stack on entry and exit
125     1 : the object
126     2 : the last entry ("next" convention)
127     each block should return according to "next" convention on success
128     each block should leave the key untouched if it doesn't know about it
129     each block should replace the key with "nil" if the key was the last entry it can handle
130 
131     */
132   // printf("aaaaa %s %d\n",__FUNCTION__,__LINE__);
133   if(luaL_getmetafield(L, 1, "__len"))
134   {
135     lua_pushvalue(L, -3);
136     lua_call(L, 1, 1);
137     int length = lua_tonumber(L, -1);
138     lua_pop(L, 1);
139     int key = 0;
140     if(lua_isnil(L, -1) && length > 0)
141     {
142       key = 1;
143     }
144     else if(lua_isnumber(L, -1) && lua_tonumber(L, -1) < length)
145     {
146       key = lua_tonumber(L, -1) + 1;
147     }
148     else if(lua_isnumber(L, -1) && lua_tonumber(L, -1) == length)
149     {
150       // numbers are done, move-on to something else
151       lua_pop(L, 1);
152       lua_pushnil(L);
153     }
154     if(key)
155     {
156       lua_pop(L, 1);
157       lua_pushinteger(L, key);
158       lua_pushinteger(L, key);
159       lua_gettable(L, -3);
160       return 2;
161     }
162   }
163   // stack at this point : {object,key}
164   int key_in_get = false;
165   luaL_getmetafield(L, 1, "__get");
166   if(lua_isnil(L, -2))
167   {
168     key_in_get = true;
169   }
170   else
171   {
172     lua_pushvalue(L, -2);
173     lua_gettable(L, -2);
174     if(lua_isnil(L, -1))
175     {
176       key_in_get = false;
177       lua_pop(L, 2);
178     }
179     else
180     {
181       key_in_get = true;
182       lua_pop(L, 1);
183     }
184   }
185   if(key_in_get)
186   {
187     lua_pushvalue(L, -2);
188     int nil_found = false;
189     while(!nil_found)
190     {
191       if(lua_next(L, -2))
192       {
193         // we have a next
194         lua_pop(L, 1);
195         lua_pushvalue(L, -4);
196         lua_pushvalue(L, -2);
197         // hacky way to avoid a subfunction just to do a pcall around getting a value in a table
198         luaL_loadstring(L,"args ={...}; return args[1][args[2]]");
199         lua_insert(L,-3);
200         int result = dt_lua_treated_pcall(L,2,1);
201         if(result == LUA_OK)
202         {
203           return 2;
204         }
205         else
206         {
207           lua_pop(L, 1);
208           // and loop to find the next possible value
209         }
210       }
211       else
212       {
213         // key was the last for __get
214         lua_pop(L, 2);
215         lua_pushnil(L);
216         nil_found = true;
217       }
218     }
219   }
220 
221   // stack at this point : {object,key}
222   if(lua_isnil(L, -1))
223   {
224     return 1;
225   }
226   else
227   {
228     return luaL_error(L, "invalid key to 'next' : %s", lua_tostring(L, 2));
229   }
230 }
231 
232 
233 
autotype_pairs(lua_State * L)234 static int autotype_pairs(lua_State *L)
235 {
236   luaL_getmetafield(L, 1, "__next");
237   lua_pushvalue(L, -2);
238   lua_pushnil(L); // index set to null for reset
239   return 3;
240 }
241 
autotype_index(lua_State * L)242 static int autotype_index(lua_State *L)
243 {
244   luaL_getmetafield(L, 1, "__get");
245   int pos_get = lua_gettop(L); // points at __get
246   lua_pushvalue(L, -2);
247   lua_gettable(L, -2);
248   if(lua_isnil(L, -1) && lua_isnumber(L, -3))
249   {
250     if(luaL_getmetafield(L, 1, "__number_index"))
251     {
252       lua_remove(L, -2);
253     }
254   }
255   if(lua_isnil(L, -1))
256   {
257     lua_pop(L, 1);
258     luaL_getmetafield(L, -3, "__luaA_TypeName");
259     return luaL_error(L, "field \"%s\" not found for type %s\n", lua_tostring(L, -3), lua_tostring(L, -1));
260   }
261   lua_pushvalue(L, -4);
262   lua_pushvalue(L, -4);
263   lua_call(L, 2, LUA_MULTRET);
264   lua_remove(L, pos_get);
265   return (lua_gettop(L) - pos_get + 1);
266 }
267 
268 
autotype_newindex(lua_State * L)269 static int autotype_newindex(lua_State *L)
270 {
271   luaL_getmetafield(L, 1, "__set");
272   int pos_set = lua_gettop(L); // points at __get
273   lua_pushvalue(L, -3);
274   lua_gettable(L, -2);
275   if(lua_isnil(L, -1) && lua_isnumber(L, -4))
276   {
277     if(luaL_getmetafield(L, -5, "__number_newindex"))
278     {
279       lua_remove(L, -2);
280     }
281   }
282   if(lua_isnil(L, -1))
283   {
284     lua_pop(L, 1);
285     luaL_getmetafield(L, -4, "__luaA_TypeName");
286     return luaL_error(L, "field \"%s\" can't be written for type %s\n", lua_tostring(L, -4),
287                       lua_tostring(L, -1));
288   }
289   lua_pushvalue(L, -5);
290   lua_pushvalue(L, -5);
291   lua_pushvalue(L, -5);
292   lua_call(L, 3, LUA_MULTRET);
293   lua_remove(L, pos_set);
294   return (lua_gettop(L) - pos_set + 1);
295 }
296 
297 
autotype_tostring(lua_State * L)298 static int autotype_tostring(lua_State *L)
299 {
300   if(luaL_getmetafield(L,1,"__real_tostring")) {
301     lua_insert(L,1);
302     lua_call(L,1,1);
303     return 1;
304   } else {
305     char tmp[256];
306     luaL_getmetafield(L,1,"__luaA_TypeName");
307     snprintf(tmp,sizeof(tmp),"%s (%p)",lua_tostring(L,-1),lua_topointer(L,1));
308     lua_pushstring(L,tmp);
309     return 1;
310   }
311 }
312 
313 /*************************/
314 /* PUSH AND TO FUNCTIONS */
315 /*************************/
316 
full_pushfunc(lua_State * L,luaA_Type type_id,const void * cin)317 static int full_pushfunc(lua_State *L, luaA_Type type_id, const void *cin)
318 {
319   size_t type_size = luaA_typesize(L, type_id);
320   void *udata = lua_newuserdata(L, type_size);
321   lua_newtable(L);
322   lua_setuservalue(L, -2);
323   if(cin)
324   {
325     memcpy(udata, cin, type_size);
326   }
327   else
328   {
329     memset(udata, 0, type_size);
330   }
331   luaL_setmetatable(L, luaA_typename(L, type_id));
332 
333   if(luaL_getmetafield(L, -1, "__init"))
334   {
335     lua_pushvalue(L, -2);                  // the new allocated object
336     lua_pushlightuserdata(L, (void *)cin); // forced to cast..
337     lua_call(L, 2, 0);
338   }
339   return 1;
340 }
341 
full_tofunc(lua_State * L,luaA_Type type_id,void * cout,int index)342 static void full_tofunc(lua_State *L, luaA_Type type_id, void *cout, int index)
343 {
344   if(!dt_lua_isa_type(L,index,type_id)) {
345     char error_msg[256];
346     snprintf(error_msg,sizeof(error_msg),"%s expected",luaA_typename(L,type_id));
347     luaL_argerror(L,index,error_msg);
348   }
349   void* udata = lua_touserdata(L,index);
350   memcpy(cout, udata, luaA_typesize(L, type_id));
351 }
352 
int_pushfunc(lua_State * L,luaA_Type type_id,const void * cin)353 static int int_pushfunc(lua_State *L, luaA_Type type_id, const void *cin)
354 {
355   luaL_getmetatable(L, luaA_typename(L, type_id));
356   luaL_getsubtable(L, -1, "__values");
357   int singleton = *(int *)cin;
358   lua_pushinteger(L, singleton);
359   lua_gettable(L, -2);
360   if(lua_isnoneornil(L, -1))
361   {
362     lua_pop(L, 1);
363     int *udata = lua_newuserdata(L, sizeof(int));
364     *udata = singleton;
365     luaL_setmetatable(L, luaA_typename(L, type_id));
366     lua_pushinteger(L, singleton);
367     // warning : no uservalue
368     lua_pushvalue(L, -2);
369     lua_settable(L, -4);
370     if(luaL_getmetafield(L, -1, "__init"))
371     {
372       lua_pushvalue(L, -2);                  // the new allocated object
373       lua_pushlightuserdata(L, (void *)cin); // forced to cast..
374       lua_call(L, 2, 0);
375     }
376   }
377   lua_remove(L, -2); //__values
378   lua_remove(L, -2); // metatable
379   return 1;
380 }
381 
int_tofunc(lua_State * L,luaA_Type type_id,void * cout,int index)382 static void int_tofunc(lua_State *L, luaA_Type type_id, void *cout, int index)
383 {
384   if(!dt_lua_isa_type(L,index,type_id)) {
385     char error_msg[256];
386     snprintf(error_msg,sizeof(error_msg),"%s expected",luaA_typename(L,type_id));
387     luaL_argerror(L,index,error_msg);
388   }
389   void* udata = lua_touserdata(L,index);
390   memcpy(cout, udata, sizeof(int));
391 }
392 
gpointer_pushfunc(lua_State * L,luaA_Type type_id,const void * cin)393 static int gpointer_pushfunc(lua_State *L, luaA_Type type_id, const void *cin)
394 {
395   gpointer singleton = *(gpointer *)cin;
396   if(!singleton) {
397     lua_pushnil(L);
398     return 1;
399   }
400   luaL_getsubtable(L, LUA_REGISTRYINDEX, "dt_lua_gpointer_values");
401   lua_pushlightuserdata(L, singleton);
402   lua_gettable(L, -2);
403   if(lua_isnoneornil(L, -1))
404   {
405     lua_pop(L, 1);
406     gpointer *udata = lua_newuserdata(L, sizeof(gpointer));
407     lua_newtable(L);
408     lua_setuservalue(L, -2);
409     *udata = singleton;
410     luaL_setmetatable(L, luaA_typename(L, type_id));
411     lua_pushlightuserdata(L, singleton);
412     lua_pushvalue(L, -2);
413     lua_settable(L, -4);
414     if(luaL_getmetafield(L, -1, "__init"))
415     {
416       lua_pushvalue(L, -2);                  // the new allocated object
417       lua_pushlightuserdata(L, (void *)cin); // forced to cast..
418       lua_call(L, 2, 0);
419     }
420   }
421   lua_remove(L, -2); //dt_lua_gpointer_values
422   return 1;
423 }
424 
gpointer_tofunc(lua_State * L,luaA_Type type_id,void * cout,int index)425 static void gpointer_tofunc(lua_State *L, luaA_Type type_id, void *cout, int index)
426 {
427   if(!dt_lua_isa_type(L,index,type_id)) {
428     char error_msg[256];
429     snprintf(error_msg,sizeof(error_msg),"%s expected",luaA_typename(L,type_id));
430     luaL_argerror(L,index,error_msg);
431   }
432   gpointer* udata = lua_touserdata(L,index);
433   memcpy(cout, udata, sizeof(gpointer));
434   if(!*udata) {
435     luaL_error(L,"Attempting to access of type %s after its destruction\n",luaA_typename(L,type_id));
436   }
437 }
438 
unknown_pushfunc(lua_State * L,luaA_Type type_id,const void * cin)439 static int unknown_pushfunc(lua_State *L, luaA_Type type_id, const void *cin)
440 {
441   gpointer singleton = *(gpointer *)cin;
442   if(!singleton) {
443     lua_pushnil(L);
444     return 1;
445   }
446   luaL_getsubtable(L, LUA_REGISTRYINDEX, "dt_lua_gpointer_values");
447   lua_pushlightuserdata(L, singleton);
448   lua_gettable(L, -2);
449   if(lua_isnoneornil(L, -1))
450   {
451     return luaL_error(L,"Attempting to push a pointer of unknown type on the stack\n");
452   }
453   lua_remove(L, -2); //dt_lua_gpointer_values
454   return 1;
455 }
456 
457 
458 /*****************/
459 /* TYPE CREATION */
460 /*****************/
dt_lua_type_register_type(lua_State * L,luaA_Type type_id,const char * name)461 void dt_lua_type_register_type(lua_State *L, luaA_Type type_id, const char *name)
462 {
463   luaL_getmetatable(L, luaA_typename(L, type_id)); // gets the metatable since it's supposed to exist
464   luaL_getsubtable(L, -1, "__get");
465   lua_pushvalue(L, -3);
466   lua_setfield(L, -2, name);
467   lua_pop(L, 1);
468 
469   luaL_getsubtable(L, -1, "__set");
470   lua_pushvalue(L, -3);
471   lua_setfield(L, -2, name);
472   lua_pop(L, 3);
473 }
474 
dt_lua_type_register_const_type(lua_State * L,luaA_Type type_id,const char * name)475 void dt_lua_type_register_const_type(lua_State *L, luaA_Type type_id, const char *name)
476 {
477   luaL_getmetatable(L, luaA_typename(L, type_id)); // gets the metatable since it's supposed to exist
478 
479   luaL_getsubtable(L, -1, "__get");
480   lua_pushvalue(L, -3);
481   lua_setfield(L, -2, name);
482   lua_pop(L, 3);
483 }
484 
dt_lua_type_register_number_const_type(lua_State * L,luaA_Type type_id)485 void dt_lua_type_register_number_const_type(lua_State *L, luaA_Type type_id)
486 {
487   luaL_getmetatable(L, luaA_typename(L, type_id)); // gets the metatable since it's supposed to exist
488 
489   lua_pushvalue(L, -2);
490   lua_setfield(L, -2, "__number_index");
491 
492   if(!lua_isnil(L, -3))
493   {
494     lua_pushvalue(L, -3);
495     lua_setfield(L, -2, "__len");
496   }
497 
498   lua_pop(L, 3);
499 }
dt_lua_type_register_number_type(lua_State * L,luaA_Type type_id)500 void dt_lua_type_register_number_type(lua_State *L, luaA_Type type_id)
501 {
502   luaL_getmetatable(L, luaA_typename(L, type_id)); // gets the metatable since it's supposed to exist
503 
504   lua_pushvalue(L, -2);
505   lua_setfield(L, -2, "__number_index");
506 
507   lua_pushvalue(L, -2);
508   lua_setfield(L, -2, "__number_newindex");
509 
510   if(!lua_isnil(L, -3))
511   {
512     lua_pushvalue(L, -3);
513     lua_setfield(L, -2, "__len");
514   }
515 
516   lua_pop(L, 3);
517 }
518 
dt_lua_type_member_luaautoc(lua_State * L)519 int dt_lua_type_member_luaautoc(lua_State *L)
520 {
521   const char *member_name = luaL_checkstring(L, 2);
522   luaL_getmetafield(L, 1, "__luaA_Type");
523   luaA_Type my_type = luaL_checkinteger(L, -1);
524   lua_pop(L, 1);
525   void *object = lua_touserdata(L, 1);
526   if(lua_gettop(L) != 3)
527   {
528     luaA_struct_push_member_name_type(L, my_type, member_name, object);
529     return 1;
530   }
531   else
532   {
533     luaA_struct_to_member_name_type(L, my_type, member_name, object, 3);
534     return 0;
535   }
536 }
537 
dt_lua_type_register_struct_type(lua_State * L,luaA_Type type_id)538 void dt_lua_type_register_struct_type(lua_State *L, luaA_Type type_id)
539 {
540   const char *member_name = luaA_struct_next_member_name_type(L, type_id, LUAA_INVALID_MEMBER_NAME);
541   while(member_name != LUAA_INVALID_MEMBER_NAME)
542   {
543     lua_pushvalue(L, -1);
544     luaA_Type member_type = luaA_struct_typeof_member_name_type(L, type_id, member_name);
545     if(luaA_conversion_to_registered_type(L, member_type) || luaA_struct_registered_type(L, member_type)
546        || luaA_enum_registered_type(L, member_type))
547     {
548       dt_lua_type_register_type(L, type_id, member_name);
549     }
550     else
551     {
552       dt_lua_type_register_const_type(L, type_id, member_name);
553     }
554     member_name = luaA_struct_next_member_name_type(L, type_id, member_name);
555   }
556   lua_pop(L, 1);
557 }
558 
559 
dt_lua_type_member_common(lua_State * L)560 int dt_lua_type_member_common(lua_State *L)
561 {
562   if(lua_gettop(L) != 2)
563   {
564     luaL_getmetafield(L, 1, "__luaA_TypeName");
565     return luaL_error(L, "field \"%s\" can't be written for type %s\n", lua_tostring(L, 2),
566                       lua_tostring(L, -1));
567   }
568   lua_pushvalue(L, lua_upvalueindex(1));
569   return 1;
570 }
571 
dt_lua_type_register_parent_type(lua_State * L,luaA_Type type_id,luaA_Type parent_type_id)572 void dt_lua_type_register_parent_type(lua_State *L, luaA_Type type_id, luaA_Type parent_type_id)
573 {
574   luaL_getmetatable(L, luaA_typename(L, type_id));        // gets the metatable since it's supposed to exist
575   luaL_getmetatable(L, luaA_typename(L, parent_type_id)); // gets the metatable since it's supposed to exist
576 
577   lua_pushvalue(L, -1);
578   lua_setfield(L, -3, "__luaA_ParentMetatable");
579 
580   lua_getfield(L, -2, "__get");
581   lua_getfield(L, -2, "__get");
582   lua_pushnil(L); /* first key */
583   while(lua_next(L, -2) != 0)
584   {
585     lua_getfield(L,-4,lua_tostring(L,-2));
586     if(lua_isnil(L,-1)) {
587       lua_pop(L,1);
588       lua_setfield(L, -4, lua_tostring(L,-2));
589     } else {
590       lua_pop(L,2);
591     }
592   }
593   lua_pop(L, 2);
594 
595   lua_getfield(L, -2, "__set");
596   lua_getfield(L, -2, "__set");
597   lua_pushnil(L); /* first key */
598   while(lua_next(L, -2) != 0)
599   {
600     lua_getfield(L,-4,lua_tostring(L,-2));
601     if(lua_isnil(L,-1)) {
602       lua_pop(L,1);
603       lua_setfield(L, -4, lua_tostring(L,-2));
604     } else {
605       lua_pop(L,2);
606     }
607   }
608   lua_pop(L, 2);
609 
610   lua_pushnil(L); /* first key */
611   while(lua_next(L, -2) != 0)
612   {
613     lua_getfield(L,-4,lua_tostring(L,-2));
614     if(lua_isnil(L,-1)) {
615       lua_pop(L,1);
616       lua_setfield(L, -4, lua_tostring(L,-2));
617     } else {
618       lua_pop(L,2);
619     }
620   }
621 
622 
623   lua_pop(L, 2);
624 }
625 
init_metatable(lua_State * L,luaA_Type type_id)626 static void init_metatable(lua_State *L, luaA_Type type_id)
627 {
628   luaL_newmetatable(L, luaA_typename(L, type_id));
629 
630   lua_pushstring(L, luaA_typename(L, type_id));
631   lua_setfield(L, -2, "__luaA_TypeName");
632 
633   lua_pushinteger(L, type_id);
634   lua_setfield(L, -2, "__luaA_Type");
635 
636   lua_pushvalue(L, -1);
637   lua_pushcclosure(L, autotype_next, 1);
638   lua_setfield(L, -2, "__next");
639 
640   lua_pushvalue(L, -1);
641   lua_pushcclosure(L, autotype_pairs, 1);
642   lua_setfield(L, -2, "__pairs");
643 
644   lua_pushvalue(L, -1);
645   lua_pushcclosure(L, autotype_index, 1);
646   lua_setfield(L, -2, "__index");
647 
648   lua_pushvalue(L, -1);
649   lua_pushcclosure(L, autotype_newindex, 1);
650   lua_setfield(L, -2, "__newindex");
651 
652   lua_newtable(L);
653   lua_setfield(L, -2, "__get");
654 
655   lua_newtable(L);
656   lua_setfield(L, -2, "__set");
657 
658   lua_pushvalue(L, -1);
659   lua_pushcclosure(L, autotype_tostring, 1);
660   lua_setfield(L, -2, "__tostring");
661 
662   // leave metatable on top of stack
663 }
664 
665 
dt_lua_init_type_type(lua_State * L,luaA_Type type_id)666 luaA_Type dt_lua_init_type_type(lua_State *L, luaA_Type type_id)
667 {
668   init_metatable(L, type_id);
669   lua_pop(L, 1);
670   luaA_conversion_type(L, type_id, full_pushfunc, full_tofunc);
671   return type_id;
672 }
673 
dt_lua_init_singleton(lua_State * L,const char * unique_name,void * data)674 luaA_Type dt_lua_init_singleton(lua_State *L, const char *unique_name, void *data)
675 {
676   char tmp_name[1024];
677   snprintf(tmp_name, sizeof(tmp_name), "dt_lua_singleton_%s", unique_name);
678 
679   luaA_Type type_id = luaA_type_add(L, tmp_name, sizeof(void *));
680   init_metatable(L, type_id);
681 
682   void **udata = lua_newuserdata(L, sizeof(void *));
683   lua_newtable(L);
684   lua_setuservalue(L, -2);
685   if(!data)
686   {
687     memset(udata, 0, sizeof(void *));
688   }
689   else
690   {
691     *udata = data;
692     luaL_getsubtable(L, LUA_REGISTRYINDEX, "dt_lua_gpointer_values");
693     lua_pushlightuserdata(L, data);
694     lua_pushvalue(L,-3);
695     lua_settable(L,-3);
696     lua_pop(L,1);
697   }
698 
699   lua_pushvalue(L, -1);
700   luaL_setmetatable(L, tmp_name);
701   lua_setfield(L, -3, "__singleton");
702   if(luaL_getmetafield(L, -1, "__init"))
703   {
704     lua_pushvalue(L, -2);                   // the new allocated object
705     lua_pushlightuserdata(L, (void *)data); // forced to cast..
706     lua_call(L, 2, 0);
707   }
708   lua_remove(L, -2);
709 
710   return type_id;
711 }
712 
713 
wrapped_index(lua_State * L)714 static int wrapped_index(lua_State *L)
715 {
716   luaL_getmetafield(L, 1, "__pusher");
717   lua_pushvalue(L, 1);
718   lua_call(L, 1, 1);
719   lua_pushvalue(L, 2);
720   lua_gettable(L, -2);
721   lua_remove(L, 1);
722   lua_remove(L, 1);
723   return 1;
724 }
725 
wrapped_pairs(lua_State * L)726 static int wrapped_pairs(lua_State *L)
727 {
728   luaL_getmetafield(L, 1, "__pusher");
729   lua_pushvalue(L, 1);
730   lua_call(L, 1, 1);
731   luaL_getmetafield(L, -1, "__pairs");
732   lua_pushvalue(L, -2);
733   lua_call(L, 1, 3);
734   return 3;
735 }
wrapped_newindex(lua_State * L)736 static int wrapped_newindex(lua_State *L)
737 {
738   return luaL_error(L, "TBSL");
739 }
wrapped_tostring(lua_State * L)740 static int wrapped_tostring(lua_State *L)
741 {
742   return luaL_error(L, "TBSL");
743 }
744 
745 
dt_lua_init_wrapped_singleton(lua_State * L,lua_CFunction pusher,lua_CFunction getter,const char * unique_name,void * data)746 luaA_Type dt_lua_init_wrapped_singleton(lua_State *L, lua_CFunction pusher, lua_CFunction getter,
747                                         const char *unique_name, void *data)
748 {
749   luaA_Type result = dt_lua_init_singleton(L, unique_name, data);
750   lua_getmetatable(L, -1);
751   lua_pushcfunction(L, wrapped_index);
752   lua_setfield(L, -2, "__index");
753   lua_pushcfunction(L, wrapped_newindex);
754   lua_setfield(L, -2, "__newindex");
755   lua_pushcfunction(L, wrapped_pairs);
756   lua_setfield(L, -2, "__pairs");
757   lua_pushcfunction(L, wrapped_tostring);
758   lua_setfield(L, -2, "__tostring");
759   lua_pushcfunction(L, pusher);
760   lua_setfield(L, -2, "__pusher");
761   lua_pushcfunction(L, getter);
762   lua_setfield(L, -2, "__getter");
763   lua_pop(L, 1);
764   return result;
765 }
766 
dt_lua_init_int_type_type(lua_State * L,luaA_Type type_id)767 luaA_Type dt_lua_init_int_type_type(lua_State *L, luaA_Type type_id)
768 {
769   init_metatable(L, type_id);
770   lua_newtable(L);
771   // metatable of __values
772   lua_newtable(L);
773   lua_pushstring(L, "kv");
774   lua_setfield(L, -2, "__mode");
775   lua_setmetatable(L, -2);
776 
777   lua_setfield(L, -2, "__values");
778   lua_pop(L, 1);
779   luaA_conversion_type(L, type_id, int_pushfunc, int_tofunc);
780   return type_id;
781 }
782 
gpointer_wrapper(lua_State * L)783 static int gpointer_wrapper(lua_State*L)
784 {
785   gpointer *udata = (gpointer*)lua_touserdata(L,1);
786   if(!*udata) {
787     luaL_getmetafield(L,1,"__luaA_TypeName");
788     luaL_error(L,"Attempting to access an invalid object of type %s",lua_tostring(L,-1));
789   }
790   lua_CFunction callback = lua_tocfunction(L,lua_upvalueindex(1));
791   return callback(L);
792 }
793 
794 
dt_lua_init_gpointer_type_type(lua_State * L,luaA_Type type_id)795 luaA_Type dt_lua_init_gpointer_type_type(lua_State *L, luaA_Type type_id)
796 {
797   init_metatable(L, type_id);
798 
799   lua_getfield(L,-1,"__next");
800   lua_pushcclosure(L, gpointer_wrapper,1);
801   lua_setfield(L, -2, "__next");
802 
803   lua_getfield(L,-1,"__index");
804   lua_pushcclosure(L, gpointer_wrapper,1);
805   lua_setfield(L, -2, "__index");
806 
807   lua_getfield(L,-1,"__newindex");
808   lua_pushcclosure(L, gpointer_wrapper,1);
809   lua_setfield(L, -2, "__newindex");
810 
811   lua_getfield(L,-1,"__pairs");
812   lua_pushcclosure(L, gpointer_wrapper,1);
813   lua_setfield(L, -2, "__pairs");
814 
815   lua_getfield(L,-1,"__tostring");
816   lua_pushcclosure(L, gpointer_wrapper,1);
817   lua_setfield(L, -2, "__tostring");
818 
819   lua_pop(L, 1);
820 
821   luaA_conversion_type(L, type_id, gpointer_pushfunc, gpointer_tofunc);
822   return type_id;
823 }
824 
dt_lua_type_gpointer_alias_type(lua_State * L,luaA_Type type_id,void * pointer,void * alias)825 void dt_lua_type_gpointer_alias_type(lua_State*L,luaA_Type type_id,void* pointer,void* alias)
826 {
827   luaL_getsubtable(L, LUA_REGISTRYINDEX, "dt_lua_gpointer_values");
828   lua_pushlightuserdata(L, pointer);
829   lua_gettable(L, -2);
830   if(lua_isnoneornil(L, -1))
831   {
832     luaL_error(L,"Adding an alias to an unknown object for type %s",luaA_typename(L,type_id));
833   }
834   lua_pushlightuserdata(L,alias);
835   lua_insert(L,-2);
836   lua_settable(L,-3);
837   lua_pop(L,1);
838 
839 
840 }
841 
dt_lua_type_gpointer_drop(lua_State * L,void * pointer)842 void dt_lua_type_gpointer_drop(lua_State*L, void* pointer)
843 {
844   luaL_getsubtable(L, LUA_REGISTRYINDEX, "dt_lua_gpointer_values");
845 
846   lua_pushlightuserdata(L, pointer);
847   lua_gettable(L,-2);
848   gpointer *udata = (gpointer*)lua_touserdata(L,-1);
849   if(lua_isnil(L,-1)) {
850     lua_pop(L,2);
851     return; // this table is weak, the object has been gc
852   }
853   *udata = NULL;
854   lua_pop(L,1);
855 
856   lua_pushlightuserdata(L, pointer);
857   lua_pushnil(L);
858   lua_settable(L,-3);
859 
860   lua_pop(L,1);
861 
862 }
863 
dt_lua_isa_type(lua_State * L,int index,luaA_Type type_id)864 gboolean dt_lua_isa_type(lua_State *L, int index, luaA_Type type_id)
865 {
866   if(!luaL_getmetafield(L, index, "__luaA_Type")) return false;
867   int obj_type = luaL_checkinteger(L, -1);
868   lua_pop(L, 1);
869   return dt_lua_typeisa_type(L, obj_type, type_id);
870 }
871 
dt_lua_typeisa_type(lua_State * L,luaA_Type obj_type,luaA_Type type_id)872 gboolean dt_lua_typeisa_type(lua_State *L, luaA_Type obj_type, luaA_Type type_id)
873 {
874   if(obj_type == type_id) return true;
875   luaL_getmetatable(L, luaA_typename(L, obj_type));
876   lua_getfield(L, -1, "__luaA_ParentMetatable");
877   if(lua_isnil(L, -1))
878   {
879     lua_pop(L, 2);
880     return false;
881   }
882   lua_getfield(L, -1, "__luaA_Type");
883   int parent_type = luaL_checkinteger(L, -1);
884   lua_pop(L, 3);
885   return dt_lua_typeisa_type(L, parent_type, type_id);
886 }
887 
dt_lua_type_setmetafield_type(lua_State * L,luaA_Type type_id,const char * method_name)888 void dt_lua_type_setmetafield_type(lua_State*L,luaA_Type type_id,const char* method_name)
889 {
890   // These metafields should never be overridden by user code
891   if(
892       !strcmp(method_name,"__index") ||
893       !strcmp(method_name,"__newindex") ||
894       !strcmp(method_name,"__number_index") ||
895       !strcmp(method_name,"__number_newindex") ||
896       !strcmp(method_name,"__pairs") ||
897       !strcmp(method_name,"__next") ||
898       !strcmp(method_name,"__get") ||
899       !strcmp(method_name,"__set") ||
900       !strcmp(method_name,"__len") ||
901       !strcmp(method_name,"__luaA_Type") ||
902       !strcmp(method_name,"__luaA_TypeName") ||
903       !strcmp(method_name,"__luaA_ParentMetatable") ||
904       !strcmp(method_name,"__init") ||
905       !strcmp(method_name,"__values") ||
906       !strcmp(method_name,"__singleton") ||
907       !strcmp(method_name,"__pusher") ||
908       !strcmp(method_name,"__getter") ||
909       !strcmp(method_name,"__mode") ||
910       0) {
911         luaL_error(L,"non-core lua code is not allowed to change meta-field %s\n",method_name);
912   } else if(!strcmp(method_name,"__tostring")) {
913     luaL_getmetatable(L, luaA_typename(L, type_id));
914     lua_pushvalue(L,-2);
915     lua_setfield(L, -2, "__real_tostring");
916     lua_pop(L, 2); // pop the metatable and the value
917     return;
918   // whitelist for specific types
919   } else if(
920       // if you add a type here, make sure it handles inheritance of metamethods itself
921       // typically, set the metamethod not for the parent type but just after inheritance
922       ( !strcmp(method_name,"__associated_object")&& dt_lua_typeisa_type(L,type_id,luaA_type_find(L,"dt_imageio_module_format_t"))) ||
923       ( !strcmp(method_name,"__associated_object")&& dt_lua_typeisa_type(L,type_id,luaA_type_find(L,"dt_imageio_module_storage_t"))) ||
924       ( !strcmp(method_name,"__gc")&& dt_lua_typeisa_type(L,type_id,luaA_type_find(L,"dt_style_t"))) ||
925       ( !strcmp(method_name,"__gc")&& dt_lua_typeisa_type(L,type_id,luaA_type_find(L,"dt_style_item_t"))) ||
926       ( !strcmp(method_name,"__gc")&& dt_lua_typeisa_type(L,type_id,luaA_type_find(L,"lua_widget"))) ||
927       ( !strcmp(method_name,"__call")&& dt_lua_typeisa_type(L,type_id,luaA_type_find(L,"lua_widget"))) ||
928       ( !strcmp(method_name,"__gtk_signals")&& dt_lua_typeisa_type(L,type_id,luaA_type_find(L,"lua_widget"))) ||
929       0) {
930     // Nothing to be done
931   } else {
932     luaL_error(L,"metafield not handled :%s for type %s\n",method_name,luaA_typename(L,type_id));
933   }
934   luaL_getmetatable(L, luaA_typename(L, type_id));
935   lua_pushvalue(L,-2);
936   lua_setfield(L, -2, method_name);
937   lua_pop(L, 2); // pop the metatable and the value
938 }
939 
dt_lua_init_early_types(lua_State * L)940 int dt_lua_init_early_types(lua_State *L)
941 {
942   luaA_conversion(L, char_20, push_char_array, to_char20);
943   luaA_conversion_push(L, const char_20, push_char_array);
944   luaA_conversion(L, char_32, push_char_array, to_char32);
945   luaA_conversion_push(L, const char_32, push_char_array);
946   luaA_conversion(L, char_52, push_char_array, to_char52);
947   luaA_conversion_push(L, const char_52, push_char_array);
948   luaA_conversion(L, char_64, push_char_array, to_char64);
949   luaA_conversion_push(L, const char_64, push_char_array);
950   luaA_conversion(L, char_128, push_char_array, to_char128);
951   luaA_conversion_push(L, const char_128, push_char_array);
952   luaA_conversion(L, char_256, push_char_array, to_char256);
953   luaA_conversion_push(L, const char_256, push_char_array);
954   luaA_conversion(L, char_512, push_char_array, to_char512);
955   luaA_conversion_push(L, const char_512, push_char_array);
956   luaA_conversion(L, char_1024, push_char_array, to_char1024);
957   luaA_conversion_push(L, const char_1024, push_char_array);
958   luaA_conversion(L, char_filename_length, push_char_array, to_charfilename_length);
959   luaA_conversion_push(L, const char_filename_length, push_char_array);
960   luaA_conversion(L, char_path_length, push_char_array, to_charpath_length);
961   luaA_conversion_push(L, const char_path_length, push_char_array);
962   luaA_conversion(L, int32_t, luaA_push_int, luaA_to_int);
963   luaA_conversion_push(L, const int32_t, luaA_push_int);
964   luaA_conversion_push(L, const_string, luaA_push_const_char_ptr);
965   luaA_conversion(L, protected_double, push_protected_double, luaA_to_double);
966   luaA_conversion(L, progress_double, push_progress_double, to_progress_double);
967 
968   luaA_conversion_push_type(L, luaA_type_add(L,"unknown",sizeof(void*)), unknown_pushfunc);
969   // table of gpointer values
970   lua_newtable(L);
971   lua_newtable(L);
972   lua_pushstring(L, "kv");
973   lua_setfield(L, -2, "__mode");
974   lua_setmetatable(L, -2);
975 
976   lua_setfield(L, LUA_REGISTRYINDEX, "dt_lua_gpointer_values");
977 
978   luaA_enum(L,dt_lua_orientation_t);
979   luaA_enum_value_name(L,dt_lua_orientation_t,GTK_ORIENTATION_HORIZONTAL,"horizontal");
980   luaA_enum_value_name(L,dt_lua_orientation_t,GTK_ORIENTATION_VERTICAL,"vertical");
981 
982   luaA_enum(L, dt_lua_align_t);
983   luaA_enum_value_name(L, dt_lua_align_t, GTK_ALIGN_FILL, "fill");
984   luaA_enum_value_name(L, dt_lua_align_t, GTK_ALIGN_START, "start");
985   luaA_enum_value_name(L, dt_lua_align_t, GTK_ALIGN_END, "end");
986   luaA_enum_value_name(L, dt_lua_align_t, GTK_ALIGN_CENTER, "center");
987   luaA_enum_value_name(L, dt_lua_align_t, GTK_ALIGN_BASELINE, "baseline");
988 
989   luaA_enum(L, dt_lua_ellipsize_mode_t);
990   luaA_enum_value_name(L, dt_lua_ellipsize_mode_t, PANGO_ELLIPSIZE_NONE, "none");
991   luaA_enum_value_name(L, dt_lua_ellipsize_mode_t, PANGO_ELLIPSIZE_START, "start");
992   luaA_enum_value_name(L, dt_lua_ellipsize_mode_t, PANGO_ELLIPSIZE_MIDDLE, "middle");
993   luaA_enum_value_name(L, dt_lua_ellipsize_mode_t, PANGO_ELLIPSIZE_END, "end");
994 
995   return 0;
996 }
997 
998 // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
999 // vim: shiftwidth=2 expandtab tabstop=2 cindent
1000 // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1001