lua+js: implement utils.file_info()

This commit introduces mp.utils.file_info() for querying information
on file paths, implemented for both Lua and Javascript.

The function takes a file path as an argument and returns a Lua table /
JS object upon success. The table/object will contain the values:
mode, size, atime, mtime, ctime and the convenience booleans is_file, is_dir.

On error, the Lua side will return `nil, error` and the Javascript side
will return `undefined` (and mark the last error).

This feature utilizes the already existing cross-platform `mp_stat()`
function.
This commit is contained in:
TSaaristo 2017-12-11 23:04:51 +02:00 committed by Jan Ekström
parent 47131365a3
commit 522bfe5be1
4 changed files with 109 additions and 0 deletions

View File

@ -168,6 +168,8 @@ Otherwise, where the Lua APIs return ``nil`` on error, JS returns ``undefined``.
``mp.utils.readdir(path [, filter])`` (LE) ``mp.utils.readdir(path [, filter])`` (LE)
``mp.utils.file_info(path)`` (LE)
``mp.utils.split_path(path)`` ``mp.utils.split_path(path)``
``mp.utils.join_path(p1, p2)`` ``mp.utils.join_path(p1, p2)``

View File

@ -591,6 +591,34 @@ strictly part of the guaranteed API.
On error, ``nil, error`` is returned. On error, ``nil, error`` is returned.
``utils.file_info(path)``
Stats the given path for information and returns a table with the
following entries:
``mode``
protection bits (on Windows, always 755 (octal) for directories
and 644 (octal) for files)
``size``
size in bytes
``atime``
time of last access
``mtime``
time of last modification
``ctime``
time of last metadata change (Linux) / time of creation (Windows)
``is_file``
Whether ``path`` is a regular file (boolean)
``is_dir``
Whether ``path`` is a directory (boolean)
``mode`` and ``size`` are integers.
Timestamps (``atime``, ``mtime`` and ``ctime``) are integer seconds since
the Unix epoch (Unix time).
The booleans ``is_file`` and ``is_dir`` are provided as a convenience;
they can be and are derived from ``mode``.
On error (eg. path does not exist), ``nil, error`` is returned.
``utils.split_path(path)`` ``utils.split_path(path)``
Split a path into directory component and filename component, and return Split a path into directory component and filename component, and return
them. The first return value is always the directory. The second return them. The first return value is always the directory. The second return

View File

@ -836,6 +836,41 @@ static void script_readdir(js_State *J, void *af)
} }
} }
static void script_file_info(js_State *J)
{
const char *path = js_tostring(J, 1);
struct stat statbuf;
if (stat(path, &statbuf) != 0) {
push_failure(J, "Cannot stat path");
return;
}
// Clear last error
set_last_error(jctx(J), 0, NULL);
const char * stat_names[] = {
"mode", "size",
"atime", "mtime", "ctime", NULL
};
const double stat_values[] = {
statbuf.st_mode,
statbuf.st_size,
statbuf.st_atime,
statbuf.st_mtime,
statbuf.st_ctime
};
// Create an object and add all fields
push_nums_obj(J, stat_names, stat_values);
// Convenience booleans
js_pushboolean(J, S_ISREG(statbuf.st_mode));
js_setproperty(J, -2, "is_file");
js_pushboolean(J, S_ISDIR(statbuf.st_mode));
js_setproperty(J, -2, "is_dir");
}
static void script_split_path(js_State *J) static void script_split_path(js_State *J)
{ {
const char *p = js_tostring(J, 1); const char *p = js_tostring(J, 1);
@ -1255,6 +1290,7 @@ static const struct fn_entry main_fns[] = {
static const struct fn_entry utils_fns[] = { static const struct fn_entry utils_fns[] = {
AF_ENTRY(readdir, 2), AF_ENTRY(readdir, 2),
FN_ENTRY(file_info, 1),
FN_ENTRY(split_path, 1), FN_ENTRY(split_path, 1),
AF_ENTRY(join_path, 2), AF_ENTRY(join_path, 2),
AF_ENTRY(get_user_path, 1), AF_ENTRY(get_user_path, 1),

View File

@ -1085,6 +1085,48 @@ static int script_readdir(lua_State *L)
return 1; return 1;
} }
static int script_file_info(lua_State *L)
{
const char *path = luaL_checkstring(L, 1);
struct stat statbuf;
if (stat(path, &statbuf) != 0) {
lua_pushnil(L);
lua_pushstring(L, "error");
return 2;
}
lua_newtable(L); // Result stat table
const char * stat_names[] = {
"mode", "size",
"atime", "mtime", "ctime", NULL
};
const unsigned int stat_values[] = {
statbuf.st_mode,
statbuf.st_size,
statbuf.st_atime,
statbuf.st_mtime,
statbuf.st_ctime
};
// Add all fields
for (int i = 0; stat_names[i]; i++) {
lua_pushinteger(L, stat_values[i]);
lua_setfield(L, -2, stat_names[i]);
}
// Convenience booleans
lua_pushboolean(L, S_ISREG(statbuf.st_mode));
lua_setfield(L, -2, "is_file");
lua_pushboolean(L, S_ISDIR(statbuf.st_mode));
lua_setfield(L, -2, "is_dir");
// Return table
return 1;
}
static int script_split_path(lua_State *L) static int script_split_path(lua_State *L)
{ {
const char *p = luaL_checkstring(L, 1); const char *p = luaL_checkstring(L, 1);
@ -1291,6 +1333,7 @@ static const struct fn_entry main_fns[] = {
static const struct fn_entry utils_fns[] = { static const struct fn_entry utils_fns[] = {
FN_ENTRY(readdir), FN_ENTRY(readdir),
FN_ENTRY(file_info),
FN_ENTRY(split_path), FN_ENTRY(split_path),
FN_ENTRY(join_path), FN_ENTRY(join_path),
FN_ENTRY(subprocess), FN_ENTRY(subprocess),