diff options
| author | dsl <dsl@NetBSD.org> | 2003-02-24 14:42:27 +0000 |
|---|---|---|
| committer | dsl <dsl@NetBSD.org> | 2003-02-24 14:42:27 +0000 |
| commit | a5f73640386f652b62a267c85ad793318f104d7b (patch) | |
| tree | ee3f472275d77faf135331b04a88d90ad686546e /usr.bin/printf/printf.c | |
| parent | a01816b2805603188706706b6aa8b456da3486c3 (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.c | 114 |
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; } |
