summary refs log tree commit diff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2016-10-16 17:05:50 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2016-10-16 17:05:50 +0000
commita431f0ccec5c7d965a8fbbe3494b60bb439b6fb9 (patch)
tree9b8f86d0321625f3c8258900fe006a17578878a8
parentff4ac0ca4b41deba5e3cb100bee23431c694963f (diff)
downloadexecline-a431f0ccec5c7d965a8fbbe3494b60bb439b6fb9.tar.gz
execline-a431f0ccec5c7d965a8fbbe3494b60bb439b6fb9.tar.xz
execline-a431f0ccec5c7d965a8fbbe3494b60bb439b6fb9.zip
Add the -s option to execlineb (suggested by jjk)
-rw-r--r--doc/execlineb.html20
-rw-r--r--src/execline/execlineb.c26
2 files changed, 28 insertions, 18 deletions
diff --git a/doc/execlineb.html b/doc/execlineb.html
index e865199..96e804f 100644
--- a/doc/execlineb.html
+++ b/doc/execlineb.html
@@ -25,7 +25,7 @@
 <h2> Interface </h2>
 
 <pre>
-     execlineb [ -q | -w | -W ] [ -p | -P | -S <em>nmin</em> ] -c <em>script</em> [ <em>args...</em> ]
+     execlineb [ -q | -w | -W ] [ -p | -P | -S <em>nmin</em> | -s <em>nmin</em> ] -c <em>script</em> [ <em>args...</em> ]
 </pre>
 
 <p>
@@ -33,7 +33,7 @@ or
 </p>
 
 <pre>
-     execlineb [ -q | -w | -W ] [ -p | -P | -S <em>nmin</em> ] <em>scriptfile</em> [ <em>args...</em> ]
+     execlineb [ -q | -w | -W ] [ -p | -P | -S <em>nmin</em> | -s <em>nmin</em> ] <em>scriptfile</em> [ <em>args...</em> ]
 </pre>
 
 <p>
@@ -62,15 +62,15 @@ exits 0. </li>
 </p>
 
 <ul>
- <li> <em>Pushing the current stack frame.</em> If neither the
-<tt>-p</tt> nor the <tt>-P</tt> nor the <tt>-S</tt> option is set:
+ <li> <em>Pushing the current stack frame.</em> If none of the
+<tt>-p</tt>, <tt>-P</tt>, <tt>-S</tt> or <tt>-s</tt> options is set:
 <tt>execlineb</tt> <a href="el_pushenv.html">pushes</a>
 the current positional parameters, i.e. environment variables that
 start with <tt>#</tt>, <tt>0</tt>, <tt>1</tt>, ..., <tt>9</tt>.
 To get the previous values back, use
 <a href="emptyenv.html"><tt>emptyenv&nbsp;-P</tt></a>. </li>
- <li> <em>Setting the new stack frame.</em> If neither the <tt>-P</tt>
-nor the <tt>-S</tt> option is set:
+ <li> <em>Setting the new stack frame.</em> If none of the <tt>-P</tt>,
+<tt>-S</tt> or <tt>-s</tt> options is set:
  <ul>
   <li> <tt>execlineb</tt> sets the <tt>#</tt> environment variable to
 the number <em>n</em> of <em>args</em> it is given. </li>
@@ -229,6 +229,10 @@ variables. <tt>execlineb -S3 -c "<em>script</em>"</tt> is equivalent to,
 but more efficient than, <tt>execlineb -c "elgetpositionals -P3 emptyenv
 -P <em>script</em>"</tt>. See
 <a href="el_pushenv.html#integrated">the details</a>. </li>
+ <li> The <tt>-s&nbsp;<em>nmin</em></tt> option behaves just like the
+<tt>-S</tt> option, except that it defines <tt>$@</tt> as the rest of the
+command line <strong>after</strong> <em>nmin</em> arguments have been
+removed. </li>
 </ul>
 
 <h2> Current limitations </h2>
@@ -239,8 +243,8 @@ but more efficient than, <tt>execlineb -c "elgetpositionals -P3 emptyenv
 limitations such as the kernel buffer size for <em>argv</em> and <em>envp</em>
  - at least 64 kB on most systems. This means that <tt>execlineb</tt> cannot
 execute arbitrarily large scripts. Be careful with deeply nested scripts too:
-without the <tt>-p</tt>/<tt>-P</tt>/<tt>-S</tt> option, each execlineb
-invocation uses up some space in the environment.
+without the <tt>-p</tt>/<tt>-P</tt>/<tt>-S</tt>/<tt>-s</tt> option, each
+execlineb invocation uses up some space in the environment.
 </p>
 
 </body>
