You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
383 lines
8.6 KiB
383 lines
8.6 KiB
#include "luavgl.h"
|
|
#include "private.h"
|
|
|
|
typedef struct luavgl_fs_s {
|
|
lv_fs_file_t file;
|
|
bool closed; /* userdata exists but lv_fs has been closed */
|
|
} luavgl_fs_t;
|
|
|
|
typedef struct luavgl_dir_s {
|
|
lv_fs_dir_t dir;
|
|
bool closed; /* userdata exists but lv_fs has been closed */
|
|
} luavgl_dir_t;
|
|
|
|
static luavgl_fs_t *luavgl_to_fs(lua_State *L, int index)
|
|
{
|
|
luavgl_fs_t *v = luaL_checkudata(L, index, "lv_fs");
|
|
if (v->closed) {
|
|
luaL_error(L, "attempt to use a closed file");
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
static luavgl_dir_t *luavgl_to_dir(lua_State *L, int index)
|
|
{
|
|
luavgl_dir_t *v = luaL_checkudata(L, index, "lv_dir");
|
|
if (v->closed) {
|
|
luaL_error(L, "attempt to use a closed file");
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
/**
|
|
* luavgl.open_file(filename, [mode])
|
|
* mode: "r" "w", others not supported.
|
|
*/
|
|
static int luavgl_fs_open(lua_State *L)
|
|
{
|
|
const char *path = lua_tostring(L, 1);
|
|
const char *mode = "r";
|
|
if (lua_type(L, 2) == LUA_TSTRING) {
|
|
mode = lua_tostring(L, 2);
|
|
}
|
|
|
|
luavgl_fs_t *f = lua_newuserdata(L, sizeof(luavgl_fs_t));
|
|
f->closed = false;
|
|
|
|
lv_fs_mode_t lmode = 0;
|
|
if (luavgl_strchr(mode, 'r'))
|
|
lmode |= LV_FS_MODE_RD;
|
|
|
|
if (luavgl_strchr(mode, 'w'))
|
|
lmode |= LV_FS_MODE_WR;
|
|
|
|
lv_fs_res_t res = lv_fs_open(&f->file, path, lmode);
|
|
if (res != LV_FS_RES_OK) {
|
|
LV_LOG_ERROR("open failed: %s", path);
|
|
lua_pushnil(L);
|
|
lua_pushfstring(L, "open failed: %s\n", path);
|
|
lua_pushinteger(L, res); /* return lv_fs error number */
|
|
return 3;
|
|
}
|
|
|
|
luaL_getmetatable(L, "lv_fs");
|
|
lua_setmetatable(L, -2);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* read_chars modified for lv_fs */
|
|
static int read_chars(lua_State *L, lv_fs_file_t *f, size_t n)
|
|
{
|
|
uint32_t nr; /* number of chars actually read */
|
|
char *p;
|
|
|
|
luaL_Buffer b;
|
|
luaL_buffinit(L, &b);
|
|
p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */
|
|
lv_fs_res_t res = lv_fs_read(f, p, n, &nr);
|
|
if (res != LV_FS_RES_OK)
|
|
return false;
|
|
|
|
luaL_pushresultsize(&b, nr);
|
|
return (nr > 0); /* true iff read something */
|
|
}
|
|
|
|
/* read_all modified for lv_fs */
|
|
static void read_all(lua_State *L, lv_fs_file_t *f)
|
|
{
|
|
uint32_t nr;
|
|
luaL_Buffer b;
|
|
luaL_buffinit(L, &b);
|
|
do { /* read file in chunks of LUAL_BUFFERSIZE bytes */
|
|
char *p = luaL_prepbuffer(&b);
|
|
lv_fs_read(f, p, LUAL_BUFFERSIZE, &nr);
|
|
luaL_addsize(&b, nr);
|
|
} while (nr == LUAL_BUFFERSIZE);
|
|
luaL_pushresult(&b); /* close buffer */
|
|
}
|
|
|
|
/**
|
|
* f:read()
|
|
*/
|
|
static int luavgl_fs_read(lua_State *L)
|
|
{
|
|
luavgl_fs_t *f = luavgl_to_fs(L, 1);
|
|
int nargs = lua_gettop(L) - 1;
|
|
int n, success;
|
|
|
|
if (nargs == 0)
|
|
return luaL_error(L, "read mode required: 'a' or num ");
|
|
|
|
/* ensure stack space for all results and for auxlib's buffer */
|
|
luaL_checkstack(L, nargs + LUA_MINSTACK, "too many arguments");
|
|
success = 1;
|
|
for (n = 2; nargs-- && success; n++) {
|
|
if (lua_type(L, n) == LUA_TNUMBER) {
|
|
size_t l = (size_t)luaL_checkinteger(L, n);
|
|
success = read_chars(L, &f->file, l);
|
|
} else {
|
|
const char *p = luaL_checkstring(L, n);
|
|
if (*p == '*')
|
|
p++; /* skip optional '*' (for compatibility) */
|
|
switch (*p) {
|
|
case 'a': /* file */
|
|
read_all(L, &f->file); /* read entire file */
|
|
success = 1; /* always success */
|
|
break;
|
|
case 'n': /* number */
|
|
case 'l': /* line */
|
|
case 'L': /* line with end-of-line */
|
|
default:
|
|
return luaL_argerror(L, n, "invalid format");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!success) {
|
|
lua_pop(L, 1); /* remove last result */
|
|
lua_pushnil(L); /* push nil instead */
|
|
}
|
|
|
|
return n - 2;
|
|
}
|
|
|
|
static int luavgl_fs_write(lua_State *L)
|
|
{
|
|
luavgl_fs_t *f = luavgl_to_fs(L, 1);
|
|
lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */
|
|
|
|
int arg = 2;
|
|
int nargs = lua_gettop(L) - arg;
|
|
int status = 1;
|
|
lv_fs_res_t res;
|
|
size_t l;
|
|
uint32_t nw;
|
|
const char *s;
|
|
|
|
for (; nargs--; arg++) {
|
|
if (lua_type(L, arg) == LUA_TNUMBER) {
|
|
s = luaL_tolstring(L, arg, &l);
|
|
res = lv_fs_write(&f->file, s, l, &nw);
|
|
lua_pop(L, 1);
|
|
} else {
|
|
s = luaL_checklstring(L, arg, &l);
|
|
res = lv_fs_write(&f->file, s, l, &nw);
|
|
}
|
|
status = status && nw == l && res == LV_FS_RES_OK;
|
|
}
|
|
|
|
if (status) {
|
|
return 1; /* file handle already on stack top */
|
|
}
|
|
|
|
lua_pushnil(L);
|
|
lua_pushstring(L, "failed"); /* no details */
|
|
lua_pushinteger(L, res);
|
|
return 3;
|
|
}
|
|
|
|
static int luavgl_fs_close(lua_State *L)
|
|
{
|
|
luavgl_fs_t *f = luavgl_to_fs(L, 1);
|
|
|
|
LV_LOG_INFO("enter");
|
|
f->closed = true;
|
|
lv_fs_close(&f->file);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int luavgl_fs_seek(lua_State *L)
|
|
{
|
|
static const int mode[] = {LV_FS_SEEK_SET, LV_FS_SEEK_CUR, LV_FS_SEEK_END};
|
|
static const char *const modenames[] = {"set", "cur", "end", NULL};
|
|
luavgl_fs_t *f = luavgl_to_fs(L, 1);
|
|
int op = luaL_checkoption(L, 2, "cur", modenames);
|
|
lua_Integer p3 = luaL_optinteger(L, 3, 0);
|
|
uint32_t offset = (uint32_t)p3;
|
|
luaL_argcheck(L, (lua_Integer)offset == p3, 3,
|
|
"not an integer in proper range");
|
|
|
|
lv_fs_res_t res = lv_fs_seek(&f->file, offset, mode[op]);
|
|
if (res != LV_FS_RES_OK) {
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, "failed");
|
|
lua_pushinteger(L, res);
|
|
return 3;
|
|
}
|
|
|
|
uint32_t pos;
|
|
res = lv_fs_tell(&f->file, &pos);
|
|
if (res != LV_FS_RES_OK) {
|
|
lua_pushinteger(L, 0);
|
|
} else {
|
|
lua_pushinteger(L, (lua_Integer)pos);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int luavgl_fs_tostring(lua_State *L)
|
|
{
|
|
lua_pushfstring(L, "lv_fs handler: %p\n", luavgl_to_fs(L, 1));
|
|
return 1;
|
|
}
|
|
|
|
static int luavgl_fs_gc(lua_State *L)
|
|
{
|
|
LV_LOG_INFO("enter");
|
|
|
|
luavgl_fs_t *v = luaL_checkudata(L, 1, "lv_fs");
|
|
if (!v->closed) {
|
|
v->closed = true;
|
|
lv_fs_close(&v->file);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* luavgl.open_dir(path)
|
|
*/
|
|
static int luavgl_dir_open(lua_State *L)
|
|
{
|
|
const char *path = lua_tostring(L, 1);
|
|
|
|
luavgl_dir_t *d = lua_newuserdata(L, sizeof(luavgl_dir_t));
|
|
d->closed = false;
|
|
|
|
lv_fs_res_t res = lv_fs_dir_open(&d->dir, path);
|
|
if (res != LV_FS_RES_OK) {
|
|
LV_LOG_ERROR("open failed: %s", path);
|
|
lua_pushnil(L);
|
|
lua_pushfstring(L, "open failed: %s\n", path);
|
|
lua_pushinteger(L, res); /* return lv_fs error number */
|
|
return 3;
|
|
}
|
|
|
|
luaL_getmetatable(L, "lv_dir");
|
|
lua_setmetatable(L, -2);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int luavgl_dir_read(lua_State *L)
|
|
{
|
|
luavgl_dir_t *d = luavgl_to_dir(L, 1);
|
|
char buffer[PATH_MAX];
|
|
lv_fs_res_t res = lv_fs_dir_read(&d->dir, buffer, sizeof(buffer));
|
|
if (res != LV_FS_RES_OK || buffer[0] == '\0') {
|
|
lua_pushnil(L);
|
|
} else {
|
|
lua_pushstring(L, buffer);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int luavgl_dir_close(lua_State *L)
|
|
{
|
|
LV_LOG_INFO("error");
|
|
luavgl_dir_t *d = luavgl_to_dir(L, 1);
|
|
d->closed = true;
|
|
lv_fs_dir_close(&d->dir);
|
|
return 0;
|
|
}
|
|
|
|
static int luavgl_dir_tostring(lua_State *L)
|
|
{
|
|
lua_pushfstring(L, "lv_fs dir handler: %p\n", luavgl_to_dir(L, 1));
|
|
return 1;
|
|
}
|
|
|
|
static int luavgl_dir_gc(lua_State *L)
|
|
{
|
|
LV_LOG_INFO("enter");
|
|
|
|
luavgl_dir_t *v = luaL_checkudata(L, 1, "lv_dir");
|
|
if (!v->closed) {
|
|
v->closed = true;
|
|
lv_fs_dir_close(&v->dir);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* luavgl.fs lib
|
|
*
|
|
*/
|
|
static const luaL_Reg fs_lib[] = {
|
|
{"open_file", luavgl_fs_open },
|
|
{"open_dir", luavgl_dir_open},
|
|
|
|
{NULL, NULL },
|
|
};
|
|
|
|
/*
|
|
** methods for file handles
|
|
*/
|
|
static const luaL_Reg fs_methods[] = {
|
|
{"read", luavgl_fs_read },
|
|
{"write", luavgl_fs_write},
|
|
{"close", luavgl_fs_close},
|
|
{"seek", luavgl_fs_seek },
|
|
|
|
{NULL, NULL },
|
|
};
|
|
|
|
static const luaL_Reg fs_meta[] = {
|
|
{"__gc", luavgl_fs_gc },
|
|
{"__close", luavgl_fs_gc },
|
|
{"__tostring", luavgl_fs_tostring},
|
|
{"__index", NULL }, /* place holder */
|
|
|
|
{NULL, NULL }
|
|
};
|
|
|
|
/*
|
|
** methods for dir handles
|
|
*/
|
|
static const luaL_Reg dir_methods[] = {
|
|
{"read", luavgl_dir_read },
|
|
{"close", luavgl_dir_close},
|
|
|
|
{NULL, NULL },
|
|
};
|
|
|
|
static const luaL_Reg dir_meta[] = {
|
|
{"__gc", luavgl_dir_gc },
|
|
{"__close", luavgl_dir_gc },
|
|
{"__tostring", luavgl_dir_tostring},
|
|
{"__index", NULL }, /* place holder */
|
|
|
|
{NULL, NULL }
|
|
};
|
|
|
|
static void luavgl_fs_init(lua_State *L)
|
|
{
|
|
/* create lv_fs metatable */
|
|
luaL_newmetatable(L, "lv_fs");
|
|
luaL_setfuncs(L, fs_meta, 0);
|
|
|
|
luaL_newlib(L, fs_methods);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pop(L, 1); /* pop metatable */
|
|
|
|
/* create lv_dir metatable */
|
|
luaL_newmetatable(L, "lv_dir");
|
|
luaL_setfuncs(L, dir_meta, 0);
|
|
|
|
luaL_newlib(L, dir_methods);
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pop(L, 1); /* pop metatable */
|
|
|
|
/* luavgl.fs lib */
|
|
luaL_newlib(L, fs_lib);
|
|
lua_setfield(L, -2, "fs");
|
|
}
|
|
|