summaryrefslogtreecommitdiff
path: root/src/buffer_utils.cc
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2025-02-19 20:58:49 +1100
committerMaxime Coste <mawww@kakoune.org>2025-02-19 21:25:39 +1100
commiteb7d34333b0698e8e1a8af4f2be908ab08cb2089 (patch)
tree4b53ba24111ce88901669c3e7651b5ec4edb4f87 /src/buffer_utils.cc
parent9eda509282ebc881207c2d8278085cb53835641c (diff)
Cleanup file.cc/hh dependencies
file.cc/hh should not know about Context, Buffer, etc... It should be a pretty low level set of helper functions. Move buffer related functions to buffer_utils and extract busy indicators to callers.
Diffstat (limited to 'src/buffer_utils.cc')
-rw-r--r--src/buffer_utils.cc90
1 files changed, 90 insertions, 0 deletions
diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc
index a4fb639b..a2d2e709 100644
--- a/src/buffer_utils.cc
+++ b/src/buffer_utils.cc
@@ -166,6 +166,96 @@ void reload_file_buffer(Buffer& buffer)
buffer.flags() &= ~Buffer::Flags::New;
}
+void write_buffer_to_fd(Buffer& buffer, int fd)
+{
+ auto eolformat = buffer.options()["eolformat"].get<EolFormat>();
+ StringView eoldata;
+ if (eolformat == EolFormat::Crlf)
+ eoldata = "\r\n";
+ else
+ eoldata = "\n";
+
+
+ BufferedWriter<false> writer{fd};
+ if (buffer.options()["BOM"].get<ByteOrderMark>() == ByteOrderMark::Utf8)
+ writer.write("\xEF\xBB\xBF");
+
+ for (LineCount i = 0; i < buffer.line_count(); ++i)
+ {
+ // end of lines are written according to eolformat but always
+ // stored as \n
+ StringView linedata = buffer[i];
+ writer.write(linedata.substr(0, linedata.length()-1));
+ writer.write(eoldata);
+ }
+}
+
+void write_buffer_to_file(Buffer& buffer, StringView filename,
+ WriteMethod method, WriteFlags flags)
+{
+ auto zfilename = filename.zstr();
+ struct stat st;
+
+ bool replace = method == WriteMethod::Replace;
+ bool force = flags & WriteFlags::Force;
+
+ if ((replace or force) and (::stat(zfilename, &st) != 0 or
+ (st.st_mode & S_IFMT) != S_IFREG))
+ {
+ force = false;
+ replace = false;
+ }
+
+ if (force and ::chmod(zfilename, st.st_mode | S_IWUSR) < 0)
+ throw runtime_error(format("unable to change file permissions: {}", strerror(errno)));
+
+ char temp_filename[PATH_MAX];
+ const int fd = replace ? open_temp_file(filename, temp_filename)
+ : create_file(zfilename);
+ if (fd == -1)
+ {
+ auto saved_errno = errno;
+ if (force)
+ ::chmod(zfilename, st.st_mode);
+ throw file_access_error(filename, strerror(saved_errno));
+ }
+
+ {
+ auto close_fd = on_scope_end([fd]{ close(fd); });
+ write_buffer_to_fd(buffer, fd);
+ if (flags & WriteFlags::Sync)
+ ::fsync(fd);
+ }
+
+ if (replace and geteuid() == 0 and ::chown(temp_filename, st.st_uid, st.st_gid) < 0)
+ throw runtime_error(format("unable to set replacement file ownership: {}", strerror(errno)));
+ if (replace and ::chmod(temp_filename, st.st_mode) < 0)
+ throw runtime_error(format("unable to set replacement file permissions: {}", strerror(errno)));
+ if (force and not replace and ::chmod(zfilename, st.st_mode) < 0)
+ throw runtime_error(format("unable to restore file permissions: {}", strerror(errno)));
+
+ if (replace and rename(temp_filename, zfilename) != 0)
+ {
+ if (force)
+ ::chmod(zfilename, st.st_mode);
+ throw runtime_error("replacing file failed");
+ }
+
+ if ((buffer.flags() & Buffer::Flags::File) and
+ real_path(filename) == real_path(buffer.name()))
+ buffer.notify_saved(get_fs_status(real_path(filename)));
+}
+
+void write_buffer_to_backup_file(Buffer& buffer)
+{
+ const int fd = open_temp_file(buffer.name());
+ if (fd >= 0)
+ {
+ write_buffer_to_fd(buffer, fd);
+ close(fd);
+ }
+}
+
Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, AutoScroll scroll)
{
static ValueId fifo_watcher_id = get_free_value_id();