Also, for consistency with other APIs, mp.utils.{write,append}_file now return true on success (and still throw on any error).
Unified · Split
| @@ -221,7 +221,8 @@ Additional utilities · 220 unmodified lines | |||
| 221 | 221 | ||
| 222 | ``mp.utils.get_user_path(path)`` | 222 | ``mp.utils.get_user_path(path)`` |
| 223 | Expands (mpv) meta paths like ``~/x``, ``~~/y``, ``~~desktop/z`` etc. | 223 | Expands (mpv) meta paths like ``~/x``, ``~~/y``, ``~~desktop/z`` etc. |
| 224 | ``read_file``, ``write_file`` and ``require`` already use this internaly. | 224 | ``read_file``, ``write_file``, ``append_file`` and ``require`` already use |
| 225 | this internaly. | ||
| 225 | 226 | ||
| 226 | ``mp.utils.read_file(fname [,max])`` | 227 | ``mp.utils.read_file(fname [,max])`` |
| 227 | Returns the content of file ``fname`` as string. If ``max`` is provided and | 228 | Returns the content of file ``fname`` as string. If ``max`` is provided and |
| @@ -232,7 +233,12 @@ Additional utilities · 4 unmodified lines | |||
| 232 | prefixed with ``file://`` as simple protection against accidental arguments | 233 | prefixed with ``file://`` as simple protection against accidental arguments |
| 233 | switch, e.g. ``mp.utils.write_file("file://~/abc.txt", "hello world")``. | 234 | switch, e.g. ``mp.utils.write_file("file://~/abc.txt", "hello world")``. |
| 234 | 235 | ||
| 235 | Note: ``read_file`` and ``write_file`` throw on errors, allow text content only. | 236 | ``mp.utils.append_file(fname, str)`` |
| 237 | Same as ``mp.utils.write_file`` if the file ``fname`` does not exist. If it | ||
| 238 | does exist then append instead of overwrite. | ||
| 239 | |||
| 240 | Note: ``read_file``, ``write_file`` and ``append_file`` throw on errors, allow | ||
| 241 | text content only. | ||
| 236 | 242 | ||
| 237 | ``mp.get_time_ms()`` | 243 | ``mp.get_time_ms()`` |
| 238 | Same as ``mp.get_time()`` but in ms instead of seconds. | 244 | Same as ``mp.get_time()`` but in ms instead of seconds. |
| @@ -924,27 +924,31 @@ static void script_get_user_path(js_State *J, void *af) · 923 unmodified lines | |||
| 924 | js_pushstring(J, mp_get_user_path(af, jctx(J)->mpctx->global, path)); | 924 | js_pushstring(J, mp_get_user_path(af, jctx(J)->mpctx->global, path)); |
| 925 | } | 925 | } |
| 926 | 926 | ||
| 927 | // args: prefixed file name, data (c-str) | 927 | // args: is_append, prefixed file name, data (c-str) |
| 928 | static void script_write_file(js_State *J, void *af) | 928 | static void script__write_file(js_State *J, void *af) |
| 929 | { | 929 | { |
| 930 | static const char *prefix = "file://"; | 930 | static const char *prefix = "file://"; |
| 931 | const char *fname = js_tostring(J, 1); | 931 | bool append = js_toboolean(J, 1); |
| 932 | const char *data = js_tostring(J, 2); | 932 | const char *fname = js_tostring(J, 2); |
| 933 | const char *data = js_tostring(J, 3); | ||
| 934 | const char *opstr = append ? "append" : "write"; | ||
| 935 | |||
| 933 | if (strstr(fname, prefix) != fname) // simple protection for incorrect use | 936 | if (strstr(fname, prefix) != fname) // simple protection for incorrect use |
| 934 | js_error(J, "File name must be prefixed with '%s'", prefix); | 937 | js_error(J, "File name must be prefixed with '%s'", prefix); |
| 935 | fname += strlen(prefix); | 938 | fname += strlen(prefix); |
| 936 | fname = mp_get_user_path(af, jctx(J)->mpctx->global, fname); | 939 | fname = mp_get_user_path(af, jctx(J)->mpctx->global, fname); |
| 937 | MP_VERBOSE(jctx(J), "Writing file '%s'\n", fname); | 940 | MP_VERBOSE(jctx(J), "%s file '%s'\n", opstr, fname); |
| 938 | 941 | ||
| 939 | FILE *f = fopen(fname, "wb"); | 942 | FILE *f = fopen(fname, append ? "ab" : "wb"); |
| 940 | if (!f) | 943 | if (!f) |
| 941 | js_error(J, "Cannot open file for writing: '%s'", fname); | 944 | js_error(J, "Cannot open (%s) file: '%s'", opstr, fname); |
| 942 | add_af_file(af, f); | 945 | add_af_file(af, f); |
| 943 | 946 | ||
| 944 | int len = strlen(data); // limited by terminating null | 947 | int len = strlen(data); // limited by terminating null |
| 945 | int wrote = fwrite(data, 1, len, f); | 948 | int wrote = fwrite(data, 1, len, f); |
| 946 | if (len != wrote) | 949 | if (len != wrote) |
| 947 | js_error(J, "Cannot write to file: '%s'", fname); | 950 | js_error(J, "Cannot %s to file: '%s'", opstr, fname); |
| 951 | js_pushboolean(J, 1); // success. doesn't touch last_error | ||
| 948 | } | 952 | } |
| 949 | 953 | ||
| 950 | // args: env var name | 954 | // args: env var name |
| @@ -1179,7 +1183,7 @@ static const struct fn_entry utils_fns[] = { · 228 unmodified lines | |||
| 1179 | FN_ENTRY(get_env_list, 0), | 1183 | FN_ENTRY(get_env_list, 0), |
| 1180 | 1184 | ||
| 1181 | FN_ENTRY(read_file, 2), | 1185 | FN_ENTRY(read_file, 2), |
| 1182 | AF_ENTRY(write_file, 2), | 1186 | AF_ENTRY(_write_file, 3), |
| 1183 | FN_ENTRY(getenv, 1), | 1187 | FN_ENTRY(getenv, 1), |
| 1184 | FN_ENTRY(compile_js, 2), | 1188 | FN_ENTRY(compile_js, 2), |
| 1185 | FN_ENTRY(_gc, 1), | 1189 | FN_ENTRY(_gc, 1), |
| @@ -665,6 +665,8 @@ mp.get_time = function() { return mp.get_time_ms() / 1000 }; · 664 unmodified lines | |||
| 665 | mp.utils.getcwd = function() { return mp.get_property("working-directory") }; | 665 | mp.utils.getcwd = function() { return mp.get_property("working-directory") }; |
| 666 | mp.utils.getpid = function() { return mp.get_property_number("pid") } | 666 | mp.utils.getpid = function() { return mp.get_property_number("pid") } |
| 667 | mp.get_mouse_pos = function() { return mp.get_property_native("mouse-pos") }; | 667 | mp.get_mouse_pos = function() { return mp.get_property_native("mouse-pos") }; |
| 668 | mp.utils.write_file = mp.utils._write_file.bind(null, false); | ||
| 669 | mp.utils.append_file = mp.utils._write_file.bind(null, true); | ||
| 668 | mp.dispatch_event = dispatch_event; | 670 | mp.dispatch_event = dispatch_event; |
| 669 | mp.process_timers = process_timers; | 671 | mp.process_timers = process_timers; |
| 670 | mp.notify_idle_observers = notify_idle_observers; | 672 | mp.notify_idle_observers = notify_idle_observers; |