diff --git a/src/execline/execlineb.c b/src/execline/execlineb.c
index bfe1d7e..fbbaeee 100644
--- a/src/execline/execlineb.c
+++ b/src/execline/execlineb.c
@@ -15,9 +15,9 @@
 #include <execline/execline.h>
 #include "exlsn.h"
 
-#define USAGE "execlineb [ -p | -P | -S nmin ] [ -q | -w | -W ] [ -c commandline ] script args"
+#define USAGE "execlineb [ -p | -P | -S nmin | -s nmin ] [ -q | -w | -W ] [ -c commandline ] script args"
 
-static int myexlp (stralloc *sa, char const *const *argv, unsigned int argc, unsigned int nmin, char const *dollar0)
+static int myexlp (stralloc *sa, char const *const *argv, unsigned int argc, unsigned int nmin, char const *dollar0, int doshift)
 {
   exlsn_t info = EXLSN_ZERO ;
   unsigned int n = argc > nmin ? argc : nmin ;
@@ -33,17 +33,22 @@ static int myexlp (stralloc *sa, char const *const *argv, unsigned int argc, uns
     if (!stralloc_catb(&info.values, fmt, uint_fmt(fmt, argc)) || !stralloc_0(&info.values)) goto err ;
     blah[1].var = 2 ; blah[1].value = info.values.len ; blah[1].n = 1 ;
     if (!stralloc_catb(&info.values, dollar0, str_len(dollar0) + 1)) goto err ;
-    blah[2].var = 4 ; blah[2].value = info.values.len ; blah[2].n = argc ;
+    blah[2].var = 4 ; blah[2].value = info.values.len ; blah[2].n = doshift && n == nmin ? 0 : argc ;
     genalloc_catb(elsubst_t, &info.data, blah, 3) ;
   }
   for (; i < n ; i++)
   {
-    elsubst_t blah ;
+    elsubst_t blah = { .var = info.vars.len, .value = info.values.len, .n = 1 } ;
     char fmt[UINT_FMT] ;
-    blah.var = info.vars.len ; blah.value = info.values.len ; blah.n = 1 ;
     if (!stralloc_catb(&info.vars, fmt, uint_fmt(fmt, i+1)) || !stralloc_0(&info.vars)) goto err ;
     if (!stralloc_catb(&info.values, i < argc ? argv[i] : "", i < argc ? str_len(argv[i]) + 1 : 1)) goto err ;
     genalloc_append(elsubst_t, &info.data, &blah) ;
+    if (i == nmin && doshift)
+    {
+      elsubst_t *p = genalloc_s(elsubst_t, &info.data) + 2 ; /* hit $@ in-place */
+      p->value = blah.value ;
+      p->n = argc - nmin ;
+    }
   }
   {
     stralloc dst = STRALLOC_ZERO ;
@@ -75,7 +80,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
     subgetopt_t l = SUBGETOPT_ZERO ;
     for (;;)
     {
-      register int opt = subgetopt_r(argc, argv, "pPqwWc:S:", &l) ;
+      register int opt = subgetopt_r(argc, argv, "pPqwWc:S:s:", &l) ;
       if (opt == -1) break ;
       switch (opt)
       {
@@ -86,9 +91,10 @@ int main (int argc, char const *const *argv, char const *const *envp)
         case 'W' : flagstrict = 2 ; break ;
         case 'c' : stringarg = l.arg ; break ;
         case 'S' :
+        case 's' :
         {
           if (!uint0_scan(l.arg, &nmin)) strerr_dieusage(100, USAGE) ;
-          flagpushenv = 3 ;
+          flagpushenv = 3 + (opt == 's') ;
           break ;
         }
         default : strerr_dieusage(100, USAGE) ;
@@ -130,9 +136,8 @@ int main (int argc, char const *const *argv, char const *const *envp)
     if (!env_addmodif(&modif, "EXECLINE_STRICT", flagstrict ? fmt : 0)) goto errenv ;
   }
 
-  if (flagpushenv == 3)
+  if (flagpushenv == 3 || flagpushenv == 4)
   {
-    flagpushenv = 0 ;
     if (flagstrict && ((unsigned int)argc < nmin))
     {
       char fmtn[UINT_FMT] ;
@@ -144,8 +149,9 @@ int main (int argc, char const *const *argv, char const *const *envp)
       else
         strerr_warnw4x("too few arguments: expecting at least ", fmtn, " but got ", fmta) ;
     }
-    nc = myexlp(&sa, argv, argc, nmin, dollar0) ;
+    nc = myexlp(&sa, argv, argc, nmin, dollar0, flagpushenv == 4) ;
     if (nc < 0) strerr_diefu1sys(111, "substitute positional parameters") ;
+    flagpushenv = 0 ;
   }
   else if (flagpushenv)
   {