diff options
Diffstat (limited to 'lib/luavgl/src/fs.c')
| -rw-r--r-- | lib/luavgl/src/fs.c | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/lib/luavgl/src/fs.c b/lib/luavgl/src/fs.c new file mode 100644 index 00000000..e6fbf712 --- /dev/null +++ b/lib/luavgl/src/fs.c @@ -0,0 +1,383 @@ +#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"); +} |
