--- old/usr/src/cmd/printf/printf.c	Fri May  2 20:34:24 2014
+++ new/usr/src/cmd/printf/printf.c	Fri May  2 20:34:24 2014
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -38,6 +39,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <alloca.h>
+#include <ctype.h>
 #include <locale.h>
 #include <note.h>
 
@@ -51,11 +54,6 @@
 
 #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); \
@@ -69,8 +67,6 @@
 		(void) fputs(b, stdout);				\
 		free(b);						\
 	}								\
-	if (dollar)							\
-		*f = '$';						\
 _NOTE(CONSTCOND) } while (0)
 
 static int	 asciicode(void);
@@ -85,9 +81,12 @@
 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[])
@@ -130,7 +129,7 @@
 	gargv = ++argv;
 
 	for (;;) {
-		char **maxargv = gargv;
+		maxargv = gargv;
 
 		myargv = gargv;
 		for (myargc = 0; gargv[myargc]; myargc++)
@@ -174,57 +173,115 @@
 
 
 static char *
-doformat(char *start, int *rval)
+doformat(char *fmt, int *rval)
 {
 	static const char skip1[] = "#'-+ 0";
-	static const char skip2[] = "0123456789";
-	char *fmt;
+	char **save;
 	int fieldwidth, haveprec, havewidth, mod_ldbl, precision;
 	char convch, nextch;
+	char *start;
+	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++;
-	} else {
-		fmt = start + 1;
+		if (gargv > maxargv) {
+			maxargv = gargv;
+		}
+		fmt += l + 1;
 	}
 
+	save = gargv;
+
 	/* 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;
@@ -232,6 +289,8 @@
 		warnx1(_("missing format character"), NULL, NULL);
 		return (NULL);
 	}
+	*dptr++ = *fmt;
+	*dptr = 0;
 
 	/*
 	 * Look for a length modifier.  POSIX doesn't have these, so
@@ -254,8 +313,10 @@
 		mod_ldbl = 0;
 	}
 
+	gargv = save;
 	convch = *fmt;
 	nextch = *++fmt;
+
 	*fmt = '\0';
 	switch (convch) {
 	case 'b': {
