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(&current_lua_script->mutex);
95 #define unlock_callback()                                 \
96 	pthread_mutex_unlock(&current_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