[osx,config.ld] Add LDoc documentation.

This commit is contained in:
Lorenzo Cogotti 2022-12-14 12:28:41 +01:00
parent 405da8b141
commit d440a40863
2 changed files with 295 additions and 74 deletions

1
config.ld Normal file
View File

@ -0,0 +1 @@
readme = "README.md"

368
osx.c
View File

@ -6,6 +6,15 @@
* Author: Lorenzo Cogotti * Author: Lorenzo Cogotti
*/ */
/**
* Operating System eXtension module.
*
* @license LGPL-3.0-or-later
* @copyright 2022, The DoubleFourteen Code Forge
* @author Lorenzo Cogotti
* @module osx
*/
#include "xconf.h" #include "xconf.h"
#include "osx.h" #include "osx.h"
#include "osx_dir.h" #include "osx_dir.h"
@ -264,19 +273,13 @@ static bool os_dir_filter(lua_State *L, const char *name)
return result; return result;
} }
static int os_dir_open(lua_State *L) static int os_dir_close(lua_State *L)
{ {
const char *path = luaL_checkstring(L, 1); df_os_dir *dir = todir(L);
df_os_dir *dir = lua_newuserdata(L, sizeof(*dir)); os_closedir(dir->hn);
dir->closeflag = true;
dir->hn = os_opendir(path); return 0;
dir->closeflag = false;
if (!dir->hn)
return os_pushfail(L, path);
luaL_setmetatable(L, DF_LUA_DIRHANDLE);
return 1;
} }
static int os_dir_tostring(lua_State *L) static int os_dir_tostring(lua_State *L)
@ -299,68 +302,6 @@ static int os_dir_tostring(lua_State *L)
return 1; 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_dir_iter(lua_State *L);
static int os_dir(lua_State *L)
{
lua_pushcfunction(L, os_dir_open);
lua_pushvalue(L, 1);
lua_call(L, 1, 2);
if (lua_isnil(L, -2))
lua_error(L);
lua_pop(L, 1);
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_readdir(lua_State *L) static int os_dir_readdir(lua_State *L)
{ {
df_os_dir *dir = todir(L); df_os_dir *dir = todir(L);
@ -417,6 +358,106 @@ static int os_dir_listfiles(lua_State *L)
return os_dir_dolistfiles(L, false, NULL); return os_dir_dolistfiles(L, false, NULL);
} }
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;
}
/**
* Open a directory.
*
* @string path path to the directory to be opened
* @treturn[1] Dir handle to the newly opened directory
* @error[2] error message
* @treturn[2] int system error code
* @function opendir
*/
static int os_dir_open(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)
return os_pushfail(L, path);
luaL_setmetatable(L, DF_LUA_DIRHANDLE);
return 1;
}
static int os_dir_iter(lua_State *L);
/**
* Iterate directory.
*
* Enumerates directory contents one filename at a time, '.' and '..' are
* filtered out. Function is intended to control a for loop.
*
* @string path path to directory to be traversed
* @treturn string next file in directory
* @raise error if the directory could not be opened, or an error occurs during its traversal.
* @function dir
*/
static int os_dir(lua_State *L)
{
lua_pushcfunction(L, os_dir_open);
lua_pushvalue(L, 1);
lua_call(L, 1, 2);
if (lua_isnil(L, -2))
lua_error(L);
lua_pop(L, 1);
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;
}
/**
* List directory contents.
*
* @string path path to directory to be listed
* @tparam[opt] function filter a function taking a filename string and returning
* a boolean to accept/reject each entry
* @treturn[1] {string,...} array of filenames within the directory,
* excluding '.' and '..'
* @error[2] error message
* @treturn[2] int system error code
* @function listfiles
*/
static int os_listfiles(lua_State *L) static int os_listfiles(lua_State *L)
{ {
const char *path = luaL_checkstring(L, 1); const char *path = luaL_checkstring(L, 1);
@ -435,6 +476,26 @@ static int os_listfiles(lua_State *L)
return os_dir_dolistfiles(L, true, path); return os_dir_dolistfiles(L, true, path);
} }
/**
* File info returned on success by @{stat}.
*
* @string type file type, either of 'regular', 'directory', or 'other', for
* regular files, directories and any other file respectively
* @int mtime last modified time in seconds since Unix Epoch, only available for
* 'regular' and 'directory'
* @int size file size in bytes, only available for 'regular' files
* @table FileStat
*/
/**
* Get file info.
*
* @tparam ?string|File f path or opened file handle
* @treturn[1] FileStat on success
* @error[2] error message
* @treturn[2] int system error code
* @function stat
*/
static int os_stat(lua_State *L) static int os_stat(lua_State *L)
{ {
const char *path = NULL; const char *path = NULL;
@ -471,6 +532,16 @@ static int os_stat(lua_State *L)
return 1; return 1;
} }
/**
* Create a new directory.
*
* @string path path to the directory to be created
* @treturn[1] bool true on success and a new directory is created at path
* @treturn[2] bool false on failure (note: directory may already exist)
* @treturn[2] string error message
* @treturn[2] int system error code
* @function mkdir
*/
static int os_mkdir(lua_State *L) static int os_mkdir(lua_State *L)
{ {
const char *path = luaL_checkstring(L, 1); const char *path = luaL_checkstring(L, 1);
@ -479,6 +550,14 @@ static int os_mkdir(lua_State *L)
return os_result(L, ec, path); return os_result(L, ec, path);
} }
/**
* Get process current working directory.
*
* @treturn[1] string path to current working directory on success
* @error[2] error message
* @treturn[2] int system error code
* @function getcwd
*/
static int os_getcwd(lua_State *L) static int os_getcwd(lua_State *L)
{ {
#if LUA_VERSION_NUM >= 502 #if LUA_VERSION_NUM >= 502
@ -542,6 +621,16 @@ fail:
#endif #endif
} }
/**
* Change process current working directory.
*
* @string path path to the new working directory
* @treturn[1] boolean true on success
* @treturn[2] boolean false on failure
* @treturn[2] string error message
* @treturn[2] int system error code
* @function chdir
*/
static int os_chdir(lua_State *L) static int os_chdir(lua_State *L)
{ {
const char *path = luaL_checkstring(L, 1); const char *path = luaL_checkstring(L, 1);
@ -550,6 +639,15 @@ static int os_chdir(lua_State *L)
return os_result(L, ec, path); return os_result(L, ec, path);
} }
/**
* Get the active drive letter.
*
* @treturn[1] string the current drive letter on systems supporting multiple drives
* (e.g. Windows), an empty string otherwise
* @error[2] error message
* @treturn[2] int system error code
* @function getdrive
*/
static int os_getdrive(lua_State *L) static int os_getdrive(lua_State *L)
{ {
errno = 0; errno = 0;
@ -569,6 +667,19 @@ static int os_getdrive(lua_State *L)
return 1; return 1;
} }
/**
* Change active drive.
*
* May only succeed on systems with multiple drives (e.g. Windows).
* On any other system this function always fail with an appropriate error.
*
* @string drive new drive letter (e.g. 'A', 'C', 'D')
* @treturn[1] bool true on success
* @treturn[2] bool false on failure
* @treturn[2] string error message
* @treturn[2] int system error code
* @function chdrive
*/
static int os_chdrive(lua_State *L) static int os_chdrive(lua_State *L)
{ {
size_t len; size_t len;
@ -584,6 +695,22 @@ static int os_chdrive(lua_State *L)
return os_result(L, ec, NULL); return os_result(L, ec, NULL);
} }
/**
* Set file mode.
*
* May only succeed on systems where multiple file mode exist (e.g. Windows),
* will always fail anywhere else (e.g. Unix).
* Typically such error can be ignored.
*
* @tparam File f a file opened for read
* @string mode new mode for file, either of 'binary', 'text', 'u8text',
* 'u16text' or 'wtext'
* @treturn[1] bool true on success
* @treturn[2] bool false on failure
* @treturn[2] string error message
* @treturn[2] int system error code
* @function setmode
*/
static int os_setmode(lua_State *L) static int os_setmode(lua_State *L)
{ {
static const char *modes[] = { static const char *modes[] = {
@ -609,6 +736,17 @@ static int os_setmode(lua_State *L)
return os_result(L, ec, NULL); return os_result(L, ec, NULL);
} }
/**
* Change file size.
*
* @tparam ?string|File f path or file opened for write
* @int size new file size in bytes
* @treturn[1] bool true on success
* @treturn[2] bool false on failure
* @treturn[2] string error string
* @treturn[2] int system error code
* @function chsize
*/
static int os_chsize(lua_State *L) static int os_chsize(lua_State *L)
{ {
lua_Integer size = luaL_checkinteger(L, 2); lua_Integer size = luaL_checkinteger(L, 2);
@ -629,6 +767,17 @@ static int os_chsize(lua_State *L)
return os_result(L, ec, path); return os_result(L, ec, path);
} }
/**
* Advise kernel on file access pattern.
*
* @tparam File f a file opened for read
* @string advise read access pattern (either of: 'normal', 'sequential', 'random', 'noreuse')
* @treturn[1] boolean true on success
* @treturn[2] boolean false on failure
* @treturn[2] string error message
* @treturn[2] int system error code
* @function fadvise
*/
static int os_fadvise(lua_State *L) static int os_fadvise(lua_State *L)
{ {
static const char *hints[] = { static const char *hints[] = {
@ -652,6 +801,16 @@ static int os_fadvise(lua_State *L)
return os_result(L, ec, NULL); return os_result(L, ec, NULL);
} }
/**
* Commit any pending write to disk.
*
* @tparam File f a file opened for write
* @treturn[1] boolean true on success
* @treturn[2] boolean false on failure
* @treturn[2] string error message
* @treturn[2] int system error code
* @function commit
*/
static int os_commit(lua_State *L) static int os_commit(lua_State *L)
{ {
luaL_Stream *stream = luaL_checkudata(L, 1, LUA_FILEHANDLE); luaL_Stream *stream = luaL_checkudata(L, 1, LUA_FILEHANDLE);
@ -660,6 +819,20 @@ static int os_commit(lua_State *L)
return os_result(L, ec, NULL); return os_result(L, ec, NULL);
} }
/**
* Place or remove a read (shared) or write (exclusive) lock to a file.
*
* @tparam File f a file opened with appropriate mode for the requested lock
* @string mode lock mode, any of 'r' (read), 'w' (write), 'u' (release lock)
* @int[opt=0] start initial offset for the requested section
* @int[optchain=0] len length of the requested section, 0 has a special meaning,
* indicating the whole file starting from the initial offset
* @treturn[1] boolean true on success
* @treturn[2] boolean false on failure
* @treturn[2] string error message
* @treturn[2] int system error code
* @function locking
*/
static int os_locking(lua_State *L) static int os_locking(lua_State *L)
{ {
static const char *modes[] = { "r", "w", "u", NULL }; static const char *modes[] = { "r", "w", "u", NULL };
@ -674,6 +847,53 @@ static int os_locking(lua_State *L)
return os_result(L, ec, NULL); return os_result(L, ec, NULL);
} }
/**
* preferred path separator char: '\\' on Windows, '/' anywhere else
*
* @string sep
*/
/**
* Directory handle.
*
* Allows convenient file traversal on directories.
* Entries traversal order is system-specific, and may not be ordered at all.
* Provides metamethods: __gc to close directories on garbage collect,
* __close (on Lua 5.4) to close directories automatically, and __tostring for
* adequate formatting.
*
* @type Dir
*/
/**
* Read next directory entry.
*
* @treturn[1] string next filename in directory, '.' and '..' are also returned
* @error[2] error message on failure
* @treturn[2] int system error code
* @raise error message when attempting to read from a closed directory
* @function readdir
*/
/**
* Read and filter subsequent directory entries.
*
* @tparam[opt] function filter a function taking a filename string and returning
* a boolean to accept/reject each entry
* @treturn[1] {string,...} subsequent filtered contents, '.' and '..' are always filtered out.
* @error[2] error message on failure
* @treturn[2] int system error code
* @raise error message when attempting to read from a closed directory
* @function listfiles
*/
/**
* Close opened directory.
*
* @raise error message when closing a directory twice
* @function close
*/
static void createmeta(lua_State *L) static void createmeta(lua_State *L)
{ {
static const luaL_Reg metameth[] = { static const luaL_Reg metameth[] = {
@ -703,9 +923,9 @@ static void createmeta(lua_State *L)
DF_OSXMOD_API int luaopen_osx(lua_State *L) DF_OSXMOD_API int luaopen_osx(lua_State *L)
{ {
static const luaL_Reg funcs[] = { static const luaL_Reg funcs[] = {
{ "listfiles", os_listfiles },
{ "opendir", os_dir_open }, { "opendir", os_dir_open },
{ "dir", os_dir }, { "dir", os_dir },
{ "listfiles", os_listfiles },
{ "stat", os_stat }, { "stat", os_stat },
{ "mkdir", os_mkdir }, { "mkdir", os_mkdir },
{ "getcwd", os_getcwd }, { "getcwd", os_getcwd },