Fork of Tangara with customizations
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.
 
 
 
 
 
 
tangara-fw/lib/luavgl/src/fs.c

383 lines
8.5 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 (strchr(mode, 'r'))
lmode |= LV_FS_MODE_RD;
if (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) {
debug("open failed: %s\n", 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 = 0;
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);
debug("\n");
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)
{
debug("\n");
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) {
debug("open failed: %s\n", 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);
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)
{
debug("\n");
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)
{
debug("\n");
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");
}