commit 1e10bf6069f472637450f3f1f1933b73dff88a83
parent b710ee81fcdb077d6ff088aa5beab021f58dc3d9
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Wed, 29 Nov 2023 13:25:07 +0100
ed: Add getinput() and setinput()
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.
Diffstat:
M | ed.c | | | 171 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
1 file changed, 92 insertions(+), 79 deletions(-)
diff --git 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);
}
@@ -172,30 +156,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
@@ -203,7 +179,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;
@@ -426,18 +403,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 == '[') {
@@ -521,9 +494,8 @@ ensureblank(void)
case ' ':
case '\t':
skipblank();
- case '\n':
+ case '\0':
back(c);
- case EOF:
break;
default:
error("unknown command");
@@ -681,6 +653,46 @@ quit(void)
exit(exstatus);
}
+static void
+setinput(char *s)
+{
+ copystring(&cmdline, s);
+ inputidx = 0;
+}
+
+static void
+getinput(void)
+{
+ int ch;
+
+ string(&cmdline);
+
+ 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
@@ -872,12 +884,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;
@@ -885,7 +897,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) {
@@ -1040,7 +1052,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");
@@ -1067,12 +1079,10 @@ getrhs(int delim)
static String s;
string(&s);
- 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);
}
@@ -1201,8 +1211,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();
@@ -1210,21 +1219,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;
@@ -1378,7 +1384,7 @@ repeat:
ensureblank();
if (nlines > 0)
goto unexpected;
- if (back(input()) != '\n')
+ if (back(input()) != '\0')
getfname(cmd);
else
puts(savfname);
@@ -1410,21 +1416,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
@@ -1469,12 +1465,26 @@ chkglobal(void)
}
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);
gflag = 1;
if (uflag)
chkprint(0);
@@ -1491,15 +1501,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
@@ -1527,12 +1540,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();
}