From owner-freebsd-bugs@FreeBSD.ORG Wed Dec 8 19:30:20 2010 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 542331065679 for ; Wed, 8 Dec 2010 19:30:20 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 167578FC23 for ; Wed, 8 Dec 2010 19:30:20 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.4/8.14.4) with ESMTP id oB8JUJ5i045697 for ; Wed, 8 Dec 2010 19:30:19 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id oB8JUJCs045689; Wed, 8 Dec 2010 19:30:19 GMT (envelope-from gnats) Resent-Date: Wed, 8 Dec 2010 19:30:19 GMT Resent-Message-Id: <201012081930.oB8JUJCs045689@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, "Pedro F. Giffuni" Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 0A05A106564A for ; Wed, 8 Dec 2010 19:29:27 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from red.freebsd.org (unknown [IPv6:2001:4f8:fff6::22]) by mx1.freebsd.org (Postfix) with ESMTP id D31918FC12 for ; Wed, 8 Dec 2010 19:29:26 +0000 (UTC) Received: from red.freebsd.org (localhost [127.0.0.1]) by red.freebsd.org (8.14.4/8.14.4) with ESMTP id oB8JTQT6062823 for ; Wed, 8 Dec 2010 19:29:26 GMT (envelope-from nobody@red.freebsd.org) Received: (from nobody@localhost) by red.freebsd.org (8.14.4/8.14.4/Submit) id oB8JTQDV062822; Wed, 8 Dec 2010 19:29:26 GMT (envelope-from nobody) Message-Id: <201012081929.oB8JTQDV062822@red.freebsd.org> Date: Wed, 8 Dec 2010 19:29:26 GMT From: "Pedro F. Giffuni" To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: bin/152934: Enhancements to printf(1) X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 08 Dec 2010 19:30:20 -0000 >Number: 152934 >Category: bin >Synopsis: Enhancements to printf(1) >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Wed Dec 08 19:30:19 UTC 2010 >Closed-Date: >Last-Modified: >Originator: Pedro F. Giffuni >Release: 8.1-RELEASE >Organization: >Environment: FreeBSD mogwai.giffuni.net 8.1-RELEASE FreeBSD 8.1-RELEASE #0: Mon Jul 19 02:55:53 UTC 2010 root@almeida.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC i386 >Description: I took an Illumos patch from Garret D'Amore and back ported it to FreeBSD: >From Garret's blog: http://gdamore.blogspot.com/2010/10/new-implementation-of-printf.html "Specifically, I added handling of %n$ processing to get parameterized position handling. This is needed for internationalization -- it allows you to change the order of output as part of the output from something like gettext(1). (This is needed when you have to change word order to accommodate different natural language grammars.)" The patch includes: - Removal of 3rd Berkeley clause and added Nexenta's copyright. - Some style fixes. - Use char in all arguments of mknum. - Accomodate "--" per a POSIX requirement. - Contrary to the illumos patch, I preserved the shell/builtin mode. >How-To-Repeat: >Fix: Patch attached. Patch attached with submission follows: diff -ru printf.orig/printf.c printf/printf.c --- printf.orig/printf.c 2010-12-08 14:03:49.000000000 +0000 +++ printf/printf.c 2010-12-08 14:22:10.000000000 +0000 @@ -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. * @@ -10,10 +11,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -72,22 +69,30 @@ #ifndef BUILTIN #include #endif +#define _(x) gettext(x) -#define PF(f, func) do { \ - char *b = NULL; \ - if (havewidth) \ - if (haveprec) \ - (void)asprintf(&b, f, fieldwidth, precision, func); \ - else \ - (void)asprintf(&b, f, fieldwidth, func); \ - else if (haveprec) \ - (void)asprintf(&b, f, precision, func); \ - else \ - (void)asprintf(&b, f, func); \ - if (b) { \ - (void)fputs(b, stdout); \ - free(b); \ - } \ +#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); \ + else \ + (void) asprintf(&b, f, fieldwidth, func); \ + else if (haveprec) \ + (void) asprintf(&b, f, precision, func); \ + else \ + (void) asprintf(&b, f, func); \ + if (b) { \ + (void) fputs(b, stdout); \ + free(b); \ + } \ + if (dollar) \ + *f = '$'; \ } while (0) static int asciicode(void); @@ -99,9 +104,11 @@ static int getnum(intmax_t *, uintmax_t *, int); static const char *getstr(void); -static char *mknum(char *, int); +static char *mknum(char *, char); static void usage(void); +static int myargc; +static char **myargv; static char **gargv; int @@ -112,7 +119,7 @@ #endif { size_t len; - int ch, chopped, end, rval; + int chopped, end, rval; char *format, *fmt, *start; #if !defined(BUILTIN) && !defined(SHELL) @@ -121,15 +128,19 @@ #ifdef SHELL optreset = 1; optind = 1; opterr = 0; /* initialize getopt */ #endif - while ((ch = getopt(argc, argv, "")) != -1) - switch (ch) { - case '?': - default: - usage(); - return (1); - } - argc -= optind; - argv += optind; + + argv++; + argc--; + + /* + * POSIX says: Standard utilities that do not accept options, + * but that do accept operands, shall recognize "--" as a + * first argument to be discarded. + */ + if (strcmp(argv[0], "--") == 0) { + argc--; + argv++; + } if (argc < 1) { usage(); @@ -151,14 +162,22 @@ 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] == '%') { - fwrite(start, 1, fmt - start, stdout); + (void) fwrite(start, 1, + (uintptr_t)fmt - (uintptr_t)start, stdout); + if (fmt[1] == '%') { /* %% prints a % */ - putchar('%'); + (void) putchar('%'); fmt += 2; } else { fmt = printf_doformat(fmt, &rval); @@ -173,7 +192,10 @@ start = fmt; } else fmt++; + if (gargv > maxargv) + maxargv = gargv; } + gargv = maxargv; if (end == 1) { warnx1("missing format character", NULL, NULL); @@ -182,7 +204,8 @@ #endif return (1); } - fwrite(start, 1, fmt - start, stdout); + (void) fwrite(start, 1, (uintptr_t)fmt - (uintptr_t)start, + stdout); if (chopped || !*gargv) { #ifdef SHELL INTON; @@ -207,6 +230,22 @@ 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 == '*') { @@ -347,7 +386,7 @@ } static char * -mknum(char *str, int ch) +mknum(char *str, char ch) { static char *copy; static size_t copy_size; @@ -370,7 +409,7 @@ copy_size = newlen; } - memmove(copy, str, len - 3); + (void) memmove(copy, str, len - 3); copy[len - 3] = 'j'; copy[len - 2] = ch; copy[len - 1] = '\0'; @@ -380,10 +419,10 @@ static int escape(char *fmt, int percent, size_t *len) { - char *save, *store; - int value, c; + char *save, *store, c; + int value; - for (save = store = fmt; (c = *fmt); ++fmt, ++store) { + for (save = store = fmt; ((c = *fmt) != 0); ++fmt, ++store) { if (c != '\\') { *store = c; continue; @@ -392,7 +431,7 @@ case '\0': /* EOS, user error */ *store = '\\'; *++store = '\0'; - *len = store - save; + *len = (uintptr_t)store - (uintptr_t)save; return (0); case '\\': /* backslash */ case '\'': /* single quote */ @@ -406,7 +445,7 @@ break; case 'c': *store = '\0'; - *len = store - save; + *len = (uintptr_t)store - (uintptr_t)save; return (1); case 'f': /* form-feed */ *store = '\f'; @@ -437,7 +476,7 @@ *store++ = '%'; *store = '%'; } else - *store = value; + *store = (char)value; break; default: *store = *fmt; @@ -445,7 +484,7 @@ } } *store = '\0'; - *len = store - save; + *len = (uintptr_t)store - (uintptr_t)save; return (0); } @@ -572,5 +611,5 @@ static void usage(void) { - (void)fprintf(stderr, "usage: printf format [arguments ...]\n"); + (void) fprintf(stderr, "usage: printf format [arguments ...]\n"); } >Release-Note: >Audit-Trail: >Unformatted: