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.
This commit is contained in:
Roberto E. Vargas Caballero 2023-11-29 13:25:07 +01:00 committed by k0ga
parent b710ee81fc
commit 1e10bf6069
1 changed files with 93 additions and 80 deletions

173
ed.c
View File

@ -64,30 +64,15 @@ static int pflag, modflag, uflag, gflag;
static size_t csize; static size_t csize;
static String cmdline; static String cmdline;
static char *ocmdline; static char *ocmdline;
static int repidx; static int inputidx;
static char *rhs; static char *rhs;
static char *lastmatch; static char *lastmatch;
static struct undo udata; static struct undo udata;
static int newcmd; static int newcmd;
int eol, bol; static int eol, bol;
static sig_atomic_t intr, hup; 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 undo(void);
static void static void
@ -102,7 +87,6 @@ error(char *msg)
if (!newcmd) if (!newcmd)
undo(); undo();
discard();
curln = ocurln; curln = ocurln;
longjmp(savesp, 1); longjmp(savesp, 1);
} }
@ -172,30 +156,22 @@ static void chksignals(void);
static int static int
input(void) input(void)
{ {
int c; int ch;
if (repidx >= 0)
return ocmdline[repidx++];
if ((c = getchar()) != EOF)
addchar(c, &cmdline);
chksignals(); chksignals();
return c; ch = cmdline.str[inputidx];
if (ch != '\0')
inputidx++;
return ch;
} }
static int static int
back(int c) back(int c)
{ {
if (repidx > 0) { if (c == '\0')
--repidx; return c;
} else { return cmdline.str[--inputidx] = c;
ungetc(c, stdin);
if (c != EOF)
--cmdline.siz;
}
return c;
} }
static int static int
@ -203,7 +179,8 @@ makeline(char *s, int *off)
{ {
struct hline *lp; struct hline *lp;
size_t len; size_t len;
char c, *begin = s; char *begin = s;
int c;
if (lastidx >= idxsize) { if (lastidx >= idxsize) {
lp = NULL; lp = NULL;
@ -426,18 +403,14 @@ compile(int delim)
eol = bol = bracket = lastre.siz = 0; eol = bol = bracket = lastre.siz = 0;
for (n = 0;; ++n) { for (n = 0;; ++n) {
if ((c = input()) == delim && !bracket) c = input();
if (c == delim && !bracket || c == '\0') {
break; break;
if (c == '^') { } else if (c == '^') {
bol = 1; bol = 1;
} else if (c == '$') { } else if (c == '$') {
eol = 1; eol = 1;
} else if (c == '\n' || c == EOF) { } else if (c == '\\') {
back(c);
break;
}
if (c == '\\') {
addchar(c, &lastre); addchar(c, &lastre);
c = input(); c = input();
} else if (c == '[') { } else if (c == '[') {
@ -521,9 +494,8 @@ ensureblank(void)
case ' ': case ' ':
case '\t': case '\t':
skipblank(); skipblank();
case '\n': case '\0':
back(c); back(c);
case EOF:
break; break;
default: default:
error("unknown command"); error("unknown command");
@ -681,6 +653,46 @@ quit(void)
exit(exstatus); 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 dowrite(const char *, int);
static void static void
@ -872,12 +884,12 @@ chkprint(int flag)
else else
back(c); back(c);
} }
if (input() != '\n') if (input() != '\0')
error("invalid command suffix"); error("invalid command suffix");
} }
static char * static char *
getfname(char comm) getfname(int comm)
{ {
int c; int c;
char *bp; char *bp;
@ -885,7 +897,7 @@ getfname(char comm)
skipblank(); skipblank();
for (bp = fname; bp < &fname[FILENAME_MAX]; *bp++ = c) { for (bp = fname; bp < &fname[FILENAME_MAX]; *bp++ = c) {
if ((c = input()) == EOF || c == '\n') if ((c = input()) == '\0')
break; break;
} }
if (bp == fname) { if (bp == fname) {
@ -1040,7 +1052,7 @@ execsh(void)
error("no previous command"); 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 (c == '%' && (cmd.siz == 0 || cmd.str[cmd.siz - 1] != '\\')) {
if (savfname[0] == '\0') if (savfname[0] == '\0')
error("no current filename"); error("no current filename");
@ -1067,12 +1079,10 @@ getrhs(int delim)
static String s; static String s;
string(&s); string(&s);
while ((c = input()) != '\n' && c != EOF && c != delim) while ((c = input()) != '\0' && c != delim)
addchar(c, &s); addchar(c, &s);
addchar('\0', &s); addchar('\0', &s);
if (c == EOF) if (c == '\0') {
error("invalid pattern delimiter");
if (c == '\n') {
pflag = 'p'; pflag = 'p';
back(c); back(c);
} }
@ -1201,8 +1211,7 @@ subst(int nth)
static void static void
docmd(void) docmd(void)
{ {
char cmd; int cmd, c, line3, num, trunc;
int rep = 0, c, line3, num, trunc;
repeat: repeat:
skipblank(); skipblank();
@ -1210,21 +1219,18 @@ repeat:
trunc = pflag = 0; trunc = pflag = 0;
switch (cmd) { switch (cmd) {
case '&': case '&':
/* This is not working now */
skipblank(); skipblank();
chkprint(0); chkprint(0);
if (!ocmdline) if (!ocmdline)
error("no previous command"); error("no previous command");
rep = 1; setinput(ocmdline);
repidx = 0;
getlst(); getlst();
goto repeat; goto repeat;
case '!': case '!':
execsh(); execsh();
break; break;
case EOF: case '\0':
if (cmdline.siz == 0)
quit();
case '\n':
if (gflag && uflag) if (gflag && uflag)
return; return;
num = gflag ? curln : curln+1; num = gflag ? curln : curln+1;
@ -1378,7 +1384,7 @@ repeat:
ensureblank(); ensureblank();
if (nlines > 0) if (nlines > 0)
goto unexpected; goto unexpected;
if (back(input()) != '\n') if (back(input()) != '\0')
getfname(cmd); getfname(cmd);
else else
puts(savfname); puts(savfname);
@ -1410,21 +1416,11 @@ repeat:
} }
if (!pflag) if (!pflag)
goto save_last_cmd; return;
line1 = line2 = curln; line1 = line2 = curln;
print: print:
doprint(); 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 static int
@ -1469,12 +1465,26 @@ chkglobal(void)
} }
static void static void
doglobal(void) savecmd(void)
{ {
int cnt, ln, k; 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, idx;
skipblank(); skipblank();
string(&cmdline);
gflag = 1; gflag = 1;
if (uflag) if (uflag)
chkprint(0); chkprint(0);
@ -1491,15 +1501,18 @@ doglobal(void)
line1 = line2 = ln; line1 = line2 = ln;
pflag = 0; pflag = 0;
doprint(); doprint();
getinput();
savecmd();
} }
idx = inputidx;
getlst(); getlst();
docmd(); docmd();
inputidx = idx;
} else { } else {
cnt++; cnt++;
ln = nextln(ln); ln = nextln(ln);
} }
} }
discard(); /* cover the case of not matching anything */
} }
static void static void
@ -1527,12 +1540,12 @@ edit(void)
newcmd = 1; newcmd = 1;
ocurln = curln; ocurln = curln;
olastln = lastln; olastln = lastln;
cmdline.siz = 0;
repidx = -1;
if (optprompt) { if (optprompt) {
fputs(prompt, stdout); fputs(prompt, stdout);
fflush(stdout); fflush(stdout);
} }
getinput();
getlst(); getlst();
chkglobal() ? doglobal() : docmd(); chkglobal() ? doglobal() : docmd();
} }