summaryrefslogtreecommitdiff
path: root/usr.bin/printf/printf.c
diff options
context:
space:
mode:
authordsl <dsl@NetBSD.org>2003-02-24 14:42:27 +0000
committerdsl <dsl@NetBSD.org>2003-02-24 14:42:27 +0000
commita5f73640386f652b62a267c85ad793318f104d7b (patch)
treeee3f472275d77faf135331b04a88d90ad686546e /usr.bin/printf/printf.c
parenta01816b2805603188706706b6aa8b456da3486c3 (diff)
Fix the output of NUL bytes within %b formats.
(Approved by Christos)
Diffstat (limited to 'usr.bin/printf/printf.c')
-rw-r--r--usr.bin/printf/printf.c114
1 files changed, 86 insertions, 28 deletions
diff --git a/usr.bin/printf/printf.c b/usr.bin/printf/printf.c
index ae085b74aef..f000fa6c0df 100644
--- a/usr.bin/printf/printf.c
+++ b/usr.bin/printf/printf.c
@@ -1,4 +1,4 @@
-/* $NetBSD: printf.c,v 1.25 2002/11/24 22:35:45 christos Exp $ */
+/* $NetBSD: printf.c,v 1.26 2003/02/24 14:42:27 dsl Exp $ */
/*
* Copyright (c) 1989, 1993
@@ -45,7 +45,7 @@ __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
#if 0
static char sccsid[] = "@(#)printf.c 8.2 (Berkeley) 3/22/95";
#else
-__RCSID("$NetBSD: printf.c,v 1.25 2002/11/24 22:35:45 christos Exp $");
+__RCSID("$NetBSD: printf.c,v 1.26 2003/02/24 14:42:27 dsl Exp $");
#endif
#endif /* not lint */
@@ -69,7 +69,7 @@ __RCSID("$NetBSD: printf.c,v 1.25 2002/11/24 22:35:45 christos Exp $");
#define ESCAPE 033
#endif
-static char *conv_escape_str(char *);
+static void conv_escape_str(char *, void (*)(int));
static char *conv_escape(char *, char *);
static char *conv_expand(const char *);
static int getchr(void);
@@ -82,6 +82,11 @@ static char *mklong(const char *, int);
static void check_conversion(const char *, const char *);
static void usage(void);
+static void b_count(int);
+static void b_output(int);
+static int b_length;
+static char *b_fmt;
+
static int rval;
static char **gargv;
@@ -106,6 +111,18 @@ static char **gargv;
(void)printf(f, func); \
}
+#define APF(cpp, f, func) { \
+ if (fieldwidth != -1) { \
+ if (precision != -1) \
+ (void)asprintf(cpp, f, fieldwidth, precision, func); \
+ else \
+ (void)asprintf(cpp, f, fieldwidth, func); \
+ } else if (precision != -1) \
+ (void)asprintf(cpp, f, precision, func); \
+ else \
+ (void)asprintf(cpp, f, func); \
+}
+
int main(int, char **);
int main(int argc, char *argv[])
{
@@ -197,9 +214,34 @@ int main(int argc, char *argv[])
break;
}
case 'b': {
- char *p = conv_escape_str(getstr());
+ /* There has to be a better way to do this,
+ * but the string we generate might have
+ * embedded nulls. */
+ static char *a, *t;
+ char *cp = getstr();
+ /* Free on entry in case shell longjumped out */
+ if (a != NULL)
+ free(a);
+ a = NULL;
+ if (t != NULL)
+ free(t);
+ t = NULL;
+ /* Count number of bytes we want to output */
+ b_length = 0;
+ conv_escape_str(cp, b_count);
+ t = malloc(b_length + 1);
+ if (t == NULL)
+ break;
+ memset(t, 'x', b_length);
+ t[b_length] = 0;
+ /* Get printf to calculate the lengths */
*fmt = 's';
- PF(start, p);
+ APF(&a, start, t);
+ b_fmt = a;
+ /* Output leading spaces and data bytes */
+ conv_escape_str(cp, b_output);
+ /* Add any trailing spaces */
+ printf("%s", b_fmt);
break;
}
case 'c': {
@@ -252,30 +294,49 @@ int main(int argc, char *argv[])
return (rval);
}
+/* helper functions for conv_escape_str */
+
+static void
+b_count(int ch)
+{
+ b_length++;
+}
+
+/* Output one converted character for every 'x' in the 'format' */
+
+static void
+b_output(int ch)
+{
+ for (;;) {
+ switch (*b_fmt++) {
+ case 0:
+ b_fmt--;
+ return;
+ case ' ':
+ putchar(' ');
+ break;
+ default:
+ putchar(ch);
+ return;
+ }
+ }
+}
+
/*
* Print SysV echo(1) style escape string
* Halts processing string if a \c escape is encountered.
*/
-static char *
-conv_escape_str(char *str)
+static void
+conv_escape_str(char *str, void (*do_putchar)(int))
{
int value;
int ch;
- static char *conv_str;
- char *cp;
-
- /* convert string into a temporary buffer... */
- if (conv_str)
- free(conv_str);
- conv_str = malloc(strlen(str) + 4);
- if (!conv_str)
- return "<no memory>";
- cp = conv_str;
+ char c;
while ((ch = *str++)) {
if (ch != '\\') {
- *cp++ = ch;
+ do_putchar(ch);
continue;
}
@@ -297,14 +358,14 @@ conv_escape_str(char *str)
octnum[1] = str[1];
octnum[2] = str[2];
octnum[3] = 0;
- *cp++ = strtoul(octnum, &oct_end, 8);
+ do_putchar(strtoul(octnum, &oct_end, 8));
str += oct_end - octnum;
continue;
}
/* \[M][^|-]C as defined by vis(3) */
if (ch == 'M' && *str == '-') {
- *cp++ = 0200 | str[1];
+ do_putchar(0200 | str[1]);
str += 2;
continue;
}
@@ -320,17 +381,14 @@ conv_escape_str(char *str)
value |= 0177;
else
value |= ch & 037;
- *cp++ = value;
+ do_putchar(value);
continue;
}
/* Finally test for sequences valid in the format string */
- str = conv_escape(str - 1, cp);
- cp++;
+ str = conv_escape(str - 1, &c);
+ do_putchar(c);
}
- *cp = 0;
-
- return conv_str;
}
/*
@@ -383,9 +441,9 @@ conv_escape(char *str, char *conv_ch)
case 'v': value = '\v'; break; /* vertical-tab */
default:
- warnx("unknown escape sequence `\\%c'", *str);
+ warnx("unknown escape sequence `\\%c'", ch);
rval = 1;
- value = *str;
+ value = ch;
break;
}