GCC Code Coverage Report


Directory: src/gate/
File: src/gate/scripting/luascripts.c
Date: 2025-09-22 22:57:09
Exec Total Coverage
Lines: 0 792 0.0%
Functions: 0 43 0.0%
Branches: 0 273 0.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/scripting/luascripts.h"
30 #include "gate/results.h"
31 #include "gate/guids.h"
32 #include "gate/times.h"
33 #include "gate/console.h"
34 #include "gate/functions.h"
35 #include "gate/files.h"
36 #include "gate/platforms.h"
37
38 #if defined(GATE_EXTLIB_LUA)
39 # define GATE_SCRIPTING_LUA_USE_LUA 1
40 #else
41 # define GATE_SCRIPTING_LUA_NO_IMPL 1
42 #endif
43
44
45 #if defined(GATE_SCRIPTING_LUA_USE_LUA)
46
47 #include <lua.h>
48 #include <lualib.h>
49 #include <lauxlib.h>
50
51
52 #define GATE_SCRIPT_LUA_SESSION_POINTER_NAME "__gate_script_lua_session"
53
54 ✗ void gate_lua_writestring(char const* str, size_t len, gate_bool_t flushcon)
55 {
56 ✗ gate_size_t written = 0;
57 ✗ gate_console_t* con = gate_console();
58 ✗ gate_stream_write_block((gate_stream_t*)con, str, len, &written);
59 ✗ if (flushcon)
60 {
61 ✗ gate_stream_flush((gate_stream_t*)con);
62 }
63 ✗ }
64
65 ✗ void gate_lua_writestring_err(char const* str, size_t len, gate_bool_t flushcon)
66 {
67 ✗ gate_size_t written = 0;
68 ✗ gate_console_t* con = gate_console();
69 ✗ gate_stream_write_block((gate_stream_t*)con, str, len, &written);
70 ✗ if (flushcon)
71 {
72 ✗ gate_stream_flush((gate_stream_t*)con);
73 }
74 ✗ }
75
76 ✗ gate_result_t gate_script_lua_init(gate_script_lua_session_t* session)
77 {
78 gate_result_t ret;
79
80 do
81 {
82 ✗ gate_mem_clear(session, sizeof(gate_script_lua_session_t));
83 ✗ ret = gate_script_lua_reset(session);
84 } while (0);
85 ✗ return ret;
86 }
87 ✗ gate_result_t gate_script_lua_uninit(gate_script_lua_session_t* session)
88 {
89 ✗ gate_result_t ret = GATE_RESULT_FAILED;
90 ✗ lua_State* lstate = NULL;
91
92 do
93 {
94 ✗ lstate = (lua_State*)session->state;
95 ✗ if (lstate != NULL)
96 {
97 ✗ lua_close(lstate);
98 ✗ session->state = NULL;
99 }
100 ✗ ret = GATE_RESULT_OK;
101 } while (0);
102
103 ✗ return ret;
104 }
105 ✗ gate_result_t gate_script_lua_reset(gate_script_lua_session_t* session)
106 {
107 ✗ gate_result_t ret = GATE_RESULT_FAILED;
108 ✗ lua_State* lstate = NULL;
109
110 do
111 {
112 ✗ lstate = luaL_newstate();
113 ✗ if (NULL == lstate)
114 {
115 ✗ ret = GATE_RESULT_OUTOFRESOURCES;
116 ✗ break;
117 }
118
119 ✗ luaopen_base(lstate);
120 ✗ luaopen_table(lstate);
121 ✗ luaopen_string(lstate);
122 ✗ luaopen_math(lstate);
123 ✗ luaopen_coroutine(lstate);
124 ✗ luaopen_utf8(lstate);
125
126 ✗ if (session->state != NULL)
127 {
128 ✗ lua_close((lua_State*)session->state);
129 }
130 ✗ lua_pushlightuserdata(lstate, session);
131 ✗ lua_setglobal(lstate, GATE_SCRIPT_LUA_SESSION_POINTER_NAME);
132 ✗ session->state = lstate;
133 ✗ lstate = NULL;
134 ✗ ret = GATE_RESULT_OK;
135 } while (0);
136
137 ✗ if (lstate != NULL)
138 {
139 ✗ lua_close(lstate);
140 }
141
142 ✗ return ret;
143 }
144
145 ✗ static gate_script_lua_session_t* gate_script_lua_get_session(lua_State* L)
146 {
147 ✗ lua_getglobal(L, GATE_SCRIPT_LUA_SESSION_POINTER_NAME);
148 ✗ return (gate_script_lua_session_t*)lua_touserdata(L, -1);
149 }
150
151
152 struct gate_script_lua_code_block
153 {
154 char const* data;
155 gate_size_t size;
156 };
157
158 ✗ static char const* gate_script_lua_code_reader(lua_State* L, void* data, size_t* size)
159 {
160 ✗ char const* ret = NULL;
161 ✗ struct gate_script_lua_code_block* block = (struct gate_script_lua_code_block*)data;
162
163 (void)L;
164 ✗ *size = 0;
165 ✗ if (block->size > 0)
166 {
167 ✗ ret = block->data;
168 ✗ *size = block->size;
169
170 ✗ block->data += block->size;
171 ✗ block->size = 0;
172 }
173 ✗ return ret;
174 }
175
176 ✗ static gate_result_t gate_script_lua_map_error(int lua_result_code)
177 {
178 ✗ switch (lua_result_code)
179 {
180 ✗ case LUA_OK: return GATE_RESULT_OK;
181 ✗ case LUA_YIELD: return GATE_RESULT_OK_PARTIAL;
182 ✗ case LUA_ERRRUN: return GATE_RESULT_EXECUTIONFAILED;
183 ✗ case LUA_ERRSYNTAX: return GATE_RESULT_INVALIDDATA;
184 ✗ case LUA_ERRMEM: return GATE_RESULT_OUTOFMEMORY;
185 ✗ case LUA_ERRERR: return GATE_RESULT_CRITICALERROR;
186 ✗ default: return GATE_RESULT_FAILED;
187 }
188 }
189
190 ✗ static gate_result_t gate_script_lua_load_impl(lua_State* lstate, gate_string_t const* code, gate_bool_t print_error)
191 {
192 ✗ gate_result_t ret = GATE_RESULT_FAILED;
193 int result;
194 struct gate_script_lua_code_block block;
195
196 (void)print_error;
197 do
198 {
199 ✗ block.data = gate_string_ptr(code, 0);
200 ✗ block.size = gate_string_length(code);
201 ✗ result = lua_load(lstate, &gate_script_lua_code_reader, &block, "gate_lua_code", NULL);
202 ✗ ret = gate_script_lua_map_error(result);
203 ✗ GATE_BREAK_IF_FAILED(ret);
204
205 ✗ result = lua_pcall(lstate, 0, 0, 0);
206 ✗ ret = gate_script_lua_map_error(result);
207 ✗ GATE_BREAK_IF_FAILED(ret);
208 } while (0);
209
210 ✗ return ret;
211
212 }
213
214 ✗ gate_result_t gate_script_lua_load(gate_script_lua_session_t* session, gate_string_t const* code)
215 {
216 ✗ return gate_script_lua_load_impl((lua_State*)session->state, code, false);
217 }
218
219
220 ✗ static gate_result_t gate_script_lua_push_value(lua_State* L, gate_value_t const* val)
221 {
222 ✗ gate_result_t ret = GATE_RESULT_FAILED;
223 ✗ gate_type_id_t value_type = gate_value_type(val);
224 ✗ void const* value_ptr = gate_value_get_ptr(val);
225
226 char buffer[8192];
227 ✗ gate_size_t buffer_used = 0;
228 ✗ gate_datetime_t datetime = GATE_INIT_EMPTY;
229
230 do
231 {
232 ✗ if (!value_ptr)
233 {
234 ✗ ret = GATE_RESULT_NOTAVAILABLE;
235 ✗ break;
236 }
237
238 ✗ ret = GATE_RESULT_OK;
239
240 ✗ switch (value_type)
241 {
242 ✗ case GATE_TYPE_BOOL: lua_pushboolean(L, *((gate_bool_t const*)value_ptr) ? 1 : 0); break;
243 ✗ case GATE_TYPE_I8: lua_pushinteger(L, (lua_Integer) * ((gate_int8_t const*)value_ptr)); break;
244 ✗ case GATE_TYPE_UI8: lua_pushinteger(L, (lua_Integer) * ((gate_uint8_t const*)value_ptr)); break;
245 ✗ case GATE_TYPE_I16: lua_pushinteger(L, (lua_Integer) * ((gate_int16_t const*)value_ptr)); break;
246 ✗ case GATE_TYPE_UI16: lua_pushinteger(L, (lua_Integer) * ((gate_uint16_t const*)value_ptr)); break;
247 ✗ case GATE_TYPE_I32: lua_pushinteger(L, (lua_Integer) * ((gate_int32_t const*)value_ptr)); break;
248 ✗ case GATE_TYPE_UI32: lua_pushinteger(L, (lua_Integer) * ((gate_uint32_t const*)value_ptr)); break;
249 ✗ case GATE_TYPE_I64: lua_pushinteger(L, (lua_Integer) * ((gate_int64_t const*)value_ptr)); break;
250 ✗ case GATE_TYPE_UI64: lua_pushinteger(L, (lua_Integer) * ((gate_uint64_t const*)value_ptr)); break;
251 ✗ case GATE_TYPE_ADDRESS: lua_pushinteger(L, (lua_Integer) * ((gate_uintptr_t const*)value_ptr)); break;
252 ✗ case GATE_TYPE_R32: lua_pushnumber(L, (lua_Number) * ((gate_real32_t const*)value_ptr)); break;
253 ✗ case GATE_TYPE_R64: lua_pushnumber(L, (lua_Number) * ((gate_real64_t const*)value_ptr)); break;
254
255 ✗ case GATE_TYPE_CSTR: lua_pushlstring(L, (char const*)value_ptr, gate_str_length((char const*)value_ptr)); break;
256 ✗ case GATE_TYPE_WSTR:
257 ✗ buffer_used = gate_str_utf16_2_utf8((gate_char16_t const*)value_ptr,
258 gate_str16_length((gate_char16_t const*)value_ptr),
259 buffer, sizeof(buffer));
260 ✗ lua_pushlstring(L, buffer, buffer_used);
261 ✗ break;
262 ✗ case GATE_TYPE_GUID:
263 ✗ gate_guid_to_string((gate_guid_t const*)value_ptr, buffer);
264 ✗ lua_pushlstring(L, buffer, 36);
265 ✗ break;
266 ✗ case GATE_TYPE_DATE:
267 ✗ datetime.date = *((gate_date_t const*)value_ptr);
268 ✗ buffer_used = sizeof(buffer);
269 ✗ gate_date_to_string(&datetime, 0, "{YYYY}-{MM}-{DD}", buffer, &buffer_used);
270 ✗ lua_pushlstring(L, buffer, buffer_used);
271 ✗ break;
272 ✗ case GATE_TYPE_DAYTIME:
273 ✗ datetime.time = *((gate_daytime_t const*)value_ptr);
274 ✗ buffer_used = sizeof(buffer);
275 ✗ gate_date_to_string(&datetime, 0, "{hh}:{mm}:{ss}.{SSS}", buffer, &buffer_used);
276 ✗ lua_pushlstring(L, buffer, buffer_used);
277 ✗ break;
278 ✗ case GATE_TYPE_DATETIME:
279 ✗ buffer_used = sizeof(buffer);
280 ✗ gate_date_to_string((gate_datetime_t const*)value_ptr, 0, NULL, buffer, &buffer_used);
281 ✗ lua_pushlstring(L, buffer, buffer_used);
282 ✗ break;
283 ✗ case GATE_TYPE_TIME:
284 ✗ gate_time_to_datetime((gate_time_t const*)value_ptr, &datetime);
285 ✗ buffer_used = sizeof(buffer);
286 ✗ gate_date_to_string((gate_datetime_t const*)value_ptr, 0, NULL, buffer, &buffer_used);
287 ✗ lua_pushlstring(L, buffer, buffer_used);
288 ✗ break;
289 ✗ case GATE_TYPE_STRING:
290 ✗ lua_pushlstring(L, gate_string_ptr((gate_string_t const*)value_ptr, 0),
291 gate_string_length((gate_string_t const*)value_ptr));
292 ✗ break;
293
294
295 ✗ default:
296 ✗ ret = GATE_RESULT_NOTSUPPORTED;
297 ✗ break;
298 }
299
300
301 } while (0);
302
303 ✗ return ret;
304 }
305
306
307 ✗ static gate_result_t gate_script_lua_get_value(lua_State* L, int index, gate_value_t* value)
308 {
309 ✗ int ltype = lua_type(L, index);
310
311 ✗ gate_value_t* ret_value = NULL;
312 ✗ gate_bool_t bool_val = false;
313 ✗ gate_real64_t real_val = 0.0;
314 ✗ gate_string_t str_val = GATE_STRING_INIT_EMPTY;
315 ✗ size_t str_len = 0;
316 ✗ gate_cstr_t cstr = NULL;
317
318
319 ✗ switch (ltype)
320 {
321 ✗ case LUA_TNIL:
322 {
323 ✗ ret_value = gate_value_create(GATE_TYPE_EMPTY, NULL, value);
324 ✗ break;
325 }
326 ✗ case LUA_TBOOLEAN:
327 {
328 ✗ bool_val = (lua_toboolean(L, index) == 0) ? false : true;
329 ✗ ret_value = gate_value_create(GATE_TYPE_BOOL, &bool_val, value);
330 ✗ break;
331 }
332 ✗ case LUA_TNUMBER:
333 {
334 ✗ real_val = (gate_real64_t)lua_tonumber(L, index);
335 ✗ ret_value = gate_value_create(GATE_TYPE_R64, &real_val, value);
336 ✗ break;
337 }
338 ✗ case LUA_TSTRING:
339 {
340 ✗ cstr = lua_tolstring(L, index, &str_len);
341 ✗ if (gate_string_create(&str_val, cstr, str_len))
342 {
343 ✗ ret_value = gate_value_create(GATE_TYPE_STRING, &str_val, value);
344 }
345 ✗ break;
346 }
347 ✗ case LUA_TFUNCTION:
348 case LUA_TTABLE:
349 default:
350 {
351 ✗ break;
352 }
353 }
354
355 ✗ gate_string_release(&str_val);
356 ✗ return ret_value == NULL ? GATE_RESULT_NOTSUPPORTED : GATE_RESULT_OK;
357 }
358
359 ✗ gate_result_t gate_script_lua_invoke(gate_script_lua_session_t* session, gate_string_t const* func_name,
360 gate_value_t* args, gate_size_t arg_count, gate_value_t* ret_val)
361 {
362 ✗ gate_result_t ret = GATE_RESULT_FAILED;
363 lua_State* lstate;
364 int result;
365 char buffer[4096];
366 int index;
367
368 do
369 {
370 ✗ lstate = (lua_State*)session->state;
371 ✗ gate_string_to_buffer(func_name, buffer, sizeof(buffer));
372
373 ✗ lua_checkstack(lstate, (int)(arg_count + 2));
374 ✗ result = lua_getglobal(lstate, buffer);
375 ✗ ret = gate_script_lua_map_error(result);
376 ✗ GATE_BREAK_IF_FAILED(ret);
377
378 ✗ for (index = 0; index != arg_count; ++index)
379 {
380 ✗ ret = gate_script_lua_push_value(lstate, &args[index]);
381 ✗ if (GATE_FAILED(ret))
382 {
383 ✗ lua_pop(lstate, index + 1);
384 ✗ break;
385 }
386 }
387 ✗ GATE_BREAK_IF_FAILED(ret);
388
389 ✗ result = lua_pcall(lstate, (int)arg_count, 1, 0);
390 ✗ ret = gate_script_lua_map_error(result);
391 ✗ GATE_BREAK_IF_FAILED(ret);
392
393 ✗ ret = gate_script_lua_get_value(lstate, -1, ret_val);
394 ✗ lua_pop(lstate, 1);
395
396 } while (0);
397
398 ✗ return ret;
399 }
400 ✗ gate_result_t gate_script_lua_set_var(gate_script_lua_session_t* session,
401 gate_string_t const* name, gate_value_t const* value)
402 {
403 ✗ gate_result_t ret = GATE_RESULT_FAILED;
404 lua_State* lstate;
405 char buffer[4096];
406
407 do
408 {
409 ✗ gate_string_to_buffer(name, buffer, sizeof(buffer));
410 ✗ lstate = (lua_State*)session->state;
411 ✗ ret = gate_script_lua_push_value(lstate, value);
412 ✗ lua_setglobal(lstate, buffer);
413 } while (0);
414 ✗ return ret;
415 }
416 ✗ gate_result_t gate_script_lua_get_var(gate_script_lua_session_t* session,
417 gate_string_t const* name, gate_value_t* value)
418 {
419 ✗ gate_result_t ret = GATE_RESULT_FAILED;
420 lua_State* lstate;
421 char buffer[4096];
422
423 do
424 {
425 ✗ gate_string_to_buffer(name, buffer, sizeof(buffer));
426 ✗ lstate = (lua_State*)session->state;
427 ✗ lua_getglobal(lstate, buffer);
428
429 ✗ ret = gate_script_lua_get_value(lstate, -1, value);
430 ✗ GATE_BREAK_IF_FAILED(ret);
431
432 ✗ lua_pop(lstate, 1);
433 ✗ ret = GATE_RESULT_OK;
434 } while (0);
435
436 ✗ return ret;
437 }
438
439 ✗ gate_result_t gate_script_lua_cfunc_add(
440 gate_script_lua_session_t* session,
441 gate_string_t const* func_name,
442 int(*lua_cfunc)(void* lstate),
443 void* userparam)
444 {
445 ✗ gate_result_t ret = GATE_RESULT_FAILED;
446 lua_State* lstate;
447 ✗ gate_cstrbuffer_t name_buffer = GATE_INIT_EMPTY;
448
449 do
450 {
451 ✗ if (!session || !func_name || !lua_cfunc)
452 {
453 ✗ ret = GATE_RESULT_INVALIDARG;
454 ✗ break;
455 }
456
457 ✗ if (NULL == gate_cstrbuffer_create_string(&name_buffer, func_name, false))
458 {
459 ✗ ret = GATE_RESULT_OUTOFMEMORY;
460 ✗ break;
461 }
462
463 ✗ lstate = (lua_State*)session->state;
464
465 ✗ if (userparam)
466 {
467 /* add userparam to stack */
468 ✗ lua_pushlightuserdata(lstate, userparam);
469 ✗ lua_pushcclosure(lstate, (lua_CFunction)lua_cfunc, 1);
470 }
471 else
472 {
473 /* add function dispatcher with one upvalue (cfunc-def) */
474 ✗ lua_pushcclosure(lstate, (lua_CFunction)lua_cfunc, 0);
475 }
476
477 /* set global name of function */
478 ✗ lua_setglobal(lstate, gate_cstrbuffer_get(&name_buffer));
479
480 ✗ ret = GATE_RESULT_OK;
481 } while (0);
482
483 ✗ gate_cstrbuffer_destroy(&name_buffer);
484
485 ✗ return ret;
486 }
487
488 ✗ gate_size_t gate_script_lua_cfunc_get_arg_count(void* lstate)
489 {
490 ✗ lua_State* L = (lua_State*)lstate;
491 ✗ return (gate_size_t)lua_gettop(L);
492 }
493
494 ✗ static void lua_stack_get_bool(lua_State* state, int index, gate_bool_t* ptr)
495 {
496 ✗ *ptr = lua_toboolean(state, index) == 0 ? false : true;
497 ✗ }
498
499 ✗ static void lua_stack_get_int(lua_State* state, int index, gate_int32_t* ptr)
500 {
501 ✗ *ptr = (gate_int32_t)lua_tointeger(state, index);
502 ✗ }
503
504 ✗ static void lua_stack_get_number(lua_State* state, int index, gate_real64_t* ptr)
505 {
506 ✗ *ptr = (gate_real64_t)lua_tonumber(state, index);
507 ✗ }
508
509 ✗ static void lua_stack_get_string(lua_State* state, int index, gate_string_t* ptr)
510 {
511 ✗ size_t len = 0;
512 ✗ char const* str = lua_tolstring(state, index, &len);
513 ✗ gate_string_create(ptr, str, len);
514 ✗ }
515
516 ✗ static gate_result_t lua_stack_item_to_prop(lua_State* L, int index, gate_property_t* prop)
517 {
518 gate_result_t result;
519 ✗ gate_property_t* ret = NULL;
520 ✗ if (lua_isboolean(L, index))
521 {
522 ✗ gate_bool_t v = false;
523 ✗ lua_stack_get_bool(L, index, &v);
524 ✗ ret = gate_property_create_bool(prop, v);
525 }
526 ✗ else if (lua_isinteger(L, index))
527 {
528 ✗ gate_int32_t v = 0;
529 ✗ lua_stack_get_int(L, index, &v);
530 ✗ ret = gate_property_create_int(prop, (gate_int64_t)v);
531 }
532 ✗ else if (lua_isnumber(L, index))
533 {
534 ✗ gate_real64_t v = 0.0;
535 ✗ lua_stack_get_number(L, index, &v);
536 ✗ ret = gate_property_create_real(prop, (gate_real64_t)v);
537 }
538 ✗ else if (lua_isstring(L, index))
539 {
540 ✗ gate_string_t gstr = GATE_STRING_INIT_EMPTY;
541 ✗ lua_stack_get_string(L, index, &gstr);
542 ✗ ret = gate_property_create_string(prop, &gstr);
543 ✗ gate_string_release(&gstr);
544 }
545 ✗ else if (lua_istable(L, index))
546 {
547 ✗ gate_bool_t prop_init = false;
548 /* empty-pre-first-key to search next: */
549 ✗ lua_pushnil(L);
550
551 /* search next key from stack and push key-vakue pair */
552 ✗ while (lua_next(L, index) != 0)
553 {
554 ✗ gate_property_t item = GATE_INIT_EMPTY;
555 ✗ result = lua_stack_item_to_prop(L, -1, &item);
556 ✗ if (GATE_SUCCEEDED(result))
557 {
558 ✗ if (lua_isnumber(L, -2))
559 {
560 /* lua_Integer tbl_ndx = lua_tointeger(L, -2); */
561 ✗ if (!prop_init)
562 {
563 /* first key is a number -> table is an array */
564 ✗ ret = gate_property_create_array(prop, NULL, 0);
565 ✗ prop_init = true;
566 }
567 ✗ gate_property_array_add(prop, &item);
568 }
569 ✗ else if (lua_isstring(L, -2))
570 {
571 size_t key_len;
572 char const* key_value;
573 ✗ gate_string_t key_str = GATE_STRING_INIT_EMPTY;
574 ✗ if (!prop_init)
575 {
576 /* first key is a string -> table is a property object */
577 ✗ ret = gate_property_create_object(prop);
578 ✗ prop_init = true;
579 }
580 ✗ key_value = lua_tolstring(L, -2, &key_len);
581 ✗ gate_string_create(&key_str, key_value, key_len);
582 ✗ gate_property_member_add(prop, &key_str, &item);
583 ✗ gate_string_release(&key_str);
584 }
585
586 ✗ gate_property_destroy(&item);
587 }
588 ✗ lua_pop(L, 1);
589 }
590 }
591 ✗ if (ret == NULL)
592 {
593 ✗ return GATE_RESULT_FAILED;
594 }
595 ✗ return GATE_RESULT_OK;
596 }
597
598 ✗ gate_result_t gate_script_lua_cfunc_get_stack_item(void* lstate, int arg_index, gate_property_t* prop)
599 {
600 ✗ lua_State* const L = (lua_State*)lstate;
601 ✗ return lua_stack_item_to_prop(L, arg_index, prop);
602 }
603
604 ✗ gate_result_t gate_script_lua_cfunc_get_arg(void* lstate, gate_size_t arg_index, gate_property_t* prop)
605 {
606 ✗ lua_State* const L = (lua_State*)lstate;
607 ✗ int const lua_func_arg_count = lua_gettop(L);
608 ✗ int const lua_func_arg_index = (int)arg_index + 1;
609
610 ✗ if (lua_func_arg_index > lua_func_arg_count)
611 {
612 ✗ return GATE_RESULT_OUTOFBOUNDS;
613 }
614
615 ✗ return lua_stack_item_to_prop(L, lua_func_arg_index, prop);
616 }
617
618
619 ✗ static void lua_stack_push_property(lua_State* L, gate_property_t const* prop)
620 {
621 ✗ switch (gate_property_get_type(prop))
622 {
623 ✗ case GATE_PROPERTY_TYPE_EMPTY:
624 {
625 ✗ lua_pushnil(L);
626 ✗ return;
627 }
628 ✗ case GATE_PROPERTY_TYPE_BOOL:
629 {
630 ✗ gate_bool_t b = false;
631 ✗ gate_property_get_bool(prop, &b);
632 ✗ lua_pushboolean(L, b ? 1 : 0);
633 ✗ return;
634 }
635 ✗ case GATE_PROPERTY_TYPE_INT:
636 {
637 ✗ gate_int64_t v = 0;
638 ✗ gate_property_get_int(prop, &v);
639 ✗ if ((v < -2147483648LL) || (v > 2147483647LL))
640 {
641 ✗ lua_pushnumber(L, (lua_Number)v);
642 }
643 else
644 {
645 ✗ lua_pushinteger(L, (lua_Integer)v);
646 }
647 ✗ return;
648 }
649 ✗ case GATE_PROPERTY_TYPE_REAL:
650 {
651 ✗ gate_real64_t v = 0.0;
652 ✗ gate_property_get_real(prop, &v);
653 ✗ lua_pushnumber(L, (lua_Number)v);
654 ✗ return;
655 }
656 ✗ case GATE_PROPERTY_TYPE_STRING:
657 {
658 ✗ gate_string_t str = GATE_STRING_INIT_EMPTY;
659 ✗ gate_property_get_string(prop, &str);
660 ✗ lua_pushlstring(L, gate_string_ptr(&str, 0), gate_string_length(&str));
661 ✗ gate_string_release(&str);
662 ✗ return;
663 }
664 ✗ case GATE_PROPERTY_TYPE_ARRAY:
665 {
666 gate_size_t ndx;
667 ✗ const gate_size_t length = gate_property_array_length(prop);
668 ✗ lua_createtable(L, (int)length, 0);
669 ✗ for (ndx = 0; ndx < (int)length; ++ndx)
670 {
671 ✗ gate_property_t const* item = gate_property_array_get(prop, ndx);
672 ✗ if (item)
673 {
674 ✗ lua_stack_push_property(L, item);
675 }
676 else
677 {
678 ✗ lua_pushnil(L);
679 }
680 ✗ lua_rawseti(L, -2, (lua_Integer)(ndx + 1));
681 }
682 ✗ return;
683 }
684 ✗ case GATE_PROPERTY_TYPE_OBJECT:
685 {
686 gate_size_t ndx, length;
687 ✗ gate_array_t names = GATE_INIT_EMPTY;
688 ✗ gate_property_member_names(prop, &names);
689 ✗ length = gate_array_length(&names);
690
691 ✗ lua_newtable(L);
692 ✗ for (ndx = 0; ndx != length; ++ndx)
693 {
694 ✗ gate_string_t const* name = (gate_string_t const*)gate_array_get(&names, ndx);
695 gate_property_t const* item;
696 ✗ if (!name)
697 {
698 ✗ continue;
699 }
700 ✗ item = gate_property_member_get(prop, name);
701 ✗ if (!item)
702 {
703 ✗ continue;
704 }
705 ✗ lua_pushlstring(L, gate_string_ptr(name, 0), gate_string_length(name));
706 ✗ lua_stack_push_property(L, item);
707 ✗ lua_settable(L, -3);
708 }
709 ✗ return;
710 }
711 }
712 }
713
714 ✗ gate_result_t gate_script_lua_cfunc_push_stack_item(void* lstate, gate_property_t const* prop)
715 {
716 ✗ lua_State* const L = (lua_State*)lstate;
717 ✗ if (!L || !prop)
718 {
719 ✗ return GATE_RESULT_INVALIDARG;
720 }
721 ✗ lua_stack_push_property(L, prop);
722 ✗ return GATE_RESULT_OK;
723 }
724
725 ✗ gate_size_t gate_script_lua_cfunc_def_param_count(gate_script_lua_cfunc_def_t const* cfunc_def)
726 {
727 unsigned ndx;
728 ✗ for (ndx = 0; ndx != GATE_SCRIPTING_LUA_MAX_FUNC_PARAMS; ++ndx)
729 {
730 ✗ if (cfunc_def->params[ndx] == GATE_TYPE_VOID)
731 {
732 ✗ return ndx;
733 }
734 }
735 ✗ return GATE_SCRIPTING_LUA_MAX_FUNC_PARAMS;
736 }
737
738 #define CREATE_INT_VALUE(native_type) \
739 const native_type v = (native_type)lua_tointeger(L, lua_param_index); \
740 gate_value_create(required_type, &v, ptr_val)
741
742 #define CREATE_NUM_VALUE(native_type) \
743 const native_type v = (native_type)lua_tonumber(L, lua_param_index); \
744 gate_value_create(required_type, &v, ptr_val)
745
746
747 ✗ static gate_result_t load_lua_params(lua_State* L, gate_type_id_t required_type, int lua_param_index, gate_value_t* ptr_val)
748 {
749 ✗ gate_result_t ret = GATE_RESULT_OK;
750
751 ✗ switch (required_type)
752 {
753 ✗ case GATE_TYPE_BOOL:
754 {
755 ✗ const gate_bool_t v = lua_toboolean(L, lua_param_index);
756 ✗ gate_value_create(GATE_TYPE_BOOL, &v, ptr_val);
757 ✗ break;
758 }
759 ✗ case GATE_TYPE_I8: { CREATE_INT_VALUE(gate_int8_t); break; }
760 ✗ case GATE_TYPE_UI8: { CREATE_INT_VALUE(gate_uint8_t); break; }
761 ✗ case GATE_TYPE_I16: { CREATE_INT_VALUE(gate_int16_t); break; }
762 ✗ case GATE_TYPE_UI16: { CREATE_INT_VALUE(gate_uint16_t); break; }
763 ✗ case GATE_TYPE_I32: { CREATE_INT_VALUE(gate_int32_t); break; }
764 ✗ case GATE_TYPE_UI32: { CREATE_INT_VALUE(gate_uint32_t); break; }
765 ✗ case GATE_TYPE_I64: { CREATE_NUM_VALUE(gate_int64_t); break; }
766 ✗ case GATE_TYPE_UI64: { CREATE_NUM_VALUE(gate_uint64_t); break; }
767 ✗ case GATE_TYPE_R32: { CREATE_NUM_VALUE(gate_real32_t); break; }
768 ✗ case GATE_TYPE_R64: { CREATE_NUM_VALUE(gate_real64_t); break; }
769 ✗ case GATE_TYPE_ADDRESS:
770 case GATE_TYPE_DATAPTR:
771 case GATE_TYPE_FUNCPTR:
772 {
773 ✗ ret = GATE_RESULT_NOTSUPPORTED;
774 ✗ break;
775 }
776 ✗ case GATE_TYPE_CSTR:
777 {
778 size_t l;
779 ✗ gate_cstr_t s = luaL_tolstring(L, lua_param_index, &l);
780 ✗ gate_value_create(GATE_TYPE_CSTR, &s, ptr_val);
781 ✗ break;
782 }
783 ✗ case GATE_TYPE_WSTR:
784 case GATE_TYPE_GUID:
785 {
786 ✗ ret = GATE_RESULT_NOTSUPPORTED;
787 ✗ break;
788 }
789 ✗ case GATE_TYPE_DATE:
790 {
791 ✗ gate_time_t tm = GATE_INIT_EMPTY;
792 ✗ gate_datetime_t dt = GATE_INIT_EMPTY;
793 ✗ const gate_int64_t unix_seconds = (gate_int64_t)lua_tointeger(L, lua_param_index);
794 ✗ gate_time_from_unix(unix_seconds, &tm.timestamp);
795 ✗ gate_time_to_datetime(&tm, &dt);
796 ✗ gate_value_create(GATE_TYPE_DATE, &dt.date, ptr_val);
797 ✗ break;
798 }
799 ✗ case GATE_TYPE_DAYTIME:
800 {
801 ✗ gate_time_t tm = GATE_INIT_EMPTY;
802 ✗ gate_datetime_t dt = GATE_INIT_EMPTY;
803 ✗ const gate_int64_t unix_seconds = (gate_int64_t)lua_tointeger(L, lua_param_index);
804 ✗ gate_time_from_unix(unix_seconds, &tm.timestamp);
805 ✗ gate_time_to_datetime(&tm, &dt);
806 ✗ gate_value_create(GATE_TYPE_DAYTIME, &dt.time, ptr_val);
807 ✗ break;
808 }
809 ✗ case GATE_TYPE_DATETIME:
810 {
811 ✗ gate_time_t tm = GATE_INIT_EMPTY;
812 ✗ gate_datetime_t dt = GATE_INIT_EMPTY;
813 ✗ const gate_int64_t unix_seconds = (gate_int64_t)lua_tointeger(L, lua_param_index);
814 ✗ gate_time_from_unix(unix_seconds, &tm.timestamp);
815 ✗ gate_time_to_datetime(&tm, &dt);
816 ✗ gate_value_create(GATE_TYPE_DATETIME, &dt, ptr_val);
817 ✗ break;
818 }
819 ✗ case GATE_TYPE_TIME:
820 {
821 ✗ gate_time_t tm = GATE_INIT_EMPTY;
822 ✗ const gate_int64_t unix_seconds = (gate_int64_t)lua_tointeger(L, lua_param_index);
823 ✗ gate_time_from_unix(unix_seconds, &tm.timestamp);
824 ✗ gate_value_create(GATE_TYPE_TIME, &tm, ptr_val);
825 ✗ break;
826 }
827 ✗ case GATE_TYPE_STRING:
828 {
829 ✗ gate_string_t str = GATE_STRING_INIT_EMPTY;
830 size_t l;
831 ✗ gate_cstr_t s = luaL_tolstring(L, lua_param_index, &l);
832 ✗ gate_string_create(&str, s, l);
833 ✗ gate_value_create(GATE_TYPE_STRING, &str, ptr_val);
834 ✗ gate_string_release(&str);
835 ✗ break;
836 }
837 ✗ case GATE_TYPE_BLOB:
838 {
839 ✗ gate_blob_t blob = GATE_INIT_EMPTY;
840 size_t l;
841 ✗ gate_cstr_t s = luaL_tolstring(L, lua_param_index, &l);
842 ✗ gate_blob_create(&blob, s, l);
843 ✗ gate_value_create(GATE_TYPE_BLOB, &blob, ptr_val);
844 ✗ gate_blob_release(&blob);
845 ✗ break;
846 }
847 ✗ case GATE_TYPE_STRUCT:
848 case GATE_TYPE_OBJECT:
849 case GATE_TYPE_PROPERTY:
850
851 case GATE_TYPE_ARRAY:
852 case GATE_TYPE_ARRAYLIST:
853 case GATE_TYPE_ARRAYLIST_BOOL:
854 case GATE_TYPE_ARRAYLIST_I8:
855 case GATE_TYPE_ARRAYLIST_UI8:
856 case GATE_TYPE_ARRAYLIST_I16:
857 case GATE_TYPE_ARRAYLIST_UI16:
858 case GATE_TYPE_ARRAYLIST_I32:
859 case GATE_TYPE_ARRAYLIST_UI32:
860 case GATE_TYPE_ARRAYLIST_I64:
861 case GATE_TYPE_ARRAYLIST_UI64:
862 case GATE_TYPE_ARRAYLIST_R32:
863 case GATE_TYPE_ARRAYLIST_R64:
864 case GATE_TYPE_ARRAYLIST_ADDRESS:
865
866 case GATE_TYPE_ARRAYLIST_DATAPTR:
867 case GATE_TYPE_ARRAYLIST_FUNCPTR:
868 case GATE_TYPE_ARRAYLIST_CSTR:
869 case GATE_TYPE_ARRAYLIST_WSTR:
870 case GATE_TYPE_ARRAYLIST_GUID:
871 case GATE_TYPE_ARRAYLIST_DATE:
872 case GATE_TYPE_ARRAYLIST_DAYTIME:
873 case GATE_TYPE_ARRAYLIST_DATETIME:
874 case GATE_TYPE_ARRAYLIST_TIME:
875
876 case GATE_TYPE_ARRAYLIST_STRING:
877 case GATE_TYPE_ARRAYLIST_ARRAY:
878 case GATE_TYPE_ARRAYLIST_BLOB:
879
880 case GATE_TYPE_ARRAYLIST_STRUCT:
881 case GATE_TYPE_ARRAYLIST_OBJECT:
882 case GATE_TYPE_ARRAYLIST_PROPERTY:
883 default:
884 {
885 /*TODO*/
886 ✗ ret = GATE_RESULT_NOTSUPPORTED;
887 ✗ break;
888 }
889
890 }
891
892 ✗ return ret;
893 }
894
895 ✗ static gate_result_t convert_value_to_func_arg(gate_value_t const* ptr_val, gate_function_argument_t* ptr_arg)
896 {
897 ✗ gate_result_t ret = GATE_RESULT_OK;
898 ✗ gate_type_id_t const gt = gate_value_type(ptr_val);
899 ✗ switch (gt)
900 {
901 ✗ case GATE_TYPE_BOOL:
902 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_UCHAR;
903 ✗ ptr_arg->arg_value.u_chr = ptr_val->content.bool_value;
904 ✗ break;
905 ✗ case GATE_TYPE_I8:
906 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_SCHAR;
907 ✗ ptr_arg->arg_value.s_chr = ptr_val->content.i8_value;
908 ✗ break;
909 ✗ case GATE_TYPE_UI8:
910 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_UCHAR;
911 ✗ ptr_arg->arg_value.u_chr = ptr_val->content.ui8_value;
912 ✗ break;
913 ✗ case GATE_TYPE_I16:
914 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_SSHORT;
915 ✗ ptr_arg->arg_value.s_short = ptr_val->content.i16_value;
916 ✗ break;
917 ✗ case GATE_TYPE_UI16:
918 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_USHORT;
919 ✗ ptr_arg->arg_value.u_short = ptr_val->content.ui16_value;
920 ✗ break;
921 ✗ case GATE_TYPE_I32:
922 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_SLONG;
923 ✗ ptr_arg->arg_value.s_long = ptr_val->content.i32_value;
924 ✗ break;
925 ✗ case GATE_TYPE_UI32:
926 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_ULONG;
927 ✗ ptr_arg->arg_value.u_long = ptr_val->content.ui32_value;
928 ✗ break;
929 ✗ case GATE_TYPE_I64:
930 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_SLONGLONG;
931 ✗ ptr_arg->arg_value.s_long_long = ptr_val->content.i64_value;
932 ✗ break;
933 ✗ case GATE_TYPE_UI64:
934 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_ULONGLONG;
935 ✗ ptr_arg->arg_value.u_long_long = ptr_val->content.ui64_value;
936 ✗ break;
937 ✗ case GATE_TYPE_R32:
938 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_FLOAT;
939 ✗ ptr_arg->arg_value.flt = ptr_val->content.r32_value;
940 ✗ break;
941 ✗ case GATE_TYPE_R64:
942 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_DOUBLE;
943 ✗ ptr_arg->arg_value.dbl = ptr_val->content.r64_value;
944 ✗ break;
945 /* pointer types: */
946 ✗ case GATE_TYPE_ADDRESS:
947 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_POINTER;
948 ✗ ptr_arg->arg_value.ptr = (void*)ptr_val->content.address_value;
949 ✗ break;
950 ✗ case GATE_TYPE_DATAPTR:
951 case GATE_TYPE_FUNCPTR:
952 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_POINTER;
953 ✗ ptr_arg->arg_value.ptr = ptr_val->content.ptr_value;
954 ✗ break;
955 ✗ case GATE_TYPE_CSTR:
956 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_POINTER;
957 ✗ ptr_arg->arg_value.ptr = (void*)ptr_val->content.cstring_value;
958 ✗ break;
959 ✗ case GATE_TYPE_WSTR:
960 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_POINTER;
961 ✗ ptr_arg->arg_value.ptr = (void*)ptr_val->content.wstring_value;
962 ✗ break;
963 ✗ case GATE_TYPE_GUID:
964 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_POINTER;
965 ✗ ptr_arg->arg_value.ptr = (void*)&ptr_val->content.guid_value;
966 ✗ break;
967 ✗ case GATE_TYPE_DATE:
968 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_POINTER;
969 ✗ ptr_arg->arg_value.ptr = (void*)&ptr_val->content.date_value;
970 ✗ break;
971 ✗ case GATE_TYPE_DAYTIME:
972 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_POINTER;
973 ✗ ptr_arg->arg_value.ptr = (void*)&ptr_val->content.daytime_value;
974 ✗ break;
975 ✗ case GATE_TYPE_DATETIME:
976 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_POINTER;
977 ✗ ptr_arg->arg_value.ptr = (void*)&ptr_val->content.datetime_value;
978 ✗ break;
979 ✗ case GATE_TYPE_TIME:
980 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_POINTER;
981 ✗ ptr_arg->arg_value.ptr = (void*)&ptr_val->content.time_value;
982 ✗ break;
983 ✗ case GATE_TYPE_STRING:
984 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_POINTER;
985 ✗ ptr_arg->arg_value.ptr = (void*)&ptr_val->content.string_value;
986 ✗ break;
987 ✗ case GATE_TYPE_BLOB:
988 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_POINTER;
989 ✗ ptr_arg->arg_value.ptr = (void*)&ptr_val->content.blob_value;
990 ✗ break;
991 ✗ case GATE_TYPE_ARRAY:
992 ✗ ptr_arg->arg_type = GATE_FUNCTION_ARG_POINTER;
993 ✗ ptr_arg->arg_value.ptr = (void*)&ptr_val->content.array_value;
994 ✗ break;
995 ✗ default:
996 ✗ ret = GATE_RESULT_NOTSUPPORTED;
997 ✗ break;
998 }
999 ✗ return ret;
1000 }
1001
1002 ✗ static int gate_lua_cfunc_dispatcher(lua_State* L)
1003 {
1004 static char const* const error_msg_fmt = "LUA C-function dispatcher error: #%d %s";
1005 ✗ int const lua_func_arg_count = lua_gettop(L);
1006 gate_script_lua_cfunc_def_t const* const cfunc_def =
1007 ✗ (gate_script_lua_cfunc_def_t const*)lua_touserdata(L, lua_upvalueindex(1));
1008 ✗ gate_size_t cfunc_count = 0;
1009 ✗ gate_value_t value_store[GATE_SCRIPTING_LUA_MAX_FUNC_PARAMS] = GATE_INIT_EMPTY;
1010 ✗ gate_function_argument_t cfunc_args[GATE_SCRIPTING_LUA_MAX_FUNC_PARAMS] = GATE_INIT_EMPTY;
1011 ✗ gate_function_argument_t ret_val = GATE_INIT_EMPTY;
1012 ✗ int ret = 0;
1013 int ndx;
1014 gate_result_t result;
1015
1016 do
1017 {
1018 ✗ if (NULL == cfunc_def)
1019 {
1020 ✗ ret = luaL_error(L, error_msg_fmt, 1, "internal lua_cfunc_def parameter is missing");
1021 ✗ break;
1022 }
1023
1024 ✗ cfunc_count = gate_script_lua_cfunc_def_param_count(cfunc_def);
1025
1026 ✗ if (lua_func_arg_count < (int)cfunc_count)
1027 {
1028 ✗ ret = luaL_error(L, error_msg_fmt, (int)cfunc_count, " required parameters not available");
1029 ✗ break;
1030 }
1031
1032 ✗ if (lua_func_arg_count > GATE_SCRIPTING_LUA_MAX_FUNC_PARAMS)
1033 {
1034 ✗ ret = luaL_error(L, error_msg_fmt, (int)lua_func_arg_count, " too many parameters");
1035 ✗ break;
1036 }
1037
1038 /* store lua parameters as gate_value objects */
1039 ✗ for (ndx = 0; ndx < (int)cfunc_count; ++ndx)
1040 {
1041 ✗ result = load_lua_params(L, cfunc_def->params[ndx], ndx + 1, &value_store[ndx]);
1042 }
1043
1044 /* create generic function args from gate_value objects */
1045 ✗ for (ndx = 0; ndx < (int)cfunc_count; ++ndx)
1046 {
1047 ✗ result = convert_value_to_func_arg(&value_store[ndx], &cfunc_args[ndx]);
1048 }
1049
1050 /* call native gate-function pointer */
1051 ✗ result = gate_function_invoke_generic(cfunc_def->func_ptr, 0, cfunc_args, cfunc_count, &ret_val);
1052
1053
1054 } while (0);
1055
1056 ✗ for (ndx = 0; ndx < (int)cfunc_count; ++ndx)
1057 {
1058 ✗ gate_value_release(&value_store[ndx]);
1059 }
1060
1061 ✗ return ret;
1062 }
1063
1064 ✗ gate_result_t gate_script_lua_add_function(
1065 gate_script_lua_session_t* session,
1066 gate_string_t const* func_name,
1067 gate_script_lua_cfunc_def_t const* func_def)
1068 {
1069 ✗ gate_result_t ret = GATE_RESULT_FAILED;
1070 lua_State* lstate;
1071 ✗ void* const cfunc_def_param = (void*)func_def;
1072 char name[128];
1073
1074 do
1075 {
1076 ✗ gate_string_to_buffer(func_name, name, sizeof(name));
1077
1078 ✗ lstate = (lua_State*)session->state;
1079
1080 /* push pointer to function definition as upvalue for function */
1081 ✗ lua_pushlightuserdata(lstate, cfunc_def_param);
1082
1083 /* add function dispatcher with one upvalue (cfunc-def) */
1084 ✗ lua_pushcclosure(lstate, &gate_lua_cfunc_dispatcher, 1);
1085
1086 /* set global name of function */
1087 ✗ lua_setglobal(lstate, name);
1088
1089 ✗ ret = GATE_RESULT_OK;
1090
1091 } while (0);
1092
1093 ✗ return ret;
1094 }
1095
1096
1097 ✗ static int gate_lua_print(lua_State* L)
1098 {
1099 ✗ int n = lua_gettop(L); /* number of arguments */
1100 int i;
1101 ✗ for (i = 1; i <= n; i++)
1102 {
1103 size_t l;
1104 ✗ const char* s = luaL_tolstring(L, i, &l); /* convert it to string */
1105 ✗ if (i > 1)
1106 {
1107 /* not the first element? */
1108 ✗ gate_lua_writestring(" ", 1, false); /* add a tab before it */
1109 }
1110 ✗ gate_lua_writestring(s, l, false); /* print it */
1111 ✗ lua_pop(L, 1); /* pop result */
1112 }
1113 ✗ gate_lua_writestring(GATE_STR_NEWLINE, GATE_STR_NEWLINE_LENGTH, true);
1114 ✗ return 0;
1115 }
1116
1117 ✗ static int gate_lua_printerr(lua_State* L)
1118 {
1119 ✗ int n = lua_gettop(L); /* number of arguments */
1120 int i;
1121 ✗ for (i = 1; i <= n; i++)
1122 {
1123 size_t l;
1124 ✗ const char* s = luaL_tolstring(L, i, &l); /* convert it to string */
1125 ✗ if (i > 1)
1126 {
1127 /* not the first element? */
1128 ✗ gate_lua_writestring_err(" ", 1, false); /* add a tab before it */
1129 }
1130 ✗ gate_lua_writestring_err(s, l, false); /* print it */
1131 ✗ lua_pop(L, 1); /* pop result */
1132 }
1133 ✗ gate_lua_writestring_err(GATE_STR_NEWLINE, GATE_STR_NEWLINE_LENGTH, true);
1134 ✗ return 0;
1135 }
1136
1137 ✗ static int gate_lua_read(lua_State* L)
1138 {
1139 ✗ gate_string_t line = GATE_STRING_INIT_EMPTY;
1140 ✗ gate_console_t* const con = gate_console();
1141
1142 ✗ gate_console_readln(con, &line);
1143
1144 ✗ lua_pushlstring(L, gate_string_ptr(&line, 0), gate_string_length(&line));
1145
1146 ✗ gate_string_release(&line);
1147 ✗ return 1;
1148 }
1149
1150 ✗ static void add_console_feature(lua_State* lstate)
1151 {
1152 ✗ lua_register(lstate, "print", &gate_lua_print);
1153 ✗ lua_register(lstate, "printerror", &gate_lua_printerr);
1154 ✗ lua_register(lstate, "read", &gate_lua_read);
1155 ✗ }
1156
1157 ✗ static int gate_lua_fileopen(lua_State* lstate)
1158 {
1159 ✗ gate_result_t ret = 0;
1160 gate_result_t result;
1161 ✗ gate_string_t str_path = GATE_STRING_INIT_EMPTY;
1162 ✗ gate_string_t str_flags = GATE_STRING_INIT_EMPTY;
1163 ✗ gate_enumint_t openflags = GATE_STREAM_OPEN_READ;
1164 ✗ gate_bool_t truncate = false;
1165 gate_size_t arg_count;
1166 gate_file_t f;
1167
1168 do
1169 {
1170 ✗ arg_count = gate_script_lua_cfunc_get_arg_count(lstate);
1171 ✗ if (arg_count < 1)
1172 {
1173 ✗ luaL_error(lstate, "Missing arguments");
1174 ✗ break;
1175 }
1176
1177 ✗ lua_stack_get_string(lstate, 1, &str_path);
1178 ✗ if (gate_string_is_empty(&str_path))
1179 {
1180 ✗ lua_pushnil(lstate);
1181 ✗ ret = 1;
1182 ✗ break;
1183 }
1184
1185 ✗ if (arg_count >= 2)
1186 {
1187 ✗ lua_stack_get_string(lstate, 2, &str_flags);
1188 }
1189 ✗ if (gate_string_equals_str(&str_flags, "r") || gate_string_is_empty(&str_flags))
1190 {
1191 ✗ openflags = GATE_STREAM_OPEN_READ;
1192 }
1193 ✗ else if (gate_string_equals_str(&str_flags, "r+"))
1194 {
1195 ✗ openflags = GATE_STREAM_OPEN_READWRITE;
1196 }
1197 ✗ else if (gate_string_equals_str(&str_flags, "w"))
1198 {
1199 ✗ openflags = GATE_STREAM_OPEN_WRITE;
1200 }
1201 ✗ else if (gate_string_equals_str(&str_flags, "w+"))
1202 {
1203 ✗ openflags = GATE_STREAM_OPEN_READWRITE;
1204 ✗ truncate = true;
1205 }
1206 ✗ else if (gate_string_equals_str(&str_flags, "a"))
1207 {
1208 ✗ openflags = GATE_STREAM_OPEN_APPENDWRITE;
1209 }
1210 ✗ else if (gate_string_equals_str(&str_flags, "a+"))
1211 {
1212 ✗ openflags = GATE_STREAM_OPEN_APPENDREADWRITE;
1213 }
1214 else
1215 {
1216 /* unsupported open-type */
1217 ✗ lua_pushnil(lstate);
1218 ✗ ret = 1;
1219 ✗ break;
1220 }
1221
1222 ✗ result = gate_file_open(&str_path, openflags, &f);
1223 ✗ if (GATE_FAILED(result))
1224 {
1225 /* error case */
1226 ✗ lua_pushnil(lstate);
1227 ✗ ret = 1;
1228 ✗ break;
1229 }
1230
1231 ✗ if (truncate)
1232 {
1233 ✗ gate_file_truncate(f);
1234 }
1235
1236 /* success case */
1237 ✗ lua_pushinteger(lstate, (lua_Integer)(gate_intptr_t)(void*)f);
1238 ✗ ret = 1;
1239 } while (0);
1240
1241 ✗ gate_string_release(&str_flags);
1242 ✗ gate_string_release(&str_path);
1243 ✗ return ret;
1244 }
1245
1246 ✗ static int gate_lua_fileclose(lua_State* lstate)
1247 {
1248 ✗ gate_result_t ret = 0;
1249 gate_size_t arg_count;
1250 gate_int32_t file_handle;
1251 gate_file_t f;
1252
1253 do
1254 {
1255 ✗ arg_count = gate_script_lua_cfunc_get_arg_count(lstate);
1256 ✗ if (arg_count < 1)
1257 {
1258 ✗ luaL_error(lstate, "Missing arguments");
1259 ✗ break;
1260 }
1261
1262 ✗ lua_stack_get_int(lstate, 1, &file_handle);
1263 ✗ f = (gate_file_t)(gate_intptr_t)file_handle;
1264
1265 ✗ gate_file_close(f);
1266 /* success case */
1267 } while (0);
1268
1269 ✗ return ret;
1270 }
1271
1272 ✗ static int gate_lua_fileread(lua_State* lstate)
1273 {
1274 ✗ gate_result_t ret = 0;
1275 gate_result_t result;
1276 gate_size_t arg_count;
1277 ✗ gate_int32_t file_handle = 0;
1278 ✗ gate_int32_t read_len = 0;
1279 gate_file_t f;
1280 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
1281 ✗ char* ptr_buffer = &buffer[0];
1282 gate_size_t buffer_len;
1283 ✗ gate_size_t buffer_used = 0;
1284
1285 do
1286 {
1287 ✗ arg_count = gate_script_lua_cfunc_get_arg_count(lstate);
1288 ✗ if (arg_count < 2)
1289 {
1290 ✗ luaL_error(lstate, "Missing arguments");
1291 ✗ break;
1292 }
1293
1294 ✗ lua_stack_get_int(lstate, 1, &file_handle);
1295 ✗ f = (gate_file_t)(gate_intptr_t)file_handle;
1296
1297 ✗ lua_stack_get_int(lstate, 2, &read_len);
1298
1299 ✗ if (read_len <= 0)
1300 {
1301 /* invalid read-length */
1302 ✗ lua_pushnil(lstate);
1303 ✗ ret = 1;
1304 ✗ break;
1305 }
1306
1307 ✗ buffer_len = (gate_size_t)read_len;
1308 ✗ if (buffer_len > sizeof(buffer))
1309 {
1310 ✗ ptr_buffer = gate_mem_alloc(buffer_len);
1311 ✗ if (NULL == ptr_buffer)
1312 {
1313 ✗ luaL_error(lstate, "Out of memory");
1314 ✗ break;
1315 }
1316 }
1317
1318 ✗ result = gate_file_read(f, ptr_buffer, buffer_len, &buffer_used);
1319 ✗ if (GATE_FAILED(result))
1320 {
1321 /* failed to read from file */
1322 ✗ lua_pushnil(lstate);
1323 ✗ ret = 1;
1324 ✗ break;
1325 }
1326
1327 /* succes case, return buffer content as string */
1328 ✗ lua_pushlstring(lstate, ptr_buffer, buffer_used);
1329 ✗ ret = 1;
1330 } while (0);
1331
1332 ✗ if (ptr_buffer && (ptr_buffer != &buffer[0]))
1333 {
1334 ✗ gate_mem_dealloc(ptr_buffer);
1335 }
1336
1337 ✗ return ret;
1338 }
1339
1340 ✗ static int gate_lua_filewrite(lua_State* lstate)
1341 {
1342 ✗ gate_result_t ret = 0;
1343 gate_result_t result;
1344 gate_size_t arg_count;
1345 ✗ gate_int32_t file_handle = 0;
1346 gate_file_t f;
1347 ✗ gate_string_t buffer = GATE_STRING_INIT_EMPTY;
1348 gate_size_t written;
1349
1350 do
1351 {
1352 ✗ arg_count = gate_script_lua_cfunc_get_arg_count(lstate);
1353 ✗ if (arg_count < 2)
1354 {
1355 ✗ luaL_error(lstate, "Missing arguments");
1356 ✗ break;
1357 }
1358
1359 ✗ lua_stack_get_int(lstate, 1, &file_handle);
1360 ✗ f = (gate_file_t)(gate_intptr_t)file_handle;
1361
1362 ✗ lua_stack_get_string(lstate, 2, &buffer);
1363
1364 ✗ result = gate_file_write(f, gate_string_ptr(&buffer, 0), gate_string_length(&buffer), &written);
1365 ✗ if (GATE_FAILED(result))
1366 {
1367 /* failed to read from file */
1368 ✗ lua_pushnil(lstate);
1369 ✗ ret = 1;
1370 ✗ break;
1371 }
1372
1373 /* success case, return amount of written bytes */
1374 ✗ lua_pushinteger(lstate, (lua_Integer)written);
1375 ✗ ret = 1;
1376 } while (0);
1377
1378 ✗ gate_string_release(&buffer);
1379 ✗ return ret;
1380 }
1381
1382
1383
1384 ✗ static void add_fileaccess_feature(lua_State* lstate)
1385 {
1386 ✗ lua_register(lstate, "file_open", &gate_lua_fileopen);
1387 ✗ lua_register(lstate, "file_close", &gate_lua_fileclose);
1388 ✗ lua_register(lstate, "file_read", &gate_lua_fileread);
1389 ✗ lua_register(lstate, "file_write", &gate_lua_filewrite);
1390 ✗ }
1391
1392 ✗ gate_result_t gate_script_lua_add_feature(gate_script_lua_session_t* session, gate_script_lua_feature_enum_t feature)
1393 {
1394 ✗ lua_State* lstate = (lua_State*)session->state;
1395
1396 ✗ switch (feature)
1397 {
1398 ✗ case gate_script_lua_feature_console:
1399 ✗ add_console_feature(lstate);
1400 ✗ return GATE_RESULT_OK;
1401 ✗ case gate_script_lua_feature_fileaccess:
1402 ✗ add_fileaccess_feature(lstate);
1403 ✗ return GATE_RESULT_OK;
1404 ✗ case gate_script_lua_feature_filesystem:
1405 case gate_script_lua_feature_process:
1406 default:
1407 ✗ return GATE_RESULT_NOTSUPPORTED;
1408 }
1409 }
1410
1411 ✗ static int gate_script_lua_console_quit(lua_State* L)
1412 {
1413 ✗ gate_script_lua_session_t* ptr_session = gate_script_lua_get_session(L);
1414 ✗ if (ptr_session)
1415 {
1416 ✗ ptr_session->cancel = true;
1417 }
1418 ✗ return 0;
1419 }
1420
1421 ✗ gate_result_t gate_script_lua_console(gate_stream_t* console)
1422 {
1423 ✗ gate_result_t ret = GATE_RESULT_OK;
1424 ✗ gate_script_lua_session_t session = GATE_INIT_EMPTY;
1425 ✗ gate_strbuilder_t builder = GATE_INIT_EMPTY;
1426 char buffer[4096];
1427 gate_size_t buffer_used;
1428 gate_bool_t command_completed;
1429 ✗ gate_string_t command = GATE_STRING_INIT_EMPTY;
1430 lua_State* lstate;
1431 gate_size_t pos;
1432
1433 do
1434 {
1435 ✗ ret = gate_script_lua_init(&session);
1436 ✗ GATE_BREAK_IF_FAILED(ret);
1437
1438 ✗ ret = gate_script_lua_add_feature(&session, gate_script_lua_feature_console);
1439 ✗ GATE_BREAK_IF_FAILED(ret);
1440 ✗ ret = gate_script_lua_add_feature(&session, gate_script_lua_feature_fileaccess);
1441 ✗ GATE_BREAK_IF_FAILED(ret);
1442
1443 ✗ gate_strbuilder_create(&builder, 0);
1444
1445 ✗ lstate = (lua_State*)session.state;
1446 ✗ session.cancel = false;
1447
1448 ✗ lua_pushcfunction(lstate, &gate_script_lua_console_quit);
1449 ✗ lua_setglobal(lstate, "quit");
1450
1451 ✗ while (!session.cancel)
1452 {
1453 ✗ buffer_used = 0;
1454 ✗ if (gate_strbuilder_length(&builder) == 0)
1455 {
1456 ✗ gate_stream_print_cstr(console, "[LUA] > ");
1457 }
1458 else
1459 {
1460 ✗ gate_stream_print_cstr(console, " > ");
1461
1462 }
1463 ✗ ret = gate_stream_read_line(console, buffer, sizeof(buffer), &buffer_used);
1464 ✗ GATE_BREAK_IF_FAILED(ret);
1465
1466 ✗ pos = gate_str_find_last_not_of(buffer, buffer_used, " \r\n\t", 4);
1467 ✗ if (pos == GATE_STR_NPOS)
1468 {
1469 /* empty line */
1470 }
1471 else
1472 {
1473 ✗ buffer_used = pos + 1;
1474 ✗ if (gate_str_ends_with(buffer, buffer_used, "\\", 1))
1475 {
1476 ✗ gate_strbuilder_append_text(&builder, buffer, buffer_used - 1);
1477 ✗ gate_strbuilder_append_cstr(&builder, "\n");
1478 ✗ command_completed = false;
1479 }
1480 else
1481 {
1482 ✗ gate_strbuilder_append_text(&builder, buffer, buffer_used);
1483 ✗ command_completed = true;
1484 }
1485 ✗ if (command_completed)
1486 {
1487 ✗ if (gate_strbuilder_to_string(&builder, &command))
1488 {
1489 ✗ ret = gate_script_lua_load_impl(lstate, &command, true);
1490 ✗ gate_strbuilder_release(&builder);
1491 ✗ gate_strbuilder_create(&builder, 0);
1492 ✗ if (GATE_SUCCEEDED(ret))
1493 {
1494 ✗ gate_stream_println_cstr(console, NULL);
1495 ✗ gate_stream_println_cstr(console, "[LUA] : OK (^_^)");
1496 }
1497 else
1498 {
1499 ✗ gate_stream_println_cstr(console, NULL);
1500 ✗ gate_stream_print_cstr(console, "[LUA] : ERROR ");
1501 ✗ gate_stream_print_int(console, ret);
1502 ✗ gate_stream_println_cstr(console, " (>_<)");
1503 ✗ ret = GATE_RESULT_OK;
1504 }
1505 }
1506 else
1507 {
1508 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1509 }
1510 ✗ gate_string_release(&command);
1511 ✗ GATE_BREAK_IF_FAILED(ret);
1512 }
1513 }
1514
1515 }
1516 ✗ gate_script_lua_uninit(&session);
1517
1518 } while (0);
1519
1520 ✗ gate_strbuilder_release(&builder);
1521
1522 ✗ return ret;
1523 }
1524
1525 #endif /* GATE_SCRIPTING_LUA_USE_LUA */
1526
1527
1528 #if defined(GATE_SCRIPTING_LUA_NO_IMPL)
1529
1530 gate_result_t gate_script_lua_init(gate_script_lua_session_t* session)
1531 {
1532 GATE_UNUSED_ARG(session);
1533 return GATE_RESULT_NOTIMPLEMENTED;
1534 }
1535 gate_result_t gate_script_lua_uninit(gate_script_lua_session_t* session)
1536 {
1537 GATE_UNUSED_ARG(session);
1538 return GATE_RESULT_NOTIMPLEMENTED;
1539 }
1540
1541 gate_result_t gate_script_lua_reset(gate_script_lua_session_t* session)
1542 {
1543 GATE_UNUSED_ARG(session);
1544 return GATE_RESULT_NOTIMPLEMENTED;
1545 }
1546
1547 gate_result_t gate_script_lua_load(gate_script_lua_session_t* session, gate_string_t const* code)
1548 {
1549 GATE_UNUSED_ARG(session);
1550 GATE_UNUSED_ARG(code);
1551 return GATE_RESULT_NOTIMPLEMENTED;
1552 }
1553
1554 gate_result_t gate_script_lua_invoke(gate_script_lua_session_t* session,
1555 gate_string_t const* func_name,
1556 gate_value_t* args, gate_size_t arg_count,
1557 gate_value_t* ret_val)
1558 {
1559 GATE_UNUSED_ARG(session);
1560 GATE_UNUSED_ARG(func_name);
1561 GATE_UNUSED_ARG(args);
1562 GATE_UNUSED_ARG(arg_count);
1563 GATE_UNUSED_ARG(ret_val);
1564 return GATE_RESULT_NOTIMPLEMENTED;
1565 }
1566
1567 gate_result_t gate_script_lua_set_var(gate_script_lua_session_t* session,
1568 gate_string_t const* name, gate_value_t const* value)
1569 {
1570 GATE_UNUSED_ARG(session);
1571 GATE_UNUSED_ARG(name);
1572 GATE_UNUSED_ARG(value);
1573 return GATE_RESULT_NOTIMPLEMENTED;
1574 }
1575
1576 gate_result_t gate_script_lua_get_var(gate_script_lua_session_t* session,
1577 gate_string_t const* name, gate_value_t* value)
1578 {
1579 GATE_UNUSED_ARG(session);
1580 GATE_UNUSED_ARG(name);
1581 GATE_UNUSED_ARG(value);
1582 return GATE_RESULT_NOTIMPLEMENTED;
1583 }
1584
1585 gate_result_t gate_script_lua_add_feature(gate_script_lua_session_t* session, gate_script_lua_feature_enum_t feature)
1586 {
1587 GATE_UNUSED_ARG(session);
1588 GATE_UNUSED_ARG(feature);
1589 return GATE_RESULT_NOTIMPLEMENTED;
1590 }
1591
1592 gate_result_t gate_script_lua_console(gate_stream_t* console)
1593 {
1594 GATE_UNUSED_ARG(console);
1595 return GATE_RESULT_NOTIMPLEMENTED;
1596 }
1597
1598 #endif /* GATE_SCRIPTING_LUA_NO_IMPL */
1599