Fix Project Scanning (#746)
Removed dmon, and replaced with logic that works across Linux, Mac, FreeBSD and Windows. Have tested on all platforms, and seems to work. Co-authored-by: Jan200101 <sentrycraft123@gmail.com>
This commit is contained in:
+8
-5
@@ -1,20 +1,23 @@
|
||||
#include "api.h"
|
||||
|
||||
|
||||
int luaopen_system(lua_State *L);
|
||||
int luaopen_renderer(lua_State *L);
|
||||
int luaopen_regex(lua_State *L);
|
||||
int luaopen_process(lua_State *L);
|
||||
int luaopen_dirmonitor(lua_State* L);
|
||||
|
||||
static const luaL_Reg libs[] = {
|
||||
{ "system", luaopen_system },
|
||||
{ "renderer", luaopen_renderer },
|
||||
{ "regex", luaopen_regex },
|
||||
{ "process", luaopen_process },
|
||||
{ "system", luaopen_system },
|
||||
{ "renderer", luaopen_renderer },
|
||||
{ "regex", luaopen_regex },
|
||||
{ "process", luaopen_process },
|
||||
{ "dirmonitor", luaopen_dirmonitor },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
void api_load_libs(lua_State *L) {
|
||||
for (int i = 0; libs[i].name; i++)
|
||||
luaL_requiref(L, libs[i].name, libs[i].func, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#define API_TYPE_FONT "Font"
|
||||
#define API_TYPE_PROCESS "Process"
|
||||
#define API_TYPE_DIRMONITOR "Dirmonitor"
|
||||
|
||||
#define API_CONSTANT_DEFINE(L, idx, key, n) (lua_pushnumber(L, n), lua_setfield(L, idx - 1, key))
|
||||
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
#include "api.h"
|
||||
#include <stdlib.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#elif __linux__
|
||||
#include <sys/inotify.h>
|
||||
#include <limits.h>
|
||||
#else
|
||||
#include <sys/event.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*
|
||||
This is *slightly* a clusterfuck. Normally, we'd
|
||||
have windows wait on a list of handles like inotify,
|
||||
however, MAXIMUM_WAIT_OBJECTS is 64. Yes, seriously.
|
||||
|
||||
So, for windows, we are recursive.
|
||||
*/
|
||||
struct dirmonitor {
|
||||
int fd;
|
||||
#if _WIN32
|
||||
HANDLE handle;
|
||||
char buffer[8192];
|
||||
OVERLAPPED overlapped;
|
||||
bool running;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct dirmonitor* init_dirmonitor() {
|
||||
struct dirmonitor* monitor = calloc(sizeof(struct dirmonitor), 1);
|
||||
#ifndef _WIN32
|
||||
#if __linux__
|
||||
monitor->fd = inotify_init1(IN_NONBLOCK);
|
||||
#else
|
||||
monitor->fd = kqueue();
|
||||
#endif
|
||||
#endif
|
||||
return monitor;
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
static void close_monitor_handle(struct dirmonitor* monitor) {
|
||||
if (monitor->handle) {
|
||||
if (monitor->running) {
|
||||
BOOL result = CancelIoEx(monitor->handle, &monitor->overlapped);
|
||||
DWORD error = GetLastError();
|
||||
if (result == TRUE || error != ERROR_NOT_FOUND) {
|
||||
DWORD bytes_transferred;
|
||||
GetOverlappedResult( monitor->handle, &monitor->overlapped, &bytes_transferred, TRUE );
|
||||
}
|
||||
monitor->running = false;
|
||||
}
|
||||
CloseHandle(monitor->handle);
|
||||
}
|
||||
monitor->handle = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
void deinit_dirmonitor(struct dirmonitor* monitor) {
|
||||
#if _WIN32
|
||||
close_monitor_handle(monitor);
|
||||
#else
|
||||
close(monitor->fd);
|
||||
#endif
|
||||
free(monitor);
|
||||
}
|
||||
|
||||
int check_dirmonitor(struct dirmonitor* monitor, int (*change_callback)(int, const char*, void*), void* data) {
|
||||
#if _WIN32
|
||||
if (!monitor->running) {
|
||||
if (ReadDirectoryChangesW(monitor->handle, monitor->buffer, sizeof(monitor->buffer), TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME, NULL, &monitor->overlapped, NULL) == 0)
|
||||
return GetLastError();
|
||||
monitor->running = true;
|
||||
}
|
||||
DWORD bytes_transferred;
|
||||
if (!GetOverlappedResult(monitor->handle, &monitor->overlapped, &bytes_transferred, FALSE)) {
|
||||
int error = GetLastError();
|
||||
return error == ERROR_IO_PENDING || error == ERROR_IO_INCOMPLETE ? 0 : error;
|
||||
}
|
||||
monitor->running = false;
|
||||
for (FILE_NOTIFY_INFORMATION* info = (FILE_NOTIFY_INFORMATION*)monitor->buffer; (char*)info < monitor->buffer + sizeof(monitor->buffer); info = (FILE_NOTIFY_INFORMATION*)((char*)info) + info->NextEntryOffset) {
|
||||
change_callback(info->FileNameLength, (char*)info->FileName, data);
|
||||
if (!info->NextEntryOffset)
|
||||
break;
|
||||
}
|
||||
monitor->running = false;
|
||||
return 0;
|
||||
#elif __linux__
|
||||
char buf[PATH_MAX + sizeof(struct inotify_event)];
|
||||
while (1) {
|
||||
ssize_t len = read(monitor->fd, buf, sizeof(buf));
|
||||
if (len == -1 && errno != EAGAIN)
|
||||
return errno;
|
||||
if (len <= 0)
|
||||
return 0;
|
||||
for (char *ptr = buf; ptr < buf + len; ptr += sizeof(struct inotify_event) + ((struct inotify_event*)ptr)->len)
|
||||
change_callback(((const struct inotify_event *) ptr)->wd, NULL, data);
|
||||
}
|
||||
#else
|
||||
struct kevent event;
|
||||
while (1) {
|
||||
struct timespec tm = {0};
|
||||
int nev = kevent(monitor->fd, NULL, 0, &event, 1, &tm);
|
||||
if (nev == -1)
|
||||
return errno;
|
||||
if (nev <= 0)
|
||||
return 0;
|
||||
change_callback(event.ident, NULL, data);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int add_dirmonitor(struct dirmonitor* monitor, const char* path) {
|
||||
#if _WIN32
|
||||
close_monitor_handle(monitor);
|
||||
monitor->handle = CreateFileA(path, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
|
||||
if (monitor->handle && monitor->handle != INVALID_HANDLE_VALUE)
|
||||
return 1;
|
||||
monitor->handle = NULL;
|
||||
return -1;
|
||||
#elif __linux__
|
||||
return inotify_add_watch(monitor->fd, path, IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO);
|
||||
#else
|
||||
int fd = open(path, O_RDONLY);
|
||||
struct kevent change;
|
||||
EV_SET(&change, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_LINK | NOTE_RENAME, 0, (void*)path);
|
||||
kevent(monitor->fd, &change, 1, NULL, 0, NULL);
|
||||
return fd;
|
||||
#endif
|
||||
}
|
||||
|
||||
void remove_dirmonitor(struct dirmonitor* monitor, int fd) {
|
||||
#if _WIN32
|
||||
close_monitor_handle(monitor);
|
||||
#elif __linux__
|
||||
inotify_rm_watch(monitor->fd, fd);
|
||||
#else
|
||||
close(fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int f_check_dir_callback(int watch_id, const char* path, void* L) {
|
||||
#if _WIN32
|
||||
char buffer[PATH_MAX*4];
|
||||
int count = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)path, watch_id, buffer, PATH_MAX*4 - 1, NULL, NULL);
|
||||
lua_pushlstring(L, buffer, count);
|
||||
#else
|
||||
lua_pushnumber(L, watch_id);
|
||||
#endif
|
||||
lua_pcall(L, 1, 1, 0);
|
||||
int result = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return !result;
|
||||
}
|
||||
|
||||
static int f_dirmonitor_new(lua_State* L) {
|
||||
struct dirmonitor** monitor = lua_newuserdata(L, sizeof(struct dirmonitor**));
|
||||
*monitor = init_dirmonitor();
|
||||
luaL_setmetatable(L, API_TYPE_DIRMONITOR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_dirmonitor_gc(lua_State* L) {
|
||||
deinit_dirmonitor(*((struct dirmonitor**)luaL_checkudata(L, 1, API_TYPE_DIRMONITOR)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int f_dirmonitor_watch(lua_State *L) {
|
||||
lua_pushnumber(L, add_dirmonitor(*(struct dirmonitor**)luaL_checkudata(L, 1, API_TYPE_DIRMONITOR), luaL_checkstring(L, 2)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_dirmonitor_unwatch(lua_State *L) {
|
||||
remove_dirmonitor(*(struct dirmonitor**)luaL_checkudata(L, 1, API_TYPE_DIRMONITOR), luaL_checknumber(L, 2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int f_dirmonitor_check(lua_State* L) {
|
||||
lua_pushnumber(L, check_dirmonitor(*(struct dirmonitor**)luaL_checkudata(L, 1, API_TYPE_DIRMONITOR), f_check_dir_callback, L));
|
||||
return 1;
|
||||
}
|
||||
static const luaL_Reg dirmonitor_lib[] = {
|
||||
{ "new", f_dirmonitor_new },
|
||||
{ "__gc", f_dirmonitor_gc },
|
||||
{ "watch", f_dirmonitor_watch },
|
||||
{ "unwatch", f_dirmonitor_unwatch },
|
||||
{ "check", f_dirmonitor_check },
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
int luaopen_dirmonitor(lua_State* L) {
|
||||
luaL_newmetatable(L, API_TYPE_DIRMONITOR);
|
||||
luaL_setfuncs(L, dirmonitor_lib, 0);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -2, "__index");
|
||||
return 1;
|
||||
}
|
||||
+19
-112
@@ -7,7 +7,6 @@
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include "api.h"
|
||||
#include "../dirmonitor.h"
|
||||
#include "../rencache.h"
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
@@ -255,26 +254,6 @@ top:
|
||||
lua_pushinteger(L, e.wheel.y);
|
||||
return 2;
|
||||
|
||||
case SDL_USEREVENT:
|
||||
lua_pushstring(L, "dirchange");
|
||||
lua_pushinteger(L, e.user.code >> 16);
|
||||
switch (e.user.code & 0xffff) {
|
||||
case DMON_ACTION_DELETE:
|
||||
lua_pushstring(L, "delete");
|
||||
break;
|
||||
case DMON_ACTION_CREATE:
|
||||
lua_pushstring(L, "create");
|
||||
break;
|
||||
case DMON_ACTION_MODIFY:
|
||||
lua_pushstring(L, "modify");
|
||||
break;
|
||||
default:
|
||||
return luaL_error(L, "unknown dmon event action: %d", e.user.code & 0xffff);
|
||||
}
|
||||
lua_pushstring(L, e.user.data1);
|
||||
free(e.user.data1);
|
||||
return 4;
|
||||
|
||||
default:
|
||||
goto top;
|
||||
}
|
||||
@@ -592,29 +571,27 @@ static struct f_type_names fs_names[] = {
|
||||
{ 0x0, NULL },
|
||||
};
|
||||
|
||||
static int f_get_fs_type(lua_State *L) {
|
||||
const char *path = luaL_checkstring(L, 1);
|
||||
struct statfs buf;
|
||||
int status = statfs(path, &buf);
|
||||
if (status != 0) {
|
||||
return luaL_error(L, "error calling statfs on %s", path);
|
||||
}
|
||||
for (int i = 0; fs_names[i].magic; i++) {
|
||||
if (fs_names[i].magic == buf.f_type) {
|
||||
lua_pushstring(L, fs_names[i].name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
lua_pushstring(L, "unknown");
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
static int f_return_unknown(lua_State *L) {
|
||||
lua_pushstring(L, "unknown");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int f_get_fs_type(lua_State *L) {
|
||||
#if __linux__
|
||||
const char *path = luaL_checkstring(L, 1);
|
||||
struct statfs buf;
|
||||
int status = statfs(path, &buf);
|
||||
if (status != 0) {
|
||||
return luaL_error(L, "error calling statfs on %s", path);
|
||||
}
|
||||
for (int i = 0; fs_names[i].magic; i++) {
|
||||
if (fs_names[i].magic == buf.f_type) {
|
||||
lua_pushstring(L, fs_names[i].name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
lua_pushstring(L, "unknown");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int f_mkdir(lua_State *L) {
|
||||
const char *path = luaL_checkstring(L, 1);
|
||||
@@ -815,66 +792,6 @@ static int f_load_native_plugin(lua_State *L) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static int f_watch_dir(lua_State *L) {
|
||||
const char *path = luaL_checkstring(L, 1);
|
||||
/* On linux we watch non-recursively and we add/remove each sub-directory explicitly
|
||||
* using the function system.watch_dir_add/rm. On other systems we watch recursively
|
||||
* and system.watch_dir_add/rm are dummy functions that always returns true. */
|
||||
#if __linux__
|
||||
const uint32_t dmon_flags = DMON_WATCHFLAGS_FOLLOW_SYMLINKS;
|
||||
#elif __APPLE__
|
||||
const uint32_t dmon_flags = DMON_WATCHFLAGS_FOLLOW_SYMLINKS | DMON_WATCHFLAGS_RECURSIVE;
|
||||
#else
|
||||
const uint32_t dmon_flags = DMON_WATCHFLAGS_RECURSIVE;
|
||||
#endif
|
||||
dmon_error error;
|
||||
dmon_watch_id watch_id = dmon_watch(path, dirmonitor_watch_callback, dmon_flags, NULL, &error);
|
||||
if (watch_id.id == 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, dmon_error_str(error));
|
||||
return 2;
|
||||
}
|
||||
lua_pushinteger(L, watch_id.id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_unwatch_dir(lua_State *L) {
|
||||
dmon_watch_id watch_id;
|
||||
watch_id.id = luaL_checkinteger(L, 1);
|
||||
dmon_unwatch(watch_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if __linux__
|
||||
static int f_watch_dir_add(lua_State *L) {
|
||||
dmon_watch_id watch_id;
|
||||
watch_id.id = luaL_checkinteger(L, 1);
|
||||
const char *subdir = luaL_checkstring(L, 2);
|
||||
dmon_error error_code;
|
||||
int success = dmon_watch_add(watch_id, subdir, &error_code);
|
||||
if (!success) {
|
||||
lua_pushboolean(L, 0);
|
||||
lua_pushstring(L, dmon_error_str(error_code));
|
||||
return 2;
|
||||
}
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int f_watch_dir_rm(lua_State *L) {
|
||||
dmon_watch_id watch_id;
|
||||
watch_id.id = luaL_checkinteger(L, 1);
|
||||
const char *subdir = luaL_checkstring(L, 2);
|
||||
lua_pushboolean(L, dmon_watch_rm(watch_id, subdir));
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
static int f_return_true(lua_State *L) {
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PATHSEP '\\'
|
||||
#else
|
||||
@@ -961,18 +878,8 @@ static const luaL_Reg lib[] = {
|
||||
{ "fuzzy_match", f_fuzzy_match },
|
||||
{ "set_window_opacity", f_set_window_opacity },
|
||||
{ "load_native_plugin", f_load_native_plugin },
|
||||
{ "watch_dir", f_watch_dir },
|
||||
{ "unwatch_dir", f_unwatch_dir },
|
||||
{ "path_compare", f_path_compare },
|
||||
#if __linux__
|
||||
{ "watch_dir_add", f_watch_dir_add },
|
||||
{ "watch_dir_rm", f_watch_dir_rm },
|
||||
{ "get_fs_type", f_get_fs_type },
|
||||
#else
|
||||
{ "watch_dir_add", f_return_true },
|
||||
{ "watch_dir_rm", f_return_true },
|
||||
{ "get_fs_type", f_return_unknown },
|
||||
#endif
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#define DMON_IMPL
|
||||
#include "dmon.h"
|
||||
#include "dmon_extra.h"
|
||||
|
||||
#include "dirmonitor.h"
|
||||
|
||||
static void send_sdl_event(dmon_watch_id watch_id, dmon_action action, const char *filepath) {
|
||||
SDL_Event ev;
|
||||
const int size = strlen(filepath) + 1;
|
||||
/* The string allocated below should be deallocated as soon as the event is
|
||||
treated in the SDL main loop. */
|
||||
char *new_filepath = malloc(size);
|
||||
if (!new_filepath) return;
|
||||
memcpy(new_filepath, filepath, size);
|
||||
#ifdef _WIN32
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (new_filepath[i] == '/') {
|
||||
new_filepath[i] = '\\';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
SDL_zero(ev);
|
||||
ev.type = SDL_USEREVENT;
|
||||
ev.user.code = ((watch_id.id & 0xffff) << 16) | (action & 0xffff);
|
||||
ev.user.data1 = new_filepath;
|
||||
SDL_PushEvent(&ev);
|
||||
}
|
||||
|
||||
void dirmonitor_init() {
|
||||
dmon_init();
|
||||
/* In theory we should register our user event but since we
|
||||
have just one type of user event this is not really needed. */
|
||||
/* sdl_dmon_event_type = SDL_RegisterEvents(1); */
|
||||
}
|
||||
|
||||
void dirmonitor_deinit() {
|
||||
dmon_deinit();
|
||||
}
|
||||
|
||||
void dirmonitor_watch_callback(dmon_watch_id watch_id, dmon_action action, const char *rootdir,
|
||||
const char *filepath, const char *oldfilepath, void *user)
|
||||
{
|
||||
(void) rootdir;
|
||||
(void) user;
|
||||
switch (action) {
|
||||
case DMON_ACTION_MOVE:
|
||||
send_sdl_event(watch_id, DMON_ACTION_DELETE, oldfilepath);
|
||||
send_sdl_event(watch_id, DMON_ACTION_CREATE, filepath);
|
||||
break;
|
||||
default:
|
||||
send_sdl_event(watch_id, action, filepath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#ifndef DIRMONITOR_H
|
||||
#define DIRMONITOR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "dmon.h"
|
||||
#include "dmon_extra.h"
|
||||
|
||||
void dirmonitor_init();
|
||||
void dirmonitor_deinit();
|
||||
void dirmonitor_watch_callback(dmon_watch_id watch_id, dmon_action action, const char *rootdir,
|
||||
const char *filepath, const char *oldfilepath, void *user);
|
||||
|
||||
#endif
|
||||
|
||||
+1
-6
@@ -7,15 +7,13 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#elif __linux__
|
||||
#elif __linux__ || __FreeBSD__
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#elif __APPLE__
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
|
||||
#include "dirmonitor.h"
|
||||
|
||||
|
||||
SDL_Window *window;
|
||||
|
||||
@@ -108,8 +106,6 @@ int main(int argc, char **argv) {
|
||||
SDL_DisplayMode dm;
|
||||
SDL_GetCurrentDisplayMode(0, &dm);
|
||||
|
||||
dirmonitor_init();
|
||||
|
||||
window = SDL_CreateWindow(
|
||||
"", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, dm.w * 0.8, dm.h * 0.8,
|
||||
SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN);
|
||||
@@ -192,7 +188,6 @@ init_lua:
|
||||
|
||||
lua_close(L);
|
||||
ren_free_window_resources();
|
||||
dirmonitor_deinit();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,10 +1,10 @@
|
||||
lite_sources = [
|
||||
'api/api.c',
|
||||
'api/dirmonitor.c',
|
||||
'api/renderer.c',
|
||||
'api/regex.c',
|
||||
'api/system.c',
|
||||
'api/process.c',
|
||||
'dirmonitor.c',
|
||||
'renderer.c',
|
||||
'renwindow.c',
|
||||
'rencache.c',
|
||||
|
||||
Reference in New Issue
Block a user