Compare commits

...

13 Commits

Author SHA1 Message Date
Jules Maselbas e24228e062 sbase-box: Fix segmentation fault when exe without args
when sbase-box is executed without argument, the check sbase-box
options doesn't verify the argument count leading to a segfault.

Add a check on the argc before parsing sbase-box options (currently
only `-i`)
2023-12-28 20:16:54 +01:00
Roberto E. Vargas Caballero 6a557314b9 ed: Don't undo commands in sigint
If newcmd is 0 then error() undo all the modifications
that happened since the last command, but this is  not
what POSIX mandates:

SIGINT	The ed utility shall interrupt its current activity, write the
	string "?\n" to standard output, and return to command mode
	(see the EXTENDED DESCRIPTION section).
2023-12-28 17:26:50 +01:00
Roberto E. Vargas Caballero bbdd7bedc4 ed: Simplify sighup dealing
As we already have the dump() function we can move the
modification check inside the new dump() function.
2023-12-28 17:19:47 +01:00
Roberto E. Vargas Caballero 137f0917e4 ed: Print only last line in empty command 2023-12-28 17:19:17 +01:00
Roberto E. Vargas Caballero 2d4d7dc6d4 ed: Fix G and V commands 2023-12-28 17:16:34 +01:00
Roberto E. Vargas Caballero 516e7fec92 ed: Remove nothing comments
Several bugs happened in the past due to this kind of comments
and it is better to get rid of them.
2023-12-28 17:16:24 +01:00
Roberto E. Vargas Caballero 54a0fc3ecc ed: Fix makeline
Strings without newlines created problems in the function
and the global field was not updated, making that new lines
added were marked as global being processed in the current
global command.
2023-12-28 17:14:04 +01:00
Roberto E. Vargas Caballero 09dc00f995 ed: Update TODO
Remove the cases are tested to work correctly now.
2023-12-28 17:04:13 +01:00
Roberto E. Vargas Caballero 890f6c2c05 ed: Improve execsh 2023-12-28 17:02:44 +01:00
Roberto E. Vargas Caballero aacfa18b79 ed: Avoid dangling pointer in getrhs()
If the string r.str is freed but error() is called then
next call will see a pointer that maybe it will try to free
because the call to error unwind the frame stack.
2023-12-28 17:02:19 +01:00
Roberto E. Vargas Caballero b089261c3a ed: Read from input in append()
This enables using a and i commands in a global command
because the input is not anymore taken from stdin.
2023-12-28 17:01:58 +01:00
Roberto E. Vargas Caballero 1e10bf6069 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.
2023-12-28 16:49:34 +01:00
Roberto E. Vargas Caballero b710ee81fc ed: Add copystring()
This makes possible to use the function to initialize the string from
an existing char array.
2023-12-28 14:01:30 +01:00
3 changed files with 180 additions and 121 deletions

25
TODO
View File

@ -28,10 +28,6 @@ Bugs
ed
--
* Multi-line commands don't work in global commands:
g/^line/a \
line1
.
* cat <<EOF | ed
0a
int radix = 16;
@ -54,19 +50,16 @@ ed
line
.
1g/^$/p
* cat <<EOF | ed
i
foobar1
foobar2
.
1,2s/foo/&\
&/
,n
* Editing huge files doesn't work well.
* Escaping newlines in replacement doesn't work well:
% /bin/ed
i
foobar
.
s/foo/&\
->
->bar
,p
foo
->bar
Q
printf

