dash.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [0/9] Handle embedded NULs correctly in printf
@ 2014-10-27  8:25 Herbert Xu
  2014-10-27  8:26 ` [PATCH 1/9] [BUILTIN] " Herbert Xu
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Herbert Xu @ 2014-10-27  8:25 UTC (permalink / raw)
  To: dash

Hi:

This series adds embedded NUL handling to printf, and then tries
to squeeze out some fat so we don't end up bloating it up too much.

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/9] [BUILTIN] Handle embedded NULs correctly in printf
  2014-10-27  8:25 [0/9] Handle embedded NULs correctly in printf Herbert Xu
@ 2014-10-27  8:26 ` Herbert Xu
  2014-10-27  8:26 ` [PATCH 2/9] [INPUT] Replace open-coded flushall in preadbuffer Herbert Xu
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Herbert Xu @ 2014-10-27  8:26 UTC (permalink / raw)
  To: dash

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=379227

On Sat, Jul 22, 2006 at 12:48:38PM +0200, A Mennucc wrote:
> Package: dash
> Version: 0.5.3-3
> Severity: normal
> 
> hi
> 
> here are the examples
> 
> $ bash -c 'echo -n -e "A\0102C\00D\0E" | hexdump -c'
> 0000000   A   B   C  \0   D  \0   E
> 0000007
> 
> $ /bin/echo -n -e "A\0102C\00D\0E" | hexdump -c
> 0000000   A   B   C  \0   D  \0   E
> 0000007
> 
> $ zsh -c 'echo -n -e "A\0102C\00D\0E" | hexdump -c'
> 0000000   A   B   C  \0   D  \0   E
> 0000007
> 
> $ dash -c 'echo -n  "A\0102C\00D\0E" | hexdump -c'
> 0000000   A   B   C
> 0000003
> 
> and also
> 
> $ dash -c 'echo -n  "ABC\0DEFGH" | hexdump -c'
> 0000000   A   B   C
> 0000003
> 
> As you see, dash 's builtin echo truncates the output at the first \0
> 
> a.
> 
> -- System Information:
> Debian Release: testing/unstable
>   APT prefers unstable
>   APT policy: (500, 'unstable'), (500, 'testing')
> Architecture: i386 (i686)
> Shell:  /bin/sh linked to /bin/bash
> Kernel: Linux 2.6.16-1-k7
> Locale: LANG=it_IT.UTF-8, LC_CTYPE=it_IT.UTF-8 (charmap=UTF-8)
> 
> Versions of packages dash depends on:
> ii  libc6                         2.3.6-15   GNU C Library: Shared libraries
> 
> dash recommends no packages.
> 
> -- debconf information:
> * dash/sh: false
> 
> -- 
> Andrea Mennucc
>  "E' un mondo difficile. Che vita intensa!" (Tonino Carotone)

This patch fixes handling of embedded NULs using an approach similar
to the one taken by NetBSD.  In particular, we first determine the
length of the output string, and then use a sequence of Xs of the
same length as input to the underlying C printf to determine the
amount of leading and trailing padding.  Finally we replace the
Xs with the actual string before writing it out.

In order to print out the temporary string containing Xs and padding,
a new helper xasprintf is added.  Unlike asprintf though, our
xasprintf prints to the ash stack rather than using straight malloc
memory.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 ChangeLog          |    1 
 src/bltin/printf.c |   80 ++++++++++++++++++++++++++++++++++++++++-----------
 src/output.c       |   82 ++++++++++++++++++++++++++++++++++-------------------
 src/output.h       |    3 +
 4 files changed, 119 insertions(+), 47 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 46ef4c2..379672f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,7 @@
 2014-10-27  Herbert Xu <herbert@gondor.apana.org.au>
 
 	* Add printf support for format string a, A, and F.
+	* Handle embedded NULs correctly in printf.
 
 2014-10-13  Eric Blake <eblake@redhat.com>
 
diff --git a/src/bltin/printf.c b/src/bltin/printf.c
index e0ef912..213025f 100644
--- a/src/bltin/printf.c
+++ b/src/bltin/printf.c
@@ -40,7 +40,7 @@
 #include <string.h>
 #include <unistd.h>
 
-static int	 conv_escape_str(char *);
+static int	 conv_escape_str(char *, char **);
 static char	*conv_escape(char *, int *);
 static int	 getchr(void);
 static double	 getdouble(void);
@@ -73,6 +73,53 @@ static char  **gargv;
 	} \
 }
 
+#define ASPF(sp, f, func) ({ \
+	int ret; \
+	switch ((char *)param - (char *)array) { \
+	default: \
+		ret = xasprintf(sp, f, array[0], array[1], func); \
+		break; \
+	case sizeof(*param): \
+		ret = xasprintf(sp, f, array[0], func); \
+		break; \
+	case 0: \
+		ret = xasprintf(sp, f, func); \
+		break; \
+	} \
+	ret; \
+})
+
+
+static int print_escape_str(const char *f, int *param, int *array, char *s)
+{
+	struct stackmark smark;
+	char *p, *q;
+	int done;
+	int len;
+	int total;
+
+	setstackmark(&smark);
+	done = conv_escape_str(s, &p);
+	q = stackblock();
+	len = p - q;
+
+	p = makestrspace(len, p);
+	memset(p, 'X', len - 1);
+	p[len - 1] = 0;
+
+	q = stackblock();
+	total = ASPF(&p, f, p);
+
+	len = strchrnul(p, 'X') - p;
+	memcpy(p + len, q, strchrnul(p + len, ' ') - (p + len));
+
+	out1mem(p, total);
+
+	popstackmark(&smark);
+	return done;
+}
+
+
 int printfcmd(int argc, char *argv[])
 {
 	char *fmt;
@@ -154,17 +201,14 @@ pc:
 			fmt[1] = 0;
 			switch (ch) {
 
-			case 'b': {
-				int done = conv_escape_str(getstr());
-				char *p = stackblock();
+			case 'b':
 				*fmt = 's';
-				PF(start, p);
 				/* escape if a \c was encountered */
-				if (done)
+				if (print_escape_str(start, param, array,
+						     getstr()))
 					goto out;
 				*fmt = 'b';
 				break;
-			}
 			case 'c': {
 				int p = getchr();
 				PF(start, p);
@@ -223,8 +267,9 @@ err:
  *	Halts processing string if a \c escape is encountered.
  */
 static int
-conv_escape_str(char *str)
+conv_escape_str(char *str, char **sp)
 {
+	int c;
 	int ch;
 	char *cp;
 
@@ -232,16 +277,14 @@ conv_escape_str(char *str)
 	STARTSTACKSTR(cp);
 
 	do {
-		int c;
-
-		ch = *str++;
+		c = ch = *str++;
 		if (ch != '\\')
 			continue;
 
 		ch = *str++;
 		if (ch == 'c') {
 			/* \c as in SYSV echo - abort all processing.... */
-			ch = 0x100;
+			c = ch = 0x100;
 			continue;
 		}
 
@@ -253,14 +296,14 @@ conv_escape_str(char *str)
 		if (ch == '0') {
 			unsigned char i;
 			i = 3;
-			ch = 0;
+			c = 0;
 			do {
 				unsigned k = octtobin(*str);
 				if (k > 7)
 					break;
 				str++;
-				ch <<= 3;
-				ch += k;
+				c <<= 3;
+				c += k;
 			} while (--i);
 			continue;
 		}
@@ -268,7 +311,9 @@ conv_escape_str(char *str)
 		/* Finally test for sequences valid in the format string */
 		str = conv_escape(str - 1, &c);
 		ch = c;
-	} while (STPUTC(ch, cp), (char)ch);
+	} while (STPUTC(c, cp), (char)ch);
+
+	*sp = cp;
 
 	return ch;
 }
@@ -456,8 +501,7 @@ echocmd(int argc, char **argv)
 	do {
 		int c;
 
-		nonl += conv_escape_str(*argv);
-		outstr(stackblock(), outs);
+		nonl += print_escape_str("%s", NULL, NULL, *argv);
 		if (nonl > 0)
 			break;
 
diff --git a/src/output.c b/src/output.c
index f62e7ea..1b20850 100644
--- a/src/output.c
+++ b/src/output.c
@@ -99,9 +99,6 @@ struct output *out1 = &output;
 struct output *out2 = &errout;
 
 
-#ifndef USE_GLIBC_STDIO
-static void __outstr(const char *, size_t, struct output *);
-#endif
 static int xvsnprintf(char *, size_t, const char *, va_list);
 
 
@@ -134,10 +131,14 @@ RESET {
 #endif
 
 
-#ifndef USE_GLIBC_STDIO
-static void
-__outstr(const char *p, size_t len, struct output *dest)
+void
+outmem(const char *p, size_t len, struct output *dest)
 {
+#ifdef USE_GLIBC_STDIO
+	INTOFF;
+	fwrite(p, 1, len, dest->stream);
+	INTON;
+#else
 	size_t bufsize;
 	size_t offset;
 	size_t nleft;
@@ -186,8 +187,8 @@ alloc:
 err:
 		dest->flags |= OUTPUT_ERR;
 	}
-}
 #endif
+}
 
 
 void
@@ -201,7 +202,7 @@ outstr(const char *p, struct output *file)
 	size_t len;
 
 	len = strlen(p);
-	__outstr(p, len, file);
+	outmem(p, len, file);
 #endif
 }
 
@@ -213,7 +214,7 @@ void
 outcslow(int c, struct output *dest)
 {
 	char buf = c;
-	__outstr(&buf, 1, dest);
+	outmem(&buf, 1, dest);
 }
 #endif
 
@@ -283,35 +284,58 @@ fmtstr(char *outbuf, size_t length, const char *fmt, ...)
 }
 
 
+static int xvasprintf(char **sp, size_t size, const char *f, va_list ap)
+{
+	char *s;
+	int len;
+	va_list ap2;
+
+	va_copy(ap2, ap);
+	len = xvsnprintf(*sp, size, f, ap2);
+	va_end(ap2);
+	if (len < 0)
+		sh_error("xvsnprintf failed");
+	if (len < size)
+		return len;
+
+	s = stalloc((len >= stackblocksize() ? len : stackblocksize()) + 1);
+	*sp = s;
+	len = xvsnprintf(s, len + 1, f, ap);
+	return len;
+}
+
+
+int xasprintf(char **sp, const char *f, ...)
+{
+	va_list ap;
+	int ret;
+
+	va_start(ap, f);
+	ret = xvasprintf(sp, 0, f, ap);
+	va_end(ap);
+	return ret;
+}
+
+
 #ifndef USE_GLIBC_STDIO
 void
 doformat(struct output *dest, const char *f, va_list ap)
 {
 	struct stackmark smark;
 	char *s;
-	int len, ret;
-	size_t size;
-	va_list ap2;
+	int len;
+	int olen;
 
-	va_copy(ap2, ap);
-	size = dest->end - dest->nextc;
-	len = xvsnprintf(dest->nextc, size, f, ap2);
-	va_end(ap2);
-	if (len < 0) {
-		dest->flags |= OUTPUT_ERR;
-		return;
-	}
-	if (len < size) {
+	setstackmark(&smark);
+	s = dest->nextc;
+	olen = dest->end - dest->nextc;
+	len = xvasprintf(&s, olen, f, ap);
+	if (likely(olen > len)) {
 		dest->nextc += len;
-		return;
+		goto out;
 	}
-	setstackmark(&smark);
-	s = stalloc((len >= stackblocksize() ? len : stackblocksize()) + 1);
-	ret = xvsnprintf(s, len + 1, f, ap);
-	if (ret == len)
-		__outstr(s, len, dest);
-	else
-		dest->flags |= OUTPUT_ERR;
+	outmem(s, len, dest);
+out:
 	popstackmark(&smark);
 }
 #endif
diff --git a/src/output.h b/src/output.h
index f853e9d..c43d493 100644
--- a/src/output.h
+++ b/src/output.h
@@ -63,6 +63,7 @@ extern struct output memout;
 extern struct output *out1;
 extern struct output *out2;
 
+void outmem(const char *, size_t, struct output *);
 void outstr(const char *, struct output *);
 #ifndef USE_GLIBC_STDIO
 void outcslow(int, struct output *);
@@ -75,6 +76,7 @@ void out1fmt(const char *, ...)
     __attribute__((__format__(__printf__,1,2)));
 int fmtstr(char *, size_t, const char *, ...)
     __attribute__((__format__(__printf__,3,4)));
+int xasprintf(char **, const char *, ...);
 #ifndef USE_GLIBC_STDIO
 void doformat(struct output *, const char *, va_list);
 #endif
@@ -115,6 +117,7 @@ static inline void outc(int ch, struct output *file)
 #endif
 #define out1c(c)	outc((c), out1)
 #define out2c(c)	outcslow((c), out2)
+#define out1mem(s, l)	outmem((s), (l), out1)
 #define out1str(s)	outstr((s), out1)
 #define out2str(s)	outstr((s), out2)
 #define outerr(f)	(f)->flags

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/9] [INPUT] Replace open-coded flushall in preadbuffer
  2014-10-27  8:25 [0/9] Handle embedded NULs correctly in printf Herbert Xu
  2014-10-27  8:26 ` [PATCH 1/9] [BUILTIN] " Herbert Xu
