Add parameterized position handling to printf(1).

Add a new %n$ option to change the order of the parameters as
done in the ksh93 builtin printf (among others).

For example:
%printf '%2$1d %1$s\n' one 2 three 4
2 one
4 three

The feature was written by Garret D'Amore under a
BSD license for Nexenta/illumos.

Reference:
http://garrett.damore.org/2010/10/new-implementation-of-printf.html

PR:		bin/152934
Obtained from:	Illumos
MFC after:	2 weeks
This commit is contained in:
pfg 2014-04-21 22:47:18 +00:00
parent 534840ba27
commit 540cea4ebc
2 changed files with 39 additions and 1 deletions

View File

@ -31,7 +31,7 @@
.\" @(#)printf.1 8.1 (Berkeley) 6/6/93
.\" $FreeBSD$
.\"
.Dd May 28, 2011
.Dd April 21, 2014
.Dt PRINTF 1
.Os
.Sh NAME
@ -290,6 +290,9 @@ octal escapes are
.Cm \e0 Ns Ar num
instead of
.Cm \e Ns Ar num .
.It Cm n$
Allows reordering of the output according to
.Ar argument .
.It Cm \&%
Print a `%'; no argument is used.
.El

View File

@ -1,4 +1,5 @@
/*-
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
@ -69,6 +70,11 @@ static const char rcsid[] =
#define PF(f, func) do { \
char *b = NULL; \
int dollar = 0; \
if (*f == '$') { \
dollar++; \
*f = '%'; \
} \
if (havewidth) \
if (haveprec) \
(void)asprintf(&b, f, fieldwidth, precision, func); \
@ -82,6 +88,8 @@ static const char rcsid[] =
(void)fputs(b, stdout); \
free(b); \
} \
if (dollar) \
*f = '$'; \
} while (0)
static int asciicode(void);
@ -96,6 +104,8 @@ static const char
static char *mknum(char *, char);
static void usage(void);
static int myargc;
static char **myargv;
static char **gargv;
int
@ -146,7 +156,13 @@ main(int argc, char *argv[])
chopped = escape(fmt, 1, &len); /* backslash interpretation */
rval = end = 0;
gargv = ++argv;
for (;;) {
char **maxargv = gargv;
myargv = gargv;
for (myargc = 0; gargv[myargc]; myargc++)
/* nop */;
start = fmt;
while (fmt < format + len) {
if (fmt[0] == '%') {
@ -168,7 +184,10 @@ main(int argc, char *argv[])
start = fmt;
} else
fmt++;
if (gargv > maxargv)
maxargv = gargv;
}
gargv = maxargv;
if (end == 1) {
warnx("missing format character");
@ -202,6 +221,22 @@ printf_doformat(char *start, int *rval)
char convch, nextch;
fmt = start + 1;
/* look for "n$" field index specifier */
fmt += strspn(fmt, skip2);
if ((*fmt == '$') && (fmt != (start + 1))) {
int idx = atoi(start + 1);
if (idx <= myargc) {
gargv = &myargv[idx - 1];
} else {
gargv = &myargv[myargc];
}
start = fmt;
fmt++;
} else {
fmt = start + 1;
}
/* skip to field width */
fmt += strspn(fmt, skip1);
if (*fmt == '*') {