summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile36
-rw-r--r--src/dged/display.c10
-rw-r--r--src/dged/reactor-kqueue.c112
-rw-r--r--src/dged/text.c4
-rw-r--r--src/main/main.c32
5 files changed, 162 insertions, 32 deletions
diff --git a/Makefile b/Makefile
index be3022e..926487c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,11 @@
-# Makefile for bmake
+# Makefile for bmake/openbsd make
+
+default: dged
+
.PHONY: default clean check run debug debug-tests install format
.OBJDIR: ./build
SYNTAX_ENABLE ?= true
-default: dged
-
build:
mkdir -p build
@@ -35,7 +36,10 @@ datadir = share/dged
.SUFFIXES:
.SUFFIXES: .c .o .d
-CFLAGS += -Werror -g -O2 -std=c99 -I $(.CURDIR)/src -I $(.CURDIR)/src/main -DDATADIR="$(prefix)/$(datadir)"
+CFLAGS += -Werror -g -O2 -std=c99 \
+ -I $(.CURDIR)/src \
+ -I $(.CURDIR)/src/main \
+ -DDATADIR="$(prefix)/$(datadir)"
ASAN ?= false
@@ -69,7 +73,13 @@ PLATFORM_OBJS = $(PLATFORM_SOURCES:.c=.o)
MAIN_OBJS = $(MAIN_SOURCES:.c=.o)
TEST_OBJS = $(TEST_SOURCES:.c=.o)
-FILES = $(DEPS) $(MAIN_OBJS) $(OBJS) dged libdged.a $(TEST_OBJS) $(PLATFORM_OBJS)
+FILES = $(DEPS) \
+ $(MAIN_OBJS) \
+ $(OBJS) \
+ $(TEST_OBJS) \
+ $(PLATFORM_OBJS) \
+ dged \
+ libdged.a
# dependency generation
.c.d:
@@ -101,7 +111,12 @@ run-tests: $(TEST_OBJS) $(OBJS)
$(CC) $(LDFLAGS) $(TEST_OBJS) $(OBJS) -lm -o run-tests
check: run-tests
- $(FORMAT_TOOL) --dry-run --Werror $(SOURCES:%.c=../%.c) $(MAIN_SOURCES:%.c=../%.c) $(TEST_SOURCES:%c=../%c) $(HEADERS:%.h=../%.h)
+ $(FORMAT_TOOL) --dry-run --Werror \
+ $(SOURCES:%.c=../%.c) \
+ $(PLATFORM_SOURCES:%.c=../%.c) \
+ $(MAIN_SOURCES:%.c=../%.c) \
+ $(TEST_SOURCES:%c=../%c) \
+ $(HEADERS:%.h=../%.h)
./run-tests
run: dged
@@ -114,7 +129,12 @@ debug-tests: run-tests
gdb ./run-tests
format:
- $(FORMAT_TOOL) -i $(SOURCES:%.c=../%.c) $(MAIN_SOURCES:%.c=../%.c) $(TEST_SOURCES:%c=../%c) $(HEADERS:%.h=../%.h)
+ $(FORMAT_TOOL) -i \
+ $(SOURCES:%.c=../%.c) \
+ $(MAIN_SOURCES:%.c=../%.c) \
+ $(PLATFORM_SOURCES:%.c=../%.c) \
+ $(TEST_SOURCES:%c=../%c) \
+ $(HEADERS:%.h=../%.h)
clean:
rm -f $(FILES)
@@ -129,7 +149,7 @@ install: dged
install -m 644 $(.CURDIR)/dged.1 $(DESTDIR)/share/man/man1/dged.1
install -d $(DESTDIR)/$(datadir)/grammars
- cp -rL $(.OBJDIR)/grammars "$(DESTDIR)/$(datadir)/"
+ cp -RL $(.OBJDIR)/grammars "$(DESTDIR)/$(datadir)/"
docs:
doxygen $(.CURDIR)/Doxyfile
diff --git a/src/dged/display.c b/src/dged/display.c
index ed6fc00..675140a 100644
--- a/src/dged/display.c
+++ b/src/dged/display.c
@@ -99,13 +99,17 @@ struct display *display_create() {
// save old settings
struct termios orig_term;
- tcgetattr(0, &orig_term);
+ if (tcgetattr(0, &orig_term) < 0) {
+ return NULL;
+ }
// set terminal to raw mode
- struct termios term = {0};
+ struct termios term = orig_term;
cfmakeraw(&term);
- tcsetattr(0, TCSADRAIN, &term);
+ if (tcsetattr(0, TCSADRAIN, &term) < 0) {
+ return NULL;
+ }
struct display *d = calloc(1, sizeof(struct display));
d->orig_term = orig_term;
diff --git a/src/dged/reactor-kqueue.c b/src/dged/reactor-kqueue.c
index 5543c04..58ab7af 100644
--- a/src/dged/reactor-kqueue.c
+++ b/src/dged/reactor-kqueue.c
@@ -1,45 +1,141 @@
#include "reactor.h"
+#include <errno.h>
+#include <fcntl.h>
#include <stdlib.h>
+#include <string.h>
+#include <sys/event.h>
+#include <sys/types.h>
+#include <unistd.h>
-struct reactor {
+#include "minibuffer.h"
+struct reactor {
+ int queue;
+ struct kevent events[16];
+ uint32_t nevents;
};
struct reactor *reactor_create() {
- struct reactor *reactor = calloc(1, sizeof(struct reactor));
+ int queue = kqueue();
+ if (queue < 0) {
+ return NULL;
+ }
+ struct reactor *reactor = calloc(1, sizeof(struct reactor));
+ reactor->queue = queue;
+ reactor->nevents = 0;
return reactor;
}
void reactor_destroy(struct reactor *reactor) {
+ close(reactor->queue);
+ reactor->queue = -1;
free(reactor);
}
void reactor_update(struct reactor *reactor) {
+ int events = kevent(reactor->queue, NULL, 0, reactor->events, 16, NULL);
+ if (events == -1) {
+ // TODO: what to do here?
+ return;
+ }
+ reactor->nevents = events;
}
bool reactor_poll_event(struct reactor *reactor, uint32_t ev_id) {
+ for (uint32_t ei = 0; ei < reactor->nevents; ++ei) {
+ struct kevent *ev = &reactor->events[ei];
+
+ if (ev->ident == ev_id) {
+ return true;
+ }
+ }
+
return false;
}
-uint32_t reactor_register_interest(struct reactor *reactor, int fd, enum interest interest) {
- return -1;
+uint32_t reactor_register_interest(struct reactor *reactor, int fd,
+ enum interest interest) {
+ struct kevent changes[2] = {0};
+ uint32_t nchanges = 0;
+
+ if ((interest & ReadInterest) != 0) {
+ EV_SET(&changes[0], fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
+ ++nchanges;
+ }
+
+ if ((interest & WriteInterest) != 0) {
+ EV_SET(&changes[1], fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
+ ++nchanges;
+ }
+
+ if (kevent(reactor->queue, changes, nchanges, NULL, 0, NULL) < 0) {
+ return -1;
+ }
+
+ return fd;
}
-uint32_t reactor_watch_file(struct reactor *reactor, const char *path, uint32_t mask) {
- return -1;
+uint32_t reactor_watch_file(struct reactor *reactor, const char *path,
+ uint32_t mask) {
+
+ uint32_t fflags = NOTE_WRITE | NOTE_DELETE | NOTE_RENAME | NOTE_REVOKE;
+ int fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ minibuffer_echo_timeout(4, "failed to watch %s: %s", path, strerror(errno));
+ return 0;
+ }
+
+ struct kevent new_event;
+ EV_SET(&new_event, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR | EV_ENABLE, fflags, 0,
+ NULL);
+ if (kevent(reactor->queue, &new_event, 1, NULL, 0, NULL) < 0) {
+ return 0;
+ }
+
+ return fd;
}
void reactor_unwatch_file(struct reactor *reactor, uint32_t id) {
-
+ // all kevents for this fd are removed automatically when closed
+ close(id);
}
bool reactor_next_file_event(struct reactor *reactor, struct file_event *out) {
- return false;
+
+ // find the next vnode event and pop it from the events
+ struct kevent ev;
+ bool found = false;
+ for (uint32_t e = 0; e < reactor->nevents; ++e) {
+ if (reactor->events[e].filter == EVFILT_VNODE) {
+ ev = reactor->events[e];
+ reactor->events[e] = reactor->events[reactor->nevents - 1];
+ --reactor->nevents;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ return false;
+ }
+
+ out->mask = FileWritten;
+ if ((ev.fflags & NOTE_DELETE) || (ev.fflags & NOTE_RENAME) ||
+ (ev.fflags & NOTE_REVOKE)) {
+ out->mask |= LastEvent;
+ }
+
+ out->id = ev.ident;
+ return true;
}
void reactor_unregister_interest(struct reactor *reactor, uint32_t ev_id) {
+ struct kevent changes[2] = {0};
+ EV_SET(&changes[0], ev_id, EVFILT_READ, EV_DELETE, 0, 0, NULL);
+ EV_SET(&changes[1], ev_id, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
+ kevent(reactor->queue, changes, 2, NULL, 0, NULL);
}
diff --git a/src/dged/text.c b/src/dged/text.c
index 82c49bc..3d1078f 100644
--- a/src/dged/text.c
+++ b/src/dged/text.c
@@ -389,8 +389,8 @@ void text_delete(struct text *text, uint32_t start_line, uint32_t start_col,
// in this case we can "overwrite"
uint32_t dstbytei =
utf8_nbytes(firstline->data, firstline->nbytes, start_col);
- memcpy(firstline->data + dstbytei, lastline->data + bytei,
- lastline->nbytes - bytei);
+ memmove(firstline->data + dstbytei, lastline->data + bytei,
+ lastline->nbytes - bytei);
} else {
// otherwise we actually have to copy from the last line
insert_at(text, start_line, start_col, lastline->data + bytei,
diff --git a/src/main/main.c b/src/main/main.c
index b0e408d..169716d 100644
--- a/src/main/main.c
+++ b/src/main/main.c
@@ -1,3 +1,4 @@
+#include <errno.h>
#include <getopt.h>
#include <locale.h>
#include <signal.h>
@@ -93,17 +94,7 @@ void reload_buffer(struct buffer *buffer) {
}
void update_file_watches(struct reactor *reactor) {
- // first, find invalid file watches and try to update them
- VEC_FOR_EACH(&g_watched_files, struct watched_file * w) {
- if (w->watch_id == INVALID_WATCH) {
- message("re-watching: %s", w->buffer->filename);
- w->watch_id =
- reactor_watch_file(reactor, w->buffer->filename, FileWritten);
- reload_buffer(w->buffer);
- }
- }
-
- // then pick up any events we might have
+ // first, pick up any events we might have
struct file_event ev;
while (reactor_next_file_event(reactor, &ev)) {
// find the buffer we need to reload
@@ -120,6 +111,16 @@ void update_file_watches(struct reactor *reactor) {
}
}
}
+
+ // then, find invalid file watches and try to update them
+ VEC_FOR_EACH(&g_watched_files, struct watched_file * w) {
+ if (w->watch_id == INVALID_WATCH) {
+ message("re-watching: %s", w->buffer->filename);
+ w->watch_id =
+ reactor_watch_file(reactor, w->buffer->filename, FileWritten);
+ reload_buffer(w->buffer);
+ }
+ }
}
static void usage() {
@@ -218,8 +219,17 @@ int main(int argc, char *argv[]) {
frame_allocator = frame_allocator_create(16 * 1024 * 1024);
struct reactor *reactor = reactor_create();
+ if (reactor == NULL) {
+ fprintf(stderr, "Failed to create event reactor: %s\n", strerror(errno));
+ return 8;
+ }
display = display_create();
+ if (display == NULL) {
+ fprintf(stderr, "Failed to set up display: %s\n", strerror(errno));
+ return 9;
+ }
+
display_clear(display);
signal(SIGWINCH, resized);