From owner-svn-src-head@FreeBSD.ORG Wed May 7 19:30:28 2014 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id EFB9420C; Wed, 7 May 2014 19:30:28 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id D04FA238; Wed, 7 May 2014 19:30:28 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s47JUS3u043274; Wed, 7 May 2014 19:30:28 GMT (envelope-from pfg@svn.freebsd.org) Received: (from pfg@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s47JUSX7043273; Wed, 7 May 2014 19:30:28 GMT (envelope-from pfg@svn.freebsd.org) Message-Id: <201405071930.s47JUSX7043273@svn.freebsd.org> From: "Pedro F. Giffuni" Date: Wed, 7 May 2014 19:30:28 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r265592 - head/usr.bin/printf X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 07 May 2014 19:30:29 -0000 Author: pfg Date: Wed May 7 19:30:28 2014 New Revision: 265592 URL: http://svnweb.freebsd.org/changeset/base/265592 Log: 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 Modified: head/usr.bin/printf/printf.c Modified: head/usr.bin/printf/printf.c ============================================================================== --- head/usr.bin/printf/printf.c Wed May 7 19:22:54 2014 (r265591) +++ head/usr.bin/printf/printf.c Wed May 7 19:30:28 2014 (r265592) @@ -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; + + start = alloca(strlen(fmt) + 1); + + dptr = start; + *dptr++ = '%'; + *dptr = 0; - fmt = start + 1; + 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 int rval; if (!*gargv) { - *ip = *uip = 0; + *ip = 0; return (0); } if (**gargv == '"' || **gargv == '\'') {