diff options
| -rw-r--r-- | editor.c | 2 | ||||
| -rw-r--r-- | editor.h | 4 | ||||
| -rw-r--r-- | text.c | 8 | ||||
| -rw-r--r-- | text.h | 3 | ||||
| -rw-r--r-- | vis.c | 35 |
5 files changed, 52 insertions, 0 deletions
@@ -358,6 +358,8 @@ void editor_window_close(Win *win) { ed->windows = win->next; if (ed->win == win) ed->win = win->next ? win->next : win->prev; + if (ed->prompt_window == win) + ed->prompt_window = NULL; window_free(win); if (ed->win) ed->ui->window_focus(ed->win->ui); @@ -5,6 +5,7 @@ #include <signal.h> #include <stddef.h> #include <stdbool.h> +#include <setjmp.h> typedef struct Editor Editor; typedef struct File File; @@ -190,6 +191,7 @@ enum Mark { struct File { Text *text; const char *name; + volatile sig_atomic_t truncated; bool is_stdin; struct stat stat; int refcount; @@ -244,6 +246,8 @@ struct Editor { Mode *mode_before_prompt; /* user mode which was active before entering prompt */ volatile bool running; /* exit main loop once this becomes false */ volatile sig_atomic_t cancel_filter; /* abort external command */ + volatile sig_atomic_t sigbus; + sigjmp_buf sigbus_jmpbuf; }; Editor *editor_new(Ui*); @@ -1185,6 +1185,14 @@ bool text_modified(Text *txt) { return txt->saved_action != txt->history; } +bool text_sigbus(Text *txt, const char *addr) { + for (Buffer *buf = txt->buffers; buf; buf = buf->next) { + if (buf->type == MMAP && buf->data <= addr && addr < buf->data + buf->size) + return true; + } + return false; +} + enum TextNewLine text_newline_type(Text *txt){ if (!txt->newlines) { txt->newlines = TEXT_NEWLINE_NL; /* default to UNIX style \n new lines */ @@ -108,6 +108,9 @@ size_t text_history_get(Text*, size_t index); size_t text_size(Text*); /* query whether the text contains any unsaved modifications */ bool text_modified(Text*); +/* query whether `addr` is part of a memory mapped region associated with + * this text instance */ +bool text_sigbus(Text*, const char *addr); /* which type of new lines does the text use? */ enum TextNewLine { @@ -2312,8 +2312,23 @@ static Key getkey(void) { return key; } +static void sigbus_handler(int sig, siginfo_t *siginfo, void *context) { + for (File *file = vis->files; file; file = file->next) { + if (text_sigbus(file->text, siginfo->si_addr)) + file->truncated = true; + } + vis->sigbus = true; + siglongjmp(vis->sigbus_jmpbuf, 1); +} + static void mainloop() { struct timespec idle = { .tv_nsec = 0 }, *timeout = NULL; + struct sigaction sa_sigbus; + memset(&sa_sigbus, 0, sizeof sa_sigbus); + sa_sigbus.sa_flags = SA_SIGINFO; + sa_sigbus.sa_sigaction = sigbus_handler; + if (sigaction(SIGBUS, &sa_sigbus, NULL)) + die("sigaction: %s", strerror(errno)); sigset_t emptyset, blockset; sigemptyset(&emptyset); sigemptyset(&blockset); @@ -2323,11 +2338,31 @@ static void mainloop() { editor_draw(vis); vis->running = true; + sigsetjmp(vis->sigbus_jmpbuf, 1); + while (vis->running) { fd_set fds; FD_ZERO(&fds); FD_SET(STDIN_FILENO, &fds); + if (vis->sigbus) { + char *name = NULL; + for (Win *next, *win = vis->windows; win; win = next) { + next = win->next; + if (win->file->truncated) { + free(name); + name = strdup(win->file->name); + editor_window_close(win); + } + } + if (!vis->windows) + die("WARNING: file `%s' truncated!\n", name ? name : "-"); + else + editor_info_show(vis, "WARNING: file `%s' truncated!\n", name ? name : "-"); + vis->sigbus = false; + free(name); + } + editor_update(vis); idle.tv_sec = vis->mode->idle_timeout; int r = pselect(1, &fds, NULL, NULL, timeout, &emptyset); |
