]> git.neil.brown.name Git - edlib.git/commitdiff
Initial save-file support.
authorNeilBrown <neil@brown.name>
Tue, 24 Nov 2015 04:29:05 +0000 (15:29 +1100)
committerNeilBrown <neil@brown.name>
Tue, 24 Nov 2015 04:29:05 +0000 (15:29 +1100)
C-x C-s now saves the file if there is a file name.
No errors are reported if anything goes wrong.

Signed-off-by: NeilBrown <neil@brown.name>
doc-text.c
mode-emacs.c

index 9f32b92671f12a6cc18436700e31122faeb62ac5..d03b969bee87b881bd09c93bdcf3820bf7c34494 100644 (file)
@@ -57,6 +57,9 @@
 #include <string.h>
 #include <memory.h>
 #include <locale.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
 
 /* A doc_ref is treated as a pointer to a chunk, and an offset
  * from the start of 'txt'.  So 'o' must be between c->start and
@@ -233,6 +236,69 @@ err:
        return 0;
 }
 
+static int do_text_write_file(struct text *t, char *fname)
+{
+       /* Don't worry about links for now
+        * Create a temp file with #basename#~, write to that,
+        * fsync and then rename
+        */
+       char *tempname = malloc(strlen(fname) + 3 + 10);
+       char *base, *tbase;
+       int cnt = 0;
+       int fd = -1;
+       struct text_chunk *c;
+
+       strcpy(tempname, fname);
+       base = strrchr(fname, '/');
+       if (base)
+               base += 1;
+       else
+               base = fname;
+       tbase = tempname + (base - fname);
+       while (cnt < 20 && fd == -1) {
+               if (cnt)
+                       sprintf(tbase, "#%s#~%d", base, cnt);
+               else
+                       sprintf(tbase, "#%s#~", base);
+               fd = open(tempname, O_WRONLY|O_CREAT|O_EXCL, 0666);
+               if (fd < 0 && errno != EEXIST)
+                       break;
+               cnt += 1;
+       }
+       if (fd < 0)
+               return -1;
+
+       list_for_each_entry(c, &t->text, lst) {
+               char *s = c->txt + c->start;
+               int ln = c->end - c->start;
+               if (write(fd, s, ln) != ln)
+                       goto error;
+       }
+       if (fsync(fd) != 0)
+               goto error;
+       if (rename(tempname, fname) < 0)
+               goto error;
+       close(fd);
+       free(tempname);
+       return 0;
+error:
+       close(fd);
+       unlink(tempname);
+       free(tempname);
+       return -1;
+
+}
+
+DEF_CMD(text_save_file)
+{
+       struct doc *d = (*ci->pointp)->doc;
+       struct text *t = container_of(d, struct text, doc);
+
+       if (!t->fname)
+               return -1;
+       return do_text_write_file(t, t->fname);
+}
+
 DEF_CMD(text_same_file)
 {
        struct doc *d = (*ci->pointp)->doc;
@@ -1559,4 +1625,5 @@ void edlib_init(struct editor *ed)
        key_add(text_map, "doc:get-str", &text_get_str);
        key_add(text_map, "doc:destroy", &text_destroy);
        key_add(text_map, "doc:set-ref", &text_set_ref);
+       key_add(text_map, "doc:save-file", &text_save_file);
 }
index 09cc1e0c03d3a71b4cc7ea5f1a49d7144daac808..e43be7c789a4953dcec335b4fc2aed5279faa05c 100644 (file)
@@ -168,6 +168,7 @@ static struct str_command {
        {CMD(emacs_str), "NOP", NULL, "M-Chr-G"},
        {CMD(emacs_str), "NOP", NULL, "emCX-C-Chr-G"},
        {CMD(emacs_str), "NOP", NULL, "emCX4-C-Chr-G"},
+       {CMD(emacs_str), "doc:save-file", NULL, "emCX-C-Chr-S"},
 };
 
 REDEF_CMD(emacs_str)