274
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);
}
@ -121,6 +105,24 @@ prevln(int line)
return (line < 0) ? lastln : line;
}
static String *
copystring(String *s, char *from)
{
size_t len;
char *t;
if ((t = strdup(from)) == NULL)
error("out of memory");
len = strlen(t);
free(s->str);
s->str = t;
s->siz = len;
s->cap = len;
return s;
}
static String *
string(String *s)
{
@ -154,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
@ -185,25 +179,27 @@ 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;
if (idxsize <= SIZE_MAX - NUMLINES)
lp = reallocarray(zero, idxsize + NUMLINES, sizeof(*lp));
lp = reallocarray(zero, idxsize + NUMLINES, sizeof(*lp));
if (!lp)
error("out of memory");
idxsize += NUMLINES;
zero = lp;
}
lp = zero + lastidx;
lp->global = 0;
if (!s) {
lp->seek = -1;
len = 0;
} else {
while ((c = *s++) != '\n')
/* nothing */;
while ((c = *s++) && c != '\n')
;
len = s - begin;
if ((lp->seek = lseek(scratch, 0, SEEK_END)) < 0 ||
write(scratch, begin, len) < 0) {
@ -408,18 +404,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 == '[') {
@ -490,7 +482,7 @@ skipblank(void)
char c;
while ((c = input()) == ' ' || c == '\t')
/* nothing */;
;
back(c);
}
@ -503,9 +495,8 @@ ensureblank(void)
case ' ':
case '\t':
skipblank();
case '\n':
case '\0':
back(c);
case EOF:
break;
default:
error("unknown command");
@ -663,6 +654,55 @@ 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 int
moreinput(void)
{
if (!uflag)
return cmdline.str[inputidx] != '\0';
getinput();
return 1;
}
static void dowrite(const char *, int);
static void
@ -670,6 +710,9 @@ dump(void)
{
char *home;
if (modflag)
return;
line1 = nextln(0);
line2 = lastln;
@ -690,14 +733,14 @@ static void
chksignals(void)
{
if (hup) {
if (modflag)
dump();
exstatus = 1;
dump();
quit();
}
if (intr) {
intr = 0;
newcmd = 1;
clearerr(stdin);
error("Interrupt");
}
@ -846,7 +889,7 @@ dohelp(void)
static void
chkprint(int flag)
{
char c;
int c;
if (flag) {
if ((c = input()) == 'p' || c == 'l' || c == 'n')
@ -854,12 +897,12 @@ chkprint(int flag)
else
back(c);
}
if (input() != '\n')
if ((c = input()) != '\0' && c != '\n')
error("invalid command suffix");
}
static char *
getfname(char comm)
getfname(int comm)
{
int c;
char *bp;
@ -867,7 +910,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) {
@ -889,16 +932,21 @@ getfname(char comm)
static void
append(int num)
{
char *s = NULL;
size_t len = 0;
int ch;
static String line;
curln = num;
while (getline(&s, &len, stdin) > 0) {
if (*s == '.' && s[1] == '\n')
while (moreinput()) {
string(&line);
while ((ch = input()) != '\n' && ch != '\0')
addchar(ch, &line);
addchar('\n', &line);
addchar('\0', &line);
if (!strcmp(line.str, ".\n") || !strcmp(line.str, "."))
break;
inject(s, AFTER);
inject(line.str, AFTER);
}
free(s);
}
static void
@ -1022,14 +1070,22 @@ execsh(void)
error("no previous command");
}
while ((c = input()) != EOF && c != '\n') {
if (c == '%' && (cmd.siz == 0 || cmd.str[cmd.siz - 1] != '\\')) {
while ((c = input()) != '\0') {
switch (c) {
case '%':
if (savfname[0] == '\0')
error("no current filename");
repl = 1;
for (p = savfname; *p; ++p)
addchar(*p, &cmd);
} else {
break;
case '\\':
c = input();
if (c != '%') {
back(c);
c = '\\';
}
default:
addchar(c, &cmd);
}
}
@ -1049,20 +1105,18 @@ 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);
}
if (!strcmp("%", s.str)) {
free(s.str);
if (!rhs)
error("no previous substitution");
free(s.str);
} else {
free(rhs);
rhs = s.str;
@ -1183,8 +1237,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();
@ -1196,21 +1249,16 @@ repeat:
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':
if (gflag && uflag)
return;
case '\0':
num = gflag ? curln : curln+1;
deflines(num, num);
line1 = line2;
pflag = 'p';
goto print;
case 'l':
@ -1360,7 +1408,7 @@ repeat:
ensureblank();
if (nlines > 0)
goto unexpected;
if (back(input()) != '\n')
if (back(input()) != '\0')
getfname(cmd);
else
puts(savfname);
@ -1392,21 +1440,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
@ -1451,12 +1489,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);
@ -1469,19 +1521,33 @@ doglobal(void)
zero[k].global = 0;
curln = ln;
nlines = 0;
if (uflag) {
line1 = line2 = ln;
pflag = 0;
doprint();
if (!uflag) {
idx = inputidx;
getlst();
docmd();
inputidx = idx;
continue;
}
getlst();
docmd();
line1 = line2 = ln;
pflag = 0;
doprint();
for (;;) {
getinput();
if (strcmp(cmdline.str, "") == 0)
break;
savecmd();
getlst();
docmd();
}
} else {
cnt++;
ln = nextln(ln);
}
}
discard(); /* cover the case of not matching anything */
}
static void
@ -1509,12 +1575,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();
}

View File

@ -76,7 +76,7 @@ main(int argc, char *argv[])
char *s = basename(argv[0]);
struct cmd *bp;
if(!strcmp(s,"sbase-box")) {
if (!strcmp(s, "sbase-box") && argc > 1) {
argc--; argv++;
if (strcmp(argv[0], "-i") == 0) {
install(argv[1]);