diff --git a/buffer.c b/buffer.c index 25cede6..c380d26 100644 --- a/buffer.c +++ b/buffer.c @@ -1,9 +1,6 @@ -#include "load-save.h" #include "buffer.h" -#include "window.h" #include "view.h" #include "editor.h" -#include "error.h" #include "change.h" #include "block.h" #include "move.h" @@ -143,7 +140,7 @@ char *get_word_under_cursor(void) return xstrslice(lr.line, si, ei); } -static struct buffer *buffer_new(const char *encoding) +struct buffer *buffer_new(const char *encoding) { static int id; struct buffer *b; @@ -212,7 +209,7 @@ static int same_file(const struct stat *a, const struct stat *b) return a->st_dev == b->st_dev && a->st_ino == b->st_ino; } -static struct buffer *find_buffer(const char *abs_filename) +struct buffer *find_buffer(const char *abs_filename) { struct stat st; bool st_ok = stat(abs_filename, &st) == 0; @@ -283,80 +280,6 @@ void update_short_filename(struct buffer *b) set_display_filename(b, short_filename(b->abs_filename)); } -struct view *open_buffer(const char *filename, bool must_exist, const char *encoding) -{ - char *absolute = path_absolute(filename); - bool dir_missing = false; - struct buffer *b = NULL; - - if (absolute == NULL) { - // Let load_buffer() create error message. - dir_missing = errno == ENOENT; - } else { - // already open? - b = find_buffer(absolute); - } - if (b) { - if (!streq(absolute, b->abs_filename)) { - char *s = short_filename(absolute); - info_msg("%s and %s are the same file", s, b->display_filename); - free(s); - } - free(absolute); - return window_get_view(window, b); - } - - /* - /proc/$PID/fd/ contains symbolic links to files that have been opened - by process $PID. Some of the files may have been deleted but can still - be opened using the symbolic link but not by using the absolute path. - - # create file - mkdir /tmp/x - echo foo > /tmp/x/file - - # in another shell: keep the file open - tail -f /tmp/x/file - - # make the absolute path unavailable - rm /tmp/x/file - rmdir /tmp/x - - # this should still succeed - dex /proc/$(pidof tail)/fd/3 - */ - b = buffer_new(encoding); - if (load_buffer(b, must_exist, filename)) { - free_buffer(b); - return NULL; - } - if (b->st.st_mode == 0 && dir_missing) { - // New file in non-existing directory. This is usually a mistake. - error_msg("Error opening %s: Directory does not exist", filename); - free_buffer(b); - return NULL; - } - b->abs_filename = absolute; - if (b->abs_filename == NULL) { - // FIXME: obviously wrong - b->abs_filename = xstrdup(filename); - } - update_short_filename(b); - - if (options.lock_files) { - if (lock_file(b->abs_filename)) { - b->ro = true; - } else { - b->locked = true; - } - } - if (b->st.st_mode != 0 && !b->ro && access(filename, W_OK)) { - error_msg("No write permission to %s, marking read-only.", filename); - b->ro = true; - } - return window_add_buffer(window, b); -} - void filetype_changed(void) { set_file_options(buffer); diff --git a/buffer.h b/buffer.h index 8c82844..29560ee 100644 --- a/buffer.h +++ b/buffer.h @@ -95,8 +95,9 @@ char *get_word_under_cursor(void); void update_short_filename_cwd(struct buffer *b, const char *cwd); void update_short_filename(struct buffer *b); +struct buffer *find_buffer(const char *abs_filename); struct buffer *find_buffer_by_id(unsigned int id); -struct view *open_buffer(const char *filename, bool must_exist, const char *encoding); +struct buffer *buffer_new(const char *encoding); struct buffer *open_empty_buffer(void); void setup_buffer(void); void free_buffer(struct buffer *b); diff --git a/file-location.c b/file-location.c index 1e6b588..8e6a4a9 100644 --- a/file-location.c +++ b/file-location.c @@ -47,7 +47,7 @@ bool file_location_equals(const struct file_location *a, const struct file_locat bool file_location_go(struct file_location *loc) { - struct view *v = open_buffer(loc->filename, true, NULL); + struct view *v = window_open_buffer(window, loc->filename, true, NULL); bool ok = true; if (!v) { @@ -85,7 +85,7 @@ bool file_location_return(struct file_location *loc) // Try again. return false; } - v = open_buffer(loc->filename, true, NULL); + v = window_open_buffer(window, loc->filename, true, NULL); } if (v == NULL) { // Open failed. Don't try again. diff --git a/main.c b/main.c index e7499dd..8b07317 100644 --- a/main.c +++ b/main.c @@ -207,7 +207,7 @@ int main(int argc, char *argv[]) editor_status = EDITOR_RUNNING; for (; i < argc; i++) - open_buffer(argv[i], false, NULL); + window_open_buffer(window, argv[i], false, NULL); if (window->views.count == 0) window_open_empty_buffer(window); set_view(window->views.ptrs[0]); diff --git a/window.c b/window.c index ec854b6..c65b662 100644 --- a/window.c +++ b/window.c @@ -1,6 +1,10 @@ #include "window.h" #include "view.h" #include "file-history.h" +#include "path.h" +#include "lock.h" +#include "load-save.h" +#include "error.h" PTR_ARRAY(windows); struct window *window; @@ -32,6 +36,80 @@ struct view *window_open_empty_buffer(struct window *w) return window_add_buffer(w, open_empty_buffer()); } +struct view *window_open_buffer(struct window *w, const char *filename, bool must_exist, const char *encoding) +{ + char *absolute = path_absolute(filename); + bool dir_missing = false; + struct buffer *b = NULL; + + if (absolute == NULL) { + // Let load_buffer() create error message. + dir_missing = errno == ENOENT; + } else { + // already open? + b = find_buffer(absolute); + } + if (b) { + if (!streq(absolute, b->abs_filename)) { + char *s = short_filename(absolute); + info_msg("%s and %s are the same file", s, b->display_filename); + free(s); + } + free(absolute); + return window_get_view(w, b); + } + + /* + /proc/$PID/fd/ contains symbolic links to files that have been opened + by process $PID. Some of the files may have been deleted but can still + be opened using the symbolic link but not by using the absolute path. + + # create file + mkdir /tmp/x + echo foo > /tmp/x/file + + # in another shell: keep the file open + tail -f /tmp/x/file + + # make the absolute path unavailable + rm /tmp/x/file + rmdir /tmp/x + + # this should still succeed + dex /proc/$(pidof tail)/fd/3 + */ + b = buffer_new(encoding); + if (load_buffer(b, must_exist, filename)) { + free_buffer(b); + return NULL; + } + if (b->st.st_mode == 0 && dir_missing) { + // New file in non-existing directory. This is usually a mistake. + error_msg("Error opening %s: Directory does not exist", filename); + free_buffer(b); + return NULL; + } + b->abs_filename = absolute; + if (b->abs_filename == NULL) { + // FIXME: obviously wrong + b->abs_filename = xstrdup(filename); + } + update_short_filename(b); + + if (options.lock_files) { + if (lock_file(b->abs_filename)) { + b->ro = true; + } else { + b->locked = true; + } + } + if (b->st.st_mode != 0 && !b->ro && access(filename, W_OK)) { + error_msg("No write permission to %s, marking read-only.", filename); + b->ro = true; + } + return window_add_buffer(w, b); +} + struct view *window_get_view(struct window *w, struct buffer *b) { struct view *v; @@ -195,7 +273,7 @@ struct view *open_file(const char *filename, const char *encoding) { struct view *prev = view; bool useless = is_useless_empty_view(prev); - struct view *v = open_buffer(filename, false, encoding); + struct view *v = window_open_buffer(window, filename, false, encoding); if (v == NULL) return NULL; @@ -217,7 +295,7 @@ void open_files(char **filenames, const char *encoding) int i; for (i = 0; filenames[i]; i++) { - struct view *v = open_buffer(filenames[i], false, encoding); + struct view *v = window_open_buffer(window, filenames[i], false, encoding); if (v && first) { set_view(v); first = false; diff --git a/window.h b/window.h index b32f602..0c0ad28 100644 --- a/window.h +++ b/window.h @@ -35,6 +35,7 @@ extern struct ptr_array windows; struct window *new_window(void); struct view *window_add_buffer(struct window *w, struct buffer *b); struct view *window_open_empty_buffer(struct window *w); +struct view *window_open_buffer(struct window *w, const char *filename, bool must_exist, const char *encoding); struct view *window_get_view(struct window *w, struct buffer *b); struct view *window_find_unclosable_view(struct window *w, bool (*can_close)(struct view *)); void window_remove_views(struct window *w);