2014-12-12 05:39:57 -08:00
|
|
|
#include "Elua.h"
|
|
|
|
#include "elua_private.h"
|
2014-04-03 08:01:01 -07:00
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
/* bytecode caching */
|
|
|
|
|
2014-05-28 05:36:52 -07:00
|
|
|
static Eina_File *
|
2014-06-10 04:26:06 -07:00
|
|
|
check_bc(Eina_File *of, const char *fname, Eina_Bool *bc)
|
2014-05-28 05:36:52 -07:00
|
|
|
{
|
2014-06-10 04:26:06 -07:00
|
|
|
if (of)
|
|
|
|
{
|
|
|
|
struct stat bc_stat, sc_stat;
|
|
|
|
/* original file doesn't exist, only bytecode does, use bytecode */
|
|
|
|
if (stat(fname, &sc_stat) < 0)
|
|
|
|
return of;
|
2014-06-11 03:12:27 -07:00
|
|
|
if (stat(eina_file_filename_get(of), &bc_stat) < 0)
|
|
|
|
{
|
|
|
|
/* what? */
|
|
|
|
eina_file_close(of);
|
|
|
|
goto generate;
|
|
|
|
}
|
2014-06-10 04:26:06 -07:00
|
|
|
/* bytecode is newer than original file, use bytecode */
|
|
|
|
if (bc_stat.st_mtime > sc_stat.st_mtime)
|
|
|
|
return of;
|
|
|
|
/* bytecode is not new enough; trigger regeneration */
|
|
|
|
eina_file_close(of);
|
|
|
|
}
|
2014-06-11 03:12:27 -07:00
|
|
|
generate:
|
2014-06-10 04:26:06 -07:00
|
|
|
*bc = EINA_TRUE;
|
|
|
|
return eina_file_open(fname, EINA_FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_File *
|
2014-06-11 02:41:02 -07:00
|
|
|
open_src(const char *fname, Eina_Bool *bc)
|
2014-06-10 04:26:06 -07:00
|
|
|
{
|
|
|
|
Eina_File *f = NULL;
|
|
|
|
const char *ext = strstr(fname, ".lua");
|
2014-06-11 02:41:02 -07:00
|
|
|
if (ext && !ext[4])
|
2014-05-28 05:36:52 -07:00
|
|
|
{
|
2014-04-03 08:01:01 -07:00
|
|
|
char buf[PATH_MAX];
|
|
|
|
snprintf(buf, sizeof(buf), "%sc", fname);
|
2014-06-10 04:26:06 -07:00
|
|
|
f = check_bc(eina_file_open(buf, EINA_FALSE), fname, bc);
|
2014-05-28 05:36:52 -07:00
|
|
|
}
|
2014-06-10 04:26:06 -07:00
|
|
|
if (!f) f = eina_file_open(fname, EINA_FALSE);
|
|
|
|
return f;
|
2014-04-03 08:01:01 -07:00
|
|
|
}
|
|
|
|
|
2014-05-28 05:36:52 -07:00
|
|
|
static int
|
|
|
|
writef(lua_State *L EINA_UNUSED, const void *p, size_t size, void *ud)
|
|
|
|
{
|
|
|
|
FILE *f = ud;
|
|
|
|
return ferror(f) || (fwrite(p, 1, size, f) != size);
|
2014-04-03 08:01:01 -07:00
|
|
|
}
|
|
|
|
|
2014-11-06 02:57:19 -08:00
|
|
|
static FILE *
|
|
|
|
bc_tmp_open(const char *fname, char *buf, size_t buflen)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
#ifndef _WIN32
|
|
|
|
mode_t old_umask;
|
|
|
|
#endif
|
|
|
|
char *fs = strrchr(fname, '/'), *bs = strrchr(fname, '\\');
|
|
|
|
if (!fs && !bs)
|
|
|
|
snprintf(buf, buflen, "./XXXXXX");
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char *ss = (fs > bs) ? fs : bs;
|
|
|
|
snprintf(buf, buflen, "%.*sXXXXXX", (int)(ss - fname + 1), fname);
|
|
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
|
|
old_umask = umask(S_IRWXG|S_IRWXO);
|
|
|
|
#endif
|
|
|
|
fd = mkstemp(buf);
|
|
|
|
#ifndef _WIN32
|
|
|
|
umask(old_umask);
|
|
|
|
#endif
|
|
|
|
if (fd < 0)
|
|
|
|
return NULL;
|
|
|
|
return fdopen(fd, "w");
|
|
|
|
}
|
|
|
|
|
2014-05-28 05:36:52 -07:00
|
|
|
static void
|
|
|
|
write_bc(lua_State *L, const char *fname)
|
|
|
|
{
|
|
|
|
FILE *f;
|
2014-11-06 02:57:19 -08:00
|
|
|
char buf[PATH_MAX];
|
|
|
|
if ((f = bc_tmp_open(fname, buf, sizeof(buf))))
|
2014-05-28 05:36:52 -07:00
|
|
|
{
|
2014-11-06 02:57:19 -08:00
|
|
|
char buf2[PATH_MAX];
|
2014-05-28 05:36:52 -07:00
|
|
|
if (lua_dump(L, writef, f))
|
|
|
|
{
|
|
|
|
fclose(f);
|
2014-06-11 03:12:27 -07:00
|
|
|
/* there really is nothing to handle here */
|
|
|
|
(void)!!remove(buf);
|
2014-05-28 05:36:52 -07:00
|
|
|
}
|
|
|
|
else fclose(f);
|
2014-11-06 02:57:19 -08:00
|
|
|
snprintf(buf2, sizeof(buf2), "%sc", fname);
|
|
|
|
if (rename(buf, buf2))
|
|
|
|
{
|
|
|
|
/* a futile attempt at cleanup */
|
|
|
|
(void)!!remove(buf);
|
|
|
|
(void)!!remove(buf2);
|
|
|
|
}
|
2014-05-28 05:36:52 -07:00
|
|
|
}
|
2014-04-03 08:01:01 -07:00
|
|
|
}
|
|
|
|
|
2014-05-28 05:36:52 -07:00
|
|
|
static const char *
|
|
|
|
getf(lua_State *L EINA_UNUSED, void *ud, size_t *size)
|
|
|
|
{
|
|
|
|
char *buff = *((char**)ud);
|
|
|
|
if (feof(stdin)) return NULL;
|
|
|
|
*size = fread(buff, 1, LUAL_BUFFERSIZE, stdin);
|
|
|
|
return (*size > 0) ? buff : NULL;
|
2014-04-03 08:01:01 -07:00
|
|
|
}
|
|
|
|
|
2014-05-28 05:36:52 -07:00
|
|
|
static int
|
2014-06-11 02:41:02 -07:00
|
|
|
elua_loadstdin(lua_State *L)
|
2014-05-28 05:36:52 -07:00
|
|
|
{
|
|
|
|
char buff[LUAL_BUFFERSIZE];
|
2014-06-11 02:41:02 -07:00
|
|
|
int status = lua_load(L, getf, &buff, "=stdin");
|
2014-05-28 05:36:52 -07:00
|
|
|
if (ferror(stdin))
|
|
|
|
{
|
2014-04-03 08:01:01 -07:00
|
|
|
lua_pop(L, 1);
|
2014-04-04 02:56:20 -07:00
|
|
|
lua_pushfstring(L, "cannot read stdin: %s", strerror(errno));
|
2014-04-03 08:01:01 -07:00
|
|
|
return LUA_ERRFILE;
|
2014-05-28 05:36:52 -07:00
|
|
|
}
|
|
|
|
return status;
|
2014-04-03 08:01:01 -07:00
|
|
|
}
|
|
|
|
|
2014-05-28 05:36:52 -07:00
|
|
|
typedef struct Map_Stream
|
|
|
|
{
|
|
|
|
char *fmap;
|
|
|
|
size_t flen;
|
2014-04-03 08:01:01 -07:00
|
|
|
} Map_Stream;
|
|
|
|
|
2014-05-28 05:36:52 -07:00
|
|
|
static const char *
|
|
|
|
getf_map(lua_State *L EINA_UNUSED, void *ud, size_t *size)
|
|
|
|
{
|
|
|
|
Map_Stream *s = ud;
|
|
|
|
const char *fmap = s->fmap;
|
|
|
|
*size = s->flen;
|
|
|
|
/* gotta null it - tell luajit to terminate reading */
|
|
|
|
s->fmap = NULL;
|
|
|
|
return fmap;
|
2014-04-03 08:01:01 -07:00
|
|
|
}
|
|
|
|
|
2014-12-12 05:39:57 -08:00
|
|
|
EAPI int
|
2015-04-09 05:48:06 -07:00
|
|
|
elua_io_loadfile(Elua_State *es, const char *fname)
|
2014-05-28 05:36:52 -07:00
|
|
|
{
|
|
|
|
Map_Stream s;
|
|
|
|
int status;
|
|
|
|
Eina_File *f;
|
|
|
|
const char *chname;
|
|
|
|
Eina_Bool bcache = EINA_FALSE;
|
2015-04-09 05:48:06 -07:00
|
|
|
lua_State *L;
|
|
|
|
if (!es || !es->luastate) return -1;
|
|
|
|
L = es->luastate;
|
2014-05-28 05:36:52 -07:00
|
|
|
if (!fname)
|
|
|
|
{
|
2014-06-11 02:41:02 -07:00
|
|
|
return elua_loadstdin(L);
|
2014-05-28 05:36:52 -07:00
|
|
|
}
|
2014-06-11 02:41:02 -07:00
|
|
|
if (!(f = open_src(fname, &bcache)))
|
2014-05-28 05:36:52 -07:00
|
|
|
{
|
2014-04-03 08:01:01 -07:00
|
|
|
lua_pushfstring(L, "cannot open %s: %s", fname, strerror(errno));
|
|
|
|
return LUA_ERRFILE;
|
2014-05-28 05:36:52 -07:00
|
|
|
}
|
|
|
|
chname = lua_pushfstring(L, "@%s", fname);
|
|
|
|
s.flen = eina_file_size_get(f);
|
|
|
|
if (!(s.fmap = eina_file_map_all(f, EINA_FILE_RANDOM)))
|
|
|
|
{
|
2014-04-03 08:01:01 -07:00
|
|
|
lua_pushfstring(L, "cannot read %s: %s", chname + 1, strerror(errno));
|
|
|
|
lua_remove(L, -2);
|
|
|
|
return LUA_ERRFILE;
|
2014-05-28 05:36:52 -07:00
|
|
|
}
|
2014-06-11 02:41:02 -07:00
|
|
|
status = lua_load(L, getf_map, &s, chname);
|
2014-05-28 05:36:52 -07:00
|
|
|
eina_file_map_free(f, s.fmap);
|
|
|
|
eina_file_close(f);
|
|
|
|
if (!status && bcache) write_bc(L, fname);
|
|
|
|
lua_remove(L, -2);
|
|
|
|
return status;
|
2014-04-03 08:01:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* lua function */
|
|
|
|
|
2014-05-28 05:36:52 -07:00
|
|
|
static int
|
|
|
|
loadfile(lua_State *L)
|
|
|
|
{
|
2015-04-09 05:48:06 -07:00
|
|
|
Elua_State *es = elua_state_from_lua_get(L);
|
2014-05-28 05:36:52 -07:00
|
|
|
const char *fname = luaL_optstring(L, 1, NULL);
|
2015-04-09 05:48:06 -07:00
|
|
|
int status = elua_io_loadfile(es, fname),
|
2014-05-28 05:36:52 -07:00
|
|
|
hasenv = (lua_gettop(L) >= 3);
|
|
|
|
if (!status)
|
|
|
|
{
|
|
|
|
if (hasenv)
|
|
|
|
{
|
|
|
|
lua_pushvalue(L, 3);
|
|
|
|
lua_setfenv(L, -2);
|
|
|
|
}
|
2014-04-03 08:01:01 -07:00
|
|
|
return 1;
|
2014-05-28 05:36:52 -07:00
|
|
|
}
|
|
|
|
lua_pushnil(L);
|
|
|
|
lua_insert(L, -2);
|
|
|
|
return 2;
|
2014-04-03 08:01:01 -07:00
|
|
|
}
|
|
|
|
|
2014-12-12 05:39:57 -08:00
|
|
|
EAPI void
|
|
|
|
elua_io_register(lua_State *L)
|
2014-05-28 05:36:52 -07:00
|
|
|
{
|
|
|
|
lua_pushcfunction(L, loadfile);
|
|
|
|
lua_setglobal(L, "loadfile");
|
2014-06-10 04:35:54 -07:00
|
|
|
}
|