ed

simple ed
git clone git://git.2f30.org/ed.git
Log | Files | Refs | LICENSE

commit 6a49e710a774fbfe3e09f4a36378faa0864ff24f
parent 9309b6486e3de5969af21d889e30e9f19b24eb6d
Author: sin <sin@2f30.org>
Date:   Mon, 27 Aug 2018 20:16:48 +0100

Sync with sbase ed

Diffstat:
ed.c | 312+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
1 file changed, 186 insertions(+), 126 deletions(-)

diff --git a/ed.c b/ed.c @@ -1,4 +1,25 @@ /* See LICENSE file for copyright and license details. */ + +/* + * TODO: Multi-line commands don't work in global commands: + * o g/^line/a \ + * line1 + * . + * o Signal handling is broken + * o cat <<EOF | ed + * 0a + * int radix = 16; + * int Pflag; + * int Aflag; + * int vflag; + * int gflag; + * int uflag; + * int arflag; + * + * . + * ?radix?;/^$/-s/^/static / + */ + #include <sys/stat.h> #include <fcntl.h> #include <regex.h> @@ -19,6 +40,14 @@ #define LINESIZE 80 #define NUMLINES 32 #define CACHESIZ 4096 +#define AFTER 0 +#define BEFORE 1 + +typedef struct { + char *str; + size_t cap; + size_t siz; +} String; struct hline { off_t seek; @@ -27,7 +56,7 @@ struct hline { }; struct undo { - int curln; + int curln, lastln; size_t nr, cap; struct link { int to1, from1; @@ -39,26 +68,24 @@ char *argv0; static char *prompt = "*"; static regex_t *pattern; static regmatch_t matchs[10]; -static char *lastre; +static String lastre; static int optverbose, optprompt, exstatus, optdiag = 1; static int marks['z' - 'a']; static int nlines, line1, line2; -static int curln, lastln, ocurln; +static int curln, lastln, ocurln, olastln; static jmp_buf savesp; static char *lasterr; static size_t idxsize, lastidx; static struct hline *zero; -static char *text; +static String text; static char savfname[FILENAME_MAX]; static char tmpname[FILENAME_MAX]; -static size_t sizetxt, memtxt; static int scratch; static int pflag, modflag, uflag, gflag; static size_t csize; -static char *cmdline; +static String cmdline; static char *ocmdline; -static size_t cmdsiz, cmdcap; static int repidx; static char *rhs; static char *lastmatch; @@ -71,12 +98,15 @@ discard(void) { int c; - /* discard until end of line */ - if (repidx < 0 && - ((cmdsiz > 0 && cmdline[cmdsiz-1] != '\n') || cmdsiz == 0)) { - while ((c = getchar()) != '\n' && c != EOF) - /* nothing */; - } + if (repidx >= 0) + return; + + /* discard until the end of the line */ + if (cmdline.siz > 0 && cmdline.str[cmdline.siz-1] == '\n') + return; + + while ((c = getchar()) != '\n' && c != EOF) + ; } static void undo(void); @@ -86,10 +116,10 @@ error(char *msg) { exstatus = 1; lasterr = msg; - fputs("?\n", stderr); + puts("?"); if (optverbose) - fprintf(stderr, "%s\n", msg); + puts(msg); if (!newcmd) undo(); @@ -113,17 +143,19 @@ prevln(int line) } static char * -addchar(char c, char *t, size_t *capacity, size_t *size) +addchar(char c, String *s) { - size_t cap = *capacity, siz = *size; + size_t cap = s->cap, siz = s->siz; + char *t = s->str; if (siz >= cap && (cap > SIZE_MAX - LINESIZE || (t = realloc(t, cap += LINESIZE)) == NULL)) error("out of memory"); t[siz++] = c; - *size = siz; - *capacity = cap; + s->siz = siz; + s->cap = cap; + s->str = t; return t; } @@ -136,7 +168,7 @@ input(void) return ocmdline[repidx++]; if ((c = getchar()) != EOF) - cmdline = addchar(c, cmdline, &cmdcap, &cmdsiz); + addchar(c, &cmdline); return c; } @@ -148,7 +180,7 @@ back(int c) } else { ungetc(c, stdin); if (c != EOF) - --cmdsiz; + --cmdline.siz; } return c; } @@ -161,8 +193,10 @@ makeline(char *s, int *off) char c, *begin = s; if (lastidx >= idxsize) { - if (idxsize > SIZE_MAX - NUMLINES || - !(lp = realloc(zero, (idxsize + NUMLINES) * sizeof(*lp)))) + lp = NULL; + if (idxsize <= SIZE_MAX - NUMLINES) + lp = realloc(zero, (idxsize + NUMLINES) * sizeof(*lp)); + if (!lp) error("out of memory"); idxsize += NUMLINES; zero = lp; @@ -212,11 +246,11 @@ gettxt(int line) char *p; lp = zero + getindex(line); - sizetxt = 0; + text.siz = 0; off = lp->seek; if (off == (off_t) -1) - return text = addchar('\0', text, &memtxt, &sizetxt); + return addchar('\0', &text); repeat: if (!csize || off < lasto || off - lasto >= csize) { @@ -230,14 +264,14 @@ repeat: } for (p = buf + off - lasto; p < buf + csize && *p != '\n'; ++p) { ++off; - text = addchar(*p, text, &memtxt, &sizetxt); + addchar(*p, &text); } if (csize && p == buf + csize) goto repeat; - text = addchar('\n', text, &memtxt, &sizetxt); - text = addchar('\0', text, &memtxt, &sizetxt); - return text; + addchar('\n', &text); + addchar('\0', &text); + return text.str; } static void @@ -256,13 +290,14 @@ clearundo(void) } static void -relink(int to1, int from1, int from2, int to2) +newundo(int from1, int from2) { struct link *p; if (newcmd) { clearundo(); udata.curln = ocurln; + udata.lastln = olastln; } if (udata.nr >= udata.cap) { size_t siz = (udata.cap + 10) * sizeof(struct link); @@ -276,7 +311,16 @@ relink(int to1, int from1, int from2, int to2) p->to1 = zero[from1].next; p->from2 = from2; p->to2 = zero[from2].prev; +} +/* + * relink: to1 <- from1 + * from2 -> to2 + */ +static void +relink(int to1, int from1, int from2, int to2) +{ + newundo(from1, from2); zero[from1].next = to1; zero[from2].prev = to2; modflag = 1; @@ -289,7 +333,8 @@ undo(void) if (udata.nr == 0) return; - for (p = &udata.vec[udata.nr-1]; udata.nr--; --p) { + for (p = &udata.vec[udata.nr-1]; udata.nr > 0; --p) { + --udata.nr; zero[p->from1].next = p->to1; zero[p->from2].prev = p->to2; } @@ -297,14 +342,15 @@ undo(void) udata.vec = NULL; udata.cap = 0; curln = udata.curln; + lastln = udata.lastln; } static void -inject(char *s, int j) +inject(char *s, int where) { int off, k, begin, end; - if (j) { + if (where == BEFORE) { begin = getindex(curln-1); end = getindex(nextln(curln-1)); } else { @@ -360,13 +406,12 @@ static void compile(int delim) { int n, ret, c,bracket; - static size_t siz, cap; static char buf[BUFSIZ]; if (!isgraph(delim)) error("invalid pattern delimiter"); - eol = bol = bracket = siz = 0; + eol = bol = bracket = lastre.siz = 0; for (n = 0;; ++n) { if ((c = input()) == delim && !bracket) break; @@ -380,27 +425,27 @@ compile(int delim) } if (c == '\\') { - lastre = addchar(c, lastre, &cap, &siz); + addchar(c, &lastre); c = input(); } else if (c == '[') { bracket = 1; } else if (c == ']') { bracket = 0; } - lastre = addchar(c, lastre, &cap, &siz); + addchar(c, &lastre); } if (n == 0) { if (!pattern) error("no previous pattern"); return; } - lastre = addchar('\0', lastre, &cap, &siz); + addchar('\0', &lastre); if (pattern) regfree(pattern); if (!pattern && (!(pattern = malloc(sizeof(*pattern))))) error("out of memory"); - if ((ret = regcomp(pattern, lastre, REG_NEWLINE))) { + if ((ret = regcomp(pattern, lastre.str, REG_NEWLINE))) { regerror(ret, pattern, buf, sizeof(buf)); error(buf); } @@ -642,7 +687,7 @@ doread(const char *fname) s[n-1] = '\n'; s[n] = '\0'; } - inject(s, 0); + inject(s, AFTER); } if (optdiag) printf("%zu\n", cnt); @@ -704,7 +749,7 @@ static void dohelp(void) { if (lasterr) - fprintf(stderr, "%s\n", lasterr); + puts(lasterr); } static void @@ -760,7 +805,7 @@ append(int num) while (getline(&s, &len, stdin) > 0) { if (*s == '.' && s[1] == '\n') break; - inject(s, 0); + inject(s, AFTER); } free(s); } @@ -811,48 +856,59 @@ join(void) { int i; char *t, c; - size_t len = 0, cap = 0; - static char *s; + static String s; - free(s); - for (s = NULL, i = line1;; i = nextln(i)) { + free(s.str); + s.siz = s.cap = 0; + for (i = line1;; i = nextln(i)) { for (t = gettxt(i); (c = *t) != '\n'; ++t) - s = addchar(*t, s, &cap, &len); + addchar(*t, &s); if (i == line2) break; } - s = addchar('\n', s, &cap, &len); - s = addchar('\0', s, &cap, &len); + addchar('\n', &s); + addchar('\0', &s); delete(line1, line2); - inject(s, 1); - free(s); + inject(s.str, BEFORE); + free(s.str); } static void scroll(int num) { - int i; + int max, ln, cnt; if (!line1 || line1 == lastln) error("incorrect address"); - for (i = line1; i <= line1 + num && i <= lastln; ++i) - fputs(gettxt(i), stdout); - curln = i; + ln = line1; + max = line1 + num; + if (max > lastln) + max = lastln; + for (cnt = line1; cnt < max; cnt++) { + fputs(gettxt(ln), stdout); + ln = nextln(ln); + } + curln = ln; } static void copy(int where) { - int i; - if (!line1 || (where >= line1 && where <= line2)) + if (!line1) error("incorrect address"); curln = where; - for (i = line1; i <= line2; ++i) - inject(gettxt(i), 0); + while (line1 <= line2) { + inject(gettxt(line1), AFTER); + if (line2 >= curln) + line2 = nextln(line2); + line1 = nextln(line1); + if (line1 >= curln) + line1 = nextln(line1); + } } static void @@ -865,38 +921,37 @@ quit(void) static void execsh(void) { - static char *cmd; - static size_t siz, cap; - char c, *p; - int repl = 0; + static String cmd; + char *p; + int c, repl = 0; skipblank(); if ((c = input()) != '!') { back(c); - siz = 0; - } else if (cmd) { - --siz; + cmd.siz = 0; + } else if (cmd.siz) { + --cmd.siz; repl = 1; } else { error("no previous command"); } while ((c = input()) != EOF && c != '\n') { - if (c == '%' && (siz == 0 || cmd[siz - 1] != '\\')) { + if (c == '%' && (cmd.siz == 0 || cmd.str[cmd.siz - 1] != '\\')) { if (savfname[0] == '\0') error("no current filename"); repl = 1; for (p = savfname; *p; ++p) - cmd = addchar(*p, cmd, &cap, &siz); + addchar(*p, &cmd); } else { - cmd = addchar(c, cmd, &cap, &siz); + addchar(c, &cmd); } } - cmd = addchar('\0', cmd, &cap, &siz); + addchar('\0', &cmd); if (repl) - puts(cmd); - system(cmd); + puts(cmd.str); + system(cmd.str); if (optdiag) puts("!"); } @@ -905,15 +960,14 @@ static void getrhs(int delim) { int c; - size_t siz, cap; - static char *s; + static String s; - free(s); - s = NULL; - siz = cap = 0; + free(s.str); + s.str = NULL; + s.siz = s.cap = 0; while ((c = input()) != '\n' && c != EOF && c != delim) - s = addchar(c, s, &siz, &cap); - s = addchar('\0', s, &siz, &cap); + addchar(c, &s); + addchar('\0', &s); if (c == EOF) error("invalid pattern delimiter"); if (c == '\n') { @@ -921,15 +975,15 @@ getrhs(int delim) back(c); } - if (!strcmp("%", s)) { - free(s); + if (!strcmp("%", s.str)) { + free(s.str); if (!rhs) error("no previous substitution"); } else { free(rhs); - rhs = s; + rhs = s.str; } - s = NULL; + s.str = NULL; } static int @@ -950,26 +1004,26 @@ getnth(void) } static void -addpre(char **s, size_t *cap, size_t *siz) +addpre(String *s) { char *p; for (p = lastmatch; p < lastmatch + matchs[0].rm_so; ++p) - *s = addchar(*p, *s, cap, siz); + addchar(*p, s); } static void -addpost(char **s, size_t *cap, size_t *siz) +addpost(String *s) { char c, *p; for (p = lastmatch + matchs[0].rm_eo; (c = *p); ++p) - *s = addchar(c, *s, cap, siz); - *s = addchar('\0', *s, cap, siz); + addchar(c, s); + addchar('\0', s); } static int -addsub(char **s, size_t *cap, size_t *siz, int nth, int nmatch) +addsub(String *s, int nth, int nmatch) { char *end, *q, *p, c; int sub; @@ -978,7 +1032,7 @@ addsub(char **s, size_t *cap, size_t *siz, int nth, int nmatch) q = lastmatch + matchs[0].rm_so; end = lastmatch + matchs[0].rm_eo; while (q < end) - *s = addchar(*q++, *s, cap, siz); + addchar(*q++, s); return 0; } @@ -997,11 +1051,11 @@ addsub(char **s, size_t *cap, size_t *siz, int nth, int nmatch) q = lastmatch + matchs[sub].rm_so; end = lastmatch + matchs[sub].rm_eo; while (q < end) - *s = addchar(*q++, *s, cap, siz); + addchar(*q++, s); break; default: copy_char: - *s = addchar(c, *s, cap, siz); + addchar(c, s); break; } } @@ -1012,22 +1066,21 @@ static void subline(int num, int nth) { int i, m, changed; - static char *s; - static size_t siz, cap; + static String s; - i = changed = siz = 0; + i = changed = s.siz = 0; for (m = match(num); m; m = rematch(num)) { - addpre(&s, &cap, &siz); - changed |= addsub(&s, &cap, &siz, nth, ++i); + addpre(&s); + changed |= addsub(&s, nth, ++i); if (eol || bol) break; } if (!changed) return; - addpost(&s, &cap, &siz); + addpost(&s); delete(num, num); curln = prevln(num); - inject(s, 0); + inject(s.str, AFTER); } static void @@ -1063,7 +1116,7 @@ repeat: execsh(); break; case EOF: - if (cmdsiz == 0) + if (cmdline.siz == 0) quit(); case '\n': if (gflag && uflag) @@ -1177,7 +1230,7 @@ repeat: chkprint(1); deflines(curln, curln+1); if (line1 != line2 && curln != 0) - join(); + join(); break; case 'z': if (nlines > 1) @@ -1259,8 +1312,8 @@ save_last_cmd: if (rep) return; free(ocmdline); - cmdline = addchar('\0', cmdline, &cmdcap, &cmdsiz); - if ((ocmdline = strdup(cmdline)) == NULL) + addchar('\0', &cmdline); + if ((ocmdline = strdup(cmdline.str)) == NULL) error("out of memory"); } @@ -1307,26 +1360,32 @@ chkglobal(void) static void doglobal(void) { - int i, k; + int cnt, ln, k; skipblank(); - cmdsiz = 0; + cmdline.siz = 0; gflag = 1; if (uflag) chkprint(0); - for (i = 1; i <= lastln; i++) { - k = getindex(i); - if (!zero[k].global) - continue; - curln = i; - nlines = 0; - if (uflag) { - line1 = line2 = i; - pflag = 0; - doprint(); + ln = line1; + for (cnt = 0; cnt < lastln; ) { + k = getindex(ln); + if (zero[k].global) { + zero[k].global = 0; + curln = ln; + nlines = 0; + if (uflag) { + line1 = line2 = ln; + pflag = 0; + doprint(); + } + getlst(); + docmd(); + } else { + cnt++; + ln = nextln(ln); } - docmd(); } discard(); /* cover the case of not matching anything */ } @@ -1370,14 +1429,16 @@ sighup(int dummy) static void edit(void) { - setjmp(savesp); for (;;) { newcmd = 1; ocurln = curln; - cmdsiz = 0; + olastln = lastln; + cmdline.siz = 0; repidx = -1; - if (optprompt) + if (optprompt) { fputs(prompt, stdout); + fflush(stdout); + } getlst(); chkglobal() ? doglobal() : docmd(); } @@ -1388,8 +1449,6 @@ init(char *fname) { size_t len; - if (setjmp(savesp)) - return; setscratch(); if (!fname) return; @@ -1418,11 +1477,12 @@ main(int argc, char *argv[]) if (argc > 1) usage(); - signal(SIGINT, sigintr); - signal(SIGHUP, sighup); - signal(SIGQUIT, SIG_IGN); - - init(*argv); + if (!setjmp(savesp)) { + signal(SIGINT, sigintr); + signal(SIGHUP, sighup); + signal(SIGQUIT, SIG_IGN); + init(*argv); + } edit(); /* not reached */