diff options
Diffstat (limited to 'main.c')
| -rw-r--r-- | main.c | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/main.c b/main.c new file mode 100644 index 0000000..2edc588 --- /dev/null +++ b/main.c @@ -0,0 +1,278 @@ +#ifndef _XOPEN_SOURCE_EXTENDED +#define _XOPEN_SOURCE_EXTENDED +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <dirent.h> +#include <sys/stat.h> +#include <locale.h> +#include <ncurses.h> +#include <lua/lua.h> +#include <lua/lauxlib.h> +#include <lua/lualib.h> + +extern const char main_luac[]; +extern const unsigned int main_luac_len; + +static lua_State *G_L = NULL; +static volatile int g_resize = 0; + +static void on_sigwinch(int sig) { (void)sig; g_resize = 1; } + +static int push_error(lua_State *L, const char *msg) { + lua_pushnil(L); + lua_pushstring(L, msg); + return 2; +} + +static int l_init_ncurses(lua_State *L) { + (void)L; + setlocale(LC_ALL, ""); + initscr(); + cbreak(); + raw(); + noecho(); + keypad(stdscr, TRUE); + nodelay(stdscr, FALSE); + curs_set(0); + start_color(); + use_default_colors(); + init_pair(1, COLOR_BLACK, COLOR_WHITE); + signal(SIGWINCH, on_sigwinch); + return 0; +} + +static int l_end_ncurses(lua_State *L) { + (void)L; + endwin(); + return 0; +} + +static int l_resize_terminal(lua_State *L) { + (void)L; + if (g_resize) { + g_resize = 0; + endwin(); + refresh(); + clearok(stdscr, TRUE); + } + return 0; +} + +static int l_refresh_screen(lua_State *L) { + (void)L; + wrefresh(stdscr); + return 0; +} + +static int l_get_wchar(lua_State *L) { + wint_t ch; + int res = wget_wch(stdscr, &ch); + if (res == ERR) + lua_pushinteger(L, -1); + else + lua_pushinteger(L, (lua_Integer)ch); + return 1; +} + +static int l_set_title(lua_State *L) { + const char *title = luaL_checkstring(L, 1); + printf("\033]0;%s\007", title); + fflush(stdout); + return 0; +} + +static int l_get_screen_size(lua_State *L) { + int rows, cols; + getmaxyx(stdscr, rows, cols); + lua_pushinteger(L, rows); + lua_pushinteger(L, cols + 1); + return 2; +} + +static int l_clear_screen(lua_State *L) { + (void)L; + clear(); + return 0; +} + +static int l_move_cursor(lua_State *L) { + int y = (int)luaL_checkinteger(L, 1); + int x = (int)luaL_checkinteger(L, 2); + move(y, x); + return 0; +} + +static int l_print_at(lua_State *L) { + int y = (int)luaL_checkinteger(L, 1); + int x = (int)luaL_checkinteger(L, 2); + const char *str = luaL_checkstring(L, 3); + mvprintw(y, x, "%s", str); + return 0; +} + +static int l_set_reverse(lua_State *L) { + if (lua_toboolean(L, 1)) attron(A_REVERSE); else attroff(A_REVERSE); + return 0; +} + +static int l_set_bold(lua_State *L) { + if (lua_toboolean(L, 1)) attron(A_BOLD); else attroff(A_BOLD); + return 0; +} + +static int l_set_color(lua_State *L) { + int pair = (int)luaL_checkinteger(L, 1); + int enable = lua_toboolean(L, 2); + if (enable) attron(COLOR_PAIR(pair)); else attroff(COLOR_PAIR(pair)); + return 0; +} + +static int l_init_color_pair(lua_State *L) { + int pair = (int)luaL_checkinteger(L, 1); + int fg = (int)luaL_checkinteger(L, 2); + int bg = (int)luaL_checkinteger(L, 3); + init_pair((short)pair, (short)fg, (short)bg); + return 0; +} + +static int l_save_file(lua_State *L) { + const char *fname = luaL_checkstring(L, 1); + const char *content = luaL_checkstring(L, 2); + FILE *f = fopen(fname, "w"); + if (!f) return push_error(L, "Open failed"); + size_t len = strlen(content); + if (len > 0 && fwrite(content, 1, len, f) != len) { + fclose(f); + return push_error(L, "Write failed"); + } + fclose(f); + lua_pushboolean(L, 1); + return 1; +} + +static int l_load_file(lua_State *L) { + const char *fname = luaL_checkstring(L, 1); + FILE *f = fopen(fname, "r"); + if (!f) return push_error(L, "Open failed"); + fseek(f, 0, SEEK_END); + long size = ftell(f); + fseek(f, 0, SEEK_SET); + if (size < 0) { fclose(f); return push_error(L, "Seek failed"); } + char *buf = malloc((size_t)size + 1); + if (!buf) { fclose(f); return push_error(L, "Alloc failed"); } + size_t r = fread(buf, 1, (size_t)size, f); + buf[r] = '\0'; + fclose(f); + lua_pushlstring(L, buf, r); + free(buf); + return 1; +} + +static int l_list_dir(lua_State *L) { + const char *path = luaL_checkstring(L, 1); + DIR *d = opendir(path); + if (!d) { lua_pushnil(L); return 1; } + lua_newtable(L); + int idx = 1; + struct dirent *ent; + while ((ent = readdir(d)) != NULL) { + lua_pushstring(L, ent->d_name); + lua_rawseti(L, -2, idx++); + } + closedir(d); + return 1; +} + +static int l_stat_file(lua_State *L) { + const char *path = luaL_checkstring(L, 1); + struct stat st; + if (stat(path, &st) != 0) { lua_pushnil(L); return 1; } + if (S_ISREG(st.st_mode)) lua_pushstring(L, "file"); + else if (S_ISDIR(st.st_mode)) lua_pushstring(L, "dir"); + else lua_pushstring(L, "other"); + return 1; +} + +static int l_lua_eval(lua_State *L) { + const char *code = luaL_checkstring(L, 1); + int top_before = lua_gettop(G_L); + + if (luaL_loadstring(G_L, code) != LUA_OK) { + const char *err = lua_tostring(G_L, -1); + lua_pop(G_L, 1); + lua_pushstring(L, err ? err : "compile error"); + return 1; + } + if (lua_pcall(G_L, 0, LUA_MULTRET, 0) != LUA_OK) { + const char *err = lua_tostring(G_L, -1); + lua_pop(G_L, 1); + lua_pushstring(L, err ? err : "runtime error"); + return 1; + } + int nret = lua_gettop(G_L) - top_before; + if (nret > 0) { + const char *res = lua_tostring(G_L, -1); + lua_pushstring(L, res ? res : "(non-string result)"); + lua_settop(G_L, top_before); + } else { + lua_pushstring(L, "ok"); + } + return 1; +} + +static const struct { const char *name; lua_CFunction func; } bindings[] = { + {"init_ncurses", l_init_ncurses}, + {"end_ncurses", l_end_ncurses}, + {"resize_terminal", l_resize_terminal}, + {"refresh_screen", l_refresh_screen}, + {"get_wchar", l_get_wchar}, + {"set_title", l_set_title}, + {"get_screen_size", l_get_screen_size}, + {"clear_screen", l_clear_screen}, + {"move_cursor", l_move_cursor}, + {"print_at", l_print_at}, + {"set_reverse", l_set_reverse}, + {"set_bold", l_set_bold}, + {"set_color", l_set_color}, + {"init_color_pair", l_init_color_pair}, + {"save_file", l_save_file}, + {"load_file", l_load_file}, + {"list_dir", l_list_dir}, + {"stat_file", l_stat_file}, + {"lua_eval", l_lua_eval}, + {NULL, NULL} +}; + +int main(int argc, char *argv[]) { + lua_State *L = luaL_newstate(); + if (!L) { fprintf(stderr, "Lua init failed\n"); return 1; } + G_L = L; + luaL_openlibs(L); + + for (int i = 0; bindings[i].name; i++) { + lua_pushcfunction(L, bindings[i].func); + lua_setglobal(L, bindings[i].name); + } + + lua_newtable(L); + for (int i = 1; i < argc; i++) { + lua_pushstring(L, argv[i]); + lua_rawseti(L, -2, i); + } + lua_setglobal(L, "arg"); + + if (luaL_loadbuffer(L, main_luac, main_luac_len, "main.lua") || + lua_pcall(L, 0, 0, 0)) { + fprintf(stderr, "Lume: %s\n", lua_tostring(L, -1)); + lua_pop(L, 1); + lua_close(L); + return 1; + } + + lua_close(L); + return 0; +} |
