summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--Completion/Zsh/Command/_print17
-rw-r--r--Completion/Zsh/Type/_globquals3
-rw-r--r--Doc/Zsh/builtins.yo4
-rw-r--r--Src/builtin.c51
-rw-r--r--Test/B03print.ztst6
6 files changed, 66 insertions, 22 deletions
diff --git a/ChangeLog b/ChangeLog
index d1ac1cd45..1ebcc3725 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2016-11-04  Oliver Kiddle  <opk@zsh.org>
+
+	* 39389: Src/builtin.c, Test/B03print.ztst, Doc/Zsh/builtins.yo,
+	Completion/Zsh/Type/_globquals, Completion/Zsh/Command/_print:
+	when printf -v is used with an array use separate elements each
+	time the format is reused
+
 2016-11-04  Daniel Shahaf  <d.s@daniel.shahaf.name>
 
 	* users/22080: Doc/Zsh/zle.yo: bracketed-paste: Third time's
diff --git a/Completion/Zsh/Command/_print b/Completion/Zsh/Command/_print
index 38f17ab8e..8df094107 100644
--- a/Completion/Zsh/Command/_print
+++ b/Completion/Zsh/Command/_print
@@ -1,15 +1,18 @@
 #compdef print printf
 
-local state expl line eflag pflag rest ret=1
+local state expl line eflag pflag rflag rest ret=1
 
 if [[ $service = print ]]; then
   # -e flag available only after -R 
   eflag="${words[1,CURRENT-1][(r)-*R*]:+-e[enable escapes]}"
+  rflag='-r[ignore escape conventions of echo]'
 
   # -p flag only relevant if we have a coprocess
   (:>&p) 2>/dev/null &&
     pflag='(-s -u -z)-p[print arguments to input of coprocess]'
 
+  [[ -n ${words[(r)-*f]} ]] && rflag='-r[disable reuse of format string]'
+
   if [[ -n ${words[1,CURRENT][(r)-*P*]} ]]; then
     rest='*: :->prompt'
   else
@@ -17,11 +20,11 @@ if [[ $service = print ]]; then
   fi
 
   _arguments -C -s -A "-*" -S \
-    '(-f)-r[ignore escape conventions of echo]' \
+    '-r[ignore escape conventions of echo]' \
     '(-r -b -f -m -s -l -N -o -O -i -c -u -p -z -D -P)-R[emulate BSD echo (no escapes, -n & -e flags only)]' \
     '-b[recognise bindkey escape sequences]' \
-    '-m[remove arguments matching specified pattern]' \
-    '(-r -n -R -l -N -c)-f+[print arguments as for the printf builtin]:format:->printfformat' \
+    '-m[remove arguments not matching specified pattern]:pattern' \
+    '(-n -R -l -N -c)-f+[print arguments as for the printf builtin]:format:->printfformat' \
     '(-u -p -z)-s[place results in the history list]' \
     '(-c -f)-n[do not add a newline to the result]' \
     '(-N -c -f)-l[print arguments separated by newlines]' \
@@ -33,11 +36,13 @@ if [[ $service = print ]]; then
     '(-n -l -N -f -C -s -z)-c[print arguments in columns]' \
     '(-n -l -N -f -c -s -z)-C+[print arguments in specified number of columns]:columns' \
     '(-s -p -z)-u+[specify file descriptor to print arguments to]:file descriptor:_file_descriptors' \
-    '-v[store output in named parameter]:parameter:_parameters' \
+    '(-s -z -p -u)-v[store output in named parameter]:parameter:_parameters' \
     '(-s -p -u)-z[push arguments onto editing buffer stack]' \
     '-D[substitute any arguments which are named directories using ~ notation]' \
     '-P[perform prompt expansion]' \
-    $pflag $eflag $rest && ret=0
+    '(-X -f -a -C -c -z)-x+[expand leading tabs]:tab width' \
+    '(-x -f -a -C -c -z)-X+[expand all tabs]:tab width' \
+    $pflag $eflag $rflag $rest && ret=0
 elif [[ $service = printf ]]; then
   state=printf
 fi
diff --git a/Completion/Zsh/Type/_globquals b/Completion/Zsh/Type/_globquals
index 6eef16877..a904bdf0d 100644
--- a/Completion/Zsh/Type/_globquals
+++ b/Completion/Zsh/Type/_globquals
@@ -121,8 +121,7 @@ while [[ -n $PREFIX ]]; do
 	tmatch=( s m h d w M )
 	if zstyle -t ":completion:${curcontext}:time-specifiers" verbose; then
 	  zstyle -s ":completion:${curcontext}:time-specifiers" list-separator sep || sep=--
-          print -v tdisp -f "%s ${sep//(#m)[%\\]/$MATCH$MATCH} %s\0" ${tmatch:^^tdisp}
-	  tdisp=( ${(0)tdisp} )
+          print -v tdisp -f "%s ${sep//(#m)[%\\]/$MATCH$MATCH} %s" ${tmatch:^^tdisp}
 	fi
 	alts+=( "time-specifiers:time specifier:compadd -E 0 -d tdisp -S '' -a tmatch" )
       fi
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index dfbbaa034..169a31ea3 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1289,7 +1289,9 @@ required by the format than have been specified, the behaviour is as if
 zero or an empty string had been specified as the argument.
 
 The tt(-v) option causes the output to be stored as the value of the
