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 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
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();
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();
}