1 #include <limits.h>
2 #include <Ecore_File.h>
3 #include "elua_private.h"
4 
5 static Eina_Prefix *_elua_pfx = NULL;
6 
7 static int _elua_init_counter = 0;
8 int _elua_log_dom = -1;
9 
10 EAPI int
elua_init(void)11 elua_init(void)
12 {
13    const char *dom = "elua";
14    if (_elua_init_counter > 0) return ++_elua_init_counter;
15 
16    eina_init();
17    ecore_file_init();
18 
19    _elua_log_dom = eina_log_domain_register(dom, EINA_COLOR_LIGHTBLUE);
20    if (_elua_log_dom < 0)
21      {
22         EINA_LOG_ERR("Could not register log domain: %s", dom);
23         return EINA_FALSE;
24      }
25 
26    eina_log_timing(_elua_log_dom, EINA_LOG_STATE_STOP, EINA_LOG_STATE_INIT);
27    INF("elua init");
28 
29    _elua_pfx = eina_prefix_new(NULL, elua_init, "ELUA", "elua", "checkme",
30                                PACKAGE_BIN_DIR, "", PACKAGE_DATA_DIR,
31                                LOCALE_DIR);
32 
33    if (!_elua_pfx)
34      {
35         ERR("coul not find elua prefix");
36         return EINA_FALSE;
37      }
38 
39    return ++_elua_init_counter;
40 }
41 
42 EAPI int
elua_shutdown(void)43 elua_shutdown(void)
44 {
45    if (_elua_init_counter <= 0)
46      {
47         EINA_LOG_ERR("Init count not greater than 0 in shutdown.");
48         return EINA_FALSE;
49      }
50    --_elua_init_counter;
51 
52    if (_elua_init_counter > 0)
53      return _elua_init_counter;
54 
55    INF("shutdown");
56    eina_log_timing(_elua_log_dom, EINA_LOG_STATE_START, EINA_LOG_STATE_SHUTDOWN);
57 
58    eina_prefix_free(_elua_pfx);
59    _elua_pfx = NULL;
60 
61    eina_log_domain_unregister(_elua_log_dom);
62    _elua_log_dom = -1;
63 
64    ecore_file_shutdown();
65    eina_shutdown();
66    return _elua_init_counter;
67 }
68 
69 #ifdef ENABLE_LUA_OLD
70 static int
_ffi_loader(lua_State * L)71 _ffi_loader(lua_State *L)
72 {
73    lua_pushvalue(L, lua_upvalueindex(1));
74    lua_pushliteral(L, "cffi");
75    lua_pushvalue(L, lua_upvalueindex(2));
76    lua_call(L, 2, 1);
77    return 1;
78 }
79 
80 #if LUA_VERSION_NUM < 502
81 /* adapted from lua 5.2 source */
82 static const char *
_push_next_template(lua_State * L,const char * path)83 _push_next_template(lua_State *L, const char *path)
84 {
85    while (*path == *LUA_PATHSEP) ++path;
86    if (!*path)
87      return NULL;
88    const char *l = strchr(path, *LUA_PATHSEP);
89    if (!l)
90      l = path + strlen(path);
91    lua_pushlstring(L, path, l - path);
92    return l;
93 }
94 
95 static int
_elua_searchpath(lua_State * L)96 _elua_searchpath(lua_State *L)
97 {
98    const char *name = luaL_checkstring(L, 1);
99    const char *path = luaL_checkstring(L, 2);
100    const char *sep  = luaL_optstring(L, 3, ".");
101    const char *dsep = luaL_optstring(L, 4, LUA_DIRSEP);
102    luaL_Buffer msg;
103    luaL_buffinit(L, &msg);
104    if (*sep)
105      name = luaL_gsub(L, name, sep, dsep);
106    while ((path = _push_next_template(L, path)))
107      {
108         const char *fname = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name);
109         lua_remove(L, -2);
110         FILE *rf = fopen(fname, "r");
111         if (rf)
112           {
113              fclose(rf);
114              return 1; /* found */
115           }
116         lua_pushfstring(L, "\n\tno file " LUA_QS, fname);
117         lua_remove(L, -2);
118         luaL_addvalue(&msg);
119      }
120    luaL_pushresult(&msg);
121    lua_pushnil(L);
122    lua_insert(L, -2);
123    return 2; /* nil plus error message */
124 }
125 #endif
126 #endif
127 
128 EAPI Elua_State *
elua_state_new(const char * progname)129 elua_state_new(const char *progname)
130 {
131    Elua_State *ret = NULL;
132    lua_State *L = luaL_newstate();
133    if (!L)
134      return NULL;
135    ret = calloc(1, sizeof(Elua_State));
136    ret->luastate = L;
137    if (progname) ret->progname = eina_stringshare_add(progname);
138    luaL_openlibs(L);
139 #ifdef ENABLE_LUA_OLD
140    /* search for cffi-lua early, and pass it through as ffi */
141    lua_getglobal(L, "package");
142 #if LUA_VERSION_NUM < 502
143    /* lua 5.1 does not have package.searchpath, we rely on having that */
144    lua_getfield(L, -1, "searchpath");
145    if (lua_isnil(L, -1))
146      {
147         lua_pushcfunction(L, _elua_searchpath);
148         lua_setfield(L, -3, "searchpath");
149      }
150    lua_pop(L, 1);
151 #endif
152    lua_getfield(L, -1, "preload");
153    lua_getfield(L, -2, "searchers");
154    if (lua_isnil(L, -1))
155      {
156         lua_pop(L, 1);
157         lua_getfield(L, -2, "loaders");
158      }
159    if (lua_isnil(L, -1))
160      {
161         ERR("could not find a module searcher");
162         goto err;
163      }
164    lua_rawgeti(L, -1, 3);
165    lua_pushliteral(L, "cffi");
166    if (lua_pcall(L, 1, 2, 0))
167      {
168         ERR("could not find the cffi module");
169         goto err;
170      }
171    if (!lua_isfunction(L, -2))
172      {
173         ERR("could not find the cffi module: %s", lua_tostring(L, -2));
174         goto err;
175      }
176    lua_pushcclosure(L, _ffi_loader, 2);
177    lua_setfield(L, -3, "ffi");
178    lua_pop(L, 3);
179 #endif
180    /* on 64-bit, split the state pointer into two and reconstruct later */
181    size_t retn = (size_t)ret;
182    if (sizeof(void *) < sizeof(lua_Number))
183      {
184         lua_pushnumber(L, 0);
185         lua_pushnumber(L, (lua_Number)retn);
186      }
187    else
188      {
189         size_t hbits = (sizeof(void *) / 2) * CHAR_BIT;
190         lua_pushnumber(L, (lua_Number)(retn >> hbits));
191         lua_pushnumber(L, (lua_Number)(retn & (((size_t)1 << hbits) - 1)));
192      }
193    lua_setfield(L, LUA_REGISTRYINDEX, "elua_ptr1");
194    lua_setfield(L, LUA_REGISTRYINDEX, "elua_ptr2");
195    return ret;
196 err:
197    lua_close(L);
198    eina_stringshare_del(ret->progname);
199    free(ret);
200    return NULL;
201 }
202 
203 EAPI void
elua_state_free(Elua_State * es)204 elua_state_free(Elua_State *es)
205 {
206    void *data;
207    if (!es) return;
208    if (es->luastate)
209      {
210         EINA_LIST_FREE(es->cmods, data)
211           {
212              lua_rawgeti(es->luastate, LUA_REGISTRYINDEX, (size_t)data);
213              lua_call(es->luastate, 0, 0);
214           }
215         lua_close(es->luastate);
216      }
217    else if (es->cmods)
218      eina_list_free(es->cmods);
219    EINA_LIST_FREE(es->lmods, data)
220      eina_stringshare_del(data);
221    EINA_LIST_FREE(es->lincs, data)
222      eina_stringshare_del(data);
223    eina_stringshare_del(es->progname);
224    eina_stringshare_del(es->coredir);
225    eina_stringshare_del(es->moddir);
226    eina_stringshare_del(es->appsdir);
227    free(es);
228 }
229 
230 EAPI void
elua_state_dirs_set(Elua_State * es,const char * core,const char * mods,const char * apps)231 elua_state_dirs_set(Elua_State *es, const char *core, const char *mods,
232                     const char *apps)
233 {
234    char *spath = NULL;
235    EINA_SAFETY_ON_NULL_RETURN(es);
236    if (core)
237      {
238         eina_stringshare_del(es->coredir);
239         spath = eina_file_path_sanitize(core);
240         es->coredir = eina_stringshare_add(spath);
241         free(spath);
242      }
243    if (mods)
244      {
245         eina_stringshare_del(es->moddir);
246         spath = eina_file_path_sanitize(mods);
247         es->moddir = eina_stringshare_add(spath);
248         free(spath);
249      }
250    if (apps)
251      {
252         eina_stringshare_del(es->appsdir);
253         spath = eina_file_path_sanitize(apps);
254         es->appsdir = eina_stringshare_add(spath);
255         free(spath);
256      }
257 }
258 
259 EAPI void
elua_state_dirs_fill(Elua_State * es,Eina_Bool ignore_env)260 elua_state_dirs_fill(Elua_State *es, Eina_Bool ignore_env)
261 {
262    const char *coredir = NULL, *moddir = NULL, *appsdir = NULL;
263    char coredirbuf[PATH_MAX], moddirbuf[PATH_MAX], appsdirbuf[PATH_MAX];
264    EINA_SAFETY_ON_NULL_RETURN(es);
265    if (!(coredir = es->coredir))
266      {
267         if (ignore_env || !(coredir = getenv("ELUA_CORE_DIR")) || !coredir[0])
268           {
269              coredir = coredirbuf;
270              snprintf(coredirbuf, sizeof(coredirbuf), "%s/core",
271                       eina_prefix_data_get(_elua_pfx));
272           }
273         if (coredir) {
274             char *sdir = eina_file_path_sanitize(coredir);
275             es->coredir = eina_stringshare_add(sdir);
276             free(sdir);
277         }
278      }
279    if (!(moddir = es->moddir))
280      {
281         if (ignore_env || !(moddir = getenv("ELUA_MODULES_DIR")) || !moddir[0])
282           {
283              moddir = moddirbuf;
284              snprintf(moddirbuf, sizeof(moddirbuf), "%s/modules",
285                       eina_prefix_data_get(_elua_pfx));
286           }
287         if (moddir) {
288             char *sdir = eina_file_path_sanitize(moddir);
289             es->moddir = eina_stringshare_add(sdir);
290             free(sdir);
291         }
292      }
293    if (!(appsdir = es->appsdir))
294      {
295         if (ignore_env || !(appsdir = getenv("ELUA_APPS_DIR")) || !appsdir[0])
296           {
297              appsdir = appsdirbuf;
298              snprintf(appsdirbuf, sizeof(appsdirbuf), "%s/apps",
299                       eina_prefix_data_get(_elua_pfx));
300           }
301         if (appsdir) {
302             char *sdir = eina_file_path_sanitize(appsdir);
303             es->appsdir = eina_stringshare_add(sdir);
304             free(sdir);
305         }
306      }
307 }
308 
309 EAPI Eina_Stringshare *
elua_state_core_dir_get(const Elua_State * es)310 elua_state_core_dir_get(const Elua_State *es)
311 {
312    EINA_SAFETY_ON_NULL_RETURN_VAL(es, NULL);
313    return es->coredir;
314 }
315 
316 EAPI Eina_Stringshare *
elua_state_mod_dir_get(const Elua_State * es)317 elua_state_mod_dir_get(const Elua_State *es)
318 {
319    EINA_SAFETY_ON_NULL_RETURN_VAL(es, NULL);
320    return es->moddir;
321 }
322 
323 EAPI Eina_Stringshare *
elua_state_apps_dir_get(const Elua_State * es)324 elua_state_apps_dir_get(const Elua_State *es)
325 {
326    EINA_SAFETY_ON_NULL_RETURN_VAL(es, NULL);
327    return es->appsdir;
328 }
329 
330 EAPI Eina_Stringshare *
elua_state_prog_name_get(const Elua_State * es)331 elua_state_prog_name_get(const Elua_State *es)
332 {
333    EINA_SAFETY_ON_NULL_RETURN_VAL(es, NULL);
334    return es->progname;
335 }
336 
337 EAPI void
elua_state_include_path_add(Elua_State * es,const char * path)338 elua_state_include_path_add(Elua_State *es, const char *path)
339 {
340    char *spath = NULL;
341    EINA_SAFETY_ON_NULL_RETURN(es);
342    EINA_SAFETY_ON_NULL_RETURN(path);
343    EINA_SAFETY_ON_FALSE_RETURN(path[0]);
344    spath = eina_file_path_sanitize(path);
345    es->lincs = eina_list_append(es->lincs, eina_stringshare_add(spath));
346    free(spath);
347 }
348 
349 EAPI Eina_Bool
elua_state_require_ref_push(Elua_State * es)350 elua_state_require_ref_push(Elua_State *es)
351 {
352    EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
353    EINA_SAFETY_ON_FALSE_RETURN_VAL(es->requireref != LUA_REFNIL, EINA_FALSE);
354    lua_rawgeti(es->luastate, LUA_REGISTRYINDEX, es->requireref);
355    return EINA_TRUE;
356 }
357 
358 EAPI Eina_Bool
elua_state_appload_ref_push(Elua_State * es)359 elua_state_appload_ref_push(Elua_State *es)
360 {
361    EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
362    EINA_SAFETY_ON_FALSE_RETURN_VAL(es->apploadref != LUA_REFNIL, EINA_FALSE);
363    lua_rawgeti(es->luastate, LUA_REGISTRYINDEX, es->apploadref);
364    return EINA_TRUE;
365 }
366 
367 EAPI lua_State *
elua_state_lua_state_get(const Elua_State * es)368 elua_state_lua_state_get(const Elua_State *es)
369 {
370    EINA_SAFETY_ON_NULL_RETURN_VAL(es, NULL);
371    return es->luastate;
372 }
373 
374 EAPI Elua_State *
elua_state_from_lua_state_get(lua_State * L)375 elua_state_from_lua_state_get(lua_State *L)
376 {
377    EINA_SAFETY_ON_NULL_RETURN_VAL(L, NULL);
378    lua_getfield(L, LUA_REGISTRYINDEX, "elua_ptr1");
379    lua_getfield(L, LUA_REGISTRYINDEX, "elua_ptr2");
380    if (!lua_isnil(L, -1) && !lua_isnil(L, -2))
381      {
382         size_t p1 = (size_t)lua_tonumber(L, -2),
383                p2 = (size_t)lua_tonumber(L, -1);
384         if (p2 && (sizeof(void *) >= sizeof(lua_Number)))
385           p1 |= p2 << ((sizeof(void *) / 2) * CHAR_BIT);
386         lua_pop(L, 2);
387         return (Elua_State *)p1;
388      }
389    lua_pop(L, 2);
390    return NULL;
391 }
392 
393 static int
_elua_gettext_bind_textdomain(lua_State * L)394 _elua_gettext_bind_textdomain(lua_State *L)
395 {
396 #ifdef ENABLE_NLS
397    const char *textdomain = luaL_checkstring(L, 1);
398    const char *dirname    = luaL_checkstring(L, 2);
399    const char *ret;
400    if (!textdomain[0] || !strcmp(textdomain, PACKAGE))
401      {
402         lua_pushnil(L);
403         lua_pushliteral(L, "invalid textdomain");
404         return 2;
405      }
406    if (!(ret = bindtextdomain(textdomain, dirname)))
407      {
408         lua_pushnil(L);
409         lua_pushstring(L, strerror(errno));
410         return 2;
411      }
412    bind_textdomain_codeset(textdomain, "UTF-8");
413    lua_pushstring(L, ret);
414    return 1;
415 #else
416    lua_pushliteral(L, "");
417    return 1;
418 #endif
419 }
420 
421 static int
_elua_get_message_language(lua_State * L)422 _elua_get_message_language(lua_State *L)
423 {
424    const char *e;
425    e = getenv("LANGUAGE");
426    if (e && e[0]) goto success;
427    e = getenv("LC_ALL");
428    if (e && e[0]) goto success;
429    e = getenv("LC_MESSAGES");
430    if (e && e[0]) goto success;
431    e = getenv("LANG");
432    if (e && e[0]) goto success;
433    lua_pushnil(L);
434    return 1;
435 success:
436    lua_pushstring(L, e);
437    return 1;
438 };
439 
440 static int
_elua_get_localeconv(lua_State * L)441 _elua_get_localeconv(lua_State *L)
442 {
443    struct lconv *lc = localeconv();
444    lua_createtable(L, 0, 24);
445 
446 #define ELUA_LCF_S(name) \
447    lua_pushstring(L, lc->name); \
448    lua_setfield(L, -2, #name);
449 
450 #define ELUA_LCF_C(name) \
451    lua_pushinteger(L, (lc->name == CHAR_MAX) ? -1 : (int)lc->name); \
452    lua_setfield(L, -2, #name);
453 
454    ELUA_LCF_S(decimal_point);
455    ELUA_LCF_S(thousands_sep);
456    ELUA_LCF_S(grouping);
457    ELUA_LCF_S(int_curr_symbol);
458    ELUA_LCF_S(currency_symbol);
459    ELUA_LCF_S(mon_decimal_point);
460    ELUA_LCF_S(mon_thousands_sep);
461    ELUA_LCF_S(mon_grouping);
462    ELUA_LCF_S(positive_sign);
463    ELUA_LCF_S(negative_sign);
464 
465    ELUA_LCF_C(frac_digits);
466    ELUA_LCF_C(p_cs_precedes);
467    ELUA_LCF_C(n_cs_precedes);
468    ELUA_LCF_C(p_sep_by_space);
469    ELUA_LCF_C(n_sep_by_space);
470    ELUA_LCF_C(p_sign_posn);
471    ELUA_LCF_C(n_sign_posn);
472    ELUA_LCF_C(int_frac_digits);
473 
474 #undef ELUA_LCF_S
475 #undef ELUA_LCF_C
476 
477    return 1;
478 };
479 
480 #ifdef ENABLE_NLS
481 static int
_elua_dgettext(lua_State * L)482 _elua_dgettext(lua_State *L)
483 {
484    const char *domain = luaL_checkstring(L, 1);
485    const char *msgid  = luaL_checkstring(L, 2);
486    char *ret = dgettext(domain, msgid);
487    if (!ret)
488      lua_pushnil(L);
489    else
490      lua_pushstring(L, ret);
491    return 1;
492 }
493 
494 static int
_elua_dngettext(lua_State * L)495 _elua_dngettext(lua_State *L)
496 {
497    const char *domain  = luaL_checkstring(L, 1);
498    const char *msgid   = luaL_checkstring(L, 2);
499    const char *plmsgid = luaL_checkstring(L, 3);
500    char *ret = dngettext(domain, msgid, plmsgid, luaL_checklong(L, 4));
501    if (!ret)
502      lua_pushnil(L);
503    else
504      lua_pushstring(L, ret);
505    return 1;
506 }
507 #endif
508 
509 const luaL_Reg gettextlib[] =
510 {
511    { "bind_textdomain", _elua_gettext_bind_textdomain },
512    { "get_message_language", _elua_get_message_language },
513    { "get_localeconv", _elua_get_localeconv },
514 #ifdef ENABLE_NLS
515    { "dgettext", _elua_dgettext },
516    { "dngettext", _elua_dngettext },
517 #endif
518    { NULL, NULL }
519 };
520 
521 static Eina_Bool
_elua_state_i18n_setup(Elua_State * es)522 _elua_state_i18n_setup(Elua_State *es)
523 {
524    char buf[PATH_MAX];
525    EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
526    EINA_SAFETY_ON_NULL_RETURN_VAL(es->coredir, EINA_FALSE);
527    EINA_SAFETY_ON_NULL_RETURN_VAL(es->progname, EINA_FALSE);
528    snprintf(buf, sizeof(buf), "%s/gettext.lua", es->coredir);
529    if (elua_util_error_report(es, elua_io_loadfile(es, buf)))
530      return EINA_FALSE;
531    lua_createtable(es->luastate, 0, 0);
532    elua_register(es->luastate, gettextlib);
533    lua_call(es->luastate, 1, 0);
534    return EINA_TRUE;
535 }
536 
537 int _elua_module_init(lua_State *L);
538 int _elua_module_system_init(lua_State *L);
539 
540 static int
_elua_file_is_dir(lua_State * L)541 _elua_file_is_dir(lua_State *L)
542 {
543    lua_pushboolean(L, ecore_file_is_dir(luaL_checkstring(L, 1)));
544    return 1;
545 }
546 
547 static int
_elua_file_exists(lua_State * L)548 _elua_file_exists(lua_State *L)
549 {
550    lua_pushboolean(L, ecore_file_exists(luaL_checkstring(L, 1)));
551    return 1;
552 }
553 
554 static int
_elua_file_mkdir(lua_State * L)555 _elua_file_mkdir(lua_State *L)
556 {
557    lua_pushboolean(L, ecore_file_mkdir(luaL_checkstring(L, 1)));
558    return 1;
559 }
560 
561 static int
_elua_file_mkpath(lua_State * L)562 _elua_file_mkpath(lua_State *L)
563 {
564    lua_pushboolean(L, ecore_file_mkpath(luaL_checkstring(L, 1)));
565    return 1;
566 }
567 
568 static int
_elua_file_rmdir(lua_State * L)569 _elua_file_rmdir(lua_State *L)
570 {
571    lua_pushboolean(L, ecore_file_rmdir(luaL_checkstring(L, 1)));
572    return 1;
573 }
574 
575 static int
_elua_file_unlink(lua_State * L)576 _elua_file_unlink(lua_State *L)
577 {
578    lua_pushboolean(L, ecore_file_unlink(luaL_checkstring(L, 1)));
579    return 1;
580 }
581 
582 static int
_elua_file_rmrf(lua_State * L)583 _elua_file_rmrf(lua_State *L)
584 {
585    lua_pushboolean(L, ecore_file_recursive_rm(luaL_checkstring(L, 1)));
586    return 1;
587 }
588 
589 const luaL_Reg _elua_cutillib[] =
590 {
591    { "init_module", _elua_module_init },
592    { "popenv"     , _elua_io_popen    },
593    { "file_is_dir", _elua_file_is_dir },
594    { "file_exists", _elua_file_exists },
595    { "file_mkdir" , _elua_file_mkdir  },
596    { "file_mkpath", _elua_file_mkpath },
597    { "file_rmdir" , _elua_file_rmdir  },
598    { "file_unlink", _elua_file_unlink },
599    { "file_rmrf"  , _elua_file_rmrf   },
600    { NULL         , NULL              }
601 };
602 
603 static Eina_Bool
_elua_state_modules_setup(const Elua_State * es)604 _elua_state_modules_setup(const Elua_State *es)
605 {
606    char buf[PATH_MAX];
607    EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
608    EINA_SAFETY_ON_NULL_RETURN_VAL(es->coredir, EINA_FALSE);
609    EINA_SAFETY_ON_NULL_RETURN_VAL(es->progname, EINA_FALSE);
610    snprintf(buf, sizeof(buf), "%s/module.lua", es->coredir);
611    if (elua_util_error_report(es, elua_io_loadfile(es, buf)))
612      return EINA_FALSE;
613    lua_pushcfunction(es->luastate, _elua_module_system_init);
614    lua_createtable(es->luastate, 0, 0);
615    elua_register(es->luastate, _elua_cutillib);
616    lua_call(es->luastate, 2, 0);
617    return EINA_TRUE;
618 }
619 
620 int
_elua_module_init(lua_State * L)621 _elua_module_init(lua_State *L)
622 {
623    Elua_State *es = elua_state_from_lua_state_get(L);
624    if (!lua_isnoneornil(L, 1))
625      {
626         lua_pushvalue(L, 1);
627         lua_call(L, 0, 0);
628      }
629    if (!lua_isnoneornil(L, 2))
630      {
631         lua_pushvalue(L, 2);
632         es->cmods = eina_list_append(es->cmods,
633            (void*)(size_t)luaL_ref(L, LUA_REGISTRYINDEX));
634      }
635    return 0;
636 }
637 
638 int
_elua_module_system_init(lua_State * L)639 _elua_module_system_init(lua_State *L)
640 {
641    Elua_State       *es       = elua_state_from_lua_state_get(L);
642    const char       *corepath = es->coredir;
643    const char       *modpath  = es->moddir;
644    const char       *appspath = es->appsdir;
645    Eina_Stringshare *data     = NULL;
646    if (!corepath || !modpath || !appspath)
647      return 0;
648    lua_pushvalue(L, 1);
649    es->requireref = luaL_ref(L, LUA_REGISTRYINDEX);
650    lua_pushvalue(L, 2);
651    es->apploadref = luaL_ref(L, LUA_REGISTRYINDEX);
652 
653    /* module path, local directories take priority */
654    int n = 0;
655    lua_pushvalue(L, 3); ++n;
656    lua_pushfstring(L, ";%s/?.lua", corepath); ++n;
657    EINA_LIST_FREE(es->lincs, data)
658      {
659         lua_pushfstring(L, ";%s/?.lua", data);
660         eina_stringshare_del(data);
661         ++n;
662      }
663    lua_pushfstring(L, ";%s/?.eo.lua", modpath); ++n;
664    lua_pushfstring(L, ";%s/?.lua", modpath); ++n;
665    lua_pushfstring(L, ";%s/?.lua", appspath); ++n;
666    lua_concat(L, n);
667 
668    /* apps path, local directory takes priority as well */
669    lua_pushvalue(L, 4);
670    lua_pushfstring(L, ";%s/?.lua", appspath);
671    lua_concat(L, 2);
672 
673    return 2;
674 }
675 
676 EAPI Eina_Bool
elua_state_setup(Elua_State * es)677 elua_state_setup(Elua_State *es)
678 {
679    Eina_Stringshare *data;
680    Eina_Bool failed = EINA_FALSE;
681 
682    if (!_elua_state_modules_setup(es))
683      return EINA_FALSE;
684    if (!_elua_state_i18n_setup(es))
685      return EINA_FALSE;
686    if (!_elua_state_io_setup(es))
687      return EINA_FALSE;
688 
689    /* finally require the necessary modules */
690    EINA_LIST_FREE(es->lmods, data)
691      {
692         if (!failed)
693           {
694              if (!elua_state_require_ref_push(es))
695                {
696                   failed = EINA_TRUE;
697                   break;
698                }
699              lua_pushstring(es->luastate, data);
700              if (elua_util_error_report(es, lua_pcall(es->luastate, 1, 0, 0)))
701                {
702                   failed = EINA_TRUE;
703                   break;
704                }
705           }
706         eina_stringshare_del(data);
707      }
708 
709    return EINA_TRUE;
710 }
711 
712 /* Utility functions - these could be written using the other APIs */
713 
714 static int
_elua_traceback(lua_State * L)715 _elua_traceback(lua_State *L)
716 {
717    lua_getglobal(L, "debug");
718    if (!lua_istable(L, -1))
719      {
720         lua_pop(L, 1);
721         return 1;
722      }
723    lua_getfield(L, -1, "traceback");
724    if (!lua_isfunction(L, -1))
725      {
726         lua_pop(L, 2);
727         return 1;
728      }
729    lua_pushvalue(L, 1);
730    lua_pushinteger(L, 2);
731    lua_call(L, 2, 1);
732    return 1;
733 }
734 
735 static int
_elua_docall(Elua_State * es,int narg,int nret)736 _elua_docall(Elua_State *es, int narg, int nret)
737 {
738    int status;
739    EINA_SAFETY_ON_NULL_RETURN_VAL(es, -1);
740    int bs = lua_gettop(es->luastate) - narg;
741    lua_pushcfunction(es->luastate, _elua_traceback);
742    lua_insert(es->luastate, bs);
743    status = lua_pcall(es->luastate, narg, nret, bs);
744    lua_remove(es->luastate, bs);
745    if (status)
746       lua_gc(es->luastate, LUA_GCCOLLECT, 0);
747    return status;
748 }
749 
750 static int
_elua_getargs(Elua_State * es,int argc,char ** argv,int n)751 _elua_getargs(Elua_State *es, int argc, char **argv, int n)
752 {
753    int i;
754    int narg = argc - (n + 1);
755    EINA_SAFETY_ON_NULL_RETURN_VAL(es, -1);
756    luaL_checkstack(es->luastate, narg + 3, "too many arguments to script");
757    for (i = n + 1; i < argc; ++i)
758      {
759         lua_pushstring(es->luastate, argv[i]);
760      }
761    lua_createtable(es->luastate, narg, n + 1);
762    for (i = 0; i < argc; ++i)
763      {
764         lua_pushstring(es->luastate, argv[i]);
765         lua_rawseti(es->luastate, -2, i - n);
766      }
767    return narg;
768 }
769 
770 EAPI Eina_Bool
elua_util_require(Elua_State * es,const char * libname)771 elua_util_require(Elua_State *es, const char *libname)
772 {
773    EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
774    if (!elua_state_require_ref_push(es))
775      {
776         /* store stuff until things are correctly set up */
777         es->lmods = eina_list_append(es->lmods, eina_stringshare_add(libname));
778         return 0;
779      }
780    lua_pushstring(es->luastate, libname);
781    return !elua_util_error_report(es, lua_pcall(es->luastate, 1, 0, 0));
782 }
783 
784 EAPI Eina_Bool
elua_util_file_run(Elua_State * es,const char * fname)785 elua_util_file_run(Elua_State *es, const char *fname)
786 {
787    EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
788    return !elua_util_error_report(es, elua_io_loadfile(es, fname)
789                                   || _elua_docall(es, 0, 1));
790 }
791 
792 EAPI Eina_Bool
elua_util_string_run(Elua_State * es,const char * chunk,const char * chname)793 elua_util_string_run(Elua_State *es, const char *chunk, const char *chname)
794 {
795    EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
796    return !elua_util_error_report(es, luaL_loadbuffer(es->luastate, chunk,
797                                                       strlen(chunk), chname)
798                                       || _elua_docall(es, 0, 0));
799 }
800 
801 EAPI int
elua_util_app_load(Elua_State * es,const char * appname)802 elua_util_app_load(Elua_State *es, const char *appname)
803 {
804    EINA_SAFETY_ON_NULL_RETURN_VAL(es, -1);
805    EINA_SAFETY_ON_FALSE_RETURN_VAL(elua_state_appload_ref_push(es), -1);
806    lua_pushstring(es->luastate, appname);
807    lua_call(es->luastate, 1, 2);
808    if (lua_isnil(es->luastate, -2))
809      {
810         lua_remove(es->luastate, -2);
811         return 1;
812      }
813    lua_pop(es->luastate, 1);
814    return 0;
815 }
816 
817 EAPI Eina_Bool
elua_util_script_run(Elua_State * es,int argc,char ** argv,int n,int * quit)818 elua_util_script_run(Elua_State *es, int argc, char **argv, int n, int *quit)
819 {
820    int status, narg;
821    const char *fname;
822    EINA_SAFETY_ON_FALSE_RETURN_VAL(n < argc, -1);
823    EINA_SAFETY_ON_NULL_RETURN_VAL(es, -1);
824    fname = argv[n];
825    narg = _elua_getargs(es, argc, argv, n);
826    lua_setglobal(es->luastate, "arg");
827    if (fname[0] == '-' && !fname[1]) fname = NULL;
828    if (fname)
829      {
830         /* check if there is a file of that name */
831         FILE *f = fopen(fname, "rb");
832         if (f)
833           {
834              fclose(f);
835              status = elua_io_loadfile(es, fname);
836           }
837         else
838           status = elua_util_app_load(es, fname);
839      }
840    else
841      status = elua_io_loadfile(es, fname);
842    lua_insert(es->luastate, -(narg + 1));
843    if (!status)
844      status = _elua_docall(es, narg, 1);
845    else
846      lua_pop(es->luastate, narg);
847    if (!status)
848      {
849         *quit = lua_toboolean(es->luastate, -1);
850         lua_pop(es->luastate, 1);
851      }
852    return !elua_util_error_report(es, status);
853 }
854 
855 static void
_elua_errmsg(const char * pname,const char * msg)856 _elua_errmsg(const char *pname, const char *msg)
857 {
858    ERR("%s%s%s", pname ? pname : "", pname ? ": " : "", msg);
859 }
860 
861 EAPI int
elua_util_error_report(const Elua_State * es,int status)862 elua_util_error_report(const Elua_State *es, int status)
863 {
864    EINA_SAFETY_ON_FALSE_RETURN_VAL(es, status);
865    if (status && !lua_isnil(es->luastate, -1))
866      {
867         const char *msg = lua_tostring(es->luastate, -1);
868         _elua_errmsg(es->progname, msg ? msg : "(non-string error)");
869         lua_pop(es->luastate, 1);
870      }
871    return status;
872 }
873