diff --git a/DOCS/man/en/lua.rst b/DOCS/man/en/lua.rst index f500443203..fca158cad7 100644 --- a/DOCS/man/en/lua.rst +++ b/DOCS/man/en/lua.rst @@ -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 ------ diff --git a/player/lua.c b/player/lua.c index 4e1f3d04d2..60e380b554 100644 --- a/player/lua.c +++ b/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 = {