@ 2014-10-27  8:26 ` Herbert Xu
  2014-10-27  8:26 ` [PATCH 5/9] [BUILTIN] Remove unnecessary restoration of format string in printf Herbert Xu
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Herbert Xu @ 2014-10-27  8:26 UTC (permalink / raw)
  To: dash

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 ChangeLog   |    1 +
 src/input.c |    5 +----
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 379672f..e6d6cbf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,7 @@
 
 	* Add printf support for format string a, A, and F.
 	* Handle embedded NULs correctly in printf.
+	* Replace open-coded flushall in preadbuffer.
 
 2014-10-13  Eric Blake <eblake@redhat.com>
 
diff --git a/src/input.c b/src/input.c
index 9e533a4..f11ac84 100644
--- a/src/input.c
+++ b/src/input.c
@@ -245,10 +245,7 @@ preadbuffer(void)
 	}
 	if (unlikely(parsenleft == EOF_NLEFT || parsefile->buf == NULL))
 		return PEOF;
-	flushout(&output);
-#ifdef FLUSHERR
-	flushout(&errout);
-#endif
+	flushall();
 
 	more = parselleft;
 	if (more <= 0) {

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/9] [OUTPUT] Add likely tag in outmem
  2014-10-27  8:25 [0/9] Handle embedded NULs correctly in printf Herbert Xu
                   ` (3 preceding siblings ...)
  2014-10-27  8:26 ` [PATCH 4/9] [OUTPUT] Add ifdefs around MEM_OUT handling in outmem Herbert Xu
