sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | LICENSE

commit 611fb5b365d5a07d59c00db99d692850a7aa3c30
parent e9577cde96b603adc73731a24d0fd331b02019f1
Author: Santtu Lakkala <inz@inz.fi>
Date:   Fri, 30 Jan 2026 13:21:00 +0200

ed: Implement command expansion for io commands

Split command expansion functionality from execsh() for reuse in the
read and write commands. Adjust getfname() to leave the command in the
input buffer for extraction by the new expandcmd().

Diffstat:
MTODO | 2--
Med.c | 95+++++++++++++++++++++++++++++++++++++++++++------------------------------------
2 files changed, 52 insertions(+), 45 deletions(-)

diff --git a/TODO b/TODO @@ -30,8 +30,6 @@ ed -- * Editing huge files doesn't work well. -* Using % in shell escapes of r, e, E, w, W, x and X commands. -* Using !! in shell escapes of r, e, E, w, W, x and X commands. printf diff --git a/ed.c b/ed.c @@ -751,6 +751,51 @@ chksignals(void) } } +static const char * +expandcmd(void) +{ + static String cmd; + char *p; + int c, repl = 0; + + skipblank(); + if ((c = input()) != '!') { + back(c); + string(&cmd); + } else if (cmd.siz) { + --cmd.siz; + repl = 1; + } else { + error("no previous command"); + } + + 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); + break; + case '\\': + c = input(); + if (c != '%') { + back(c); + c = '\\'; + } + default: + addchar(c, &cmd); + } + } + addchar('\0', &cmd); + + if (repl) + puts(cmd.str); + + return cmd.str; +} + static void dowrite(const char *fname, int trunc) { @@ -768,8 +813,7 @@ dowrite(const char *fname, int trunc) if(fname[0] == '!') { sh = 1; - fname++; - if((fp = popen(fname, "w")) == NULL) + if((fp = popen(expandcmd(), "w")) == NULL) error("bad exec"); } else { sh = 0; @@ -822,8 +866,7 @@ doread(const char *fname) if(fname[0] == '!') { sh = 1; - fname++; - if((fp = popen(fname, "r")) == NULL) + if((fp = popen(expandcmd(), "r")) == NULL) error("bad exec"); } else if ((fp = fopen(fname, "r")) == NULL) { error("cannot open input file"); @@ -931,6 +974,10 @@ getfname(int comm) static char fname[FILENAME_MAX]; skipblank(); + if ((c = input()) == '!') { + return strcpy(fname, "!"); + } + back(c); for (bp = fname; bp < &fname[FILENAME_MAX]; *bp++ = c) { if ((c = input()) == '\0') break; @@ -1076,45 +1123,7 @@ copy(int where) static void execsh(void) { - static String cmd; - char *p; - int c, repl = 0; - - skipblank(); - if ((c = input()) != '!') { - back(c); - string(&cmd); - } else if (cmd.siz) { - --cmd.siz; - repl = 1; - } else { - error("no previous command"); - } - - 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); - break; - case '\\': - c = input(); - if (c != '%') { - back(c); - c = '\\'; - } - default: - addchar(c, &cmd); - } - } - addchar('\0', &cmd); - - if (repl) - puts(cmd.str); - system(cmd.str); + system(expandcmd()); if (optdiag) puts("!"); }