aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--text.c35
-rw-r--r--text.h1
-rw-r--r--vis.c2
3 files changed, 26 insertions, 12 deletions
diff --git a/text.c b/text.c
index 2e2e4db..c0b5eee 100644
--- a/text.c
+++ b/text.c
@@ -594,17 +594,23 @@ size_t text_redo(Text *txt) {
return pos;
}
+bool text_save(Text *txt, const char *filename) {
+ Filerange r = (Filerange){ .start = 0, .end = text_size(txt) };
+ return text_range_save(txt, &r, filename);
+}
+
/* save current content to given filename. the data is first saved to `filename~`
* and then atomically moved to its final (possibly alredy existing) destination
* using rename(2).
*/
-bool text_save(Text *txt, const char *filename) {
+bool text_range_save(Text *txt, Filerange *range, const char *filename) {
int fd = -1;
- size_t len = strlen(filename) + 10;
- char *tmpname = malloc(len);
+ size_t bufsize = strlen(filename) + 10;
+ size_t size = range->end - range->start;
+ char *tmpname = malloc(bufsize);
if (!tmpname)
return false;
- snprintf(tmpname, len, "%s~", filename);
+ snprintf(tmpname, bufsize, "%s~", filename);
// TODO preserve user/group
struct stat meta;
if (stat(filename, &meta) == -1) {
@@ -616,21 +622,28 @@ bool text_save(Text *txt, const char *filename) {
/* O_RDWR is needed because otherwise we can't map with MAP_SHARED */
if ((fd = open(tmpname, O_CREAT|O_RDWR|O_TRUNC, meta.st_mode)) == -1)
goto err;
- if (ftruncate(fd, txt->size) == -1)
+ if (ftruncate(fd, size) == -1)
goto err;
- if (txt->size > 0) {
- void *buf = mmap(NULL, txt->size, PROT_WRITE, MAP_SHARED, fd, 0);
+ if (size > 0) {
+ void *buf = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0);
if (buf == MAP_FAILED)
goto err;
char *cur = buf;
- text_iterate(txt, it, 0) {
- size_t len = it.end - it.start;
- memcpy(cur, it.start, len);
+ size_t rem = size;
+
+ for (Iterator it = text_iterator_get(txt, range->start);
+ rem > 0 && text_iterator_valid(&it);
+ text_iterator_next(&it)) {
+ size_t len = it.end - it.text;
+ if (len > rem)
+ len = rem;
+ memcpy(cur, it.text, len);
cur += len;
+ rem -= len;
}
- if (munmap(buf, txt->size) == -1)
+ if (munmap(buf, size) == -1)
goto err;
}
if (close(fd) == -1)
diff --git a/text.h b/text.h
index 98d237b..89e2bdc 100644
--- a/text.h
+++ b/text.h
@@ -85,6 +85,7 @@ bool text_modified(Text*);
/* test whether the underlying file uses UNIX style \n or Windows style \r\n newlines */
bool text_newlines_crnl(Text*);
bool text_save(Text*, const char *file);
+bool text_range_save(Text*, Filerange*, const char *file);
ssize_t text_write(Text*, int fd);
void text_free(Text*);
diff --git a/vis.c b/vis.c
index d90937f..d764eb4 100644
--- a/vis.c
+++ b/vis.c
@@ -1421,7 +1421,7 @@ static bool cmd_write(Filerange *range, const char *argv[]) {
return false;
}
for (const char **file = &argv[1]; *file; file++) {
- if (!text_save(text, *file)) {
+ if (!text_range_save(text, range, *file)) {
editor_info_show(vis, "Can't write `%s'", *file);
return false;
}