@ 2014-10-27  8:26 ` Herbert Xu
  2014-10-27  8:26 ` [PATCH 6/9] [BUILTIN] Remove getintmax in printf Herbert Xu
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Herbert Xu @ 2014-10-27  8:26 UTC (permalink / raw)
  To: dash

The branch in outmem where the string fits in the buffer is the
common case and is now marked as likely.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 ChangeLog    |    1 +
 src/output.c |    2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index e6d6cbf..9d2dc7c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,6 +3,7 @@
 	* Add printf support for format string a, A, and F.
 	* Handle embedded NULs correctly in printf.
 	* Replace open-coded flushall in preadbuffer.
+	* Add likely tag in outmem.
 
 2014-10-13  Eric Blake <eblake@redhat.com>
 
diff --git a/src/output.c b/src/output.c
index 1b20850..3e1ae25 100644
--- a/src/output.c
+++ b/src/output.c
@@ -144,7 +144,7 @@ outmem(const char *p, size_t len, struct output *dest)
 	size_t nleft;
 
 	nleft = dest->end - dest->nextc;
-	if (nleft >= len) {
+	if (likely(nleft >= len)) {
 buffered:
 		dest->nextc = mempcpy(dest->nextc, p, len);
 		return;

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/9] [BUILTIN] Remove unnecessary restoration of format string in printf
  2014-10-27  8:25 [0/9] Handle embedded NULs correctly in printf Herbert Xu
  2014-10-27  8:26 ` [PATCH 1/9] [BUILTIN] " Herbert Xu
  2014-10-27  8:26 ` [PATCH 2/9] [INPUT] Replace open-coded flushall in preadbuffer Herbert Xu
@ 2014-10-27  8:26 ` Herbert Xu
  2014-10-27  8:26 ` [PATCH 4/9] [OUTPUT] Add ifdefs around MEM_OUT handling in outmem Herbert Xu
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Herbert Xu @ 2014-10-27  8:26 UTC (permalink / raw)
  To: dash

Currently we try to preserve the format string which is stored in
argv after temporarily modifying it.  This is unnecessary as it's
only ever used once.  This patch gets rid of it.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 ChangeLog          |    1 +
 src/bltin/printf.c |    1 -
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index 47ba519..026b47c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,7 @@
 	* Replace open-coded flushall in preadbuffer.
 	* Add likely tag in outmem.
 	* Add ifdefs around MEM_OUT handling in outmem.
+	* Remove unnecessary restoration of format string in printf.
 
 2014-10-13  Eric Blake <eblake@redhat.com>
 
diff --git a/src/bltin/printf.c b/src/bltin/printf.c
index 213025f..d1181e3 100644
--- a/src/bltin/printf.c
+++ b/src/bltin/printf.c
@@ -207,7 +207,6 @@ pc:
 				if (print_escape_str(start, param, array,
 						     getstr()))
 					goto out;
-				*fmt = 'b';
 				break;
 			case 'c': {
 				int p = getchr();

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/9] [OUTPUT] Add ifdefs around MEM_OUT handling in outmem
  2014-10-27  8:25 [0/9] Handle embedded NULs correctly in printf Herbert Xu
                   ` (2 preceding siblings ...)
  2014-10-27  8:26 ` [PATCH 5/9] [BUILTIN] Remove unnecessary restoration of format string in printf Herbert Xu
@ 2014-10-27  8:26 ` Herbert Xu
  2014-10-27  8:26 ` [PATCH 3/9] [OUTPUT] Add likely tag " Herbert Xu
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Herbert Xu @ 2014-10-27  8:26 UTC (permalink / raw)
  To: dash

MEM_OUT is only used by forkless backtick processing which we do
not currently support.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 ChangeLog    |    1 +
 src/output.c |    6 ++++++
 2 files changed, 7 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 9d2dc7c..47ba519 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,7 @@
 	* Handle embedded NULs correctly in printf.
 	* Replace open-coded flushall in preadbuffer.
 	* Add likely tag in outmem.
+	* Add ifdefs around MEM_OUT handling in outmem.
 
 2014-10-13  Eric Blake <eblake@redhat.com>
 
diff --git a/src/output.c b/src/output.c
index 3e1ae25..4d3b4c2 100644
--- a/src/output.c
+++ b/src/output.c
@@ -154,10 +154,13 @@ buffered:
 	if (!bufsize) {
 		;
 	} else if (dest->buf == NULL) {
+#ifdef notyet
 		if (dest->fd == MEM_OUT && len > bufsize) {
 			bufsize = len;
 		}
+#endif
 		offset = 0;
+#ifdef notyet
 		goto alloc;
 	} else if (dest->fd == MEM_OUT) {
 		offset = bufsize;
@@ -169,6 +172,7 @@ buffered:
 		if (bufsize < offset)
 			goto err;
 alloc:
+#endif
 		INTOFF;
 		dest->buf = ckrealloc(dest->buf, bufsize);
 		dest->bufsize = bufsize;
@@ -184,7 +188,9 @@ alloc:
 		goto buffered;
 
 	if ((xwrite(dest->fd, p, len))) {
+#ifdef notyet
 err:
+#endif
 		dest->flags |= OUTPUT_ERR;
 	}
 #endif

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 6/9] [BUILTIN] Remove getintmax in printf
  2014-10-27  8:25 [0/9] Handle embedded NULs correctly in printf Herbert Xu
                   ` (4 preceding siblings ...)
  2014-10-27  8:26 ` [PATCH 3/9] [OUTPUT] Add likely tag " Herbert Xu
@ 2014-10-27  8:26 ` Herbert Xu
  2014-10-27  8:26 ` [PATCH 7/9] [BUILTIN] Use error instead of warnx for fatal errors " Herbert Xu
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Herbert Xu @ 2014-10-27  8:26 UTC (permalink / raw)
  To: dash

This patch removes getintmax and moves its functionality into
getuintmax in order to reduce code duplication.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 ChangeLog          |    1 +
 src/bltin/printf.c |   45 +++++++++++----------------------------------
 2 files changed, 12 insertions(+), 34 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 026b47c..5b9b03a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,7 @@
 	* Add likely tag in outmem.
 	* Add ifdefs around MEM_OUT handling in outmem.
 	* Remove unnecessary restoration of format string in printf.
+	* Remove getintmax in printf.
 
 2014-10-13  Eric Blake <eblake@redhat.com>
 
diff --git a/src/bltin/printf.c b/src/bltin/printf.c
index d1181e3..ebc74ae 100644
--- a/src/bltin/printf.c
+++ b/src/bltin/printf.c
@@ -44,8 +44,7 @@ static int	 conv_escape_str(char *, char **);
 static char	*conv_escape(char *, int *);
 static int	 getchr(void);
 static double	 getdouble(void);
-static intmax_t	 getintmax(void);
-static uintmax_t getuintmax(void);
+static uintmax_t getuintmax(int);
 static char	*getstr(void);
 static char	*mklong(const char *, const char *);
 static void      check_conversion(const char *, const char *);
@@ -179,14 +178,14 @@ pc:
 			/* skip to field width */
 			fmt += strspn(fmt, SKIP1);
 			if (*fmt == '*')
-				*param++ = getintmax();
+				*param++ = getuintmax(1);
 
 			/* skip to possible '.', get following precision */
 			fmt += strspn(fmt, SKIP2);
 			if (*fmt == '.')
 				++fmt;
 			if (*fmt == '*')
-				*param++ = getintmax();
+				*param++ = getuintmax(1);
 
 			fmt += strspn(fmt, SKIP2);
 
@@ -220,18 +219,18 @@ pc:
 			}
 			case 'd':
 			case 'i': {
-				intmax_t p = getintmax();
-				char *f = mklong(start, fmt);
-				PF(f, p);
+				uintmax_t p = getuintmax(1);
+				start = mklong(start, fmt);
+				PF(start, p);
 				break;
 			}
 			case 'o':
 			case 'u':
 			case 'x':
 			case 'X': {
-				uintmax_t p = getuintmax();
-				char *f = mklong(start, fmt);
-				PF(f, p);
+				uintmax_t p = getuintmax(0);
+				start = mklong(start, fmt);
+				PF(start, p);
 				break;
 			}
 			case 'a':
