summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2016-06-18 18:11:53 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2016-06-18 18:11:53 +0000
commitbdd970fe719f78ba0b13446190ede748e3f8fb4d (patch)
treeea4a80588e0b825db5a54e48428a7f2169b59fa6
parent6b91dc463642bbd63a6142f198d3710c42e74c2f (diff)
downloadexecline-bdd970fe719f78ba0b13446190ede748e3f8fb4d.tar.xz
Revert backtick to a non-wrapper; add -I to backtick and withstdinas
-rw-r--r--doc/backtick.html27
-rw-r--r--doc/withstdinas.html27
-rw-r--r--package/deps.mak4
-rw-r--r--src/execline/backtick.c132
-rw-r--r--src/execline/deps-exe/backtick1
-rw-r--r--src/execline/withstdinas.c54
6 files changed, 129 insertions, 116 deletions
diff --git a/doc/backtick.html b/doc/backtick.html
index 6aa2f01..694a29d 100644
--- a/doc/backtick.html
+++ b/doc/backtick.html
@@ -46,20 +46,27 @@ output as a value. </li>
<h2> Options </h2>
<ul>
- <li> <tt>-i</tt>&nbsp;: insist. If <em>prog1</em> crashes or exits non-zero,
-<tt>backtick</tt> exits with an
-<a href="exitcodes.html">approximation</a> of the same exit code. </li>
- <li> <tt>-D&nbsp;<em>default</em></tt>&nbsp;: default value. If
-<em>prog1</em> crashes or exits non-zero, <em>default</em> is used as
-<em>variable</em>'s value. If neither the <tt>-i</tt> nor the <tt>-D</tt>
-option have been given, <tt>backtick</tt> execs into
-<em>prog2...</em> no matter what <em>prog1</em> does, with the null word as
-<em>variable</em>'s value if <em>prog1</em> didn't write anything before
-dying. </li>
<li> <tt>-n</tt>&nbsp;: chomp an ending newline off <em>prog1...</em>'s
output. </li>
</ul>
+<p>
+ The other options tell backtick what to do if <em>prog1...</em>'s output
+is not suitable as the contents of an environment variable, i.e. it
+contains a null character:
+</p>
+
+<ul>
+ <li> <tt>-i</tt>&nbsp;: backtick exits 1. </li>
+ <li> <tt>-I</tt>&nbsp;: <em>variable</em> is <strong>removed</strong> from
+the environment, and execution proceeds. </li>
+ <li> <tt>-D&nbsp;<em>default</em></tt>&nbsp;: the value of <em>variable</em>
+is set to <em>default</em>, and execution proceeds. </li>
+ <li> neither of those options: the value of <em>variable</em> is set to whatever
+the start of <em>prog1...</em>'s output is, up to the first null character;
+then execution proceeds. </li>
+</ul>
+
<h2> Notes </h2>
<ul>
diff --git a/doc/withstdinas.html b/doc/withstdinas.html
index 29ad1b6..db49681 100644
--- a/doc/withstdinas.html
+++ b/doc/withstdinas.html
@@ -31,7 +31,7 @@ environment variable.
</p>
<pre>
- withstdinas [ -i | -D <em>default</em> ] [ -n ] <em>variable</em> <em>prog...</em>
+ withstdinas [ -i | -I | -D <em>default</em> ] [ -n ] <em>variable</em> <em>prog...</em>
</pre>
<ul>
@@ -44,18 +44,25 @@ environment variable.
<h2> Options </h2>
<ul>
- <li> <tt>-i</tt>&nbsp;: insist. If the data on stdin is invalid as
-an environment variable, for instance if it contains a null
-character, <tt>withstdinas</tt> exits 1. </li>
- <li> <tt>-D&nbsp;<em>default</em></tt>&nbsp;: default value.
-If the data on stdin is invalid, <em>default</em> is used as
-<em>variable</em>'s value. If neither the <tt>-i</tt> nor the <tt>-D</tt>
-option have been given, <tt>withstdinas</tt> execs into
-<em>prog...</em> with <em>variable</em> containing whatever value could be read on stdin,
-cut before the first null character. </li>
<li> <tt>-n</tt>&nbsp;: chomp an ending newline off stdin. </li>
</ul>
+<p>
+ The other options tell withstdinas what to do if its input is
+not suitable as the contents of an environment variable, i.e. it
+contains a null character:
+</p>
+
+<ul>
+ <li> <tt>-i</tt>&nbsp;: withstdinas exits 1. </li>
+ <li> <tt>-I</tt>&nbsp;: <em>variable</em> is <strong>removed</strong> from
+the environment, and execution proceeds. </li>
+ <li> <tt>-D&nbsp;<em>default</em></tt>&nbsp;: the value of <em>variable</em>
+is set to <em>default</em>, and execution proceeds. </li>
+ <li> neither of those options: the value of <em>variable</em> is set to whatever the
+start of the input is, up to the first null character; and execution proceeds. </li>
+</ul>
+
<h2> Notes </h2>
<ul>
diff --git a/package/deps.mak b/package/deps.mak
index d38609f..88138b3 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -3,7 +3,7 @@
#
src/execline/background.o src/execline/background.lo: src/execline/background.c src/include/execline/execline.h
-src/execline/backtick.o src/execline/backtick.lo: src/execline/backtick.c src/include/execline/config.h src/include/execline/execline.h
+src/execline/backtick.o src/execline/backtick.lo: src/execline/backtick.c src/include/execline/execline.h
src/execline/cd.o src/execline/cd.lo: src/execline/cd.c
src/execline/define.o src/execline/define.lo: src/execline/define.c src/include-local/exlsn.h
src/execline/dollarat.o src/execline/dollarat.lo: src/execline/dollarat.c
@@ -75,7 +75,7 @@ src/libexecline/exlsn_multidefine.o src/libexecline/exlsn_multidefine.lo: src/li
background: EXTRA_LIBS :=
background: src/execline/background.o ${LIBEXECLINE} -lskarnet
backtick: EXTRA_LIBS :=
-backtick: src/execline/backtick.o -lskarnet
+backtick: src/execline/backtick.o ${LIBEXECLINE} -lskarnet
cd: EXTRA_LIBS :=
cd: src/execline/cd.o -lskarnet
define: EXTRA_LIBS :=
diff --git a/src/execline/backtick.c b/src/execline/backtick.c
index 2deb9f3..2661983 100644
--- a/src/execline/backtick.c
+++ b/src/execline/backtick.c
@@ -1,84 +1,102 @@
/* ISC license. */
+#include <sys/types.h>
+#include <sys/wait.h>
#include <unistd.h>
-#include <errno.h>
-#include <skalibs/uint.h>
+#include <skalibs/bytestr.h>
#include <skalibs/sgetopt.h>
#include <skalibs/strerr2.h>
+#include <skalibs/stralloc.h>
#include <skalibs/djbunix.h>
-#include <execline/config.h>
#include <execline/execline.h>
-#define USAGE "backtick [ -i | -D default ] [ -n ] var { prog... } command..."
+#define USAGE "backtick [ -i | -I | -D default ] [ -n ] var { prog... } remainder..."
#define dieusage() strerr_dieusage(100, USAGE)
-int main (int argc, char const *const *argv, char const *const *envp)
+int main (int argc, char const **argv, char const *const *envp)
{
- char const *def = 0 ;
+ subgetopt_t localopt = SUBGETOPT_ZERO ;
+ pid_t pid ;
+ int argc1, fdwstat ;
+ stralloc modif = STRALLOC_ZERO ;
+ unsigned int modifstart ;
int insist = 0, chomp = 0 ;
+ char const *def = 0 ;
PROG = "backtick" ;
+ for (;;)
{
- subgetopt_t l = SUBGETOPT_ZERO ;
- for (;;)
+ register int opt = subgetopt_r(argc, argv, "iInD:", &localopt) ;
+ if (opt < 0) break ;
+ switch (opt)
{
- register int opt = subgetopt_r(argc, argv, "eniD:", &l) ;
- if (opt == -1) break ;
- switch (opt)
- {
- case 'e' : break ; /* compat */
- case 'n' : chomp = 1 ; break ;
- case 'i' : insist = 1 ; break ;
- case 'D' : def = l.arg ; break ;
- default : dieusage() ;
- }
+ case 'i' : insist = 2 ; break ;
+ case 'I' : insist = 1 ; break ;
+ case 'n' : chomp = 1 ; break ;
+ case 'D' : def = localopt.arg ; break ;
+ default : dieusage() ;
}
- argc -= l.ind ; argv += l.ind ;
}
+ argc -= localopt.ind ; argv += localopt.ind ;
+
if (argc < 2) dieusage() ;
- if (!argv[0][0]) dieusage() ;
- if (!argv[1][0]) strerr_dief1x(100, "empty block") ;
+ if (!*argv[0]) strerr_dief1x(100, "empty variable not accepted") ;
+ if (!stralloc_cats(&modif, argv[0]) || !stralloc_catb(&modif, "=", 1))
+ strerr_diefu1sys(111, "stralloc_catb") ;
+ modifstart = modif.len ;
+ argc-- ; argv++ ;
+ argc1 = el_semicolon(argv) ;
+ if (!argc1) strerr_dief1x(100, "empty block") ;
+ if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ;
+
+ argv[argc1] = 0 ;
+ pid = child_spawn1_pipe(argv[0], argv, envp, &fdwstat, 1) ;
+ if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ;
+ if (!slurp(&modif, fdwstat)) strerr_diefu1sys(111, "slurp") ;
+ close(fdwstat) ;
+ if (wait_pid(pid, &fdwstat) < 0) strerr_diefu1sys(111, "wait_pid") ;
+
+ if (wait_status(fdwstat))
{
- unsigned int m = 0, i = 1 ;
- int fd = dup(0) ;
- char const *newargv[argc + 15] ;
- char fmt[UINT_FMT] ;
- if (fd < 0)
+ if (insist >= 2)
+ if (WIFSIGNALED(fdwstat)) strerr_dief1x(111, "child process crashed") ;
+ else strerr_dief1x(WEXITSTATUS(fdwstat), "child process exited non-zero") ;
+ else if (insist)
{
- if (errno != EBADF) strerr_diefu1sys(111, "dup stdin") ;
+ modif.len = modifstart - 1 ;
+ chomp = 0 ;
}
- else fmt[uint_fmt(fmt, (unsigned int)fd)] = 0 ;
- newargv[m++] = EXECLINE_BINPREFIX "pipeline" ;
- newargv[m++] = "--" ;
- while (argv[i] && argv[i][0] != EXECLINE_BLOCK_END_CHAR && (!EXECLINE_BLOCK_END_CHAR || (argv[i][0] && argv[i][1])))
- newargv[m++] = argv[i++] ;
- if (!argv[i]) strerr_dief1x(100, "unterminated block") ;
- newargv[m++] = "" ; i++ ;
- if (!argv[i]) strerr_dief1x(100, "empty remainder") ;
- newargv[m++] = EXECLINE_BINPREFIX "withstdinas" ;
- if (insist) newargv[m++] = "-i" ;
- if (chomp) newargv[m++] = "-n" ;
- if (def)
+ else if (def)
{
- newargv[m++] = "-D" ;
- newargv[m++] = def ;
+ modif.len = modifstart ;
+ if (!stralloc_cats(&modif, def)) strerr_diefu1sys(111, "stralloc_catb") ;
}
- newargv[m++] = "-!" ;
- newargv[m++] = "--" ;
- newargv[m++] = argv[0] ;
- if (fd < 0)
- {
- newargv[m++] = EXECLINE_BINPREFIX "fdclose" ;
- newargv[m++] = "0" ;
- }
- else
+ }
+ if (argc == argc1 - 1) return 0 ;
+ if (!stralloc_0(&modif)) strerr_diefu1sys(111, "stralloc_catb") ;
+ {
+ unsigned int reallen = str_len(modif.s) ;
+ if (reallen < modif.len - 1)
{
- newargv[m++] = EXECLINE_BINPREFIX "fdmove" ;
- newargv[m++] = "0" ;
- newargv[m++] = fmt ;
+ if (insist >= 2)
+ strerr_dief1x(1, "child process output contained a null character") ;
+ else if (insist)
+ {
+ modif.len = modifstart ;
+ modif.s[modif.len - 1] = 0 ;
+ chomp = 0 ;
+ }
+ else if (def)
+ {
+ modif.len = modifstart ;
+ if (!stralloc_catb(&modif, def, str_len(def)+1))
+ strerr_diefu1sys(111, "stralloc_catb") ;
+ strerr_warnw2x("child process output contained a null character", " - using default instead") ;
+ }
+ else modif.len = reallen + 1 ;
}
- while (argv[i]) newargv[m++] = argv[i++] ;
- newargv[m++] = 0 ;
- pathexec_run(newargv[0], newargv, envp) ;
- strerr_dieexec(111, newargv[0]) ;
+ if (chomp && (modif.s[modif.len - 2] == '\n'))
+ modif.s[--modif.len - 1] = 0 ;
}
+ pathexec_r(argv + argc1 + 1, envp, env_len(envp), modif.s, modif.len) ;
+ strerr_dieexec(111, argv[argc1 + 1]) ;
}
diff --git a/src/execline/deps-exe/backtick b/src/execline/deps-exe/backtick
index e7187fe..97021b5 100644
--- a/src/execline/deps-exe/backtick
+++ b/src/execline/deps-exe/backtick
@@ -1 +1,2 @@
+${LIBEXECLINE}
-lskarnet
diff --git a/src/execline/withstdinas.c b/src/execline/withstdinas.c
index c1e3c36..af7140f 100644
--- a/src/execline/withstdinas.c
+++ b/src/execline/withstdinas.c
@@ -10,7 +10,7 @@
#include <skalibs/stralloc.h>
#include <skalibs/djbunix.h>
-#define USAGE "withstdinas [ -i | -D default ] [ -n ] var remainder..."
+#define USAGE "withstdinas [ -i | -I | -D default ] [ -n ] var remainder..."
#define dieusage() strerr_dieusage(100, USAGE)
int main (int argc, char const **argv, char const *const *envp)
@@ -18,19 +18,19 @@ int main (int argc, char const **argv, char const *const *envp)
subgetopt_t localopt = SUBGETOPT_ZERO ;
stralloc modif = STRALLOC_ZERO ;
unsigned int modifstart ;
- int insist = 0, chomp = 0, reapit = 0 ;
+ int insist = 0, chomp = 0 ;
char const *def = 0 ;
PROG = "withstdinas" ;
for (;;)
{
- register int opt = subgetopt_r(argc, argv, "einD:!", &localopt) ;
+ register int opt = subgetopt_r(argc, argv, "iInD:", &localopt) ;
if (opt < 0) break ;
switch (opt)
{
- case 'i' : insist = 1 ; break ;
+ case 'i' : insist = 2 ; break ;
+ case 'I' : insist = 1 ; break ;
case 'n' : chomp = 1 ; break ;
case 'D' : def = localopt.arg ; break ;
- case '!' : reapit = 1 ; break ;
default : dieusage() ;
}
}
@@ -38,42 +38,23 @@ int main (int argc, char const **argv, char const *const *envp)
if (!argc) dieusage() ;
if (!*argv[0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ;
- if (!stralloc_catb(&modif, "!", 2)
- || !stralloc_cats(&modif, argv[0])
- || !stralloc_catb(&modif, "=", 1))
+ if (!stralloc_cats(&modif, argv[0]) || !stralloc_catb(&modif, "=", 1))
strerr_diefu1sys(111, "stralloc_catb") ;
modifstart = modif.len ;
if (!slurp(&modif, 0)) strerr_diefu1sys(111, "slurp") ;
- if (reapit)
- {
- char const *x = env_get2(envp, "!") ;
- if (x)
- {
- uint64 pid ;
- int wstat ;
- if (!uint640_scan(x, &pid)) strerr_dieinvalid(100, "!") ;
- if (waitpid(pid, &wstat, 0) < 0)
- strerr_diefu1sys(111, "waitpid") ;
- if (wait_estatus(wstat))
- {
- if (insist)
- if (WIFSIGNALED(wstat)) strerr_dief1x(wait_estatus(wstat), "child process crashed") ;
- else strerr_dief1x(wait_estatus(wstat), "child process exited non-zero") ;
- else if (def)
- {
- modif.len = modifstart ;
- if (!stralloc_cats(&modif, def)) strerr_diefu1sys(111, "stralloc_catb") ;
- }
- }
- }
- }
if (!stralloc_0(&modif)) strerr_diefu1sys(111, "stralloc_catb") ;
{
- unsigned int reallen = str_len(modif.s + 2) ;
- if (reallen < modif.len - 3)
+ unsigned int reallen = str_len(modif.s) ;
+ if (reallen < modif.len - 1)
{
- if (insist)
+ if (insist >= 2)
strerr_dief1x(1, "stdin contained a null character") ;
+ else if (insist)
+ {
+ modif.len = modifstart ;
+ modif.s[modif.len - 1] = 0 ;
+ chomp = 0 ;
+ }
else if (def)
{
modif.len = modifstart ;
@@ -81,13 +62,12 @@ int main (int argc, char const **argv, char const *const *envp)
strerr_diefu1sys(111, "stralloc_catb") ;
strerr_warnw2x("stdin contained a null character", " - using default instead") ;
}
- else
- modif.len = reallen + 3 ;
+ else modif.len = reallen + 1 ;
}
if (chomp && (modif.s[modif.len - 2] == '\n'))
modif.s[--modif.len - 1] = 0 ;
}
if (!argv[1]) return 0 ;
- pathexec_r(argv + 1, envp, env_len(envp), modif.s + !reapit * 2, modif.len - !reapit * 2) ;
+ pathexec_r(argv + 1, envp, env_len(envp), modif.s, modif.len) ;
strerr_dieexec(111, argv[1]) ;
}