1 /******************************************************************************
2 Copyright (C) 2017 by Hugh Bailey <jim@obsproject.com>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
17
18 #pragma once
19
20 /* ---------------------------- */
21
22 #include <lua.h>
23 #include <lualib.h>
24 #include <lauxlib.h>
25
26 #ifdef _MSC_VER
27 #pragma warning(push)
28 #pragma warning(disable : 4100)
29 #pragma warning(disable : 4189)
30 #pragma warning(disable : 4244)
31 #pragma warning(disable : 4267)
32 #endif
33
34 #define SWIG_TYPE_TABLE obslua
35 #include "swig/swigluarun.h"
36
37 #ifdef _MSC_VER
38 #pragma warning(pop)
39 #endif
40 /* ---------------------------- */
41
42 #include <util/threading.h>
43 #include <util/base.h>
44 #include <util/bmem.h>
45
46 #include "obs-scripting-internal.h"
47 #include "obs-scripting-callback.h"
48
49 #define do_log(level, format, ...) blog(level, "[Lua] " format, ##__VA_ARGS__)
50
51 #define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
52 #define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
53 #define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
54
55 /* ------------------------------------------------------------ */
56
57 struct obs_lua_script;
58 struct lua_obs_callback;
59
60 extern THREAD_LOCAL struct lua_obs_callback *current_lua_cb;
61 extern THREAD_LOCAL struct obs_lua_script *current_lua_script;
62
63 /* ------------------------------------------------------------ */
64
65 struct lua_obs_callback;
66
67 struct obs_lua_script {
68 obs_script_t base;
69
70 struct dstr dir;
71 struct dstr log_chunk;
72
73 pthread_mutex_t mutex;
74 lua_State *script;
75
76 struct script_callback *first_callback;
77
78 int update;
79 int get_properties;
80 int save;
81
82 int tick;
83 struct obs_lua_script *next_tick;
84 struct obs_lua_script **p_prev_next_tick;
85
86 bool defined_sources;
87 };
88
89 #define lock_callback() \
90 struct obs_lua_script *__last_script = current_lua_script; \
91 struct lua_obs_callback *__last_callback = current_lua_cb; \
92 current_lua_cb = cb; \
93 current_lua_script = (struct obs_lua_script *)cb->base.script; \
94 pthread_mutex_lock(¤t_lua_script->mutex);
95 #define unlock_callback() \
96 pthread_mutex_unlock(¤t_lua_script->mutex); \
97 current_lua_script = __last_script; \
98 current_lua_cb = __last_callback;
99
100 /* ------------------------------------------------ */
101
102 struct lua_obs_callback {
103 struct script_callback base;
104
105 lua_State *script;
106 int reg_idx;
107 };
108
109 static inline struct lua_obs_callback *
add_lua_obs_callback_extra(lua_State * script,int stack_idx,size_t extra_size)110 add_lua_obs_callback_extra(lua_State *script, int stack_idx, size_t extra_size)
111 {
112 struct obs_lua_script *data = current_lua_script;
113 struct lua_obs_callback *cb =
114 add_script_callback(&data->first_callback, (obs_script_t *)data,
115 sizeof(*cb) + extra_size);
116
117 lua_pushvalue(script, stack_idx);
118 cb->reg_idx = luaL_ref(script, LUA_REGISTRYINDEX);
119 cb->script = script;
120 return cb;
121 }
122
add_lua_obs_callback(lua_State * script,int stack_idx)123 static inline struct lua_obs_callback *add_lua_obs_callback(lua_State *script,
124 int stack_idx)
125 {
126 return add_lua_obs_callback_extra(script, stack_idx, 0);
127 }
128
lua_obs_callback_extra_data(struct lua_obs_callback * cb)129 static inline void *lua_obs_callback_extra_data(struct lua_obs_callback *cb)
130 {
131 return (void *)&cb[1];
132 }
133
134 static inline struct obs_lua_script *
lua_obs_callback_script(struct lua_obs_callback * cb)135 lua_obs_callback_script(struct lua_obs_callback *cb)
136 {
137 return (struct obs_lua_script *)cb->base.script;
138 }
139
140 static inline struct lua_obs_callback *
find_next_lua_obs_callback(lua_State * script,struct lua_obs_callback * cb,int stack_idx)141 find_next_lua_obs_callback(lua_State *script, struct lua_obs_callback *cb,
142 int stack_idx)
143 {
144 struct obs_lua_script *data = current_lua_script;
145
146 cb = cb ? (struct lua_obs_callback *)cb->base.next
147 : (struct lua_obs_callback *)data->first_callback;
148
149 while (cb) {
150 lua_rawgeti(script, LUA_REGISTRYINDEX, cb->reg_idx);
151 bool match = lua_rawequal(script, -1, stack_idx);
152 lua_pop(script, 1);
153
154 if (match)
155 break;
156
157 cb = (struct lua_obs_callback *)cb->base.next;
158 }
159
160 return cb;
161 }
162
find_lua_obs_callback(lua_State * script,int stack_idx)163 static inline struct lua_obs_callback *find_lua_obs_callback(lua_State *script,
164 int stack_idx)
165 {
166 return find_next_lua_obs_callback(script, NULL, stack_idx);
167 }
168
remove_lua_obs_callback(struct lua_obs_callback * cb)169 static inline void remove_lua_obs_callback(struct lua_obs_callback *cb)
170 {
171 remove_script_callback(&cb->base);
172 luaL_unref(cb->script, LUA_REGISTRYINDEX, cb->reg_idx);
173 }
174
just_free_lua_obs_callback(struct lua_obs_callback * cb)175 static inline void just_free_lua_obs_callback(struct lua_obs_callback *cb)
176 {
177 just_free_script_callback(&cb->base);
178 }
179
free_lua_obs_callback(struct lua_obs_callback * cb)180 static inline void free_lua_obs_callback(struct lua_obs_callback *cb)
181 {
182 free_script_callback(&cb->base);
183 }
184
185 /* ------------------------------------------------ */
186
is_ptr(lua_State * script,int idx)187 static int is_ptr(lua_State *script, int idx)
188 {
189 return lua_isuserdata(script, idx) || lua_isnil(script, idx);
190 }
191
is_table(lua_State * script,int idx)192 static int is_table(lua_State *script, int idx)
193 {
194 return lua_istable(script, idx);
195 }
196
is_function(lua_State * script,int idx)197 static int is_function(lua_State *script, int idx)
198 {
199 return lua_isfunction(script, idx);
200 }
201
202 typedef int (*param_cb)(lua_State *script, int idx);
203
verify_args1_(lua_State * script,param_cb param1_check,const char * func)204 static inline bool verify_args1_(lua_State *script, param_cb param1_check,
205 const char *func)
206 {
207 if (lua_gettop(script) != 1) {
208 warn("Wrong number of parameters for %s", func);
209 return false;
210 }
211 if (!param1_check(script, 1)) {
212 warn("Wrong parameter type for parameter %d of %s", 1, func);
213 return false;
214 }
215
216 return true;
217 }
218
219 #define verify_args1(script, param1_check) \
220 verify_args1_(script, param1_check, __FUNCTION__)
221
call_func_(lua_State * script,int reg_idx,int args,int rets,const char * func,const char * display_name)222 static inline bool call_func_(lua_State *script, int reg_idx, int args,
223 int rets, const char *func,
224 const char *display_name)
225 {
226 if (reg_idx == LUA_REFNIL)
227 return false;
228
229 struct obs_lua_script *data = current_lua_script;
230
231 lua_rawgeti(script, LUA_REGISTRYINDEX, reg_idx);
232 lua_insert(script, -1 - args);
233
234 if (lua_pcall(script, args, rets, 0) != 0) {
235 script_warn(&data->base, "Failed to call %s for %s: %s", func,
236 display_name, lua_tostring(script, -1));
237 lua_pop(script, 1);
238 return false;
239 }
240
241 return true;
242 }
243
244 bool ls_get_libobs_obj_(lua_State *script, const char *type, int lua_idx,
245 void *libobs_out, const char *id, const char *func,
246 int line);
247 bool ls_push_libobs_obj_(lua_State *script, const char *type, void *libobs_in,
248 bool ownership, const char *id, const char *func,
249 int line);
250
251 extern void add_lua_source_functions(lua_State *script);
252