naev 0.12.5
nlua.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
9
11#include "physfs.h"
12
13#include "naev.h"
15
16#include "nlua.h"
17
18#include "array.h"
19#include "cmark_wrap.h"
20#include "conf.h"
21#include "console.h"
22#include "debug.h"
23#include "log.h"
24#include "lua_enet.h"
25#include "lutf8lib.h"
26#include "lyaml.h"
27#include "ndata.h"
28#include "nlua_audio.h"
29#include "nlua_cli.h"
30#include "nlua_commodity.h"
31#include "nlua_data.h"
32#include "nlua_diff.h"
33#include "nlua_faction.h"
34#include "nlua_file.h"
35#include "nlua_jump.h"
36#include "nlua_linopt.h"
37#include "nlua_naev.h"
38#include "nlua_news.h"
39#include "nlua_outfit.h"
40#include "nlua_pilot.h"
41#include "nlua_player.h"
42#include "nlua_rnd.h"
43#include "nlua_safelanes.h"
44#include "nlua_shiplog.h"
45#include "nlua_spfx.h"
46#include "nlua_spob.h"
47#include "nlua_system.h"
48#include "nlua_time.h"
49#include "nlua_var.h"
50#include "nlua_vec2.h"
51#include "nluadef.h"
52#include "nstring.h"
53
54lua_State *naevL = NULL;
55nlua_env __NLUA_CURENV = LUA_NOREF;
56static char
58static size_t common_sz;
59static int nlua_envs = LUA_NOREF;
60
64typedef struct LuaCache_ {
65 char *path;
66 int idx;
68static LuaCache_t *lua_cache = NULL;
69
70/*
71 * prototypes
72 */
73static int nlua_package_preload( lua_State *L );
74static int nlua_package_loader_lua( lua_State *L );
75static int nlua_package_loader_c( lua_State *L );
76static int nlua_package_loader_croot( lua_State *L );
77static int nlua_require( lua_State *L );
78static lua_State *nlua_newState( void ); /* creates a new state */
79static int nlua_loadBasic( lua_State *L );
80static int luaB_loadstring( lua_State *L );
81static int lua_cache_cmp( const void *p1, const void *p2 );
82static int nlua_errTraceInternal( lua_State *L, int idx );
83
84/* gettext */
85static int nlua_gettext( lua_State *L );
86static int nlua_ngettext( lua_State *L );
87static int nlua_pgettext( lua_State *L );
88static int nlua_gettext_noop( lua_State *L );
89static const luaL_Reg gettext_methods[] = {
90 { "gettext", nlua_gettext },
91 { "ngettext", nlua_ngettext },
92 { "pgettext", nlua_pgettext },
93 { "gettext_noop", nlua_gettext_noop },
94 { 0, 0 } };
95
96static const lua_CFunction loaders[] = {
99
108static int nlua_gettext( lua_State *L )
109{
110 const char *str = luaL_checkstring( L, 1 );
111 lua_pushstring( L, _( str ) );
112 return 1;
113}
114
125static int nlua_ngettext( lua_State *L )
126{
127 const char *stra = luaL_checkstring( L, 1 );
128 const char *strb = luaL_checkstring( L, 2 );
129 int n = luaL_checkinteger( L, 3 );
130 lua_pushstring( L, n_( stra, strb, n ) );
131 return 1;
132}
133
143static int nlua_pgettext( lua_State *L )
144{
145 const char *msgctxt = luaL_checkstring( L, 1 );
146 const char *msgid = luaL_checkstring( L, 2 );
147 lua_pushstring( L, pgettext_var( msgctxt, msgid ) );
148 return 1;
149}
150
160static int nlua_gettext_noop( lua_State *L )
161{
162 const char *str = luaL_checkstring( L, 1 );
163 lua_pushstring( L, str );
164 return 1;
165}
166
168static int nlua_log2( lua_State *L )
169{
170 double n = luaL_checknumber( L, 1 );
171 lua_pushnumber( L, log2( n ) );
172 return 1;
173}
174
179static int nlua_os_getenv( lua_State *L )
180{
181 const char *var = luaL_checkstring( L, 1 );
182 if ( strcmp( var, "HOME" ) )
183 return 0;
184 lua_pushstring( L, "lua_home" );
185 return 1;
186}
187
194static int nlua_panic( lua_State *L )
195{
196 ERR( _( "LUA PANIC: %s" ), lua_tostring( L, -1 ) );
197 return 0;
198}
199
200/*
201 * @brief Initializes the global Lua state.
202 */
203void lua_init( void )
204{
207
208 /* Environment table. */
209 lua_newtable( naevL );
210 nlua_envs = luaL_ref( naevL, LUA_REGISTRYINDEX );
211
212 /* Better clean up. */
213 lua_atpanic( naevL, nlua_panic );
214
215 /* Initialize the caches. */
216 lua_cache = array_create( LuaCache_t );
217}
218
222static int luaB_loadstring( lua_State *L )
223{
224 size_t l;
225 const char *s = luaL_checklstring( L, 1, &l );
226 const char *chunkname = luaL_optstring( L, 2, s );
227 int status = luaL_loadbuffer( L, s, l, chunkname );
228 if ( status == 0 ) /* OK? */
229 return 1;
230 else {
231 lua_pushnil( L );
232 lua_insert( L, -2 ); /* put before error message */
233 return 2; /* return nil plus error message */
234 }
235}
236
237/*
238 * @brief Closes the global Lua state.
239 */
240void lua_exit( void )
241{
243 array_free( lua_cache );
244 lua_cache = NULL;
245
246 free( common_script );
247 lua_close( naevL );
248 naevL = NULL;
249}
250
251int nlua_warn( lua_State *L, int idx )
252{
253 const char *msg = luaL_checkstring( L, idx );
254#if DEBUGGING
255 nlua_errTraceInternal( L, idx );
256 LOGERR( "%s", lua_tostring( L, -1 ) );
257 cli_printCoreString( lua_tostring( L, -1 ), 1 );
258 lua_pop( L, 1 );
259#endif /* DEBUGGING */
260 WARN( "%s", msg );
261 /* Add to console. */
262 cli_printCoreString( msg, 1 );
263 return 0;
264}
265
269void lua_clearCache( void )
270{
271 for ( int i = 0; i < array_size( lua_cache ); i++ ) {
272 LuaCache_t *lc = &lua_cache[i];
273 free( lc->path );
274 luaL_unref( naevL, LUA_REGISTRYINDEX,
275 lc->idx ); /* lua_close should have taken care of this. */
276 }
277 array_erase( &lua_cache, array_begin( lua_cache ), array_end( lua_cache ) );
278}
279
280/*
281 * @brief Run code from buffer in Lua environment.
282 *
283 * @param env Lua environment.
284 * @param buff Pointer to buffer.
285 * @param sz Size of buffer.
286 * @param name Name to use in error messages.
287 * @return 0 on success.
288 */
289int nlua_dobufenv( nlua_env env, const char *buff, size_t sz, const char *name )
290{
291 int ret;
292#if DEBUGGING
293 /* We don't really want to do this, but Lua seems to trigger all sorts of
294 * FPE exceptions on a daily basis.
295 * TODO get rid of if possible. */
296 if ( conf.fpu_except )
298#endif /* DEBUGGING */
299 ret = luaL_loadbuffer( naevL, buff, sz, name );
300 if ( ret != 0 )
301 return ret;
302#if DEBUGGING
303 if ( conf.fpu_except )
305#endif /* DEBUGGING */
306
307 ret = nlua_pcall( env, 0, LUA_MULTRET );
308 if ( ret != 0 )
309 return ret;
310 return 0;
311}
312
313/*
314 * @brief Run code a file in Lua environment.
315 *
316 * @param env Lua environment.
317 * @param filename Filename of Lua script.
318 */
319int nlua_dofileenv( nlua_env env, const char *filename )
320{
321 if ( luaL_loadfile( naevL, filename ) != 0 )
322 return -1;
323 if ( nlua_pcall( env, 0, LUA_MULTRET ) != 0 )
324 return -1;
325 return 0;
326}
327
328/*
329 * @brief Run code from chunk in Lua environment.
330 *
331 * @param env Lua environment.
332 * @param chunk Chunk to run.
333 * @return 0 on success.
334 */
335int nlua_dochunkenv( nlua_env env, int chunk, const char *name )
336{
337 (void)name;
338 int ret;
339 lua_rawgeti( naevL, LUA_REGISTRYINDEX, chunk );
340 ret = nlua_pcall( env, 0, LUA_MULTRET );
341 if ( ret != 0 )
342 return ret;
343#if DEBUGGING
344 lua_pushstring( naevL, name );
345 nlua_setenv( naevL, env, "__name" );
346#endif /* DEBUGGING */
347 return 0;
348}
349
350#if DEBUGGING
351void nlua_pushEnvTable( lua_State *L )
352{
353 lua_rawgeti( L, LUA_REGISTRYINDEX, nlua_envs );
354}
355#endif /* DEBUGGING */
356
357/*
358 * @brief Create an new environment in global Lua state.
359 *
360 * An "environment" is a table used with setfenv for sandboxing.
361 */
362nlua_env nlua_newEnv( const char *name )
363{
364 nlua_env ref;
365
366 /* Create new table and register it. */
367 lua_newtable( naevL ); /* t */
368 lua_pushvalue( naevL, -1 ); /* t, t */
369 ref = luaL_ref( naevL, LUA_REGISTRYINDEX ); /* t */
370
371 /* Store in the environment table. */
372 lua_rawgeti( naevL, LUA_REGISTRYINDEX, nlua_envs ); /* t, e */
373 lua_pushvalue( naevL, -2 ); /* t, e, t */
374 lua_rawseti( naevL, -2, ref ); /* t, e */
375 lua_pop( naevL, 1 ); /* t */
376
377 if ( name != NULL ) {
378 lua_pushstring( naevL, name );
379 nlua_setenv( naevL, ref, "__name" );
380 }
381
382 /* Metatable */
383 lua_newtable( naevL ); /* t, m */
384 lua_pushvalue( naevL, LUA_GLOBALSINDEX ); /* t, m, g */
385 lua_setfield( naevL, -2, "__index" ); /* t, m */
386 lua_setmetatable( naevL, -2 ); /* t */
387
388 /* Replace require() function with one that considers fenv */
389 lua_pushvalue( naevL, -1 ); /* t, t, */
390 lua_pushcclosure( naevL, nlua_require, 1 ); /* t, t, c */
391 lua_setfield( naevL, -2, "require" ); /* t, t */
392
393 /* Set up paths.
394 * "package.path" to look in the data.
395 * "package.cpath" unset */
396 nlua_getenv( naevL, ref, "package" ); /* t, t, p */
397 lua_newtable( naevL ); /* t, t, p, t */
398 lua_pushvalue( naevL, -1 ); /* t, t, p, t, t */
399 nlua_setenv( naevL, ref, NLUA_LOAD_TABLE ); /* t, t, p, t */
400 lua_setfield( naevL, -2, "loaded" ); /* t, t, p */
401 lua_newtable( naevL ); /* t, t, p, t */
402 lua_setfield( naevL, -2, "preload" ); /* t, t, p */
403 lua_pushstring( naevL, "?.lua;" LUA_INCLUDE_PATH "?.lua" ); /* t, t, p, s */
404 lua_setfield( naevL, -2, "path" ); /* t, t, p */
405 lua_pushstring( naevL, "" ); /* t, t, p, s */
406 lua_setfield( naevL, -2, "cpath" ); /* t, t, p */
407 lua_getfield( naevL, -1, "loaders" ); /* t, t, p, l */
408 for ( int i = 0; loaders[i] != NULL; i++ ) {
409 lua_pushcfunction( naevL, loaders[i] ); /* t, t, p, l, f */
410 lua_rawseti( naevL, -2, i + 1 ); /* t, t, p, l */
411 }
412 lua_pop( naevL, 2 ); /* t, t */
413
414 /* The global table _G should refer back to the environment. */
415 lua_pushvalue( naevL, -1 ); /* t, t, t */
416 lua_setfield( naevL, -2, "_G" ); /* t, t */
417
418 /* Push if naev is built with debugging. */
419#if DEBUGGING
420 lua_pushboolean( naevL, 1 ); /* t, t, b */
421 lua_setfield( naevL, -2, "__debugging" ); /* t, t, */
422#endif /* DEBUGGING */
423
424 /* Set up naev namespace. */
425 lua_newtable( naevL ); /* t, t, n */
426 lua_setfield( naevL, -2, "naev" ); /* t, t */
427
428 /* Run common script. */
429 if ( conf.loaded && common_script == NULL ) {
430 common_script = ndata_read( LUA_COMMON_PATH, &common_sz );
431 if ( common_script == NULL )
432 WARN( _( "Unable to load common script '%s'!" ), LUA_COMMON_PATH );
433 }
434 if ( common_script != NULL ) {
435 if ( luaL_loadbuffer( naevL, common_script, common_sz,
436 LUA_COMMON_PATH ) == 0 ) {
437 if ( nlua_pcall( ref, 0, 0 ) != 0 ) {
438 WARN( _( "Failed to run '%s':\n%s" ), LUA_COMMON_PATH,
439 lua_tostring( naevL, -1 ) );
440 lua_pop( naevL, 1 );
441 }
442 } else {
443 WARN( _( "Failed to load '%s':\n%s" ), LUA_COMMON_PATH,
444 lua_tostring( naevL, -1 ) );
445 lua_pop( naevL, 1 );
446 }
447 }
448
449 lua_pop( naevL, 1 ); /* t */
450 return ref;
451}
452
453/*
454 * @brief Frees an environment created with nlua_newEnv()
455 *
456 * @param env Environment to free.
457 */
458void nlua_freeEnv( nlua_env env )
459{
460 if ( naevL == NULL )
461 return;
462 if ( env == LUA_NOREF )
463 return;
464
465 /* Remove from the environment table. */
466 lua_rawgeti( naevL, LUA_REGISTRYINDEX, nlua_envs ); /* t */
467 lua_pushnil( naevL ); /* t, e */
468 lua_rawseti( naevL, -2, env ); /* t */
469 lua_pop( naevL, 1 ); /* */
470
471 /* Unref. */
472 luaL_unref( naevL, LUA_REGISTRYINDEX, env );
473}
474
475/*
476 * @brief Push environment table to stack
477 *
478 * @param env Environment.
479 */
480void nlua_pushenv( lua_State *L, nlua_env env )
481{
482 lua_rawgeti( L, LUA_REGISTRYINDEX, env );
483}
484
485/*
486 * @brief Gets variable from environment and pushes it to stack
487 *
488 * This is meant to replace lua_getglobal()
489 *
490 * @param env Environment.
491 * @param name Name of variable.
492 */
493void nlua_getenv( lua_State *L, nlua_env env, const char *name )
494{
495 nlua_pushenv( L, env ); /* env */
496 lua_getfield( L, -1, name ); /* env, value */
497 lua_remove( L, -2 ); /* value */
498}
499
500/*
501 * @brief Pops a value from the stack and sets it in the environment.
502 *
503 * This is meant to replace lua_setglobal()
504 *
505 * @param env Environment.
506 * @param name Name of variable.
507 */
508void nlua_setenv( lua_State *L, nlua_env env, const char *name )
509{
510 /* value */
511 nlua_pushenv( L, env ); /* value, env */
512 lua_insert( L, -2 ); /* env, value */
513 lua_setfield( L, -2, name ); /* env */
514 lua_pop( L, 1 ); /* */
515}
516
517/*
518 * @brief Registers C functions as lua library in environment
519 *
520 * This is meant to replace luaL_register()
521 *
522 * @param env Environment.
523 * @param libname Name of library table.
524 * @param l Array of functions to register.
525 * @param metatable Library will be used as metatable (so register __index).
526 */
527void nlua_register( nlua_env env, const char *libname, const luaL_Reg *l,
528 int metatable )
529{
530 if ( luaL_newmetatable( naevL, libname ) ) {
531 if ( metatable ) {
532 lua_pushvalue( naevL, -1 );
533 lua_setfield( naevL, -2, "__index" );
534 }
535 luaL_register( naevL, NULL, l );
536 } /* lib */
537 nlua_getenv( naevL, env, "naev" ); /* lib, naev */
538 lua_pushvalue( naevL, -2 ); /* lib, naev, lib */
539 lua_setfield( naevL, -2, libname ); /* lib, naev */
540 lua_pop( naevL, 1 ); /* lib */
541 nlua_setenv( naevL, env, libname ); /* */
542}
543
549static lua_State *nlua_newState( void )
550{
551 /* Try to create the new state */
552 lua_State *L = luaL_newstate();
553 if ( L == NULL ) {
554 WARN( _( "Failed to create new Lua state." ) );
555 return NULL;
556 }
557 return L;
558}
559
566static int nlua_loadBasic( lua_State *L )
567{
568 const char *override[] = { /* unsafe functions */
569 /*"collectgarbage",*/
570 "dofile", "getfenv", "load", "loadfile", NULL };
571
572 luaL_openlibs( L );
573
574 /* move [un]pack to table.[un]pack as in Lua5.2 */
575 lua_getglobal( L, "table" ); /* t */
576 lua_getglobal( L, "unpack" ); /* t, u */
577 lua_setfield( L, -2, "unpack" ); /* t */
578 lua_pop( L, 1 ); /* */
579 lua_pushnil( L ); /* nil */
580 lua_setglobal( L, "unpack" ); /* */
581
582 /* replace non-safe functions */
583 for ( int i = 0; override[i] != NULL; i++ ) {
584 lua_pushnil( L );
585 lua_setglobal( L, override[i] );
586 }
587
588 /* Override built-ins to use Naev for I/O. */
589 lua_register( L, "loadstring", luaB_loadstring );
590 lua_register( L, "print", cli_print );
591 lua_register( L, "printRaw", cli_printRaw );
592 lua_register( L, "warn", cli_warn );
593
594 /* Gettext functionality. */
595 lua_register( L, "_", nlua_gettext );
596 lua_register( L, "N_", nlua_gettext_noop );
597 lua_register( L, "n_", nlua_ngettext );
598 lua_register( L, "p_", nlua_pgettext );
599 luaL_register( L, "gettext", gettext_methods );
600
601 /* Sandbox "io" and "os". */
602 lua_newtable( L ); /* io table */
603 lua_setglobal( L, "io" );
604 lua_newtable( L ); /* os table */
605 lua_pushcfunction( L, nlua_os_getenv );
606 lua_setfield( L, -2, "getenv" );
607 lua_setglobal( L, "os" );
608
609 /* Special math functions function. */
610 lua_getglobal( L, "math" );
611 lua_pushcfunction( L, nlua_log2 );
612 lua_setfield( L, -2, "log2" );
613 lua_pushnil( L );
614 lua_setfield( L, -2, "mod" ); /* Get rid of math.mod */
615 lua_pop( L, 1 );
616
617 return 0;
618}
619
623static int lua_cache_cmp( const void *p1, const void *p2 )
624{
625 const LuaCache_t *lc1 = p1;
626 const LuaCache_t *lc2 = p2;
627 return strcmp( lc1->path, lc2->path );
628}
629
630static int nlua_package_preload( lua_State *L )
631{
632 const char *name = luaL_checkstring( L, 1 );
633
634 lua_getglobal( L, "package" ); /* p */
635 if ( !lua_istable( L, -1 ) ) {
636 lua_pop( L, 1 );
637 lua_pushstring( L, _( " package not found." ) );
638 return 1;
639 }
640
641 lua_getfield( L, -1, "preload" ); /* p, p */
642 lua_remove( L, -2 ); /* p */
643 if ( !lua_istable( L, -1 ) )
644 luaL_error( L, LUA_QL( "package.preload" ) " must be a table" );
645 lua_getfield( L, -1, name );
646 if ( lua_isnil( L, -1 ) ) /* not found? */
647 lua_pushfstring( L, "\n\tno field package.preload['%s']", name );
648 return 1;
649}
650
659static int nlua_package_loader_lua( lua_State *L )
660{
661 LuaCache_t *lc;
662 size_t bufsize, l = 0;
663 char *buf = NULL;
664 char path_filename[PATH_MAX], tmpname[PATH_MAX], tried_paths[STRMAX];
665 const char *packagepath, *start, *end;
666 const char *name = luaL_checkstring( L, 1 );
667 int done = 0;
668
669 /* Get paths to check. */
670 lua_getglobal( L, "package" );
671 if ( !lua_istable( L, -1 ) ) {
672 lua_pop( L, 1 );
673 lua_pushstring( L, _( " package not found." ) );
674 return 1;
675 }
676 lua_getfield( L, -1, "path" );
677 if ( !lua_isstring( L, -1 ) ) {
678 lua_pop( L, 2 );
679 lua_pushstring( L, _( " package.path not found." ) );
680 return 1;
681 }
682 packagepath = lua_tostring( L, -1 );
683 lua_pop( L, 2 );
684
685 /* Parse path. */
686 start = packagepath;
687 while ( !done ) {
688 char *q;
689 end = strchr( start, ';' );
690 if ( end == NULL ) {
691 done = 1;
692 end = &start[strlen( start )];
693 }
694 strncpy( tmpname, start, end - start );
695 tmpname[end - start] = '\0';
696 q = strchr( tmpname, '?' );
697 if ( q == NULL ) {
698 snprintf( path_filename, sizeof( path_filename ), "%s%s", tmpname,
699 name );
700 } else {
701 *q = '\0';
702 snprintf( path_filename, sizeof( path_filename ), "%s%s%s", tmpname,
703 name, q + 1 );
704 }
705 start = end + 1;
706
707 /* Replace all '.' before the last '.' with '/' as they are a security
708 * risk. */
709 q = strrchr( path_filename, '.' );
710 for ( int i = 0; i < q - path_filename; i++ )
711 if ( path_filename[i] == '.' )
712 path_filename[i] = '/';
713
714 /* See if cached. */
715 if ( L == naevL ) {
716 const LuaCache_t lcq = { .path = path_filename };
717 lc = bsearch( &lcq, lua_cache, array_size( lua_cache ),
718 sizeof( LuaCache_t ), lua_cache_cmp );
719 if ( lc != NULL ) {
720 lua_rawgeti( naevL, LUA_REGISTRYINDEX, lc->idx );
721 return 1;
722 }
723 }
724
725 /* Try to load the file. */
726 if ( PHYSFS_exists( path_filename ) ) {
727 buf = ndata_read( path_filename, &bufsize );
728 if ( buf != NULL )
729 break;
730 }
731
732 /* Didn't get to load it. */
733 l += scnprintf( &tried_paths[l], sizeof( tried_paths ) - l,
734 _( "\n no ndata path '%s'" ), path_filename );
735 }
736
737 /* Must have buf by now. */
738 if ( buf == NULL ) {
739 lua_pushstring( L, tried_paths );
740 return 1;
741 }
742
743 /* Try to process the Lua. It will leave a function or message on the stack,
744 * as required. */
745 luaL_loadbuffer( L, buf, bufsize, path_filename );
746 free( buf );
747
748 /* Cache the result. */
749 if ( L == naevL ) {
750 lc = &array_grow( &lua_cache );
751 lc->path = strdup( path_filename );
752 lua_pushvalue( L, -1 );
753 lc->idx = luaL_ref( naevL, LUA_REGISTRYINDEX ); /* pops 1 */
754 qsort( lua_cache, array_size( lua_cache ), sizeof( LuaCache_t ),
756 }
757 return 1;
758}
759
768static int nlua_package_loader_c( lua_State *L )
769{
770 const char *name = luaL_checkstring( L, 1 );
771 /* Hardcoded libraries only: we DO NOT honor package.cpath. */
772 if ( strcmp( name, "utf8" ) == 0 )
773 lua_pushcfunction( L, luaopen_utf8 );
774 else if ( strcmp( name, "enet" ) == 0 && conf.lua_enet )
775 lua_pushcfunction( L, luaopen_enet );
776 else if ( strcmp( name, "cmark" ) == 0 )
777 lua_pushcfunction( L, luaopen_cmark );
778 else if ( strcmp( name, "yaml" ) == 0 )
779 lua_pushcfunction( L, luaopen_yaml );
780 else
781 lua_pushnil( L );
782 return 1;
783}
784
793static int nlua_package_loader_croot( lua_State *L )
794{
795 lua_pushnil( L );
796 return 1;
797}
798
807static int nlua_require( lua_State *L )
808{
809 const char *filename = luaL_checkstring( L, 1 );
810
811 /* Environment table to load module into */
812 int envtab = lua_upvalueindex( 1 );
813
814 /* Check to see if already included. */
815 // lua_getglobal( L, NLUA_LOAD_TABLE ); /* t */
816 lua_getfield( L, envtab, NLUA_LOAD_TABLE ); /* t */
817 if ( !lua_isnil( L, -1 ) ) {
818 lua_getfield( L, -1, filename ); /* t, f */
819 /* Already included. */
820 if ( !lua_isnil( L, -1 ) ) {
821 lua_remove( L, -2 ); /* val */
822 return 1;
823 }
824 lua_pop( L, 2 ); /* */
825 } else
826 luaL_error( L, _( "_LOADED must be a table" ) );
827
828 lua_getglobal( L, "package" ); /* p */
829 if ( !lua_istable( L, -1 ) )
830 luaL_error( L, _( "package must be a table" ) );
831 lua_getfield( L, -1, "loaders" ); /* p, l */
832 lua_remove( L, -2 ); /* l */
833 if ( !lua_istable( L, -1 ) )
834 luaL_error( L, _( "package.loaders must be a table" ) );
835 lua_pushliteral( L, "" ); /* l, str */ /* error message accumulator */
836 for ( int i = 1;; i++ ) {
837 lua_rawgeti( L, -2, i ); /* l, str, i */ /* get a loader */
838 if ( lua_isnil( L, -1 ) )
839 luaL_error( L, _( "module '%s' not found:%s" ), filename,
840 lua_tostring( L, -2 ) );
841 lua_pushstring( L, filename ); /* l, str, i, f */
842 lua_call( L, 1, 1 ); /* l, str, r */ /* call it */
843 if ( lua_isfunction( L, -1 ) ) /* did it find module? */
844 break; /* module loaded successfully */
845 else if ( lua_isstring( L, -1 ) ) /* loader returned error message? */
846 lua_concat( L, 2 ); /* l, str */ /* accumulate it */
847 else
848 lua_pop( L, 1 ); /* l, str */
849 }
850 lua_remove( L, -2 ); /* l, r */
851 lua_remove( L, -2 ); /* r */
852
853 /* Set the environment for the call. */
854 /* TODO this is wrong when using setfenv Lua-side... */
855 lua_pushvalue( L, envtab ); /* r, e */
856 lua_setfenv( L, -2 ); /* r */
857
858 /* run the buffer */
859 lua_pushstring( L, filename ); /* pass name as first parameter */
860#if 0
861 if (lua_pcall(L, 1, 1, 0) != 0) {
862 /* will push the current error from the dobuffer */
863 lua_error(L);
864 return 1;
865 }
866#endif
867 lua_call( L, 1, 1 ); /* val */
868
869 /* Mark as loaded. */
870 if ( lua_isnil( L, -1 ) ) {
871 lua_pop( L, 1 );
872 lua_pushboolean( L, 1 );
873 }
874 // lua_getglobal( L,NLUA_LOAD_TABLE ); /* val, t */
875 lua_getfield( L, envtab, NLUA_LOAD_TABLE ); /* val, t */
876 lua_pushvalue( L, -2 ); /* val, t, val */
877 lua_setfield( L, -2, filename ); /* val, t */
878 lua_pop( L, 1 ); /* val */
879
880 /* cleanup, success */
881 return 1;
882}
883
914int nlua_loadStandard( nlua_env env )
915{
916 int r = 0;
917 r |= nlua_loadNaev( env );
918 r |= nlua_loadVar( env );
919 r |= nlua_loadSpob( env );
920 r |= nlua_loadSystem( env );
921 r |= nlua_loadJump( env );
922 r |= nlua_loadTime( env );
923 r |= nlua_loadPlayer( env );
924 r |= nlua_loadPilot( env );
925 r |= nlua_loadRnd( env );
926 r |= nlua_loadDiff( env );
927 r |= nlua_loadFaction( env );
928 r |= nlua_loadVector( env );
929 r |= nlua_loadOutfit( env );
930 r |= nlua_loadCommodity( env );
931 r |= nlua_loadNews( env );
932 r |= nlua_loadShiplog( env );
933 r |= nlua_loadFile( env );
934 r |= nlua_loadData( env );
935 r |= nlua_loadLinOpt( env );
936 r |= nlua_loadSafelanes( env );
937 r |= nlua_loadSpfx( env );
938 r |= nlua_loadAudio( env );
939
940 return r;
941}
942
946int nlua_errTrace( lua_State *L )
947{
948 return nlua_errTraceInternal( L, 1 );
949}
950
951static int nlua_errTraceInternal( lua_State *L, int idx )
952{
953 /* Handle special done case. */
954 const char *str = luaL_checkstring( L, idx );
955 if ( strcmp( str, NLUA_DONE ) == 0 )
956 return 1;
957
958 /* str */
959 /* Otherwise execute "debug.traceback( str, int )". */
960 lua_getglobal( L, "debug" ); /* str, debug */
961 if ( !lua_istable( L, -1 ) ) {
962 lua_pop( L, 1 );
963 return 1;
964 }
965 lua_getfield( L, -1, "traceback" ); /* str, debug, traceback */
966 if ( !lua_isfunction( L, -1 ) ) {
967 lua_pop( L, 2 );
968 return 1;
969 }
970 lua_pushvalue( L, -3 ); /* str, debug, traceback, str */
971 lua_pushinteger( L, 2 ); /* str, debug, traceback, str, int */
972 lua_call( L, 2, 1 ); /* str, debug, ret */
973 lua_remove( L, -2 ); /* str, ret */
974 lua_remove( L, -2 ); /* ret */
975 return 1;
976}
977
978/*
979 * @brief Wrapper around lua_pcall() that handles errors and environments
980 *
981 * @param env Environment.
982 * @param nargs Number of arguments to pass.
983 * @param nresults Number of return values to take.
984 */
985int nlua_pcall( nlua_env env, int nargs, int nresults )
986{
987 int errf, ret, prev_env;
988
989#if DEBUGGING
990 errf = lua_gettop( naevL ) - nargs;
991 lua_pushcfunction( naevL, nlua_errTrace );
992 lua_insert( naevL, errf );
993
994 /* We don't really want to do this, but Lua seems to trigger all sorts of
995 * FPE exceptions on a daily basis.
996 * TODO get rid of if possible. */
997 if ( conf.fpu_except )
999#else /* DEBUGGING */
1000 errf = 0;
1001#endif /* DEBUGGING */
1002
1003 prev_env = __NLUA_CURENV;
1004 __NLUA_CURENV = env;
1005
1006 nlua_pushenv( naevL, env );
1007 lua_setfenv( naevL, -2 - nargs );
1008 ret = lua_pcall( naevL, nargs, nresults, errf );
1009
1010 __NLUA_CURENV = prev_env;
1011
1012#if DEBUGGING
1013 lua_remove( naevL, errf );
1014
1015 if ( conf.fpu_except )
1017#endif /* DEBUGGING */
1018
1019 return ret;
1020}
1021
1029int nlua_refenv( nlua_env env, const char *name )
1030{
1031 nlua_getenv( naevL, env, name );
1032 if ( !lua_isnil( naevL, -1 ) )
1033 return luaL_ref( naevL, LUA_REGISTRYINDEX );
1034 lua_pop( naevL, 1 );
1035 return LUA_NOREF;
1036}
1037
1047int nlua_refenvtype( nlua_env env, const char *name, int type )
1048{
1049 nlua_getenv( naevL, env, name );
1050 if ( lua_type( naevL, -1 ) == type )
1051 return luaL_ref( naevL, LUA_REGISTRYINDEX );
1052 lua_pop( naevL, 1 );
1053 return LUA_NOREF;
1054}
1055
1063int nlua_reffield( int objref, const char *name )
1064{
1065 if ( objref == LUA_NOREF )
1066 return LUA_NOREF;
1067 lua_rawgeti( naevL, LUA_REGISTRYINDEX, objref );
1068 lua_getfield( naevL, -1, name );
1069 lua_remove( naevL, -2 );
1070 if ( !lua_isnil( naevL, -1 ) )
1071 return luaL_ref( naevL, LUA_REGISTRYINDEX );
1072 lua_pop( naevL, 1 );
1073 return LUA_NOREF;
1074}
1075
1079int nlua_ref( lua_State *L, int idx )
1080{
1081 lua_pushvalue( L, idx );
1082 return luaL_ref( L, LUA_REGISTRYINDEX );
1083}
1084
1088void nlua_unref( lua_State *L, int idx )
1089{
1090 if ( idx != LUA_NOREF )
1091 luaL_unref( L, LUA_REGISTRYINDEX, idx );
1092}
1093
1097void nlua_resize( void )
1098{
1099 lua_rawgeti( naevL, LUA_REGISTRYINDEX, nlua_envs ); /* t */
1100 lua_pushnil( naevL ); /* t, n */
1101 while ( lua_next( naevL, -2 ) != 0 ) { /* t, k, v */
1102 int env = lua_tointeger( naevL, -2 ); /* t, k, v */
1103 lua_getfield( naevL, -1, "__resize" ); /* t, k, v, f */
1104 if ( !lua_isnil( naevL, -1 ) ) {
1105 lua_pushinteger( naevL, SCREEN_W ); /* t, k, v, f, w */
1106 lua_pushinteger( naevL, SCREEN_H ); /* t, k, v, f, w, h */
1107 nlua_pcall( env, 2, 0 ); /* t, k, v */
1108 lua_pop( naevL, 1 ); /* t, k */
1109 } else
1110 lua_pop( naevL, 2 ); /* t, k */
1111 } /* t */
1112 lua_pop( naevL, 1 ); /* */
1113}
1114
1118int nlua_helperTags( lua_State *L, int idx, char *const *tags )
1119{
1120 if ( lua_isnoneornil( L, idx ) ) {
1121 lua_newtable( L );
1122 for ( int i = 0; i < array_size( tags ); i++ ) {
1123 lua_pushstring( L, tags[i] );
1124 lua_pushboolean( L, 1 );
1125 lua_rawset( L, -3 );
1126 }
1127 return 1;
1128 } else {
1129 const char *s = luaL_checkstring( L, idx );
1130 for ( int i = 0; i < array_size( tags ); i++ ) {
1131 if ( strcmp( s, tags[i] ) == 0 ) {
1132 lua_pushboolean( L, 1 );
1133 return 1;
1134 }
1135 }
1136 lua_pushboolean( L, 0 );
1137 return 1;
1138 }
1139}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
#define array_end(array)
Returns a pointer to the end of the reserved memory space.
Definition array.h:214
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
Definition array.h:148
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:122
#define array_begin(array)
Returns a pointer to the beginning of the reserved memory space.
Definition array.h:206
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
int cli_warn(lua_State *L)
Barebones warn implementation for Lua, allowing scripts to print warnings to stderr.
Definition console.c:169
int cli_printRaw(lua_State *L)
Prints raw markup to the console.
Definition console.c:188
int cli_print(lua_State *L)
Replacement for the internal Lua print to print to both the console and the terminal.
Definition console.c:178
void cli_printCoreString(const char *s, int escape)
Prints a string.
Definition console.c:110
void debug_disableFPUExcept(void)
Disables FPU exceptions.
Definition debug_fpu.c:37
void debug_enableFPUExcept(void)
Enables FPU exceptions. Artificially limited to Linux until link issues are figured out.
Definition debug_fpu.c:27
const char * pgettext_var(const char *msgctxt, const char *msgid)
Definition gettext.c:346
Header file with generic functions and naev-specifics.
#define PATH_MAX
Definition naev.h:57
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
Definition ndata.c:207
static int nlua_require(lua_State *L)
include( string module )
Definition nlua.c:807
void nlua_unref(lua_State *L, int idx)
Removes a reference set with nlua_ref.
Definition nlua.c:1088
static int nlua_log2(lua_State *L)
Implements the Lua function math.log2 (base-2 logarithm).
Definition nlua.c:168
static int nlua_loadBasic(lua_State *L)
Loads specially modified basic stuff.
Definition nlua.c:566
int nlua_refenv(nlua_env env, const char *name)
Gets the reference of a global in a lua environment.
Definition nlua.c:1029
static int nlua_pgettext(lua_State *L)
gettext support with context.
Definition nlua.c:143
int nlua_ref(lua_State *L, int idx)
Creates a new reference to a Lua structure at a position.
Definition nlua.c:1079
static int nlua_panic(lua_State *L)
Handles what to do when Lua panics.
Definition nlua.c:194
int nlua_loadStandard(nlua_env env)
Loads the standard Naev Lua API.
Definition nlua.c:914
static lua_State * nlua_newState(void)
Wrapper around luaL_newstate.
Definition nlua.c:549
static int nlua_gettext_noop(lua_State *L)
gettext support (noop). Does not actually do anything, but gets detected by gettext.
Definition nlua.c:160
nlua_env __NLUA_CURENV
Definition nlua.c:55
int nlua_refenvtype(nlua_env env, const char *name, int type)
Gets the reference of a global in a lua environment if it matches a type.
Definition nlua.c:1047
int nlua_helperTags(lua_State *L, int idx, char *const *tags)
Helper function to deal with tags.
Definition nlua.c:1118
static int nlua_gettext(lua_State *L)
gettext support.
Definition nlua.c:108
static const lua_CFunction loaders[]
Definition nlua.c:96
int nlua_reffield(int objref, const char *name)
Gets the reference to the specified field from an object reference.
Definition nlua.c:1063
static size_t common_sz
Definition nlua.c:58
static int nlua_package_loader_croot(lua_State *L)
load( string module ) – searcher function to replace package.loaders[4] (Lua 5.1),...
Definition nlua.c:793
static char * common_script
Definition nlua.c:57
static int nlua_package_loader_lua(lua_State *L)
load( string module ) – searcher function to replace package.loaders[2] (Lua 5.1),...
Definition nlua.c:659
void lua_clearCache(void)
Clears the cached stuff.
Definition nlua.c:269
void nlua_resize(void)
Propagates a resize event to all the environments forcibly.
Definition nlua.c:1097
lua_State * naevL
Definition nlua.c:54
static int lua_cache_cmp(const void *p1, const void *p2)
Compares two Lua caches.
Definition nlua.c:623
int nlua_errTrace(lua_State *L)
Gets a trace from Lua.
Definition nlua.c:946
static int nlua_ngettext(lua_State *L)
gettext support for singular and plurals.
Definition nlua.c:125
static int nlua_os_getenv(lua_State *L)
Implements the Lua function os.getenv. In the sandbox we only make a fake $HOME visible.
Definition nlua.c:179
static int luaB_loadstring(lua_State *L)
Replacement for the internal Lua loadstring().
Definition nlua.c:222
static int nlua_package_loader_c(lua_State *L)
load( string module ) – searcher function to replace package.loaders[3] (Lua 5.1),...
Definition nlua.c:768
static const luaL_Reg gettext_methods[]
Definition nlua.c:89
int nlua_loadAudio(nlua_env env)
Loads the audio library.
Definition nlua_audio.c:272
int nlua_loadCommodity(nlua_env env)
Loads the commodity library.
int nlua_loadData(nlua_env env)
Loads the data library.
Definition nlua_data.c:51
int nlua_loadDiff(nlua_env env)
Loads the diff Lua library.
Definition nlua_diff.c:34
int nlua_loadFaction(nlua_env env)
Loads the faction library.
int nlua_loadFile(nlua_env env)
Loads the file library.
Definition nlua_file.c:63
int nlua_loadJump(nlua_env env)
Loads the jump library.
Definition nlua_jump.c:68
int nlua_loadLinOpt(nlua_env env)
Loads the linopt library.
Definition nlua_linopt.c:73
int nlua_loadNaev(nlua_env env)
Loads the Naev Lua library.
Definition nlua_naev.c:135
int nlua_loadNews(nlua_env env)
Loads the news library.
Definition nlua_news.c:52
int nlua_loadOutfit(nlua_env env)
Loads the outfit library.
Definition nlua_outfit.c:99
int nlua_loadPilot(nlua_env env)
Loads the pilot library.
Definition nlua_pilot.c:481
int nlua_loadPlayer(nlua_env env)
Loads the player Lua library.
int nlua_loadRnd(nlua_env env)
Loads the Random Number Lua library.
Definition nlua_rnd.c:43
int nlua_loadSafelanes(nlua_env env)
Loads the safelanes Lua library.
int nlua_loadShiplog(nlua_env env)
Loads the mission Lua library.
int nlua_loadSpfx(nlua_env env)
Loads the spfx library.
Definition nlua_spfx.c:113
int nlua_loadSpob(nlua_env env)
Loads the spob library.
Definition nlua_spob.c:124
int nlua_loadSystem(nlua_env env)
Loads the system library.
int nlua_loadTime(nlua_env env)
Loads the Time Lua library.
Definition nlua_time.c:56
int nlua_loadVar(nlua_env env)
Loads the mission variable Lua library.
Definition nlua_var.c:45
int nlua_loadVector(nlua_env env)
Loads the vector metatable.
Definition nlua_vec2.c:85
int scnprintf(char *text, size_t maxlen, const char *fmt,...)
Like snprintf(), but returns the number of characters ACTUALLY "printed" into the buffer....
Definition nstring.c:102
Cache structure for loading chunks.
Definition nlua.c:64
char * path
Definition nlua.c:65
int idx
Definition nlua.c:66