[*] First commit.
This commit is contained in:
parent
d0d88a62a1
commit
7c36f77dfa
|
@ -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)
|
|
@ -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)
|
|
@ -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))
|
|
@ -0,0 +1,7 @@
|
|||
# Generic Unix configuration
|
||||
LIB_EXTENSION = so
|
||||
OBJ_EXTENSION = o
|
||||
LIBFLAG = -shared
|
||||
|
||||
_src = dir_unix.c
|
||||
_cflags = -I$(LUA_INCDIR)
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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);
|
||||
}
|
|
@ -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 <stdio.h>
|
||||
|
||||
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
|
|
@ -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 <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <direct.h>
|
||||
#include <fcntl.h>
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#include <share.h>
|
||||
|
||||
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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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
|
|
@ -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 <io.h>
|
||||
|
||||
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 <dirent.h>
|
||||
|
||||
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
|
|
@ -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
|
Loading…
Reference in New Issue