mirror of
https://github.com/mpv-player/mpv
synced 2025-04-10 11:41:37 +00:00
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:
parent
e648f7e783
commit
e2e450f961
@ -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
|
||||
------
|
||||
|
82
player/lua.c
82
player/lua.c
@ -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 = {
|
||||
|
Loading…
Reference in New Issue
Block a user