@@ -404,30 +403,8 @@ getstr(void)
 	return val;
 }
 
-static intmax_t
-getintmax(void)
-{
-	intmax_t val = 0;
-	char *cp, *ep;
-
-	cp = *gargv;
-	if (cp == NULL)
-		goto out;
-	gargv++;
-
-	val = (unsigned char) cp[1];
-	if (*cp == '\"' || *cp == '\'')
-		goto out;
-
-	errno = 0;
-	val = strtoimax(cp, &ep, 0);
-	check_conversion(cp, ep);
-out:
-	return val;
-}

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 7/9] [BUILTIN] Use error instead of warnx for fatal errors in printf
  2014-10-27  8:25 [0/9] Handle embedded NULs correctly in printf Herbert Xu
                   ` (5 preceding siblings ...)
  2014-10-27  8:26 ` [PATCH 6/9] [BUILTIN] Remove getintmax in printf Herbert Xu
@ 2014-10-27  8:26 ` Herbert Xu
  2014-10-27  8:26 ` [PATCH 8/9] [BUILTIN] Optimise handling of backslash octals " Herbert Xu
  2014-10-27  8:27 ` [PATCH 9/9] [BUILTIN] Simplify echo command Herbert Xu
  8 siblings, 0 replies; 10+ messages in thread
From: Herbert Xu @ 2014-10-27  8:26 UTC (permalink / raw)
  To: dash

This patch replaces uses of warnx where we abort with error since
the effect is the same.  The exit status however changes from 1 to
2.  Non-fatal errors where we continue are unchanged.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 ChangeLog          |    1 +
 src/bltin/printf.c |   17 +++++------------
 2 files changed, 6 insertions(+), 12 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 5b9b03a..707c24d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,6 +7,7 @@
 	* Add ifdefs around MEM_OUT handling in outmem.
 	* Remove unnecessary restoration of format string in printf.
 	* Remove getintmax in printf.
+	* Use error instead of warnx for fatal errors in printf.
 
 2014-10-13  Eric Blake <eblake@redhat.com>
 
diff --git a/src/bltin/printf.c b/src/bltin/printf.c
index ebc74ae..4812e40 100644
--- a/src/bltin/printf.c
+++ b/src/bltin/printf.c
@@ -132,10 +132,8 @@ int printfcmd(int argc, char *argv[])
 	argv = argptr;
 	format = *argv;
 
-	if (!format) {
-		warnx("usage: printf format [arg ...]");
-		goto err;
-	}
+	if (!format)
+		error("usage: printf format [arg ...]");
 
 	gargv = ++argv;
 
@@ -190,10 +188,8 @@ pc:
 			fmt += strspn(fmt, SKIP2);
 
 			ch = *fmt;
-			if (!ch) {
-				warnx("missing format character");
-				goto err;
-			}
+			if (!ch)
+				error("missing format character");
 			/* null terminate format string to we can use it
 			   as an argument to printf. */
 			nextch = fmt[1];
@@ -246,8 +242,7 @@ pc:
 				break;
 			}
 			default:
-				warnx("%s: invalid directive", start);
-				goto err;
+				error("%s: invalid directive", start);
 			}
 			*++fmt = nextch;
 		}
@@ -255,8 +250,6 @@ pc:
 
 out:
 	return rval;
-err:
-	return 1;
 }
 
 

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 8/9] [BUILTIN] Optimise handling of backslash octals in printf
  2014-10-27  8:25 [0/9] Handle embedded NULs correctly in printf Herbert Xu
                   ` (6 preceding siblings ...)
  2014-10-27  8:26 ` [PATCH 7/9] [BUILTIN] Use error instead of warnx for fatal errors " Herbert Xu
@ 2014-10-27  8:26 ` Herbert Xu
  2014-10-27  8:27 ` [PATCH 9/9] [BUILTIN] Simplify echo command Herbert Xu
  8 siblings, 0 replies; 10+ messages in thread
From: Herbert Xu @ 2014-10-27  8:26 UTC (permalink / raw)
  To: dash

This patch removes the duplicate octal handling for %b by reusing
the existing code in conv_escape.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 ChangeLog          |    1 +
 src/bltin/printf.c |   30 ++++++++----------------------
 2 files changed, 9 insertions(+), 22 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 707c24d..60fd4b6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -8,6 +8,7 @@
 	* Remove unnecessary restoration of format string in printf.
 	* Remove getintmax in printf.
 	* Use error instead of warnx for fatal errors in printf.
+	* Optimise handling of backslash octals in printf.
 
 2014-10-13  Eric Blake <eblake@redhat.com>
 
diff --git a/src/bltin/printf.c b/src/bltin/printf.c
index 4812e40..6f39526 100644
--- a/src/bltin/printf.c
+++ b/src/bltin/printf.c
@@ -272,8 +272,8 @@ conv_escape_str(char *str, char **sp)
 		if (ch != '\\')
 			continue;
 
-		ch = *str++;
-		if (ch == 'c') {
+		c = *str++;
+		if (c == 'c') {
 			/* \c as in SYSV echo - abort all processing.... */
 			c = ch = 0x100;
 			continue;
@@ -284,24 +284,11 @@ conv_escape_str(char *str, char **sp)
 		 * They start with a \0, and are followed by 0, 1, 2, 
 		 * or 3 octal digits. 
 		 */
-		if (ch == '0') {
-			unsigned char i;
-			i = 3;
-			c = 0;
-			do {
-				unsigned k = octtobin(*str);
-				if (k > 7)
-					break;
-				str++;
-				c <<= 3;
-				c += k;
-			} while (--i);
-			continue;
-		}
+		if (c == '0' && isodigit(*str))
+			str++;
 
 		/* Finally test for sequences valid in the format string */
 		str = conv_escape(str - 1, &c);
-		ch = c;
 	} while (STPUTC(c, cp), (char)ch);
 
 	*sp = cp;
@@ -322,12 +309,11 @@ conv_escape(char *str, int *conv_ch)
 
 	switch (ch) {
 	default:
-	case 0:
-		value = '\\';
-		goto out;
+		if (!isodigit(*str)) {
+			value = '\\';
+			goto out;
+		}
 
-	case '0': case '1': case '2': case '3':
-	case '4': case '5': case '6': case '7':
 		ch = 3;
 		value = 0;
 		do {

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 9/9] [BUILTIN] Simplify echo command
  2014-10-27  8:25 [0/9] Handle embedded NULs correctly in printf Herbert Xu
                   ` (7 preceding siblings ...)
  2014-10-27  8:26 ` [PATCH 8/9] [BUILTIN] Optimise handling of backslash octals " Herbert Xu
@ 2014-10-27  8:27 ` Herbert Xu
  8 siblings, 0 replies; 10+ messages in thread
