lua: add some filesystem utility functions

We need this only because Lua's stdlib is so scarce. Lua doesn't intend
to include a complete stdlib - they confine themselves to standard C,
both for portability reasons and to keep the code minimal. But standard
C does not provide much either.

It would be possible to use Lua POSIX wrapper libraries, but that would
be a messy (and unobvious) dependency. It's better to implement the
missing functions ourselves, as long as they're small in number.
This commit is contained in:
wm4 2014-05-25 19:51:11 +02:00
parent e648f7e783
commit e2e450f961
2 changed files with 114 additions and 10 deletions

View File

@ -461,6 +461,48 @@ Example command-line::
--lua-opts=myscript-optionA=TEST:myscript-optionB=0:myscript-optionC=yes
mp.utils options
----------------
This built-in module provides generic helper functions for Lua, and have
strictly speaking nothing to do with mpv or video/audio playback. They are
provided for convenience. Most compensate for Lua's scarce standard library.
``utils.readdir(path [, filter])``
Enumerate all entries at the given path on the filesystem, and return them
as array. Each entry is a directory entry (without the path).
The list is unsorted (in whatever order the operating system returns it).
If the ``filter`` argument is given, it must be one of the following
strings:
``files``
List regular files only. This excludes directories, special files
(like UNIX device files or FIFOs), and dead symlinks. It includes
UNIX symlinks to regular files.
``dirs``
List directories only, or symlinks to directories. ``.`` and ``..``
are not included.
``normal``
Include the results of both ``files`` and ``dirs``. (This is the
default.)
``all``
List all entries, even device files, dead symlinks, FIFOs, and the
``.`` and ``..`` entries.
On error, ``nil, error`` is returned.
``utils.split_path(path)``
Split a path into directory component and filename component, and return
them. The first return value is always the directory. The second return
value is the trailing part of the path, the directory entry.
``utils.join_path(p1, p2)``
Return the concatenation of the 2 paths. Tries to be clever. For example,
if ```p2`` is an absolute path, p2 is returned without change.
Events
------

View File

@ -985,14 +985,67 @@ static int script_get_wakeup_pipe(lua_State *L)
return 1;
}
struct fn_entry {
const char *name;
int (*fn)(lua_State *L);
};
static int script_readdir(lua_State *L)
{
// 0 1 2 3
const char *fmts[] = {"all", "files", "dirs", "normal", NULL};
const char *path = luaL_checkstring(L, 1);
int t = luaL_checkoption(L, 2, "normal", fmts);
DIR *dir = opendir(path);
if (!dir) {
lua_pushnil(L);
lua_pushstring(L, "error");
return 2;
}
lua_newtable(L); // list
char *fullpath = NULL;
struct dirent *e;
int n = 0;
while ((e = readdir(dir))) {
char *name = e->d_name;
if (t) {
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
continue;
if (fullpath)
fullpath[0] = '\0';
fullpath = talloc_asprintf_append(fullpath, "%s/%s", path, name);
struct stat st;
if (mp_stat(fullpath, &st))
continue;
if (!(((t & 1) && S_ISREG(st.st_mode)) ||
((t & 2) && S_ISDIR(st.st_mode))))
continue;
}
lua_pushinteger(L, ++n); // list index
lua_pushstring(L, name); // list index name
lua_settable(L, -3); // list
}
talloc_free(fullpath);
return 1;
}
static int script_split_path(lua_State *L)
{
const char *p = luaL_checkstring(L, 1);
bstr fname = mp_dirname(p);
lua_pushlstring(L, fname.start, fname.len);
lua_pushstring(L, mp_basename(p));
return 2;
}
static int script_join_path(lua_State *L)
{
const char *p1 = luaL_checkstring(L, 1);
const char *p2 = luaL_checkstring(L, 2);
char *r = mp_path_join(NULL, bstr0(p1), bstr0(p2));
lua_pushstring(L, r);
talloc_free(r);
return 1;
}
#define FN_ENTRY(name) {#name, script_ ## name}
static struct fn_entry fn_list[] = {
static struct luaL_Reg main_fns[] = {
FN_ENTRY(log),
FN_ENTRY(suspend),
FN_ENTRY(resume),
@ -1024,17 +1077,21 @@ static struct fn_entry fn_list[] = {
FN_ENTRY(format_time),
FN_ENTRY(enable_messages),
FN_ENTRY(get_wakeup_pipe),
{0}
};
static struct luaL_Reg utils_fns[] = {
FN_ENTRY(readdir),
FN_ENTRY(split_path),
FN_ENTRY(join_path),
{0}
};
// On stack: mp table
static void add_functions(struct script_ctx *ctx)
{
lua_State *L = ctx->state;
for (int n = 0; n < MP_ARRAY_SIZE(fn_list); n++) {
lua_pushcfunction(L, fn_list[n].fn);
lua_setfield(L, -2, fn_list[n].name);
}
luaL_register(L, "mp", main_fns); // mp
lua_pushinteger(L, 0);
lua_pushcclosure(L, script_get_property, 1);
@ -1043,6 +1100,11 @@ static void add_functions(struct script_ctx *ctx)
lua_pushinteger(L, 1);
lua_pushcclosure(L, script_get_property, 1);
lua_setfield(L, -2, "get_property_osd");
lua_pop(L, 1); // -
luaL_register(L, "mp.utils", utils_fns);
lua_pop(L, 1);
}
const struct mp_scripting mp_scripting_lua = {