1#include "api.h"
2#include <SDL.h>
3#include <stdlib.h>
4#include <string.h>
5#include <stdbool.h>
6
7static unsigned int DIR_EVENT_TYPE = 0;
8
9struct dirmonitor {
10 SDL_Thread* thread;
11 SDL_mutex* mutex;
12 char buffer[64512];
13 volatile int length;
14 struct dirmonitor_internal* internal;
15};
16
17
18struct dirmonitor_internal* init_dirmonitor();
19void deinit_dirmonitor(struct dirmonitor_internal*);
20int get_changes_dirmonitor(struct dirmonitor_internal*, char*, int);
21int translate_changes_dirmonitor(struct dirmonitor_internal*, char*, int, int (*)(int, const char*, void*), void*);
22int add_dirmonitor(struct dirmonitor_internal*, const char*);
23void remove_dirmonitor(struct dirmonitor_internal*, int);
24int get_mode_dirmonitor();
25
26
27static int f_check_dir_callback(int watch_id, const char* path, void* L) {
28 lua_pushvalue(L, -1);
29 if (path)
30 lua_pushlstring(L, path, watch_id);
31 else
32 lua_pushnumber(L, watch_id);
33 lua_call(L, 1, 1);
34 int result = lua_toboolean(L, -1);
35 lua_pop(L, 1);
36 return !result;
37}
38
39
40static int dirmonitor_check_thread(void* data) {
41 struct dirmonitor* monitor = data;
42 while (monitor->length >= 0) {
43 if (monitor->length == 0) {
44 int result = get_changes_dirmonitor(monitor->internal, monitor->buffer, sizeof(monitor->buffer));
45 SDL_LockMutex(monitor->mutex);
46 if (monitor->length == 0)
47 monitor->length = result;
48 SDL_UnlockMutex(monitor->mutex);
49 }
50 SDL_Delay(1);
51 SDL_Event event = { .type = DIR_EVENT_TYPE };
52 SDL_PushEvent(&event);
53 }
54 return 0;
55}
56
57
58static int f_dirmonitor_new(lua_State* L) {
59 if (DIR_EVENT_TYPE == 0)
60 DIR_EVENT_TYPE = SDL_RegisterEvents(1);
61 struct dirmonitor* monitor = lua_newuserdata(L, sizeof(struct dirmonitor));
62 luaL_setmetatable(L, API_TYPE_DIRMONITOR);
63 memset(monitor, 0, sizeof(struct dirmonitor));
64 monitor->mutex = SDL_CreateMutex();
65 monitor->internal = init_dirmonitor();
66 return 1;
67}
68
69
70static int f_dirmonitor_gc(lua_State* L) {
71 struct dirmonitor* monitor = luaL_checkudata(L, 1, API_TYPE_DIRMONITOR);
72 SDL_LockMutex(monitor->mutex);
73 monitor->length = -1;
74 deinit_dirmonitor(monitor->internal);
75 SDL_UnlockMutex(monitor->mutex);
76 SDL_WaitThread(monitor->thread, NULL);
77 free(monitor->internal);
78 SDL_DestroyMutex(monitor->mutex);
79 return 0;
80}
81
82
83static int f_dirmonitor_watch(lua_State *L) {
84 struct dirmonitor* monitor = luaL_checkudata(L, 1, API_TYPE_DIRMONITOR);
85 lua_pushnumber(L, add_dirmonitor(monitor->internal, luaL_checkstring(L, 2)));
86 if (!monitor->thread)
87 monitor->thread = SDL_CreateThread(dirmonitor_check_thread, "dirmonitor_check_thread", monitor);
88 return 1;
89}
90
91
92static int f_dirmonitor_unwatch(lua_State *L) {
93 remove_dirmonitor(((struct dirmonitor*)luaL_checkudata(L, 1, API_TYPE_DIRMONITOR))->internal, lua_tonumber(L, 2));
94 return 0;
95}
96
97
98static int f_dirmonitor_check(lua_State* L) {
99 struct dirmonitor* monitor = luaL_checkudata(L, 1, API_TYPE_DIRMONITOR);
100 SDL_LockMutex(monitor->mutex);
101 if (monitor->length < 0)
102 lua_pushnil(L);
103 else if (monitor->length > 0) {
104 if (translate_changes_dirmonitor(monitor->internal, monitor->buffer, monitor->length, f_check_dir_callback, L) == 0)
105 monitor->length = 0;
106 lua_pushboolean(L, 1);
107 } else
108 lua_pushboolean(L, 0);
109 SDL_UnlockMutex(monitor->mutex);
110 return 1;
111}
112
113
114static int f_dirmonitor_mode(lua_State* L) {
115 int mode = get_mode_dirmonitor();
116 if (mode == 1)
117 lua_pushstring(L, "single");
118 else
119 lua_pushstring(L, "multiple");
120 return 1;
121}
122
123
124static const luaL_Reg dirmonitor_lib[] = {
125 { "new", f_dirmonitor_new },
126 { "__gc", f_dirmonitor_gc },
127 { "watch", f_dirmonitor_watch },
128 { "unwatch", f_dirmonitor_unwatch },
129 { "check", f_dirmonitor_check },
130 { "mode", f_dirmonitor_mode },
131 {NULL, NULL}
132};
133
134
135int luaopen_dirmonitor(lua_State* L) {
136 luaL_newmetatable(L, API_TYPE_DIRMONITOR);
137 luaL_setfuncs(L, dirmonitor_lib, 0);
138 lua_pushvalue(L, -1);
139 lua_setfield(L, -2, "__index");
140 return 1;
141}
142