ed: Add getinput() and setinput() - sbase - suckless unix tools | |
git clone git://git.suckless.org/sbase | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 1e10bf6069f472637450f3f1f1933b73dff88a83 | |
parent b710ee81fcdb077d6ff088aa5beab021f58dc3d9 | |
Author: Roberto E. Vargas Caballero <[email protected]> | |
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(); | |
} |