diff options
| author | Quentin Carbonneaux | 2014-07-25 11:44:46 -0400 |
|---|---|---|
| committer | Quentin Carbonneaux | 2014-07-25 13:39:26 -0400 |
| commit | 85030f06ef73e18c429ef6ed4f7ef435388cbf83 (patch) | |
| tree | d474fc5cdb3f45f017a40bbcffd03333fc873fdb | |
| parent | 35fb2586c71b54655d07a9d1e246e5488ec72c1e (diff) | |
cleanup file loading/saving
| -rw-r--r-- | edit.c | 109 | ||||
| -rw-r--r-- | edit.h | 7 | ||||
| -rw-r--r-- | exec.c | 147 | ||||
| -rw-r--r-- | exec.h | 2 | ||||
| -rw-r--r-- | main.c | 3 | ||||
| -rw-r--r-- | vicmd.w | 2 |
6 files changed, 207 insertions, 63 deletions
@@ -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': @@ -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 */ @@ -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; } @@ -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 */ @@ -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); @@ -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...@>= |
