These functions allow to read from stdin the full next line or seting as input a character array. These functions avoid all the complexity about repeat commands that is very fragile and depends on having multiple global variables with weak relation between them. --- ed.c | 171 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 92 insertions(+), 79 deletions(-)
diff --git a/ed.c b/ed.c index 13e956a..7881fba 100644 --- a/ed.c +++ b/ed.c @@ -64,30 +64,15 @@ static int pflag, modflag, uflag, gflag; static size_t csize; static String cmdline; static char *ocmdline; -static int repidx; +static int inputidx; static char *rhs; static char *lastmatch; static struct undo udata; static int newcmd; -int eol, bol; +static int eol, bol; static sig_atomic_t intr, hup; -static void -discard(void) -{ - int c; - - if (repidx >= 0 || cmdline.siz == 0) - return; - - /* discard until the end of the line */ - if (cmdline.str[cmdline.siz-1] != '\n') { - while ((c = getchar()) != '\n' && c != EOF) - ; - } -} - static void undo(void); static void @@ -102,7 +87,6 @@ error(char *msg) if (!newcmd) undo(); - discard(); curln = ocurln; longjmp(savesp, 1); } @@ -166,30 +150,22 @@ static void chksignals(void); static int input(void) { - int c; - - if (repidx >= 0) - return ocmdline[repidx++]; - - if ((c = getchar()) != EOF) - addchar(c, &cmdline); + int ch; chksignals(); - return c; + ch = cmdline.str[inputidx]; + if (ch != '\0') + inputidx++; + return ch; } static int back(int c) { - if (repidx > 0) { - --repidx; - } else { - ungetc(c, stdin); - if (c != EOF) - --cmdline.siz; - } - return c; + if (c == '\0') + return c; + return cmdline.str[--inputidx] = c; } static int @@ -197,7 +173,8 @@ makeline(char *s, int *off) { struct hline *lp; size_t len; - char c, *begin = s; + char *begin = s; + int c; if (lastidx >= idxsize) { lp = NULL; @@ -420,18 +397,14 @@ compile(int delim) eol = bol = bracket = lastre.siz = 0; for (n = 0;; ++n) { - if ((c = input()) == delim && !bracket) + c = input(); + if (c == delim && !bracket || c == '\0') { break; - if (c == '^') { + } else if (c == '^') { bol = 1; } else if (c == '$') { eol = 1; - } else if (c == '\n' || c == EOF) { - back(c); - break; - } - - if (c == '\\') { + } else if (c == '\\') { addchar(c, &lastre); c = input(); } else if (c == '[') { @@ -515,9 +488,8 @@ ensureblank(void) case ' ': case '\t': skipblank(); - case '\n': + case '\0': back(c); - case EOF: break; default: error("unknown command"); @@ -675,6 +647,46 @@ quit(void) exit(exstatus); } +static void +setinput(char *s) +{ + string(&cmdline, s); + inputidx = 0; +} + +static void +getinput(void) +{ + int ch; + + string(&cmdline, NULL); + + while ((ch = getchar()) != '\n' && ch != EOF) { + if (ch == '\\') { + if ((ch = getchar()) == EOF) + break; + if (ch != '\n') { + ungetc(ch, stdin); + ch = '\\'; + } + } + addchar(ch, &cmdline); + } + + addchar('\0', &cmdline); + inputidx = 0; + + if (ch == EOF) { + chksignals(); + if (ferror(stdin)) { + exstatus = 1; + fputs("ed: error reading input\n", stderr); + } + quit(); + } +} + + static void dowrite(const char *, int); static void @@ -866,12 +878,12 @@ chkprint(int flag) else back(c); } - if (input() != '\n') + if (input() != '\0') error("invalid command suffix"); } static char * -getfname(char comm) +getfname(int comm) { int c; char *bp; @@ -879,7 +891,7 @@ getfname(char comm) skipblank(); for (bp = fname; bp < &fname[FILENAME_MAX]; *bp++ = c) { - if ((c = input()) == EOF || c == '\n') + if ((c = input()) == '\0') break; } if (bp == fname) { @@ -1034,7 +1046,7 @@ execsh(void) error("no previous command"); } - while ((c = input()) != EOF && c != '\n') { + while ((c = input()) != '\0') { if (c == '%' && (cmd.siz == 0 || cmd.str[cmd.siz - 1] != '\\')) { if (savfname[0] == '\0') error("no current filename"); @@ -1061,12 +1073,10 @@ getrhs(int delim) static String s; string(&s, NULL); - while ((c = input()) != '\n' && c != EOF && c != delim) + while ((c = input()) != '\0' && c != delim) addchar(c, &s); addchar('\0', &s); - if (c == EOF) - error("invalid pattern delimiter"); - if (c == '\n') { + if (c == '\0') { pflag = 'p'; back(c); } @@ -1195,8 +1205,7 @@ subst(int nth) static void docmd(void) { - char cmd; - int rep = 0, c, line3, num, trunc; + int cmd, c, line3, num, trunc; repeat: skipblank(); @@ -1204,21 +1213,18 @@ repeat: trunc = pflag = 0; switch (cmd) { case '&': + /* This is not working now */ skipblank(); chkprint(0); if (!ocmdline) error("no previous command"); - rep = 1; - repidx = 0; + setinput(ocmdline); getlst(); goto repeat; case '!': execsh(); break; - case EOF: - if (cmdline.siz == 0) - quit(); - case '\n': + case '\0': if (gflag && uflag) return; num = gflag ? curln : curln+1; @@ -1372,7 +1378,7 @@ repeat: ensureblank(); if (nlines > 0) goto unexpected; - if (back(input()) != '\n') + if (back(input()) != '\0') getfname(cmd); else puts(savfname); @@ -1404,21 +1410,11 @@ repeat: } if (!pflag) - goto save_last_cmd; - + return; line1 = line2 = curln; + print: doprint(); - -save_last_cmd: - if (!uflag) - repidx = 0; - if (rep) - return; - free(ocmdline); - addchar('\0', &cmdline); - if ((ocmdline = strdup(cmdline.str)) == NULL) - error("out of memory"); } static int @@ -1462,13 +1458,27 @@ chkglobal(void) return 1; } +static void +savecmd(void) +{ + int ch; + + skipblank(); + ch = input(); + if (ch != '&') { + ocmdline = strdup(cmdline.str); + if (ocmdline == NULL) + error("out of memory"); + } + back(ch); +} + static void doglobal(void) { - int cnt, ln, k; + int cnt, ln, k, idx; skipblank(); - string(&cmdline, NULL); gflag = 1; if (uflag) chkprint(0); @@ -1485,15 +1495,18 @@ doglobal(void) line1 = line2 = ln; pflag = 0; doprint(); + getinput(); + savecmd(); } + idx = inputidx; getlst(); docmd(); + inputidx = idx; } else { cnt++; ln = nextln(ln); } } - discard(); /* cover the case of not matching anything */ } static void @@ -1521,12 +1534,12 @@ edit(void) newcmd = 1; ocurln = curln; olastln = lastln; - cmdline.siz = 0; - repidx = -1; if (optprompt) { fputs(prompt, stdout); fflush(stdout); } + + getinput(); getlst(); chkglobal() ? doglobal() : docmd(); } -- 2.37.3