summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Carbonneaux2014-07-25 11:44:46 -0400
committerQuentin Carbonneaux2014-07-25 13:39:26 -0400
commit85030f06ef73e18c429ef6ed4f7ef435388cbf83 (patch)
treed474fc5cdb3f45f017a40bbcffd03333fc873fdb
parent35fb2586c71b54655d07a9d1e246e5488ec72c1e (diff)
cleanup file loading/saving
-rw-r--r--edit.c109
-rw-r--r--edit.h7
-rw-r--r--exec.c147
-rw-r--r--exec.h2
-rw-r--r--main.c3
-rw-r--r--vicmd.w2
6 files changed, 207 insertions, 63 deletions
diff --git a/edit.c b/edit.c
index 1ad7003..c5a19dd 100644
--- a/edit.c
+++ b/edit.c
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include "unicode.h"
#include "buf.h"
@@ -42,8 +43,9 @@ struct log {
static void pushlog(Log *, int);
static void rebase(Mark *, int, unsigned, unsigned);
-static void puteb(EBuf *, FILE *);
-static void putrune(Rune, FILE *);
+static void geteb(EBuf *, int);
+static void puteb(EBuf *, int);
+static void putrune(Rune, int);
void
log_insert(Log *l, unsigned p0, unsigned p1)
@@ -187,6 +189,28 @@ eb_new()
return eb;
}
+/* eb_clr - Reset the buffer contents and marks and read
+ * the new contents from the file descriptor [fd] if it is
+ * different from -1.
+ */
+void
+eb_clr(EBuf *eb, int fd)
+{
+ Mark *m;
+
+ buf_clr(&eb->b);
+ log_clr(eb->undo);
+ log_clr(eb->redo);
+ while (eb->ml) {
+ m = eb->ml->next;
+ free(eb->ml);
+ eb->ml = m;
+ }
+ if (fd != -1)
+ geteb(eb, fd);
+ assert(eb->path == 0);
+}
+
void
eb_del(EBuf *eb, unsigned p0, unsigned p1)
{
@@ -331,45 +355,10 @@ eb_look(EBuf *eb, unsigned p, Rune *str, unsigned n)
return -1u;
}
-int
-eb_read(EBuf *eb, char *path)
-{
- FILE *fp = fopen(path, "r");
-
- if (!fp)
- return 1;
-
- eb->path = path;
- buf_clr(&eb->b);
- log_clr(eb->undo);
- log_clr(eb->redo);
-
- for (unsigned char buf[11], *beg = buf;;) {
- int rd, in, ins;
-
- rd = fread(beg, 1, sizeof buf - (beg-buf), fp);
- in = rd + (beg-buf);
- ins = eb_ins_utf8(eb, eb->b.limbo, buf, in);
-
- assert(rd != 0 || in == ins);
- if (rd == 0)
- break;
- memmove(buf, buf+ins, in-ins);
- beg = buf + (in-ins);
- }
- return 0;
-}
-
-int
-eb_write(EBuf *eb)
+void
+eb_write(EBuf *eb, int fd)
{
- FILE *fp = fopen(eb->path, "w");
-
- if (!fp)
- return -1;
- puteb(eb, fp);
- fclose(fp);
- return 0;
+ puteb(eb, fd);
}
@@ -421,8 +410,28 @@ rebase(Mark *m, int type, unsigned p0, unsigned np)
}
}
+void
+geteb(EBuf *eb, int fd)
+{
+ unsigned char buf[11], *beg;
+ int rd, in, ins;
+
+ beg = buf;
+ for (;;) {
+ rd = read(fd, beg, sizeof buf - (beg-buf));
+ in = rd + (beg-buf);
+ ins = eb_ins_utf8(eb, eb->b.limbo, buf, in);
+
+ assert(rd != 0 || in == ins); /* XXX */
+ if (rd == 0)
+ break;
+ memmove(buf, buf+ins, in-ins);
+ beg = buf + (in-ins);
+ }
+}
+
static void
-puteb(EBuf *eb, FILE *fp)
+puteb(EBuf *eb, int fd)
{
enum { Munching, Spitting } state = Munching;
unsigned munchb = 0, munche = 0, nl = 0;
@@ -444,7 +453,7 @@ puteb(EBuf *eb, FILE *fp)
continue;
assert(nl == 0 || r == '\n');
nl -= (r == '\n');
- putrune(r, fp);
+ putrune(r, fd);
}
assert(munchb == munche);
state = Spitting;
@@ -458,24 +467,24 @@ puteb(EBuf *eb, FILE *fp)
assert(nl == 0);
continue;
}
- putrune(r, fp);
+ putrune(r, fd);
munchb++;
continue;
}
- putrune('\n', fp); // always terminate file with a newline
+ putrune('\n', fd); // always terminate file with a newline
}
static void
-putrune(Rune r, FILE *fp)
+putrune(Rune r, int fd)
{
- unsigned char uni[16];
+ unsigned char uni[8]; /* XXX 8 */
int i, n;
- n = utf8_encode_rune(r, uni, 16);
+ n = utf8_encode_rune(r, uni, 8);
for (i=0; i<n; i++)
- putc(uni[i], fp);
+ write(fd, &uni[i], 1);
}
@@ -495,7 +504,7 @@ dumplog(Log *l)
printf("%02d - (p0=%u np=%u)\n", n, l->p0, l->np);
printf("\t'");
for (i=l->np-1; i>=0; --i)
- putrune(l->rbuf[i], stdout);
+ putrune(l->rbuf[i], STDOUT_FILENO);
printf("'\n");
break;
case Commit:
@@ -550,7 +559,7 @@ main() {
case 'p':
i = 0;
do
- putrune(buf_get(&eb->b, i++), stdout);
+ putrune(buf_get(&eb->b, i++), STDOUT_FILENO);
while (buf_get(&eb->b, i-1) != '\n');
break;
case 'c':
diff --git a/edit.h b/edit.h
index fb69a02..41186e9 100644
--- a/edit.h
+++ b/edit.h
@@ -1,6 +1,8 @@
#ifndef EDIT_H
#define EDIT_H
+#include <time.h>
+
#include "unicode.h"
#include "buf.h"
@@ -26,10 +28,12 @@ struct ebuf {
Log *redo;
Mark *ml; /* buffer marks */
char *path; /* file path */
+ time_t mtime; /* last mtime when written/read */
};
EBuf *eb_new(void);
void eb_del(EBuf *, unsigned, unsigned);
+void eb_clr(EBuf *, int);
unsigned eb_revision(EBuf *);
void eb_ins(EBuf *, unsigned, Rune);
int eb_ins_utf8(EBuf *, unsigned, unsigned char *, int);
@@ -39,7 +43,6 @@ void eb_yank(EBuf *, unsigned, unsigned, YBuf *);
void eb_setmark(EBuf *, Rune, unsigned);
unsigned eb_getmark(EBuf *, Rune);
unsigned eb_look(EBuf *, unsigned, Rune *, unsigned);
-int eb_read(EBuf *, char *);
-int eb_write(EBuf *);
+void eb_write(EBuf *, int);
#endif /* ndef EDIT_H */
diff --git a/exec.c b/exec.c
index 01bac02..0c4661b 100644
--- a/exec.c
+++ b/exec.c
@@ -2,9 +2,14 @@
#include <assert.h>
#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
#include <unistd.h>
#include "unicode.h"
@@ -24,11 +29,14 @@ struct ecmd {
static ECmd *lookup(Buf *, unsigned, unsigned *);
static unsigned skipb(Buf *, unsigned, int);
static int get(W *, EBuf *, unsigned);
+static int put(W *, EBuf *, unsigned);
static int look(W *, EBuf *, unsigned);
static int run(W *, EBuf *, unsigned);
-ECmd etab[] = {
+static char *errstr;
+static ECmd etab[] = {
{ "Get", get },
+ { "Put", put },
{ "Look", look },
{ 0, run },
};
@@ -70,13 +78,106 @@ ex_look(W *w, Rune *s, unsigned n)
w->cu = p;
eb_setmark(w->eb, SelBeg, p);
eb_setmark(w->eb, SelEnd, p+n);
+ return 0;
+ } else {
+ errstr = "no match";
+ return 1;
+ }
+}
+
+/* ex_get - Load the buffer [eb] from the file [file]. See ex_put
+ * for more information.
+ */
+int
+ex_get(EBuf *eb, char *file)
+{
+ int fd;
+ struct stat st;
+ char *file1;
+
+ if (!file)
+ file = eb->path;
+ if (!file) {
+ errstr = "no file to read from";
+ return 1;
+ }
+ fd = open(file, O_RDONLY);
+ if (fd == -1) {
+ errstr = "cannot open file";
+ return 1;
+ }
+ file1 = malloc(strlen(file)+1);
+ assert(file1);
+ strcpy(file1, file);
+ free(eb->path);
+ eb->path = 0;
+ eb_clr(eb, fd);
+ close(fd);
+ stat(file1, &st);
+ eb->path = file1;
+ eb->mtime = st.st_mtime;
+ return 0;
+}
+
+/* ex_put - Save the buffer [eb] in the file [file]. If [file] is
+ * null the buffer path is used. One is returned if an error occurs
+ * and zero is returned otherwise. The caller is responsible to
+ * free the [file] buffer.
+ */
+int
+ex_put(EBuf *eb, char *file)
+{
+ int fd;
+ struct stat st;
+
+ if (file) {
+ if (stat(file, &st) != -1) {
+ errstr = "file exists";
+ return 1;
+ }
+ } else {
+ file = eb->path;
+ if (!file) {
+ errstr = "no file to write to";
+ return 1;
+ }
+ if (stat(file, &st) != -1)
+ if (st.st_mtime > eb->mtime) {
+ errstr = "file changed on disk";
+ return 1;
+ }
+ }
+ fd = open(file, O_TRUNC|O_WRONLY|O_CREAT);
+ if (fd == -1) {
+ errstr = "cannot open file";
+ return 1;
+ }
+ eb_write(eb, fd);
+ close(fd);
+ if (eb->path == 0) {
+ eb->path = malloc(strlen(file)+1);
+ assert(eb->path);
+ strcpy(eb->path, file);
+ }
+ if (strcmp(eb->path, file) == 0) {
+ stat(file, &st);
+ eb->mtime = st.st_mtime;
}
- return p == -1u;
+ return 0;
}
/* static functions */
+static void
+err(EBuf *eb, unsigned p0, char *e)
+{
+ p0 = buf_eol(&eb->b, p0) + 1;
+ while (*e)
+ eb_ins(eb, p0++, *e++);
+ eb_ins(eb, p0, '\n');
+}
+
static int
risblank(Rune r)
{
@@ -143,8 +244,10 @@ get(W *w, EBuf *eb, unsigned p0)
{
char *f, *p;
unsigned p1;
+ int e;
long ln;
+ f = 0;
ln = 1;
p1 = 1 + skipb(&eb->b, buf_eol(&eb->b, p0) - 1, -1);
if (p0 < p1) {
@@ -155,28 +258,54 @@ get(W *w, EBuf *eb, unsigned p0)
if (ln > INT_MAX || ln < 0)
ln = 0;
}
- } else
- f = w->eb->path;
+ }
+ e = ex_get(w->eb, f);
+ free(f);
+ if (e) {
+ err(eb, p0, errstr);
+ return 0;
+ }
+ w->cu = buf_setlc(&w->eb->b, ln-1, 0);
+ return 1;
+}
- if (eb_read(w->eb, f) == 0) {
- w->cu = buf_setlc(&w->eb->b, ln-1, 0);
- return 1;
- } else
+static int
+put(W *w, EBuf *eb, unsigned p0)
+{
+ char *f;
+ int e;
+ unsigned p1;
+
+ f = 0;
+ p1 = 1 + skipb(&eb->b, buf_eol(&eb->b, p0) - 1, -1);
+ if (p0 < p1)
+ f = buftobytes(&eb->b, p0, p1, 0);
+ e = ex_put(w->eb, f);
+ free(f);
+ if (e) {
+ err(eb, p0, errstr);
return 0;
+ }
+ return 1;
}
static int
look(W *w, EBuf *eb, unsigned p0)
{
YBuf b = {0,0,0,0};
+ int e;
unsigned p1;
if (buf_get(&eb->b, p0) == '\n')
return 0;
p1 = 1 + skipb(&eb->b, buf_eol(&eb->b, p0) - 1, -1);
eb_yank(eb, p0, p1, &b);
- ex_look(w, b.r, b.nr);
+ e = ex_look(w, b.r, b.nr);
free(b.r);
+ if (e) {
+ err(eb, p0, errstr);
+ return 0;
+ }
return 1;
}
diff --git a/exec.h b/exec.h
index 0c564c2..e6d051d 100644
--- a/exec.h
+++ b/exec.h
@@ -6,5 +6,7 @@
int ex_run(unsigned);
int ex_look(W *, Rune *, unsigned);
+int ex_put(EBuf *, char *);
+int ex_get(EBuf *, char *);
#endif /* ndef EXEC_H */
diff --git a/main.c b/main.c
index d957f07..f344d6c 100644
--- a/main.c
+++ b/main.c
@@ -76,7 +76,8 @@ main(int ac, char *av[])
win_init(g);
eb = eb_new();
- eb_read(eb, eb->path = ac > 1 ? av[1] : "dummy.txt");
+ if (ac > 1)
+ ex_get(eb, av[1]);
curwin = win_new(eb);
gev(0, ERead, 0);
diff --git a/vicmd.w b/vicmd.w
index ed397d5..a48789f 100644
--- a/vicmd.w
+++ b/vicmd.w
@@ -1056,7 +1056,7 @@ module.
static int a_write(char buf, Cmd c, Cmd mc)
{
(void)buf;@+ (void)c;@+ (void)mc;
- return eb_write(curwin->eb);
+ return ex_put(curwin->eb, 0);
}
@ @<Subr...@>=