>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 r...@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 <locale.h> #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: _______________________________________________ freebsd-bugs@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-bugs To unsubscribe, send any mail to "freebsd-bugs-unsubscr...@freebsd.org"