From 7c36f77dfa638cc80bb1626c5d5b92dd8e7c6149 Mon Sep 17 00:00:00 2001 From: Lorenzo Cogotti Date: Sun, 11 Dec 2022 18:58:11 +0100 Subject: [PATCH] [*] First commit. --- Makefile | 57 +++++ config.macosx | 7 + config.mk | 19 ++ config.unix | 7 + config.win | 9 + dir_unix.c | 27 +++ dir_win32.c | 83 ++++++++ luacompat.h | 51 +++++ osx.c | 567 ++++++++++++++++++++++++++++++++++++++++++++++++++ osx.h | 36 ++++ osx_dir.h | 55 +++++ xconf.h | 26 +++ 12 files changed, 944 insertions(+) create mode 100644 Makefile create mode 100644 config.macosx create mode 100644 config.mk create mode 100644 config.unix create mode 100644 config.win create mode 100644 dir_unix.c create mode 100644 dir_win32.c create mode 100644 luacompat.h create mode 100644 osx.c create mode 100644 osx.h create mode 100644 osx_dir.h create mode 100644 xconf.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d16e5bb --- /dev/null +++ b/Makefile @@ -0,0 +1,57 @@ +# The lua-osx Makefile +# Author: Lorenzo Cogotti, The DoubleFourteen Code Forge +# +# For general configuration see config.mk. +# For system specific configuration see other config.*s. +# +# To pick a specific system configuration use the CONFIG variable +# (config.unix by default), e.g.: +# make CONFIG=config.macosx +# +# By default we build against system's lua interpreter, +# to build against other implementations use the LUA variable, e.g.: +# make LUA=luajit +# +# To manually specify lua's include path, library path and library name use: +# LUA_INCDIR, LUA_LIBDIR and LUALIB variables respectively. +# By default these are automatically detected via pkg-config. +# +# To manually specify the module install path use the LIBDIR variable, +# By default it is automatically detected via pkg-config. +# +# NOTE: there is NO support for the MSVC compiler. + +CONFIG = config.unix + +include config.mk +include $(CONFIG) + +lib = osx.$(LIB_EXTENSION) +src = osx.c +o = $(src:.c=.o) +_o = $(_src:.c=.o) + +.c.o: + $(CC) -std=c11 $(_cflags) $(CFLAGS) -c $< + +all: $(lib) + +$(_o): $(_src) xconf.h osx_dir.h + +osx.o: osx.c xconf.h luacompat.h osx.h osx_dir.h + +$(lib): $(o) $(_o) + $(LD) $(LIBFLAG) -o $@ $(_ldflags) $(LDFLAGS) $(o) $(_o) + +install: + -$(MKDIR) $(DESTDIR)$(LIBDIR)/osx $(DESTDIR)$(LIBDIR)/osx/include + $(CP) $(lib) $(DESTDIR)$(LIBDIR)/osx/ + $(CP) osx.h osx_dir.h $(DESTDIR)$(LIBDIR)/osx/include/ + +uninstall: + -$(RM) $(DESTDIR)$(LIBDIR)/osx/$(lib) + -$(RM) $(DESTDIR)$(LIBDIR)/osx/include/osx.h $(DESTDIR)$(LIBDIR)/osx/include/osx_dir.h + -$(RMDIR) $(DESTDIR)$(LIBDIR)/osx/include $(DESTDIR)$(LIBDIR)/osx + +clean: + -$(RM) $(lib) $(o) $(_o) diff --git a/config.macosx b/config.macosx new file mode 100644 index 0000000..a2a0b6f --- /dev/null +++ b/config.macosx @@ -0,0 +1,7 @@ +# MacOSX configuration +LIB_EXTENSION = dylib +OBJ_EXTENSION = o +LIBFLAG = -bundle -undefined dynamic_lookup -all_load + +_src = dir_unix.c +_cflags = -I$(LUA_INCDIR) diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..f9f1b94 --- /dev/null +++ b/config.mk @@ -0,0 +1,19 @@ +# Compiler and tools +CC = cc +LD = $(CC) +LUA = lua +PKGCONFIG = pkg-config +CP = cp +RM = rm +MKDIR = mkdir +RMDIR = rmdir + +# Compilation flags +CFLAGS = -pipe -Os -fPIC -Wall -pedantic +# Linking options +LDFLAGS = -W -O1 + +# Lua setup +LUA_INCDIR = $(shell $(PKGCONFIG) --variable=includedir $(LUA)) +LUA_LIBDIR = $(shell $(PKGCONFIG) --variable=libdir $(LUA)) +LIBDIR = $(shell $(PKGCONFIG) --variable=INSTALL_CMOD $(LUA)) diff --git a/config.unix b/config.unix new file mode 100644 index 0000000..bf8b302 --- /dev/null +++ b/config.unix @@ -0,0 +1,7 @@ +# Generic Unix configuration +LIB_EXTENSION = so +OBJ_EXTENSION = o +LIBFLAG = -shared + +_src = dir_unix.c +_cflags = -I$(LUA_INCDIR) diff --git a/config.win b/config.win new file mode 100644 index 0000000..2f2b7b3 --- /dev/null +++ b/config.win @@ -0,0 +1,9 @@ +# Windows MinGW configuration +LIB_EXTENSION = dll +OBJ_EXTENSION = o +LIBFLAG = -shared +LUALIB = lua$(shell $(PKGCONFIG) --variable=V $(LUA)).dll.a + +_src = dir_win32.c +_cflags = -I$(LUA_INCDIR) -DDF_LUA_OSXLIB +_ldflags = $(LUA_LIBDIR)/$(LUALIB) -lm diff --git a/dir_unix.c b/dir_unix.c new file mode 100644 index 0000000..8f2f137 --- /dev/null +++ b/dir_unix.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +/* Trivial osx_dir.h implementation on Unix. + * + * Copyright: 2022, The DoubleFourteen Code Forge + * Author: Lorenzo Cogotti + */ + +#include "xconf.h" +#include "osx_dir.h" + +DF_OSXLIB_API df_os_dirhn os_opendir(const char *name) +{ + return opendir(name); +} + +DF_OSXLIB_API char *os_readdir(df_os_dirhn hn) +{ + struct dirent *ent = readdir(hn); + return ent ? ent->d_name : (char *) 0; +} + +DF_OSXLIB_API void os_closedir(df_os_dirhn hn) +{ + (void) closedir(hn); +} + diff --git a/dir_win32.c b/dir_win32.c new file mode 100644 index 0000000..0479e0b --- /dev/null +++ b/dir_win32.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +/* osx_dir.h implementation for Windows. + * + * Copyright: 2022, The DoubleFourteen Code Forge + * Author: Lorenzo Cogotti + */ + +#include "xconf.h" +#include "osx_dir.h" + +#include +#include +#include +#include + +DF_OSXLIB_API df_os_dirhn os_opendir(const char *path) +{ + if (*path == '\0') { // avoid generating \* search path + errno = ENOENT; + return NULL; + } + + char buf[_MAX_PATH + 2 + 1]; + int n = snprintf(buf, sizeof(buf), "%s\\*", path); + if (n < 0) + return NULL; + if ((size_t) n >= sizeof(buf)) { + errno = ERANGE; + return NULL; + } + + df_os_dirhn hn = malloc(sizeof(*hn)); + if (!hn) + return NULL; + + hn->dirh = _findfirst(buf, &hn->data); + if (hn->dirh == -1) { + free(hn); + return NULL; + } + + hn->startflag = true; + hn->errflag = false; + hn->endflag = false; + + return hn; +} + +DF_OSXLIB_API char *os_readdir(df_os_dirhn hn) +{ + if (hn->startflag) { + // Return first item found by _findfirst() + hn->startflag = false; + return hn->data.name; + } + + // Reset status flags and advance directory iterator + hn->errflag = false; + hn->endflag = false; + + int err = errno; + + if (_findnext(hn->dirh, &hn->data) == -1) { + if (errno == ENOENT) { + // End of directory, this is not an error, restore old errno + errno = err; + hn->endflag = true; + } else { + hn->errflag = true; + } + + return NULL; + } + + return hn->data.name; +} + +DF_OSXLIB_API void os_closedir(df_os_dirhn hn) +{ + _findclose(hn->dirh); + free(hn); +} diff --git a/luacompat.h b/luacompat.h new file mode 100644 index 0000000..d9f8dc9 --- /dev/null +++ b/luacompat.h @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +/* Compatibility layer with Lua 5.1/LuaJIT. + * + * Copyright: 2022, The DoubleFourteen Code Forge + * Author: Lorenzo Cogotti + */ + +#ifndef DF_LUA_LUACOMPAT_H_ +#define DF_LUA_LUACOMPAT_H_ + +#include "lua.h" +#if LUA_VERSION_NUM < 502 +#include + +typedef struct { + FILE *f; +} luaL_Stream; + +#define luaL_pushfail(L) lua_pushnil(L) + +static inline void luaL_requiref(lua_State *L, const char *modname, lua_CFunction openf, int glb) +{ + lua_pushstring(L, "_LOADED"); + lua_gettable(L, LUA_REGISTRYINDEX); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + lua_createtable(L, 0, 1); + lua_pushstring(L, "_LOADED"); + lua_pushvalue(L, -2); + lua_settable(L, LUA_REGISTRYINDEX); + } + + lua_getfield(L, -1, modname); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + lua_pushcfunction(L, openf); + lua_pushstring(L, modname); + lua_call(L, 1, 1); + lua_pushvalue(L, -1); + lua_setfield(L, -3, modname); + } + if (glb) { + lua_pushvalue(L, -1); + lua_setglobal(L, modname); + } + lua_replace(L, -2); +} + +#endif +#endif diff --git a/osx.c b/osx.c new file mode 100644 index 0000000..399ea8b --- /dev/null +++ b/osx.c @@ -0,0 +1,567 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +/* OS extensions for Lua, module implementation. + * + * Copyright: 2022, The DoubleFourteen Code Forge + * Author: Lorenzo Cogotti + */ + +#include "xconf.h" +#include "osx.h" +#include "osx_dir.h" +#include "luacompat.h" + +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" + +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#include +#include +#include +#include +#include + +typedef struct __stat64 os_stat_type; + +#ifndef S_ISDIR +#define S_ISDIR(mode) ((mode)&_S_IFDIR) +#endif +#ifndef S_ISREG +#define S_ISREG(mode) ((mode)&_S_IFREG) +#endif + +#define fileno(fh) _fileno(fh) +#define stat(path, buf) _stat64(path, buf) +#define fstat(fd, buf) _fstat64(fd, buf) +#define mkdir(path, mode) _mkdir(path) +#define getcwd(buf, len) _getcwd(buf, len) +#define chdir(path) _chdir(path) +#define getdrive() _getdrive() +#define chdrive(drive) _chdrive(drive) + +#ifndef _O_WTEXT +#define _O_WTEXT 0x10000 +#endif +#ifndef _O_U16TEXT +#define _O_U16TEXT 0x20000 +#endif +#ifndef _O_U8TEXT +#define _O_U8TEXT 0x40000 +#endif +#define setmode(fd, mode) _setmode(fd, mode) + +static int truncate(const char *path, __int64 size) +{ + int fd; + + if (_sopen_s(&fd, path, _O_WRONLY|_O_BINARY|_O_NOINHERIT, _SH_DENYRW, 0) != 0) + return -1; + + int ec = _chsize_s(fd, size); + _close(fd); + + return ec; +} + +#define ftruncate(fd, size) _chsize_s(fd, size) +#define fsync(fd) _commit(fd) + +#else +#include +#include +#include +#include + +typedef struct stat os_stat_type; + +#define _O_BINARY 0 +#define _O_TEXT 0 +#define _O_WTEXT 0 +#define _O_U16TEXT 0 +#define _O_U8TEXT 0 + +static inline int getdrive(void) { return 0; } + +static inline int chdrive(int drive) +{ + (void) drive; + + errno = ENOTSUP; + return -1; +} + +static inline int setmode(int fd, int mode) +{ + (void) fd, (void) mode; + + errno = ENOTSUP; + return -1; +} +#endif + +#ifdef __linux__ +#define sys_posix_fadvise(fd, advice) posix_fadvise(fd, 0, 0, advice) +#else +// Stub posix_fadvise() +#define POSIX_FADV_NORMAL 0 +#define POSIX_FADV_SEQUENTIAL 0 +#define POSIX_FADV_RANDOM 0 +#define POSIX_FADV_NOREUSE 0 + +static inline int sys_posix_fadvise(int fd, int advice) +{ + (void) fd; + (void) advice; + + errno = ENOTSUP; + return -1; +} +#endif + +static int os_pusherror(lua_State *L, const char *path) +{ + int err = errno; + + lua_pushboolean(L, false); + + if (path) + lua_pushfstring(L, "%s: %s", path, strerror(err)); + else + lua_pushstring(L, strerror(err)); + + lua_pushinteger(L, err); + return 3; +} + +static int os_pushfail(lua_State *L, const char *path) +{ + int err = errno; + + luaL_pushfail(L); + + if (path) + lua_pushfstring(L, "%s: %s", path, strerror(err)); + else + lua_pushstring(L, strerror(err)); + + lua_pushinteger(L, err); + return 3; +} + +static int os_result(lua_State *L, int ec, const char *path) +{ + if (ec == 0) { + lua_pushboolean(L, true); + return 1; + } + + return os_pusherror(L, path); +} + +static df_os_dir *todir(lua_State *L) +{ + df_os_dir *dir = luaL_checkudata(L, 1, DF_LUA_DIRHANDLE); + if (dir->closeflag) + luaL_error(L, "attempt to use a closed directory"); + + return dir; +} + +static bool os_dir_filter(lua_State *L, const char *name) +{ + // Preserve errno across filter calls + int err = errno; + + lua_pushvalue(L, 2); + lua_pushstring(L, name); + lua_call(L, 1, 1); + + errno = err; + + bool result = lua_toboolean(L, -1); + lua_pop(L, 1); + + return result; +} + +static int os_dir_iter(lua_State *L); + +static int os_dir(lua_State *L) +{ + const char *path = luaL_checkstring(L, 1); + + df_os_dir *dir = lua_newuserdata(L, sizeof(*dir)); + + dir->hn = os_opendir(path); + dir->closeflag = false; + if (!dir->hn) + luaL_error(L, "%s: %s", path, strerror(errno)); + + luaL_setmetatable(L, DF_LUA_DIRHANDLE); + + lua_pushcclosure(L, os_dir_iter, 2); + return 1; +} + +static int os_dir_iter(lua_State *L) +{ + const char *path = lua_tostring(L, lua_upvalueindex(1)); + df_os_dir *dir = lua_touserdata(L, lua_upvalueindex(2)); + const char *filename; + + errno = 0; + +nextfilename: + filename = os_readdir(dir->hn); + if (!filename) { + // Error or end of directory + if (errno != 0) + luaL_error(L, lua_pushfstring(L, "%s: %s", path, strerror(errno))); + + return 0; + } + + // Skip dot and dotdot + if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0) + goto nextfilename; + + // New directory entry + lua_pushstring(L, filename); + return 1; +} + +static int os_dir_read(lua_State *L) +{ + df_os_dir *dir = todir(L); + + errno = 0; + + const char *filename = os_readdir(dir->hn); + if (!filename) + return (errno == 0) ? 0 : os_pusherror(L, NULL); + + lua_pushstring(L, filename); + return 1; +} + +static int os_dir_close(lua_State *L) +{ + df_os_dir *dir = todir(L); + + os_closedir(dir->hn); + dir->closeflag = true; + return 0; +} + +static int os_dir_gc(lua_State *L) +{ + df_os_dir *dir = luaL_checkudata(L, 1, DF_LUA_DIRHANDLE); + + if (!dir->closeflag) + os_dir_close(L); + + return 0; +} + +static int os_listfiles(lua_State *L) +{ + const char *path = luaL_checkstring(L, 1); + bool dofilter = false; + + if (!lua_isnoneornil(L, 2)) { + luaL_checktype(L, 2, LUA_TFUNCTION); + dofilter = true; + } + + df_os_dirhn hn = os_opendir(path); + if (!hn) + return os_pushfail(L, path); + + lua_newtable(L); + + const char *filename; + int i = 1; + int err; + + errno = 0; + while ((filename = os_readdir(hn)) != NULL) { + if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0) + continue; + if (dofilter && !os_dir_filter(L, filename)) + continue; + + lua_pushinteger(L, i++); + lua_pushstring(L, filename); + lua_settable(L, -3); + } + err = errno; + + os_closedir(hn); + if (err != 0) + return os_pushfail(L, path); + + return 1; +} + +static int os_stat(lua_State *L) +{ + const char *path = NULL; + os_stat_type buf; + int ec; + + if (lua_isstring(L, 1)) { + path = lua_tostring(L, 1); + ec = stat(path, &buf); + } else { + luaL_Stream *stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); + ec = fstat(fileno(stream->f), &buf); + } + if (ec != 0) + return os_pushfail(L, path); + + lua_createtable(L, 0, 3); + if (S_ISREG(buf.st_mode)) { + lua_pushliteral(L, "regular"); + lua_setfield(L, -2, "type"); + lua_pushinteger(L, buf.st_size); + lua_setfield(L, -2, "size"); + lua_pushinteger(L, (lua_Integer) buf.st_mtime); + lua_setfield(L, -2, "mtime"); + } else if (S_ISDIR(buf.st_mode)) { + lua_pushliteral(L, "directory"); + lua_setfield(L, -2, "type"); + lua_pushinteger(L, (lua_Integer) buf.st_mtime); + lua_setfield(L, -2, "mtime"); + } else { + lua_pushstring(L, "other"); + lua_setfield(L, -2, "type"); + } + return 1; +} + +static int os_mkdir(lua_State *L) +{ + const char *path = luaL_checkstring(L, 1); + + int ec = mkdir(path, 0666); + return os_result(L, ec, path); +} + +static int os_getcwd(lua_State *L) +{ + char *p = NULL; + size_t size = 128; + + while (true) { + char *np = realloc(p, size); + if (!np) + goto fail; + + p = np; + if (getcwd(p, size)) + break; // got working directory + + if (errno != ERANGE) + goto fail; + + size <<= 1; + if (size == 0) // PARANOID + goto fail; + } + + lua_pushstring(L, p); + free(p); + return 1; + +fail: + free(p); + + return os_pusherror(L, NULL); +} + +static int os_chdir(lua_State *L) +{ + const char *path = luaL_checkstring(L, 1); + + int ec = chdir(path); + return os_result(L, ec, path); +} + +static int os_getdrive(lua_State *L) +{ + errno = 0; + + int drive = getdrive(); + if (drive == 0) { + if (errno != 0) + return os_pusherror(L, NULL); + + lua_pushliteral(L, ""); + return 1; + } + + char letter = 'A' + drive - 1; + + lua_pushlstring(L, &letter, 1); + return 1; +} + +static int os_chdrive(lua_State *L) +{ + size_t len; + const char *s = luaL_checklstring(L, 1, &len); + if (len != 1) + luaL_argerror(L, 1, "invalid drive"); + + int drive = *s - 'A' + 1; + if (drive < 1 || drive > 26) + luaL_argerror(L, 1, "invalid drive"); + + int ec = chdrive(drive); + return os_result(L, ec, NULL); +} + +static int os_setmode(lua_State *L) +{ + static const char *modes[] = { + "binary", + "text", + "u8text", + "u16text", + "wtext", + NULL + }; + static const int imodes[] = { + _O_BINARY, + _O_TEXT, + _O_U8TEXT, + _O_U16TEXT, + _O_WTEXT + }; + + luaL_Stream *stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); + int i = luaL_checkoption(L, 2, NULL, modes); + + int ec = setmode(fileno(stream->f), imodes[i]); + return os_result(L, ec, NULL); +} + +static int os_chsize(lua_State *L) +{ + lua_Integer size = luaL_checkinteger(L, 2); + if (size < 0) + size = 0; + + const char *path = NULL; + int ec; + + if (lua_isstring(L, 1)) { + path = lua_tostring(L, 1); + ec = truncate(path, size); + } else { + luaL_Stream *stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); + ec = ftruncate(fileno(stream->f), size); + } + + return os_result(L, ec, path); +} + +static int os_fadvise(lua_State *L) +{ + static const char *hints[] = { + "normal", + "sequential", + "random", + "noreuse", + NULL + }; + static const int ihints[] = { + POSIX_FADV_NORMAL, + POSIX_FADV_SEQUENTIAL, + POSIX_FADV_RANDOM, + POSIX_FADV_NOREUSE + }; + + luaL_Stream *stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); + int i = luaL_checkoption(L, 2, NULL, hints); + + int ec = sys_posix_fadvise(fileno(stream->f), ihints[i]); + return os_result(L, ec, NULL); +} + +static int os_commit(lua_State *L) +{ + luaL_Stream *stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); + + int ec = fsync(fileno(stream->f)); + return os_result(L, ec, NULL); +} + +static void createmeta(lua_State *L) +{ + static const luaL_Reg metameth[] = { + { "__index", NULL }, // placeholder + { "__gc", os_dir_gc }, +#if LUA_VERSION_NUM >= 504 + { "__close", os_dir_gc}, +#endif + { NULL, NULL } + }; + static const luaL_Reg meth[] = { + { "read", os_dir_read }, + { "close", os_dir_close }, + { NULL, NULL } + }; + + luaL_newmetatable(L, DF_LUA_DIRHANDLE); + luaL_setfuncs(L, metameth, 0); + luaL_newlibtable(L, meth); + luaL_setfuncs(L, meth, 0); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); +} + +DF_OSXMOD_API int luaopen_osx(lua_State *L) +{ + static const luaL_Reg funcs[] = { + { "listfiles", os_listfiles }, + { "dir", os_dir }, + { "stat", os_stat }, + { "mkdir", os_mkdir }, + { "getcwd", os_getcwd }, + { "chdir", os_chdir }, + { "getdrive", os_getdrive }, + { "chdrive", os_chdrive }, + { "setmode", os_setmode }, + { "chsize", os_chsize }, + { "fadvise", os_fadvise }, + { "commit", os_commit }, + { NULL, NULL } + }; + + createmeta(L); + luaL_newlib(L, funcs); + + lua_createtable(L, 0, 1); + luaL_requiref(L, LUA_OSLIBNAME, luaopen_os, false); + lua_setfield(L, -2, "__index"); + lua_setmetatable(L, -2); + +#ifdef _WIN32 + lua_pushliteral(L, "\\"); +#else + lua_pushliteral(L, "/"); +#endif + lua_setfield(L, -2, "sep"); + + return 1; +} diff --git a/osx.h b/osx.h new file mode 100644 index 0000000..bdbd755 --- /dev/null +++ b/osx.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +/* Lua OS extensions, low level system facilities. + * + * Copyright: 2022, The DoubleFourteen Code Forge + * Author: Lorenzo Cogotti + */ + +#ifndef DF_LUA_OSX_H_ +#define DF_LUA_OSX_H_ + +#include "lua.h" + +#ifdef _WIN32 + +#if defined(DF_LUA_OSXLIB) +#define DF_OSXMOD_API __declspec(dllexport) +#else +#define DF_OSXMOD_API __declspec(dllimport) +#endif + +#else +#define DF_OSXMOD_API +#endif + +typedef struct { + void *hn; // df_os_dirhn - see osx_dir.h + _Bool closeflag; // whether the directory has been closed +} df_os_dir; + +#define DF_LUA_DIRHANDLE "DIR*" +#define DF_LUA_OSXLIBNAME "osx" + +DF_OSXMOD_API int luaopen_osx(lua_State *L); + +#endif diff --git a/osx_dir.h b/osx_dir.h new file mode 100644 index 0000000..8fc7114 --- /dev/null +++ b/osx_dir.h @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +/* Portable low level system directory access. + * + * Copyright: 2022, The DoubleFourteen Code Forge + * Author: Lorenzo Cogotti + */ + +#ifndef DF_LUA_OSXDIR_H_ +#define DF_LUA_OSXDIR_H_ + +#include "lua.h" + +#ifdef _WIN32 +#include + +typedef struct { + intptr_t dirh; // raw system directory handle + _Bool startflag; // whether data references the first directory entry + _Bool endflag; // whether we've made to the end of the directory + _Bool errflag; // whether last call encountered an error + struct _finddata_t data; // directory entry info +} *df_os_dirhn; + +#ifdef DF_LUA_OSXLIB +#define DF_OSXLIB_API __declspec(dllexport) +#else +#define DF_OSXLIB_API __declspec(dllimport) +#endif + +#else +#include + +typedef DIR *df_os_dirhn; + +#define DF_OSXLIB_API +#endif + +/* Open directory at 'path' (not NULL). + * Returns opened directory handle on success, NULL on failure (sets errno). + */ +DF_OSXLIB_API df_os_dirhn os_opendir(const char *path); + +/* Read next entry from opened directory handle 'hn' (not NULL). + * Returns: + * - next entry filename on success. + * - NULL leaving errno unchanged when no more entries are available. + * - NULL and sets errno on failure. + */ +DF_OSXLIB_API char *os_readdir(df_os_dirhn hn); + +/* Close opened directory handle 'hn' (not NULL). */ +DF_OSXLIB_API void os_closedir(df_os_dirhn hn); + +#endif diff --git a/xconf.h b/xconf.h new file mode 100644 index 0000000..04d82c5 --- /dev/null +++ b/xconf.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +/* Cross platform configuration. + * + * Deals with platform and compiler specific definitions. + * Must be included first in every .c source. + * + * Copyright 2022, The DoubleFourteen Code Forge + * Author: Lorenzo Cogotti + */ + +#ifndef DF_LUA_PREFIX_H_ +#define DF_LUA_PREFIX_H_ + +#ifdef __unix__ +#define _POSIX_C_SOURCE 200809L +#ifdef _AIX +#define _LARGE_FILES 1 +#else +#define _FILE_OFFSET_BITS 64 +#endif + +#define _LARGEFILE64_SOURCE +#endif + +#endif