summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-05-25 19:51:11 +0200
committerwm4 <wm4@nowhere>2014-05-25 19:51:11 +0200
commite2e450f96177c17bea5f15abee87b1671ecdc75d (patch)
treea235911e1fbe620532b41f32a647ff45f7ced378
parente648f7e783e9b063bbef4dcbb5f2c9e7a8c8e4e4 (diff)
downloadmpv-e2e450f96177c17bea5f15abee87b1671ecdc75d.tar.bz2
mpv-e2e450f96177c17bea5f15abee87b1671ecdc75d.tar.xz
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.
-rw-r--r--DOCS/man/en/lua.rst42
-rw-r--r--player/lua.c82
2 files changed, 114 insertions, 10 deletions
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 = {