// public domain 20080410 lua@ztact.com #include #include #include #include #include #include #include #include #include "lua.h" #include "lauxlib.h" #include #define POZIX "pozix" #define POZIX_VERSION POZIX " library for " LUA_VERSION " / March 2008" struct constant { char* name; int value; }; static const struct constant constants[] = { // ------------------ constants { "F_OK", F_OK }, { "R_OK", R_OK }, { "W_OK", W_OK }, { "X_OK", X_OK }, //{ "", }, { NULL, 0 }, }; // typesdefs --------------------------------------------------------- typedefs typedef struct { DIR* dir; } Z_DIR; static struct stat stat_buf; // helpers ------------------------------------------------------------ helpers /* kill? 20080311 static int push_integer_boolean // -------------------- push_integer_boolean ( lua_State* L, int i ) { if (i) { lua_pushinteger (L, i); } else { lua_pushboolean (L, i); } } */ static int push_boolean (lua_State* L, int b) { // ------------ push_boolean lua_pushboolean (L, b); return 1; } static int push_error (lua_State* L, const char* info) { // ----- push_error lua_pushnil (L); if (info == NULL) { lua_pushstring (L, strerror (errno)); } else { lua_pushfstring (L, "%s: %s", info, strerror (errno)); } lua_pushnumber (L, errno); return 3; } static int check_integer // ---------------------------------- check_integer ( lua_State* L, int return_value, const char* info ) { // printf ("check_integer: %d\n", return_value); if (return_value != -1) { lua_pushnumber (L, return_value); return 1; } else { return push_error (L, info); } } /* kill? 20080311 static int check_string // ------------------------------------ check_string ( lua_State* L, char* return_value, const char* info ) { // printf ("check_integer: %d\n", return_value); if (return_value) { lua_pushstring (L, return_value); return 1; } else { return push_error (L, info); } } */ static void rv_error (lua_State* L, int rv, char* message) { // --- rv_error if (rv) { luaL_error (L, "%s: %s", message, strerror (errno)); } } static int return_nil_strerror // ---------------------- return_nil_strerror ( lua_State* L, char* message, int rv ) { lua_pushnil (L); if (message) { lua_pushfstring (L, "%s: %s", message, strerror (errno)); } else { lua_pushfstring (L, "%s", strerror (errno)); } lua_pushinteger (L, rv); lua_pushinteger (L, errno); return 4; } static void table_convert // --------------------------------- table_convert ( lua_State* L, int table, int argc, const char* argv[] ) { int i; for (i = 0; i < argc; i++) { lua_pushinteger (L, i+1); lua_gettable (L, table); argv[i] = luaL_checkstring (L, -1); } } // pozix ---------------------------------------------------------------- pozix static int Z_And (lua_State* L) { // --------------------------------- Z_And } static int Z_Or (lua_State* L) { // ----------------------------------- Z_Or } static int Z_WEXITSTATUS (lua_State* L) { // ----------------- Z_WEXITSTATUS lua_pushinteger (L, WEXITSTATUS (luaL_checkinteger (L, 1))); return 1; } static int Z_WIFEXITED (lua_State* L) { // --------------------- Z_WIFEXITED lua_pushboolean (L, WIFEXITED (luaL_checkinteger (L, 1))); return 1; } static int Z_WIFSIGNALED (lua_State* L) { // ----------------- Z_WIFSIGNALED lua_pushboolean (L, WIFSIGNALED (luaL_checkinteger (L, 1))); return 1; } static int Z_WIFSTOPPED (lua_State* L) { // ------------------- Z_WIFSTOPPED lua_pushboolean (L, WIFSTOPPED (luaL_checkinteger (L, 1))); return 1; } static int Z_WSTOPSIG (lua_State* L) { // ----------------------- Z_WSTOPSIG lua_pushinteger (L, WSTOPSIG (luaL_checkinteger (L, 1))); return 1; } static int Z_WTERMSIG (lua_State* L) { // ----------------------- Z_WTERMSIG lua_pushinteger (L, WTERMSIG (luaL_checkinteger (L, 1))); return 1; } static int Z_access (lua_State* L) { // --------------------------- Z_access const char* pathname = luaL_checkstring (L, 1); int mode = luaL_checkinteger (L, 2); int rv = access (pathname, mode); return check_integer (L, rv, NULL); } static int Z_chdir (lua_State* L) { // ----------------------------- Z_chdir const char* dir = luaL_checkstring (L, 1); int rv = chdir (dir); return check_integer (L, rv, NULL); } static int Z_closedir (lua_State* L) { // ----------------------- Z_closedir Z_DIR* dir = (Z_DIR*) luaL_checkudata (L, 1, "pozix.DIR"); if (!dir->dir) { return 0; } int rv = closedir (dir->dir); dir->dir = NULL; return check_integer (L, rv, NULL); } static int Z_execv (lua_State* L) { // ----------------------------- Z_execv const char* path = luaL_checkstring (L, 1); luaL_checktype (L, 2, LUA_TTABLE); const int argc = lua_objlen (L, 2); const char* argv[argc+1]; table_convert (L, 2, argc, argv); argv[argc] = NULL; // warning: strange cast needed to suppress compile time warning! int rv = execv (path, (char* const*) argv); return check_integer (L, rv, NULL); } static int Z_execve (lua_State* L) { // --------------------------- Z_execve const char* filename = luaL_checkstring (L, 1); luaL_checktype (L, 2, LUA_TTABLE); const int argc = lua_objlen (L, 2); const char* argv[argc+1]; int i; for (i = 0; i < argc; i++) { lua_pushinteger (L, i+1); lua_gettable (L, 2); argv[i] = luaL_checkstring (L, -1); } for (i = 0; i < argc; i++) { printf ("%d %s\n", i, argv[i]); } return 0; } static int Z_fork (lua_State* L) { // ------------------------------- Z_fork return check_integer (L, fork (), NULL); } static int Z_getenv (lua_State* L) { // --------------------------- Z_getenv const char* name = luaL_checkstring (L, 1); char* rv = getenv (name); if (rv) { lua_pushstring (L, rv); } else { lua_pushnil (L); } return 1; } static int Z_getpid (lua_State* L) { // --------------------------- Z_getpid lua_pushinteger (L, getpid ()); return 1; } static int Z_getppid (lua_State* L) { // ------------------------- Z_getppid lua_pushinteger (L, getppid ()); return 1; } static int Z_mkstemp (lua_State* L) { // ------------------------- Z_mkstemp const char* template = luaL_checkstring (L, 1); int len = strlen (template) +1; char buf[len]; strcpy (buf, template); int fd = mkstemp (buf); rv_error (L, fd == -1, "mkstemp"); chmod (buf, 0600); // just to be safe close (fd); // return file-object, path lua_getfield (L, LUA_GLOBALSINDEX, "io"); lua_getfield (L, -1, "open"); lua_pushlstring (L, buf, len); lua_pushliteral (L, "r+"); lua_call (L, 2, 1); lua_pushlstring (L, buf, len); return 2; } static int Z_opendir (lua_State* L) { // ------------------------- Z_opendir const char* path = luaL_checkstring (L, 1); DIR* dir = opendir (path); if (!dir) { luaL_error (L, "opendir failed"); } Z_DIR* z_dir = (Z_DIR*) lua_newuserdata (L, sizeof (Z_DIR)); luaL_getmetatable (L, "pozix.DIR"); lua_setmetatable (L, -2); z_dir->dir = dir; return 1; } static int Z_readdir (lua_State* L) { // ------------------------- Z_readdir Z_DIR* dir = (Z_DIR*) luaL_checkudata (L, 1, "pozix.DIR"); struct dirent* dirent = readdir (dir->dir); if (!dirent) { return 0; } // todo: check errno lua_pushstring (L, dirent->d_name); return 1; } static int Z_rename (lua_State* L) { // --------------------------- Z_rename const char* oldpath = luaL_checkstring (L, 1); const char* newpath = luaL_checkstring (L, 2); int rv = rename (oldpath, newpath); rv_error (L, rv == -1, "rename"); return 0; } static int Z_setenv (lua_State* L) { // --------------------------- Z_setenv const char* name = luaL_checkstring (L, 1); const char* value = luaL_checkstring (L, 2); int overwrite = lua_gettop (L) > 2 ? lua_toboolean (L, 3) : 1 ; int rv = setenv (name, value, overwrite); return check_integer (L, rv, NULL); } static int Z_stat_fields // ---------------------------------- Z_stat_fields ( lua_State* L, struct stat* st, int start ) { int top = lua_gettop (L); int i; for (i = start; i <= top; i++) { const char* key = luaL_checkstring (L, i); char* guess = 0; lua_Number value; int is_boolean = 0; int len, mode; switch (key[0]) { case 'a': guess = "atime"; value = st->st_atime; break; case 'c': guess = "ctime"; value = st->st_ctime; break; case 'd': guess = "dev"; value = st->st_dev; break; case 'g': guess = "gid"; value = st->st_gid; break; case 'n': guess = "nlink"; value = st->st_nlink; break; case 's': guess = "size"; value = st->st_size; break; case 'u': guess = "uid"; value = st->st_uid; break; case 'm': switch (key[1]) { case 'o': guess = "mode"; value = st->st_mode; break; case 't': guess = "mtime"; value = st->st_mtime; break; } break; case 'i': len = strlen (key); if (len < 3) { break; } if (key[3] == '\0') { guess = "ino"; value = st->st_ino; break; } mode = st->st_mode; is_boolean = 1; switch (key[3]) { case 'b': guess = "is_block"; value = S_ISBLK (mode); break; case 'c': guess = "is_char"; value = S_ISCHR (mode); break; case 'd': guess = "is_dir"; value = S_ISDIR (mode); break; case 'f': guess = "is_fifo"; value = S_ISFIFO (mode); break; case 'l': guess = "is_link"; value = S_ISLNK (mode); break; case 'r': guess = "is_reg"; value = S_ISREG (mode); break; case 's': if (len < 4) { break; } switch (key[4]) { case 'g': guess = "is_sgid"; value = mode & S_ISGID; break; case 'o': guess = "is_socket"; value = S_ISSOCK (mode); break; case 't': guess = "is_sticky"; value = mode & S_ISVTX; break; case 'u': guess = "is_suid"; value = mode & S_ISUID; break; } break; } } if ( guess && strcmp (key, guess) == 0 ) { if (is_boolean) { lua_pushboolean (L, value); } else { lua_pushnumber (L, value); } } else { luaL_error (L, "invalid key"); } } return top - start + 1; } static int Z_stat (lua_State* L) { // ------------------------------- Z_stat const char* path = luaL_checkstring (L, 1); struct stat st; int rv = stat (path, &st); if (lua_gettop (L) > 1) { if (rv) { return 0; } else { return Z_stat_fields (L, &st, 2); } } if (rv) { return return_nil_strerror (L, "stat", rv); } *((struct stat*) lua_newuserdata (L, sizeof (struct stat))) = st; luaL_getmetatable (L, "pozix.stat"); lua_setmetatable (L, -2); return 1; } static int Z_stat__index (lua_State* L) { // ----------------- Z_stat__index struct stat* st = (struct stat*) luaL_checkudata (L, 1, "pozix.stat"); return Z_stat_fields (L, st, 2); } static int Z_wait (lua_State* L) { // ------------------------------- Z_wait int rv, status; rv = wait (&status); lua_pushinteger (L, rv); lua_pushinteger (L, status); return 2; } static const luaL_reg pozix_functions[] = { // ------------- pozix_functions { "And", Z_And }, { "Or", Z_Or }, { "WEXITSTATUS", Z_WEXITSTATUS }, { "WIFEXITED", Z_WIFEXITED }, { "WIFSIGNALED", Z_WIFSIGNALED }, { "WIFSTOPPED", Z_WIFSTOPPED }, { "WSTOPSIG", Z_WSTOPSIG }, { "WTERMSIG", Z_WTERMSIG }, { "access", Z_access }, { "chdir", Z_chdir }, { "closedir", Z_closedir }, { "execv", Z_execv }, { "execve", Z_execve }, { "fork", Z_fork }, { "getenv", Z_getenv }, { "getpid", Z_getpid }, { "getppid", Z_getppid }, { "mkstemp", Z_mkstemp }, { "opendir", Z_opendir }, { "readdir", Z_readdir }, { "rename", Z_rename }, { "setenv", Z_setenv }, { "stat", Z_stat }, { "wait", Z_wait }, //{ "", }, { NULL, NULL }, }; static const luaL_reg DIR_functions[] = { // ----------------- DIR_functions { "__call", Z_readdir }, { "__gc", Z_closedir }, { "close", Z_closedir }, { "read", Z_readdir }, //{ "", }, { NULL, NULL }, }; LUALIB_API int luaopen_pozix (lua_State* L) { // ------------- luaopen_pozix // pozix.DIR luaL_newmetatable (L, "pozix.DIR"); lua_pushstring (L, "__index"); lua_pushvalue (L, -2); /* pushes the metatable */ lua_settable (L, -3); /* metatable.__index = metatable */ luaL_register (L, NULL, DIR_functions); // todo: pop the table? // pozix.stat luaL_newmetatable (L, "pozix.stat"); lua_pushstring (L, "__index"); lua_pushcfunction (L, Z_stat__index); lua_settable (L, -3); /* metatable.__index = Z_stat__index */ // todo: pop the table? // register pozix_functions luaL_register (L, POZIX, pozix_functions); // register pozix constants const struct constant* c; for (c = constants; c->name; c++) { lua_pushstring (L, c->name); lua_pushinteger (L, c->value); lua_settable (L, -3); } /* luaL_openlib (L, POZIX, functions, 0); lua_pushliteral (L, "version"); lua_pushliteral (L, POZIX_VERSION); lua_settable (L, -3); */ return 1; }