bin/152934: Enhancements to printf(1)

Pedro F. Giffuni giffunip at tutopia.com
Wed Dec 8 19:30:20 UTC 2010


>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 at 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:


More information about the freebsd-bugs mailing list