summaryrefslogtreecommitdiff
path: root/lib/luavgl/src/fs.c
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-11-12 19:14:09 +1100
committerjacqueline <me@jacqueline.id.au>2023-11-12 19:14:09 +1100
commit8a0a167adbf3d9b6f8b6f16aaf20ca39ad5549de (patch)
tree02b6cf23f591915747ec2994381854a79979c4a0 /lib/luavgl/src/fs.c
parent8471046a95ab9e00f7d42b56dbbc9ce3e5b424b9 (diff)
downloadtangara-fw-8a0a167adbf3d9b6f8b6f16aaf20ca39ad5549de.tar.gz
Convert the main menu screen to lua lol
Diffstat (limited to 'lib/luavgl/src/fs.c')
-rw-r--r--lib/luavgl/src/fs.c383
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");
+}