From: Herbert Xu @ 2014-10-27  8:27 UTC (permalink / raw)
  To: dash

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 ChangeLog          |    1 +
 src/bltin/printf.c |   28 ++++++++--------------------
 2 files changed, 9 insertions(+), 20 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 60fd4b6..f015066 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -9,6 +9,7 @@
 	* Remove getintmax in printf.
 	* Use error instead of warnx for fatal errors in printf.
 	* Optimise handling of backslash octals in printf.
+	* Simplify echo command.
 
 2014-10-13  Eric Blake <eblake@redhat.com>
 
diff --git a/src/bltin/printf.c b/src/bltin/printf.c
index 6f39526..9673e10 100644
--- a/src/bltin/printf.c
+++ b/src/bltin/printf.c
@@ -442,33 +442,21 @@ check_conversion(const char *s, const char *ep)
 int
 echocmd(int argc, char **argv)
 {
-	int nonl = 0;
-	struct output *outs = out1;
-
-	if (!*++argv)
-		goto end;
-	if (equal(*argv, "-n")) {
-		nonl = ~nonl;
-		if (!*++argv)
-			goto end;
-	}
+	int nonl;
+
+	nonl = *++argv ? equal(*argv, "-n") : 0;
+	argv += nonl;
 
 	do {
 		int c;
 
-		nonl += print_escape_str("%s", NULL, NULL, *argv);
+		if (likely(*argv))
+			nonl += print_escape_str("%s", NULL, NULL, *argv++);
 		if (nonl > 0)
 			break;
 
-		c = ' ';
-		if (!*++argv) {
-end:
-			if (nonl) {
-				break;
-			}
-			c = '\n';
-		}
-		outc(c, outs);
+		c = *argv ? ' ' : '\n';
+		out1c(c);
 	} while (*argv);
 	return 0;
 }

^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2014-10-27  8:27 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-10-27  8:25 [0/9] Handle embedded NULs correctly in printf Herbert Xu
2014-10-27  8:26 ` [PATCH 1/9] [BUILTIN] " Herbert Xu
2014-10-27  8:26 ` [PATCH 2/9] [INPUT] Replace open-coded flushall in preadbuffer Herbert Xu
2014-10-27  8:26 ` [PATCH 5/9] [BUILTIN] Remove unnecessary restoration of format string in printf Herbert Xu
2014-10-27  8:26 ` [PATCH 4/9] [OUTPUT] Add ifdefs around MEM_OUT handling in outmem Herbert Xu
2014-10-27  8:26 ` [PATCH 3/9] [OUTPUT] Add likely tag " Herbert Xu
2014-10-27  8:26 ` [PATCH 6/9] [BUILTIN] Remove getintmax in printf Herbert Xu
2014-10-27  8:26 ` [PATCH 7/9] [BUILTIN] Use error instead of warnx for fatal errors " Herbert Xu
2014-10-27  8:26 ` [PATCH 8/9] [BUILTIN] Optimise handling of backslash octals " Herbert Xu
2014-10-27  8:27 ` [PATCH 9/9] [BUILTIN] Simplify echo command Herbert Xu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).