mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 15:43:01 +00:00 
			
		
		
		
	Merge branch 'filewatch'
This commit is contained in:
		| @@ -2,6 +2,7 @@ | |||||||
| All notable changes to this project will be documented in this file. | All notable changes to this project will be documented in this file. | ||||||
|  |  | ||||||
| ## Unreleased - ??? | ## Unreleased - ??? | ||||||
|  | - Add experimental `filewatch/` module for listening to file system changes. | ||||||
| - Add `bundle/who-is` to query which bundle a file on disk was installed by. | - Add `bundle/who-is` to query which bundle a file on disk was installed by. | ||||||
| - Add `geomean` function | - Add `geomean` function | ||||||
| - Add `:R` and `:W` flags to `os/pipe` to create blocking pipes on Posix and Windows systems. | - Add `:R` and `:W` flags to `os/pipe` to create blocking pipes on Posix and Windows systems. | ||||||
|   | |||||||
| @@ -79,6 +79,7 @@ conf.set('JANET_EV_NO_KQUEUE', not get_option('kqueue')) | |||||||
| conf.set('JANET_NO_INTERPRETER_INTERRUPT', not get_option('interpreter_interrupt')) | conf.set('JANET_NO_INTERPRETER_INTERRUPT', not get_option('interpreter_interrupt')) | ||||||
| conf.set('JANET_NO_FFI', not get_option('ffi')) | conf.set('JANET_NO_FFI', not get_option('ffi')) | ||||||
| conf.set('JANET_NO_FFI_JIT', not get_option('ffi_jit')) | conf.set('JANET_NO_FFI_JIT', not get_option('ffi_jit')) | ||||||
|  | conf.set('JANET_NO_FILEWATCH', not get_option('filewatch')) | ||||||
| conf.set('JANET_NO_CRYPTORAND', not get_option('cryptorand')) | conf.set('JANET_NO_CRYPTORAND', not get_option('cryptorand')) | ||||||
| if get_option('os_name') != '' | if get_option('os_name') != '' | ||||||
|   conf.set('JANET_OS_NAME', get_option('os_name')) |   conf.set('JANET_OS_NAME', get_option('os_name')) | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ option('kqueue', type : 'boolean', value : true) | |||||||
| option('interpreter_interrupt', type : 'boolean', value : true) | option('interpreter_interrupt', type : 'boolean', value : true) | ||||||
| option('ffi', type : 'boolean', value : true) | option('ffi', type : 'boolean', value : true) | ||||||
| option('ffi_jit', type : 'boolean', value : true) | option('ffi_jit', type : 'boolean', value : true) | ||||||
|  | option('filewatch', type : 'boolean', value : true) | ||||||
|  |  | ||||||
| option('recursion_guard', type : 'integer', min : 10, max : 8000, value : 1024) | option('recursion_guard', type : 'integer', min : 10, max : 8000, value : 1024) | ||||||
| option('max_proto_depth', type : 'integer', min : 10, max : 8000, value : 200) | option('max_proto_depth', type : 'integer', min : 10, max : 8000, value : 200) | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ | |||||||
| /* #define JANET_NO_NET */ | /* #define JANET_NO_NET */ | ||||||
| /* #define JANET_NO_INT_TYPES */ | /* #define JANET_NO_INT_TYPES */ | ||||||
| /* #define JANET_NO_EV */ | /* #define JANET_NO_EV */ | ||||||
|  | /* #define JANET_NO_FILEWATCH */ | ||||||
| /* #define JANET_NO_REALPATH */ | /* #define JANET_NO_REALPATH */ | ||||||
| /* #define JANET_NO_SYMLINKS */ | /* #define JANET_NO_SYMLINKS */ | ||||||
| /* #define JANET_NO_UMASK */ | /* #define JANET_NO_UMASK */ | ||||||
|   | |||||||
| @@ -456,7 +456,7 @@ JANET_CORE_FN(janet_core_range, | |||||||
|     } |     } | ||||||
|     JanetArray *array = janet_array(int_count); |     JanetArray *array = janet_array(int_count); | ||||||
|     for (int32_t i = 0; i < int_count; i++) { |     for (int32_t i = 0; i < int_count; i++) { | ||||||
|         array->data[i] = janet_wrap_number(start + (double) i * step); |         array->data[i] = janet_wrap_number((double) start + (double) i * step); | ||||||
|     } |     } | ||||||
|     array->count = int_count; |     array->count = int_count; | ||||||
|     return janet_wrap_array(array); |     return janet_wrap_array(array); | ||||||
| @@ -1127,6 +1127,9 @@ static void janet_load_libs(JanetTable *env) { | |||||||
| #endif | #endif | ||||||
| #ifdef JANET_EV | #ifdef JANET_EV | ||||||
|     janet_lib_ev(env); |     janet_lib_ev(env); | ||||||
|  | #ifdef JANET_FILEWATCH | ||||||
|  |     janet_lib_filewatch(env); | ||||||
|  | #endif | ||||||
| #endif | #endif | ||||||
| #ifdef JANET_NET | #ifdef JANET_NET | ||||||
|     janet_lib_net(env); |     janet_lib_net(env); | ||||||
|   | |||||||
| @@ -316,8 +316,9 @@ static const JanetMethod ev_default_stream_methods[] = { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| /* Create a stream*/ | /* Create a stream*/ | ||||||
| JanetStream *janet_stream(JanetHandle handle, uint32_t flags, const JanetMethod *methods) { | JanetStream *janet_stream_ext(JanetHandle handle, uint32_t flags, const JanetMethod *methods, size_t size) { | ||||||
|     JanetStream *stream = janet_abstract(&janet_stream_type, sizeof(JanetStream)); |     janet_assert(size >= sizeof(JanetStream), "bad size"); | ||||||
|  |     JanetStream *stream = janet_abstract(&janet_stream_type, size); | ||||||
|     stream->handle = handle; |     stream->handle = handle; | ||||||
|     stream->flags = flags; |     stream->flags = flags; | ||||||
|     stream->read_fiber = NULL; |     stream->read_fiber = NULL; | ||||||
| @@ -329,6 +330,10 @@ JanetStream *janet_stream(JanetHandle handle, uint32_t flags, const JanetMethod | |||||||
|     return stream; |     return stream; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | JanetStream *janet_stream(JanetHandle handle, uint32_t flags, const JanetMethod *methods) { | ||||||
|  |     return janet_stream_ext(handle, flags, methods, sizeof(JanetStream)); | ||||||
|  | } | ||||||
|  |  | ||||||
| static void janet_stream_close_impl(JanetStream *stream) { | static void janet_stream_close_impl(JanetStream *stream) { | ||||||
|     stream->flags |= JANET_STREAM_CLOSED; |     stream->flags |= JANET_STREAM_CLOSED; | ||||||
| #ifdef JANET_WINDOWS | #ifdef JANET_WINDOWS | ||||||
| @@ -988,6 +993,20 @@ int janet_channel_take(JanetChannel *channel, Janet *out) { | |||||||
|     return janet_channel_pop(channel, out, 2); |     return janet_channel_pop(channel, out, 2); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | JanetChannel *janet_channel_make(uint32_t limit) { | ||||||
|  |     janet_assert(limit <= INT32_MAX, "bad limit"); | ||||||
|  |     JanetChannel *channel = janet_abstract(&janet_channel_type, sizeof(JanetChannel)); | ||||||
|  |     janet_chan_init(channel, (int32_t) limit, 0); | ||||||
|  |     return channel; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | JanetChannel *janet_channel_make_threaded(uint32_t limit) { | ||||||
|  |     janet_assert(limit <= INT32_MAX, "bad limit"); | ||||||
|  |     JanetChannel *channel = janet_abstract_threaded(&janet_channel_type, sizeof(JanetChannel)); | ||||||
|  |     janet_chan_init(channel, (int32_t) limit, 0); | ||||||
|  |     return channel; | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Channel Methods */ | /* Channel Methods */ | ||||||
|  |  | ||||||
| JANET_CORE_FN(cfun_channel_push, | JANET_CORE_FN(cfun_channel_push, | ||||||
|   | |||||||
| @@ -27,24 +27,47 @@ | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef JANET_EV | #ifdef JANET_EV | ||||||
|  | #ifdef JANET_FILEWATCH | ||||||
| typedef struct { |  | ||||||
|     JanetTable *watch_descriptors; |  | ||||||
|     JanetStream *stream; |  | ||||||
|     JanetChannel *channel; |  | ||||||
|     uint32_t default_flags; |  | ||||||
| } JanetWatcher; |  | ||||||
|  |  | ||||||
| #ifdef JANET_LINUX | #ifdef JANET_LINUX | ||||||
| #include <sys/inotify.h> | #include <sys/inotify.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef JANET_WINDOWS | ||||||
|  | #include <windows.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
| typedef struct { | typedef struct { | ||||||
|     const char *name; |     const char *name; | ||||||
|     uint32_t flag; |     uint32_t flag; | ||||||
| } JanetWatchFlagName; | } JanetWatchFlagName; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  | #ifndef JANET_WINDOWS | ||||||
|  |     JanetStream *stream; | ||||||
|  | #endif | ||||||
|  |     JanetTable watch_descriptors; | ||||||
|  |     JanetChannel *channel; | ||||||
|  |     uint32_t default_flags; | ||||||
|  | } JanetWatcher; | ||||||
|  |  | ||||||
|  | /* Reject certain filename events without sending anything to the channel | ||||||
|  |  * to make things faster and not waste time and memory creating events. This | ||||||
|  |  * should also let us watch only certain file names, patterns, etc. */ | ||||||
|  | static int janet_watch_filter(JanetWatcher *watcher, Janet filename, int wd) { | ||||||
|  |     /* TODO - add filtering */ | ||||||
|  |     (void) watcher; | ||||||
|  |     (void) filename; | ||||||
|  |     (void) wd; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #ifdef JANET_LINUX | ||||||
|  |  | ||||||
|  | #include <sys/inotify.h> | ||||||
|  | #include <unistd.h> | ||||||
|  |  | ||||||
| static const JanetWatchFlagName watcher_flags_linux[] = { | static const JanetWatchFlagName watcher_flags_linux[] = { | ||||||
|     {"access", IN_ACCESS}, |     {"access", IN_ACCESS}, | ||||||
|     {"all", IN_ALL_EVENTS}, |     {"all", IN_ALL_EVENTS}, | ||||||
| @@ -63,7 +86,8 @@ static const JanetWatchFlagName watcher_flags_linux[] = { | |||||||
|     {"q-overflow", IN_Q_OVERFLOW}, |     {"q-overflow", IN_Q_OVERFLOW}, | ||||||
|     {"unmount", IN_UNMOUNT}, |     {"unmount", IN_UNMOUNT}, | ||||||
| }; | }; | ||||||
| static uint32_t decode_inotify_flags(const Janet *options, int32_t n) { |  | ||||||
|  | static uint32_t decode_watch_flags(const Janet *options, int32_t n) { | ||||||
|     uint32_t flags = 0; |     uint32_t flags = 0; | ||||||
|     for (int32_t i = 0; i < n; i++) { |     for (int32_t i = 0; i < n; i++) { | ||||||
|         if (!(janet_checktype(options[i], JANET_KEYWORD))) { |         if (!(janet_checktype(options[i], JANET_KEYWORD))) { | ||||||
| @@ -87,7 +111,10 @@ static void janet_watcher_init(JanetWatcher *watcher, JanetChannel *channel, uin | |||||||
|     do { |     do { | ||||||
|         fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); |         fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); | ||||||
|     } while (fd == -1 && errno == EINTR); |     } while (fd == -1 && errno == EINTR); | ||||||
|     watcher->watch_descriptors = janet_table(0); |     if (fd == -1) { | ||||||
|  |         janet_panicv(janet_ev_lasterr()); | ||||||
|  |     } | ||||||
|  |     janet_table_init_raw(&watcher->watch_descriptors, 0); | ||||||
|     watcher->channel = channel; |     watcher->channel = channel; | ||||||
|     watcher->default_flags = default_flags; |     watcher->default_flags = default_flags; | ||||||
|     watcher->stream = janet_stream(fd, JANET_STREAM_READABLE, NULL); |     watcher->stream = janet_stream(fd, JANET_STREAM_READABLE, NULL); | ||||||
| @@ -99,15 +126,18 @@ static void janet_watcher_add(JanetWatcher *watcher, const char *path, uint32_t | |||||||
|     do { |     do { | ||||||
|         result = inotify_add_watch(watcher->stream->handle, path, flags); |         result = inotify_add_watch(watcher->stream->handle, path, flags); | ||||||
|     } while (result == -1 && errno == EINTR); |     } while (result == -1 && errno == EINTR); | ||||||
|  |     if (result == -1) { | ||||||
|  |         janet_panicv(janet_ev_lasterr()); | ||||||
|  |     } | ||||||
|     Janet name = janet_cstringv(path); |     Janet name = janet_cstringv(path); | ||||||
|     Janet wd = janet_wrap_integer(result); |     Janet wd = janet_wrap_integer(result); | ||||||
|     janet_table_put(watcher->watch_descriptors, name, wd); |     janet_table_put(&watcher->watch_descriptors, name, wd); | ||||||
|     janet_table_put(watcher->watch_descriptors, wd, name); |     janet_table_put(&watcher->watch_descriptors, wd, name); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void janet_watcher_remove(JanetWatcher *watcher, const char *path) { | static void janet_watcher_remove(JanetWatcher *watcher, const char *path) { | ||||||
|     if (watcher->stream == NULL) janet_panic("watcher closed"); |     if (watcher->stream == NULL) janet_panic("watcher closed"); | ||||||
|     Janet check = janet_table_get(watcher->watch_descriptors, janet_cstringv(path)); |     Janet check = janet_table_get(&watcher->watch_descriptors, janet_cstringv(path)); | ||||||
|     janet_assert(janet_checktype(check, JANET_NUMBER), "bad watch descriptor"); |     janet_assert(janet_checktype(check, JANET_NUMBER), "bad watch descriptor"); | ||||||
|     int watch_handle = janet_unwrap_integer(check); |     int watch_handle = janet_unwrap_integer(check); | ||||||
|     int result; |     int result; | ||||||
| @@ -115,7 +145,7 @@ static void janet_watcher_remove(JanetWatcher *watcher, const char *path) { | |||||||
|         result = inotify_rm_watch(watcher->stream->handle, watch_handle); |         result = inotify_rm_watch(watcher->stream->handle, watch_handle); | ||||||
|     } while (result != -1 && errno == EINTR); |     } while (result != -1 && errno == EINTR); | ||||||
|     if (result == -1) { |     if (result == -1) { | ||||||
|         janet_panicf("%s", janet_strerror(errno)); |         janet_panicv(janet_ev_lasterr()); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -189,8 +219,11 @@ static void watcher_callback_read(JanetFiber *fiber, JanetAsyncEvent event) { | |||||||
|                         cursor += inevent.len; |                         cursor += inevent.len; | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|  |                     /* Filter events by pattern */ | ||||||
|  |                     if (!janet_watch_filter(watcher, name, inevent.wd)) continue; | ||||||
|  |  | ||||||
|                     /* Got an event */ |                     /* Got an event */ | ||||||
|                     Janet path = janet_table_get(watcher->watch_descriptors, janet_wrap_integer(inevent.wd)); |                     Janet path = janet_table_get(&watcher->watch_descriptors, janet_wrap_integer(inevent.wd)); | ||||||
|                     JanetKV *event = janet_struct_begin(6); |                     JanetKV *event = janet_struct_begin(6); | ||||||
|                     janet_struct_put(event, janet_ckeywordv("wd"), janet_wrap_integer(inevent.wd)); |                     janet_struct_put(event, janet_ckeywordv("wd"), janet_wrap_integer(inevent.wd)); | ||||||
|                     janet_struct_put(event, janet_ckeywordv("wd-path"), path); |                     janet_struct_put(event, janet_ckeywordv("wd-path"), path); | ||||||
| @@ -218,31 +251,200 @@ static void janet_watcher_listen(JanetWatcher *watcher) { | |||||||
|     janet_async_start(watcher->stream, JANET_ASYNC_LISTEN_READ, watcher_callback_read, watcher); |     janet_async_start(watcher->stream, JANET_ASYNC_LISTEN_READ, watcher_callback_read, watcher); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #elif JANET_WINDOWS | ||||||
|  |  | ||||||
|  | static const JanetWatchFlagName watcher_flags_windows[] = { | ||||||
|  |     {"file-name", FILE_NOTIFY_CHANGE_FILE_NAME}, | ||||||
|  |     {"dir-name", FILE_NOTIFY_CHANGE_DIR_NAME}, | ||||||
|  |     {"attributes", FILE_NOTIFY_CHANGE_ATTRIBUTES}, | ||||||
|  |     {"size", FILE_NOTIFY_CHANGE_SIZE}, | ||||||
|  |     {"last-write", FILE_NOTIFY_CHANGE_LAST_WRITE}, | ||||||
|  |     {"last-access", FILE_NOTIFY_CHANGE_LAST_ACCESS}, | ||||||
|  |     {"creation", FILE_NOTIFY_CHANGE_CREATION}, | ||||||
|  |     {"security", FILE_NOTIFY_CHANGE_SECURITY} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static uint32_t decode_watch_flags(const Janet *options, int32_t n) { | ||||||
|  |     uint32_t flags = 0; | ||||||
|  |     for (int32_t i = 0; i < n; i++) { | ||||||
|  |         if (!(janet_checktype(options[i], JANET_KEYWORD))) { | ||||||
|  |             janet_panicf("expected keyword, got %v", options[i]); | ||||||
|  |         } | ||||||
|  |         JanetKeyword keyw = janet_unwrap_keyword(options[i]); | ||||||
|  |         const JanetWatchFlagName *result = janet_strbinsearch(watcher_flags_windows, | ||||||
|  |                 sizeof(watcher_flags_windows) / sizeof(JanetWatchFlagName), | ||||||
|  |                 sizeof(JanetWatchFlagName), | ||||||
|  |                 keyw); | ||||||
|  |         if (!result) { | ||||||
|  |             janet_panicf("unknown windows filewatch flag %v", options[i]); | ||||||
|  |         } | ||||||
|  |         flags |= result->flag; | ||||||
|  |     } | ||||||
|  |     return flags; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void janet_watcher_init(JanetWatcher *watcher, JanetChannel *channel, uint32_t default_flags) { | ||||||
|  |     janet_table_init_raw(&watcher->watch_descriptors, 0); | ||||||
|  |     watcher->channel = channel; | ||||||
|  |     watcher->default_flags = default_flags; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |     JanetStream stream; | ||||||
|  |     OVERLAPPED overlapped; | ||||||
|  |     uint32_t flags; | ||||||
|  |     FILE_NOTIFY_INFORMATION fni; | ||||||
|  | } OverlappedWatch; | ||||||
|  |  | ||||||
|  | static void janet_watcher_add(JanetWatcher *watcher, const char *path, uint32_t flags) { | ||||||
|  |     HANDLE handle = CreateFileA(path, GENERIC_READ, | ||||||
|  |             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | ||||||
|  |             NULL, | ||||||
|  |             OPEN_EXISTING, | ||||||
|  |             FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL, | ||||||
|  |             0); | ||||||
|  |     if (handle == INVALID_HANDLE_VALUE) { | ||||||
|  |         janet_panicv(janet_ev_lasterr()); | ||||||
|  |     } | ||||||
|  |     JanetStream *stream = janet_stream_ext(handle, 0, NULL, sizeof(OverlappedWatch)); | ||||||
|  |     Janet pathv = janet_cstringv(path); | ||||||
|  |     stream->flags = flags | watcher->default_flags; | ||||||
|  |     Janet streamv = janet_wrap_abstract(stream); | ||||||
|  |     janet_table_put(&watcher->watch_descriptors, pathv, streamv); | ||||||
|  |     janet_table_put(&watcher->watch_descriptors, streamv, pathv); | ||||||
|  |     /* TODO - if listening, also listen for this new path */ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void janet_watcher_remove(JanetWatcher *watcher, const char *path) { | ||||||
|  |     Janet pathv = janet_cstringv(path); | ||||||
|  |     Janet streamv = janet_table_get(&watcher->watch_descriptors, pathv); | ||||||
|  |     if (janet_checktype(streamv, JANET_NIL)) { | ||||||
|  |         janet_panicf("path %v is not being watched", pathv); | ||||||
|  |     } | ||||||
|  |     janet_table_remove(&watcher->watch_descriptors, pathv); | ||||||
|  |     janet_table_remove(&watcher->watch_descriptors, streamv); | ||||||
|  |     OverlappedWatch *ow = janet_unwrap_abstract(streamv); | ||||||
|  |     janet_stream_close((JanetStream *) ow); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void watcher_callback_read(JanetFiber *fiber, JanetAsyncEvent event) { | ||||||
|  |     JanetWatcher *watcher = (JanetWatcher *) fiber->ev_state; | ||||||
|  |     char buf[1024]; | ||||||
|  |     switch (event) { | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |         case JANET_ASYNC_EVENT_MARK: | ||||||
|  |             janet_mark(janet_wrap_abstract(watcher)); | ||||||
|  |             break; | ||||||
|  |         case JANET_ASYNC_EVENT_CLOSE: | ||||||
|  |             janet_schedule(fiber, janet_wrap_nil()); | ||||||
|  |             fiber->ev_state = NULL; | ||||||
|  |             janet_async_end(fiber); | ||||||
|  |             break; | ||||||
|  |         case JANET_ASYNC_EVENT_ERR: | ||||||
|  |             { | ||||||
|  |                 janet_schedule(fiber, janet_wrap_nil()); | ||||||
|  |                 fiber->ev_state = NULL; | ||||||
|  |                 janet_async_end(fiber); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void janet_watcher_listen(JanetWatcher *watcher) { | ||||||
|  |     for (int32_t i = 0; i < watcher.watch_descriptors.capacity; i++) { | ||||||
|  |         const JanetKV *kv = watcher.watch_descriptors.items + i; | ||||||
|  |         if (!janet_checktype(kv->key, JANET_POINTER)) continue; | ||||||
|  |         OverlappedWatch *ow = janet_unwrap_pointer(kv->key); | ||||||
|  |         Janet pathv = kv->value; | ||||||
|  |         BOOL result = ReadDirecoryChangesW(ow->handle, | ||||||
|  |                 &ow->fni, | ||||||
|  |                 sizeof(FILE_NOTIFY_INFORMATION), | ||||||
|  |                 TRUE, | ||||||
|  |                 ow->flags, | ||||||
|  |                 NULL, | ||||||
|  |                 &ow->overlapped, | ||||||
|  |                 NULL); | ||||||
|  |         if (!result) { | ||||||
|  |             janet_panicv(janet_ev_lasterr()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     janet_panic("nyi"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #else | ||||||
|  |  | ||||||
|  | /* Default implementation */ | ||||||
|  |  | ||||||
|  | static uint32_t decode_watch_flags(const Janet *options, int32_t n) { | ||||||
|  |     (void) options; | ||||||
|  |     (void) n; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void janet_watcher_init(JanetWatcher *watcher, JanetChannel *channel, uint32_t default_flags) { | ||||||
|  |     (void) watcher; | ||||||
|  |     (void) channel; | ||||||
|  |     (void) default_flags; | ||||||
|  |     janet_panic("filewatch not supported on this platform"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void janet_watcher_add(JanetWatcher *watcher, const char *path, uint32_t flags) { | ||||||
|  |     (void) watcher; | ||||||
|  |     (void) flags; | ||||||
|  |     (void) path; | ||||||
|  |     janet_panic("nyi"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void janet_watcher_remove(JanetWatcher *watcher, const char *path) { | ||||||
|  |     (void) watcher; | ||||||
|  |     (void) path; | ||||||
|  |     janet_panic("nyi"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void janet_watcher_listen(JanetWatcher *watcher) { | ||||||
|  |     (void) watcher; | ||||||
|  |     janet_panic("nyi"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
| /* C Functions */ | /* C Functions */ | ||||||
|  |  | ||||||
| static int janet_filewatch_mark(void *p, size_t s) { | static int janet_filewatch_mark(void *p, size_t s) { | ||||||
|     JanetWatcher *watcher = (JanetWatcher *) p; |     JanetWatcher *watcher = (JanetWatcher *) p; | ||||||
|     (void) s; |     (void) s; | ||||||
|  | #ifndef JANET_WINDOWS | ||||||
|     janet_mark(janet_wrap_abstract(watcher->stream)); |     janet_mark(janet_wrap_abstract(watcher->stream)); | ||||||
|  | #endif | ||||||
|     janet_mark(janet_wrap_abstract(watcher->channel)); |     janet_mark(janet_wrap_abstract(watcher->channel)); | ||||||
|     janet_mark(janet_wrap_table(watcher->watch_descriptors)); |     janet_mark(janet_wrap_table(&watcher->watch_descriptors)); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int janet_filewatch_gc(void *p, size_t s) { | ||||||
|  |     JanetWatcher *watcher = (JanetWatcher *) p; | ||||||
|  |     (void) s; | ||||||
|  |     janet_table_deinit(&watcher->watch_descriptors); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static const JanetAbstractType janet_filewatch_at = { | static const JanetAbstractType janet_filewatch_at = { | ||||||
|     "filewatch/watcher", |     "filewatch/watcher", | ||||||
|     NULL, |     janet_filewatch_gc, | ||||||
|     janet_filewatch_mark, |     janet_filewatch_mark, | ||||||
|     JANET_ATEND_GCMARK |     JANET_ATEND_GCMARK | ||||||
| }; | }; | ||||||
|  |  | ||||||
| JANET_CORE_FN(cfun_filewatch_make, | JANET_CORE_FN(cfun_filewatch_make, | ||||||
|         "(filewatch/make channel &opt default-flags)", |         "(filewatch/make channel &opt default-flags)", | ||||||
|         "Create a new filewatcher.") { |         "Create a new filewatcher that will give events to a channel channel.") { | ||||||
|     janet_arity(argc, 1, -1); |     janet_arity(argc, 1, -1); | ||||||
|     JanetChannel *channel = janet_getchannel(argv, 0); |     JanetChannel *channel = janet_getchannel(argv, 0); | ||||||
|     JanetWatcher *watcher = janet_abstract(&janet_filewatch_at, sizeof(JanetWatcher)); |     JanetWatcher *watcher = janet_abstract(&janet_filewatch_at, sizeof(JanetWatcher)); | ||||||
|     uint32_t default_flags = decode_inotify_flags(argv + 1, argc - 1); |     uint32_t default_flags = decode_watch_flags(argv + 1, argc - 1); | ||||||
|     janet_watcher_init(watcher, channel, default_flags); |     janet_watcher_init(watcher, channel, default_flags); | ||||||
|     return janet_wrap_abstract(watcher); |     return janet_wrap_abstract(watcher); | ||||||
| } | } | ||||||
| @@ -253,7 +455,7 @@ JANET_CORE_FN(cfun_filewatch_add, | |||||||
|     janet_arity(argc, 2, -1); |     janet_arity(argc, 2, -1); | ||||||
|     JanetWatcher *watcher = janet_getabstract(argv, 0, &janet_filewatch_at); |     JanetWatcher *watcher = janet_getabstract(argv, 0, &janet_filewatch_at); | ||||||
|     const char *path = janet_getcstring(argv, 1); |     const char *path = janet_getcstring(argv, 1); | ||||||
|     uint32_t flags = watcher->default_flags | decode_inotify_flags(argv + 2, argc - 2); |     uint32_t flags = watcher->default_flags | decode_watch_flags(argv + 2, argc - 2); | ||||||
|     janet_watcher_add(watcher, path, flags); |     janet_watcher_add(watcher, path, flags); | ||||||
|     return argv[0]; |     return argv[0]; | ||||||
| } | } | ||||||
| @@ -290,3 +492,4 @@ void janet_lib_filewatch(JanetTable *env) { | |||||||
| } | } | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  | #endif | ||||||
|   | |||||||
| @@ -190,9 +190,6 @@ void janet_lib_debug(JanetTable *env); | |||||||
| #ifdef JANET_PEG | #ifdef JANET_PEG | ||||||
| void janet_lib_peg(JanetTable *env); | void janet_lib_peg(JanetTable *env); | ||||||
| #endif | #endif | ||||||
| #ifdef JANET_TYPED_ARRAY |  | ||||||
| void janet_lib_typed_array(JanetTable *env); |  | ||||||
| #endif |  | ||||||
| #ifdef JANET_INT_TYPES | #ifdef JANET_INT_TYPES | ||||||
| void janet_lib_inttypes(JanetTable *env); | void janet_lib_inttypes(JanetTable *env); | ||||||
| #endif | #endif | ||||||
| @@ -204,10 +201,12 @@ extern const JanetAbstractType janet_address_type; | |||||||
| void janet_lib_ev(JanetTable *env); | void janet_lib_ev(JanetTable *env); | ||||||
| void janet_ev_mark(void); | void janet_ev_mark(void); | ||||||
| int janet_make_pipe(JanetHandle handles[2], int mode); | int janet_make_pipe(JanetHandle handles[2], int mode); | ||||||
|  | #ifdef JANET_FILEWATCH | ||||||
| void janet_lib_filewatch(JanetTable *env); | void janet_lib_filewatch(JanetTable *env); | ||||||
| #endif | #endif | ||||||
| #ifdef JANET_FFI | #ifdef JANET_FFI | ||||||
| void janet_lib_ffi(JanetTable *env); | void janet_lib_ffi(JanetTable *env); | ||||||
| #endif | #endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -210,6 +210,11 @@ extern "C" { | |||||||
| #define JANET_EV | #define JANET_EV | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | /* Enable or disable the filewatch/ module */ | ||||||
|  | #if !defined(JANET_NO_FILEWATCH) | ||||||
|  | #define JANET_FILEWATCH | ||||||
|  | #endif | ||||||
|  |  | ||||||
| /* Enable or disable networking */ | /* Enable or disable networking */ | ||||||
| #if defined(JANET_EV) && !defined(JANET_NO_NET) && !defined(__EMSCRIPTEN__) | #if defined(JANET_EV) && !defined(JANET_NO_NET) && !defined(__EMSCRIPTEN__) | ||||||
| #define JANET_NET | #define JANET_NET | ||||||
| @@ -1414,6 +1419,7 @@ JANET_API void janet_loop1_interrupt(JanetVM *vm); | |||||||
|  |  | ||||||
| /* Wrapper around streams */ | /* Wrapper around streams */ | ||||||
| JANET_API JanetStream *janet_stream(JanetHandle handle, uint32_t flags, const JanetMethod *methods); | JANET_API JanetStream *janet_stream(JanetHandle handle, uint32_t flags, const JanetMethod *methods); | ||||||
|  | JANET_API JanetStream *janet_stream_ext(JanetHandle handle, uint32_t flags, const JanetMethod *methods, size_t size); /* Allow for type punning streams */ | ||||||
| JANET_API void janet_stream_close(JanetStream *stream); | JANET_API void janet_stream_close(JanetStream *stream); | ||||||
| JANET_API Janet janet_cfun_stream_close(int32_t argc, Janet *argv); | JANET_API Janet janet_cfun_stream_close(int32_t argc, Janet *argv); | ||||||
| JANET_API Janet janet_cfun_stream_read(int32_t argc, Janet *argv); | JANET_API Janet janet_cfun_stream_read(int32_t argc, Janet *argv); | ||||||
| @@ -1445,6 +1451,8 @@ JANET_API int32_t janet_abstract_incref(void *abst); | |||||||
| JANET_API int32_t janet_abstract_decref(void *abst); | JANET_API int32_t janet_abstract_decref(void *abst); | ||||||
|  |  | ||||||
| /* Expose channel utilities */ | /* Expose channel utilities */ | ||||||
|  | JanetChannel *janet_channel_make(uint32_t limit); | ||||||
|  | JanetChannel *janet_channel_make_threaded(uint32_t limit); | ||||||
| JanetChannel *janet_getchannel(const Janet *argv, int32_t n); | JanetChannel *janet_getchannel(const Janet *argv, int32_t n); | ||||||
| JanetChannel *janet_optchannel(const Janet *argv, int32_t argc, int32_t n, JanetChannel *dflt); | JanetChannel *janet_optchannel(const Janet *argv, int32_t argc, int32_t n, JanetChannel *dflt); | ||||||
| JANET_API int janet_channel_give(JanetChannel *channel, Janet x); | JANET_API int janet_channel_give(JanetChannel *channel, Janet x); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose