GCC Code Coverage Report


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