Fix the output of NUL bytes within %b formats.

(Approved by Christos)
This commit is contained in:
dsl 2003-02-24 14:42:27 +00:00
parent a01816b280
commit a5f7364038
1 changed files with 86 additions and 28 deletions

View File

@ -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 * Copyright (c) 1989, 1993
@ -45,7 +45,7 @@ __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
#if 0 #if 0
static char sccsid[] = "@(#)printf.c 8.2 (Berkeley) 3/22/95"; static char sccsid[] = "@(#)printf.c 8.2 (Berkeley) 3/22/95";
#else #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
#endif /* not lint */ #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 #define ESCAPE 033
#endif #endif
static char *conv_escape_str(char *); static void conv_escape_str(char *, void (*)(int));
static char *conv_escape(char *, char *); static char *conv_escape(char *, char *);
static char *conv_expand(const char *); static char *conv_expand(const char *);
static int getchr(void); static int getchr(void);
@ -82,6 +82,11 @@ static char *mklong(const char *, int);
static void check_conversion(const char *, const char *); static void check_conversion(const char *, const char *);
static void usage(void); 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 int rval;
static char **gargv; static char **gargv;
@ -106,6 +111,18 @@ static char **gargv;
(void)printf(f, func); \ (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, char **);
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -197,9 +214,34 @@ int main(int argc, char *argv[])
break; break;
} }
case 'b': { 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'; *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; break;
} }
case 'c': { case 'c': {
@ -252,30 +294,49 @@ int main(int argc, char *argv[])
return (rval); 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 * Print SysV echo(1) style escape string
* Halts processing string if a \c escape is encountered. * Halts processing string if a \c escape is encountered.
*/ */
static char * static void
conv_escape_str(char *str) conv_escape_str(char *str, void (*do_putchar)(int))
{ {
int value; int value;
int ch; int ch;
static char *conv_str; char c;
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;
while ((ch = *str++)) { while ((ch = *str++)) {
if (ch != '\\') { if (ch != '\\') {
*cp++ = ch; do_putchar(ch);
continue; continue;
} }
@ -297,14 +358,14 @@ conv_escape_str(char *str)
octnum[1] = str[1]; octnum[1] = str[1];
octnum[2] = str[2]; octnum[2] = str[2];
octnum[3] = 0; octnum[3] = 0;
*cp++ = strtoul(octnum, &oct_end, 8); do_putchar(strtoul(octnum, &oct_end, 8));
str += oct_end - octnum; str += oct_end - octnum;
continue; continue;
} }
/* \[M][^|-]C as defined by vis(3) */ /* \[M][^|-]C as defined by vis(3) */
if (ch == 'M' && *str == '-') { if (ch == 'M' && *str == '-') {
*cp++ = 0200 | str[1]; do_putchar(0200 | str[1]);
str += 2; str += 2;
continue; continue;
} }
@ -320,17 +381,14 @@ conv_escape_str(char *str)
value |= 0177; value |= 0177;
else else
value |= ch & 037; value |= ch & 037;
*cp++ = value; do_putchar(value);
continue; continue;
} }
/* Finally test for sequences valid in the format string */ /* Finally test for sequences valid in the format string */
str = conv_escape(str - 1, cp); str = conv_escape(str - 1, &c);
cp++; 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 */ case 'v': value = '\v'; break; /* vertical-tab */
default: default:
warnx("unknown escape sequence `\\%c'", *str); warnx("unknown escape sequence `\\%c'", ch);
rval = 1; rval = 1;
value = *str; value = ch;
break; break;
} }