summaryrefslogtreecommitdiffstats
path: root/usr.bin/printf/printf.c
diff options
context:
space:
mode:
authorpfg <pfg@FreeBSD.org>2014-05-07 19:30:28 +0000
committerpfg <pfg@FreeBSD.org>2014-05-07 19:30:28 +0000
commit9ea4556f36ce28f396d3100b29e0586d7eeef1c4 (patch)
treeec745f8f792583b77bae9d7a343f0220d70cc6f6 /usr.bin/printf/printf.c
parent939c7d3f2dc2df1015aca64ad6da3fa2b0cb77da (diff)
downloadFreeBSD-src-9ea4556f36ce28f396d3100b29e0586d7eeef1c4.zip
FreeBSD-src-9ea4556f36ce28f396d3100b29e0586d7eeef1c4.tar.gz
Add width and precision specifiers to printf(1) %n$.
This actually completes r264743 so that width and precision specifiers work properly with %n$. These keeps consistency with ksh93 and zsh. Requested by: jilles Obtained from: Garrett D'Amore (Illumos) MFC after: 4 days
Diffstat (limited to 'usr.bin/printf/printf.c')
-rw-r--r--usr.bin/printf/printf.c115
1 files changed, 90 insertions, 25 deletions
diff --git a/usr.bin/printf/printf.c b/usr.bin/printf/printf.c
index 7ed0c21..c5f56a6 100644
--- a/usr.bin/printf/printf.c
+++ b/usr.bin/printf/printf.c
@@ -1,4 +1,5 @@
/*-
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
@@ -50,6 +51,7 @@ static const char rcsid[] =
#include <sys/types.h>
+#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <inttypes.h>
@@ -70,11 +72,6 @@ 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); \
@@ -88,8 +85,6 @@ static const char rcsid[] =
(void)fputs(b, stdout); \
free(b); \
} \
- if (dollar) \
- *f = '$'; \
} while (0)
static int asciicode(void);
@@ -104,9 +99,12 @@ static const char
static char *mknum(char *, char);
static void usage(void);
+static const char digits[] = "0123456789";
+
static int myargc;
static char **myargv;
static char **gargv;
+static char **maxargv;
int
main(int argc, char *argv[])
@@ -158,7 +156,7 @@ main(int argc, char *argv[])
gargv = ++argv;
for (;;) {
- char **maxargv = gargv;
+ maxargv = gargv;
myargv = gargv;
for (myargc = 0; gargv[myargc]; myargc++)
@@ -212,57 +210,115 @@ main(int argc, char *argv[])
static char *
-printf_doformat(char *start, int *rval)
+printf_doformat(char *fmt, int *rval)
{
static const char skip1[] = "#'-+ 0";
- static const char skip2[] = "0123456789";
- char *fmt;
int fieldwidth, haveprec, havewidth, mod_ldbl, precision;
char convch, nextch;
+ char *start;
+ char **fargv;
+ char *dptr;
+ int l;
+
+ start = alloca(strlen(fmt) + 1);
- fmt = start + 1;
+ dptr = start;
+ *dptr++ = '%';
+ *dptr = 0;
+
+ fmt++;
/* look for "n$" field index specifier */
- fmt += strspn(fmt, skip2);
- if ((*fmt == '$') && (fmt != (start + 1))) {
- int idx = atoi(start + 1);
+ l = strspn(fmt, digits);
+ if ((l > 0) && (fmt[l] == '$')) {
+ int idx = atoi(fmt);
if (idx <= myargc) {
gargv = &myargv[idx - 1];
} else {
gargv = &myargv[myargc];
}
- start = fmt;
- fmt++;
+ if (gargv > maxargv)
+ maxargv = gargv;
+ fmt += l + 1;
+
+ /* save format argument */
+ fargv = gargv;
} else {
- fmt = start + 1;
+ fargv = NULL;
}
/* skip to field width */
- fmt += strspn(fmt, skip1);
+ while (strchr(skip1, *fmt) != NULL) {
+ *dptr++ = *fmt++;
+ *dptr = 0;
+ }
+
if (*fmt == '*') {
+
+ fmt++;
+ l = strspn(fmt, digits);
+ if ((l > 0) && (fmt[l] == '$')) {
+ int idx = atoi(fmt);
+ if (idx <= myargc) {
+ gargv = &myargv[idx - 1];
+ } else {
+ gargv = &myargv[myargc];
+ }
+ fmt += l + 1;
+ }
+
if (getint(&fieldwidth))
return (NULL);
+ if (gargv > maxargv)
+ maxargv = gargv;
havewidth = 1;
- ++fmt;
+
+ *dptr++ = '*';
+ *dptr = 0;
} else {
havewidth = 0;
/* skip to possible '.', get following precision */
- fmt += strspn(fmt, skip2);
+ while (isdigit(*fmt)) {
+ *dptr++ = *fmt++;
+ *dptr = 0;
+ }
}
+
if (*fmt == '.') {
/* precision present? */
- ++fmt;
+ fmt++;
+ *dptr++ = '.';
+
if (*fmt == '*') {
+
+ fmt++;
+ l = strspn(fmt, digits);
+ if ((l > 0) && (fmt[l] == '$')) {
+ int idx = atoi(fmt);
+ if (idx <= myargc) {
+ gargv = &myargv[idx - 1];
+ } else {
+ gargv = &myargv[myargc];
+ }
+ fmt += l + 1;
+ }
+
if (getint(&precision))
return (NULL);
+ if (gargv > maxargv)
+ maxargv = gargv;
haveprec = 1;
- ++fmt;
+ *dptr++ = '*';
+ *dptr = 0;
} else {
haveprec = 0;
/* skip to conversion char */
- fmt += strspn(fmt, skip2);
+ while (isdigit(*fmt)) {
+ *dptr++ = *fmt++;
+ *dptr = 0;
+ }
}
} else
haveprec = 0;
@@ -270,6 +326,8 @@ printf_doformat(char *start, int *rval)
warnx("missing format character");
return (NULL);
}
+ *dptr++ = *fmt;
+ *dptr = 0;
/*
* Look for a length modifier. POSIX doesn't have these, so
@@ -292,8 +350,14 @@ printf_doformat(char *start, int *rval)
mod_ldbl = 0;
}
+ /* save the current arg offset, and set to the format arg */
+ if (fargv != NULL) {
+ gargv = fargv;
+ }
+
convch = *fmt;
nextch = *++fmt;
+
*fmt = '\0';
switch (convch) {
case 'b': {
@@ -365,6 +429,7 @@ printf_doformat(char *start, int *rval)
return (NULL);
}
*fmt = nextch;
+ /* return the gargv to the next element */
return (fmt);
}
@@ -508,7 +573,7 @@ getnum(intmax_t *ip, uintmax_t *uip, int signedconv)
int rval;
if (!*gargv) {
- *ip = *uip = 0;
+ *ip = 0;
return (0);
}
if (**gargv == '"' || **gargv == '\'') {
OpenPOWER on IntegriCloud