diff --git a/usr.bin/printf/printf.c b/usr.bin/printf/printf.c index 7ed0c215f5d4..c5f56a6e8fab 100644 --- a/usr.bin/printf/printf.c +++ b/usr.bin/printf/printf.c @@ -1,4 +1,5 @@ /*- + * Copyright 2014 Garrett D'Amore * 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 +#include #include #include #include @@ -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; - fmt = start + 1; + start = alloca(strlen(fmt) + 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 == '\'') {