Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 7 May 2014 19:30:28 +0000 (UTC)
From:      "Pedro F. Giffuni" <pfg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r265592 - head/usr.bin/printf
Message-ID:  <201405071930.s47JUSX7043273@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <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.
@@ -50,6 +51,7 @@ static const char rcsid[] =
 
 #include <sys/types.h>
 
+#include <ctype.h>
 #include <err.h>
 #include <errno.h>
 #include <inttypes.h>
@@ -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 == '\'') {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405071930.s47JUSX7043273>