-parameter var(name), instead of printed.
+parameter var(name), instead of printed. If var(name) is an array and
+the format string is reused when consuming arguments then one
+array element will be used for each use of the format string.
 )
 findex(pushd)
 pindex(PUSHD_TO_HOME, use of)
diff --git a/Src/builtin.c b/Src/builtin.c
index 986ace238..083a3aeb3 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -4087,10 +4087,11 @@ bin_print(char *name, char **args, Options ops, int func)
 {
     int flen, width, prec, type, argc, n, narg, curlen = 0;
     int nnl = 0, fmttrunc = 0, ret = 0, maxarg = 0, nc = 0;
-    int flags[6], *len;
+    int flags[6], *len, visarr = 0;
     char *start, *endptr, *c, *d, *flag, *buf = NULL, spec[14], *fmt = NULL;
     char **first, **argp, *curarg, *flagch = "'0+- #", save = '\0', nullstr = '\0';
     size_t rcount = 0, count = 0;
+    size_t *cursplit, *splits = 0;
     FILE *fout = stdout;
 #ifdef HAVE_OPEN_MEMSTREAM
     size_t mcount;
@@ -4122,7 +4123,7 @@ bin_print(char *name, char **args, Options ops, int func)
             return 1; \
         } \
         unlink(tmpf); \
-        if ((fout = fdopen(tempfd, "w+")) == NULL) { \
+        if ((FOUT = fdopen(tempfd, "w+")) == NULL) { \
             close(tempfd); \
             zwarnnam(name, "can't open temp file: %e", errno); \
             return 1; \
@@ -4647,11 +4648,23 @@ bin_print(char *name, char **args, Options ops, int func)
      * special cases of printing to a ZLE buffer or the history, however.
      */
 
+    if (OPT_ISSET(ops,'v')) {
+	struct value vbuf;
+	char* s = OPT_ARG(ops,'v');
+	Value v = getvalue(&vbuf, &s, 0);
+	visarr = v && PM_TYPE(v->pm->node.flags) == PM_ARRAY;
+    }
     /* printf style output */
     *spec = '%';
     argp = args;
     do {
     	rcount = count;
+	if (argp > args && visarr) { /* reusing format string */
+	    if (!splits)
+		cursplit = splits = (size_t *)zhalloc(sizeof(size_t) *
+			(arrlen(args) / (argp - args) + 1));
+	    *cursplit++ = count;
+	}
     	if (maxarg) {
 	    first += maxarg;
 	    argc -= maxarg;
@@ -5019,18 +5032,30 @@ bin_print(char *name, char **args, Options ops, int func)
 	    if (buf)
 		free(buf);
 	} else {
-	    stringval = metafy(buf, rcount, META_REALLOC);
-	    if (OPT_ISSET(ops,'z')) {
-		zpushnode(bufstack, stringval);
-	    } else if (OPT_ISSET(ops,'v')) {
-		setsparam(OPT_ARG(ops, 'v'), stringval);
+	    if (visarr) {
+		char **arrayval = zshcalloc((cursplit - splits + 2) * sizeof(char *));
+		for (;cursplit >= splits; cursplit--) {
+		    int start = cursplit == splits ? 0 : cursplit[-1];
+		    arrayval[cursplit - splits] =
+			    metafy(buf + start, count - start, META_DUP);
+		    count = start;
+		}
+		setaparam(OPT_ARG(ops, 'v'), arrayval);
+		free(buf);
 	    } else {
-		ent = prepnexthistent();
-		ent->node.nam = stringval;
-		ent->stim = ent->ftim = time(NULL);
-		ent->node.flags = 0;
-		ent->words = (short *)NULL;
-		addhistnode(histtab, ent->node.nam, ent);
+		stringval = metafy(buf, rcount, META_REALLOC);
+		if (OPT_ISSET(ops,'z')) {
+		    zpushnode(bufstack, stringval);
+		} else if (OPT_ISSET(ops,'v')) {
+		    setsparam(OPT_ARG(ops, 'v'), stringval);
+		} else {
+		    ent = prepnexthistent();
+		    ent->node.nam = stringval;
+		    ent->stim = ent->ftim = time(NULL);
+		    ent->node.flags = 0;
+		    ent->words = (short *)NULL;
+		    addhistnode(histtab, ent->node.nam, ent);
+		}
 	    }
 	}
 	unqueue_signals();
diff --git a/Test/B03print.ztst b/Test/B03print.ztst
index a4431cbc8..6ee2a09c6 100644
--- a/Test/B03print.ztst
+++ b/Test/B03print.ztst
@@ -310,3 +310,9 @@
 0:print and printf into a variable
 >typeset -g foo='once more'
 >typeset -g foo=$'into\C-@the-breach\C-@-'
+
+ typeset -a foo
+ print -f '%2$d %4s' -v foo one 1 two 2 three 3
+ typeset -p foo
+0:printf into an array variable
+>typeset -a foo=( '1  one' '2  two' '3 three' )