diff options
author | Alex Auvolat <alex@adnab.me> | 2017-04-19 15:34:04 +0200 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2017-04-19 15:34:04 +0200 |
commit | e53a39d9ec28b24ea0d408f1500e987d005cd651 (patch) | |
tree | 639c93f2a17aabee7759cd16645b4d7da693ae4c | |
parent | d4a89538d381bb62b4c7c864b09d3d8274cf0bdb (diff) | |
download | kogata-e53a39d9ec28b24ea0d408f1500e987d005cd651.tar.gz kogata-e53a39d9ec28b24ea0d408f1500e987d005cd651.zip |
Lua shell :)
-rw-r--r-- | src/sysbin/lx/lxinit.c | 48 | ||||
-rw-r--r-- | src/sysbin/lx/lxlib.h | 15 | ||||
-rw-r--r-- | src/sysbin/lx/lxsyslib.c | 221 | ||||
-rw-r--r-- | src/sysbin/lx/main.c | 50 | ||||
-rw-r--r-- | src/syslua/lx/lxinit.lua | 48 | ||||
-rw-r--r-- | src/syslua/lx/shell.lua | 88 | ||||
-rw-r--r-- | src/syslua/lx/sysdef.lua | 36 |
7 files changed, 445 insertions, 61 deletions
diff --git a/src/sysbin/lx/lxinit.c b/src/sysbin/lx/lxinit.c new file mode 100644 index 0000000..c0059c7 --- /dev/null +++ b/src/sysbin/lx/lxinit.c @@ -0,0 +1,48 @@ + + +#define lxinit_c +#define LUA_LIB + +/* +** If you embed Lua in your program and need to open the standard +** libraries, call luaL_openlibs in your program. If you need a +** different set of libraries, copy this file to your project and edit +** it to suit your needs. +** +** You can also *preload* libraries, so that a later 'require' can +** open the library, which is already linked to the application. +** For that, do the following code: +** +** luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); +** lua_pushcfunction(L, luaopen_modname); +** lua_setfield(L, -2, modname); +** lua_pop(L, 1); // remove _PRELOAD table +*/ + +#include <lua/lprefix.h> + + +#include <stddef.h> + +#include <lua/lua.h> + +#include <lua/lualib.h> +#include <lua/lauxlib.h> + +#include "lxlib.h" + + +static const luaL_Reg loadedlibs[] = { + {LX_SYSLIBNAME, lx_open_sys}, + {NULL, NULL} +}; + +LUALIB_API void lx_openlibs (lua_State *L) { + const luaL_Reg *lib; + /* "require" functions from 'loadedlibs' and set results to global table */ + for (lib = loadedlibs; lib->func; lib++) { + luaL_requiref(L, lib->name, lib->func, 1); + lua_pop(L, 1); /* remove lib */ + } +} + diff --git a/src/sysbin/lx/lxlib.h b/src/sysbin/lx/lxlib.h new file mode 100644 index 0000000..e65ab6f --- /dev/null +++ b/src/sysbin/lx/lxlib.h @@ -0,0 +1,15 @@ +/* +** Lua eXtended libraries +*/ +#pragma once + +#include <lua/lua.h> + + +#define LX_SYSLIBNAME "lx.sys" +LUAMOD_API int (lx_open_sys) (lua_State *L); + + +/* open all previous libraries */ +LUALIB_API void (lx_openlibs) (lua_State *L); + diff --git a/src/sysbin/lx/lxsyslib.c b/src/sysbin/lx/lxsyslib.c new file mode 100644 index 0000000..5bfec3e --- /dev/null +++ b/src/sysbin/lx/lxsyslib.c @@ -0,0 +1,221 @@ +/* +** Lua eXtended system library +*/ + +#define lxsyslib_c +#define LUA_LIB + +#include <lua/lprefix.h> + + +#include <errno.h> +#include <locale.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <lua/lua.h> + +#include <lua/lauxlib.h> +#include <lua/lualib.h> + +#include "lxlib.h" + + + +static void setintfield (lua_State *L, const char *key, int value) { + lua_pushinteger(L, value); + lua_setfield(L, -2, key); +} + +static void setstrfield (lua_State *L, const char *key, const char* value) { + lua_pushstring(L, value); + lua_setfield(L, -2, key); +} + + +static int sys_dbg_print(lua_State *L) { + const char *str = luaL_checkstring(L, 1); + sc_dbg_print(str); + return 0; +} + +static int sys_yield(lua_State *L) { + sc_yield(); + return 0; +} + +static int sys_exit(lua_State *L) { + int code = luaL_checkinteger(L, 1); + sc_exit(code); + return 0; +} + +static int sys_usleep(lua_State *L) { + int usecs = luaL_checkinteger(L, 1); + sc_usleep(usecs); + return 0; +} + +/* + Missing syscalls : + - sys_new_thread, exit_thread -> into specific threading library + - mmap, mmap_file, mchmap, munmap -> into specific memory-related library ?? +*/ + +static int sys_create(lua_State *L) { + const char *name = luaL_checkstring(L, 1); + int type = luaL_checkinteger(L, 2); + lua_pushboolean(L, sc_create(name, type)); + return 1; +} + +static int sys_delete(lua_State *L) { + const char *name = luaL_checkstring(L, 1); + lua_pushboolean(L, sc_delete(name)); + return 1; +} + +static int sys_move(lua_State *L) { + const char *oldname = luaL_checkstring(L, 1); + const char *newname = luaL_checkstring(L, 2); + lua_pushboolean(L, sc_move(oldname, newname)); + return 1; +} + +static int sys_stat(lua_State *L) { + const char* name = luaL_checkstring(L, 1); + stat_t s; + if (sc_stat(name, &s)) { + lua_createtable(L, 0, 3); + setintfield(L, "type", s.type); + setintfield(L, "access", s.access); + setintfield(L, "size", s.size); + } else { + lua_pushnil(L); + } + return 1; +} + + +static int sys_open(lua_State *L) { + const char* name = luaL_checkstring(L, 1); + int mode = luaL_checkinteger(L, 2); + fd_t fh = sc_open(name, mode); + if (fh) { + lua_pushinteger(L, fh); + } else { + lua_pushnil(L); + } + return 1; +} + +static int sys_close(lua_State *L) { + int fd = luaL_checkinteger(L, 1); + sc_close(fd); + return 0; +} + +static int sys_read(lua_State *L) { + int fd = luaL_checkinteger(L, 1); + int offset = luaL_checkinteger(L, 2); + int len = luaL_checkinteger(L, 3); + + luaL_Buffer b; + char* bufptr = luaL_buffinitsize(L, &b, len); + int ret = sc_read(fd, offset, len, bufptr); + + luaL_pushresultsize(&b, ret); + lua_pushinteger(L, ret); + return 2; +} + +static int sys_write(lua_State *L) { + int fd = luaL_checkinteger(L, 1); + int offset = luaL_checkinteger(L, 2); + const char* str = luaL_checkstring(L, 3); + int len = luaL_len(L, 3); + + int ret = sc_write(fd, offset, len, str); + lua_pushinteger(L, ret); + return 1; +} + +static int sys_readdir(lua_State *L) { + int fd = luaL_checkinteger(L, 1); + int ent_no = luaL_checkinteger(L, 2); + + dirent_t d; + bool ret = sc_readdir(fd, ent_no, &d); + if (ret) { + lua_createtable(L, 0, 4); + setstrfield(L, "name", d.name); + setintfield(L, "type", d.st.type); + setintfield(L, "access", d.st.access); + setintfield(L, "size", d.st.size); + } else { + lua_pushnil(L); + } + return 1; +} + +static int sys_stat_open(lua_State *L) { + int fd = luaL_checkinteger(L, 1); + stat_t s; + if (sc_stat_open(fd, &s)) { + lua_createtable(L, 0, 3); + setintfield(L, "type", s.type); + setintfield(L, "access", s.access); + setintfield(L, "size", s.size); + } else { + lua_pushnil(L); + } + return 1; +} + +static int sys_ioctl(lua_State *L) { + // TODO + return 0; +} + +static int sys_fctl(lua_State *L) { + // TODO + return 0; +} + +static int sys_select(lua_State *L) { + // TODO + return 0; +} + + +static const luaL_Reg syslib[] = { + {"dbg_print", sys_dbg_print}, + {"yield", sys_yield}, + {"exit", sys_exit}, + {"usleep", sys_usleep}, + {"create", sys_create}, + {"delete", sys_delete}, + {"move", sys_move}, + {"stat", sys_stat}, + {"open", sys_open}, + {"close", sys_close}, + {"read", sys_read}, + {"write", sys_write}, + {"readdir", sys_readdir}, + {"stat_open", sys_stat_open}, + + {NULL, NULL} +}; + +/* }====================================================== */ + + + +LUAMOD_API int lx_open_sys (lua_State *L) { + luaL_newlib(L, syslib); + return 1; +} + + +/* vim: set sts=2 ts=2 sw=2 tw=0 et :*/ diff --git a/src/sysbin/lx/main.c b/src/sysbin/lx/main.c index ecfecd8..b7e08d9 100644 --- a/src/sysbin/lx/main.c +++ b/src/sysbin/lx/main.c @@ -16,6 +16,8 @@ #include <lua/lauxlib.h> #include <lua/lualib.h> +#include "lxlib.h" + #define LUA_PROMPT "> " #define LUA_PROMPT2 ">> " @@ -183,20 +185,6 @@ int dostring (lua_State *L, const char *s, const char *name) { } -/* -** Calls 'require(name)' and stores the result in a global variable -** with the given name. -*/ -int dolibrary (lua_State *L, const char *name) { - int status; - lua_getglobal(L, "require"); - lua_pushstring(L, name); - status = docall(L, 1, 1); /* call 'require(name)' */ - if (status == LUA_OK) - lua_setglobal(L, name); /* global[name] = require return */ - return report(L, status); -} - /* ** Returns the string to be used as a prompt by the interpreter. @@ -349,36 +337,6 @@ void doREPL (lua_State *L) { } -/* -** Push on the stack the contents of table 'arg' from 1 to #arg -*/ -int pushargs (lua_State *L) { - int i, n; - if (lua_getglobal(L, "arg") != LUA_TTABLE) - luaL_error(L, "'arg' is not a table"); - n = (int)luaL_len(L, -1); - luaL_checkstack(L, n + 3, "too many arguments to script"); - for (i = 1; i <= n; i++) - lua_rawgeti(L, -i, i); - lua_remove(L, -i); /* remove table from the stack */ - return n; -} - - -int handle_script (lua_State *L, char **argv) { - int status; - const char *fname = argv[0]; - if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0) - fname = NULL; /* stdin */ - status = luaL_loadfile(L, fname); - if (status == LUA_OK) { - int n = pushargs(L); /* push arguments to script */ - status = docall(L, n, LUA_MULTRET); - } - return report(L, status); -} - - int handle_luainit (lua_State *L) { const char *name = "=" LUA_INITVARVERSION; @@ -395,10 +353,11 @@ int handle_luainit (lua_State *L) { int pmain (lua_State *L) { int status; luaL_checkversion(L); /* check that interpreter has correct version */ - + print_version(); luaL_openlibs(L); /* open standard libraries */ + lx_openlibs(L); if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */ return 0; /* error running LUA_INIT */ @@ -409,7 +368,6 @@ int pmain (lua_State *L) { if (status != LUA_OK) { // no main, launch a REPL if (lua_stdin_is_tty()) { /* running in interactive mode? */ - print_version(); doREPL(L); /* do read-eval-print loop */ } else { dofile(L, NULL); /* executes stdin as a file */ diff --git a/src/syslua/lx/lxinit.lua b/src/syslua/lx/lxinit.lua index 6b23aa8..1c8d116 100644 --- a/src/syslua/lx/lxinit.lua +++ b/src/syslua/lx/lxinit.lua @@ -3,20 +3,38 @@ print "Lua eXtended helpers for Kogata v1" do local old_tostring = tostring function tostring(x) - if type(x) == "table" then - if next(x) == nil then - return '{}' - end - local q = '{\n ' - for k, v in pairs(x) do - if q:len() > 4 then - q = q .. ',\n ' - end - q = q .. k .. ': ' .. tostring(v):gsub('\n', '\n ') - end - return q .. '\n}' - else - return old_tostring(x) - end + local seen = {} + function aux(x) + if type(x) == "table" then + if next(x) == nil then + return '{}' + end + + if seen[x] then + return '...' + end + seen[x] = true + + local q = '{\n ' + for k, v in pairs(x) do + if q:len() > 4 then + q = q .. ',\n ' + end + q = q .. k .. ': ' .. aux(v):gsub('\n', '\n ') + end + return q .. '\n}' + else + return old_tostring(x) + end + end + return aux(x) end end + + +function string.split(str, sep) + local sep, fields = sep or ":", {} + local pattern = string.format("([^%s]*)", sep) + str:gsub(pattern, function(c) fields[#fields+1] = c end) + return fields +end diff --git a/src/syslua/lx/shell.lua b/src/syslua/lx/shell.lua new file mode 100644 index 0000000..62f210f --- /dev/null +++ b/src/syslua/lx/shell.lua @@ -0,0 +1,88 @@ +local sys = require 'lx.sys' +local sysdef = require 'lx.sysdef' + +local _cwd = 'root:/' + +function pathcat(path1, path2) + assert(path1, "invalid argument") + if not path2 then + return path1 + end + + function explode_path(path) + local _, _, dr, p = string.find(path, '^(%w+):(.*)$') + if not dr or not p then + dr, p = nil, path + end + local pp = string.split(p, '/') + if #pp > 1 and pp[#pp] == '' then + table.remove(pp) + end + return dr, pp + end + + function implode_path(dr, p) + assert(p[1] == '', 'bad first path component') + return dr .. ':' .. table.concat(p, '/') + end + + local dr2, p2 = explode_path(path2) + if dr2 then + return implode_path(dr2, p2) + else + local dr, p1 = explode_path(path1) + assert(p1[1] == '', 'bad path1!') + local p = p1 + if p2[1] == '' then + p = {} + end + for _, v in pairs(p2) do + if v == '..' then + table.remove(p) + elseif v ~= '.' then + table.insert(p, v) + end + end + return implode_path(dr, p) + end +end + +function cd(path) + -- TODO path simplification etc + local newcwd = pathcat(_cwd, path) + local s = sys.stat(newcwd) + if not s then + print("not found: " .. newcwd) + elseif s.type & sysdef.FT_DIR == 0 then + print("not a directory: " .. newcwd) + else + _cwd = newcwd + print(_cwd) + end +end + +function cwd() + return _cwd +end + +function ls(path) + path = pathcat(_cwd, path) + + local fd = sys.open(path, sysdef.FM_READDIR) + if not fd then + print("Could not open " .. path) + else + local i = 0 + while true do + x = sys.readdir(fd, i) + if not x then break end + if x.type & sysdef.FT_DIR ~= 0 then + x.name = x.name .. '/' + end + print(x.type, x.access, x.size, x.name) + i = i + 1 + end + sys.close(fd) + end +end + diff --git a/src/syslua/lx/sysdef.lua b/src/syslua/lx/sysdef.lua new file mode 100644 index 0000000..7c0d14f --- /dev/null +++ b/src/syslua/lx/sysdef.lua @@ -0,0 +1,36 @@ +-- Constant definitions based on common/include/proto/fs.h + +return { + -- FILE TYPES + FT_REGULAR = 0, + FT_DIR = 0x01, + FT_DEV = 0x02, + FT_BLOCKDEV = 0x04, + FT_CHARDEV = 0x08, + FT_CHANNEL = 0x10, + FT_FRAMEBUFFER = 0x20, + + -- FILE MODES + FM_READ = 0x01, + FM_WRITE = 0x02, + FM_READDIR = 0x04, + FM_MMAP = 0x08, + FM_CREATE = 0x10, + FM_TRUNC = 0x20, + FM_APPEND = 0x40, + FM_IOCTL = 0x100, + FM_BLOCKING = 0x200, + FM_DCREATE = 0x1000, + FM_DMOVE = 0x2000, + FM_DDELETE = 0x4000, + FM_ALL_MODES = 0xFFFF, + + -- IOCTL calls + IOCTL_BLOCKDEV_GET_BLOCK_SIZE = 40, + IOCTL_BLOCKDEV_GET_BLOCK_COUNT = 41, + + -- Modes for select call + SEL_READ = 0x01, + SEL_WRITE = 0x02, + SEL_ERROR = 0x04, +} |