Back out rev 1.11, about which bde had concerns, and instead implement

appropriate bounds-checking and typecasts based on our knowledge of
the desired conversion format specifier.

Simplify diagnostics and take care to print the correct conversion
format specifier when %l is involved.
This commit is contained in:
Sheldon Hearn 2000-01-06 15:37:37 +00:00
parent 029b2bd09e
commit 5249bd84d6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=55515
2 changed files with 72 additions and 66 deletions

View File

@ -183,18 +183,16 @@ from column 10 and ending in column 132, use
.Pp
and to print all lines 80 characters or longer,
.Dl grep `jot -s \&"\&" -b \&. 80`
.Pp
.Sh SEE ALSO
.Xr ed 1 ,
.Xr expand 1 ,
.Xr rs 1 ,
.Xr yes 1 ,
.Xr printf 3 ,
.Xr random 3
.Sh BUGS
Conversion format specifiers for
.Sh DIAGNOSTICS
The
.Nm
utility exits 0 on success, and >0 if an error occurs.
The following diagnostic messages deserve special explanation:
.Bl -diag
.It "illegal or unsupported format '%s'"
The requested conversion format specifier for
.Xr printf 3
are limited to those of the form
was not of the form
.Dl %[#][ ][{+,-}][0-9]*[.[0-9]*]?
where
.Dq ?
@ -202,6 +200,17 @@ must be one of
.Dl [l]{d,i,o,u,x}
or
.Dl {c,e,f,g,D,E,G,O,U,X}
.Pp
No bounds-checking is performed on numeric values, so arithmetic overflow
will cause a fatal error.
.It "range error in conversion"
A value to be printed fell outside the range of the data type
associated with the requested output format.
.It "too many conversions"
More than one conversion format specifier has been supplied,
but only one is allowed.
.El
.Sh SEE ALSO
.Xr ed 1 ,
.Xr expand 1 ,
.Xr rs 1 ,
.Xr yes 1 ,
.Xr printf 3 ,
.Xr random 3

View File

@ -54,7 +54,6 @@ static const char rcsid[] =
#include <ctype.h>
#include <err.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -76,21 +75,18 @@ int randomize;
int infinity;
int boring;
int prec;
int longdata;
int intdata;
int chardata;
int nosign;
int nofinalnl;
int oflowlen;
char *oflowstr;
char *sepstring = "\n";
char format[BUFSIZ];
struct sigaction act, oact;
void arith_oflow __P((int));
void getargs __P((int, char *[]));
void getformat __P((void));
int getprec __P((char *));
void putdata __P((double, long));
int putdata __P((double, long));
static void usage __P((void));
int
@ -104,23 +100,18 @@ main(argc, argv)
register double *y = &yd;
register long *i = &id;
act.sa_handler = arith_oflow;
act.sa_flags = 0;
sigfillset(&act.sa_mask);
oflowstr = "caught SIGFPE: arithmetic overflow\n";
oflowlen = strlen(oflowstr);
if (sigaction(SIGFPE, &act, &oact))
err(1, "loading SIGFPE handler");
getargs(argc, argv);
if (randomize) {
*x = (ender - begin) * (ender > begin ? 1 : -1);
for (*i = 1; *i <= reps || infinity; (*i)++) {
*y = (double) arc4random() / ULONG_MAX;
putdata(*y * *x + begin, reps - *i);
if (putdata(*y * *x + begin, reps - *i))
errx(1, "range error in conversion");
}
} else
for (*i = 1, *x = begin; *i <= reps || infinity; (*i)++, *x += s)
putdata(*x, reps - *i);
if (putdata(*x, reps - *i))
errx(1, "range error in conversion");
if (!nofinalnl)
putchar('\n');
exit(0);
@ -317,24 +308,41 @@ getargs(ac, av)
infinity = 1;
}
void
int
putdata(x, notlast)
double x;
long notlast;
{
if (boring) /* repeated word */
if (boring)
printf(format);
else if (chardata) /* character representation */
printf(format, (int)x);
else if (intdata && nosign) /* scalar */
printf(format, (unsigned long)x);
else if (intdata)
printf(format, (long)x);
else /* real */
else if (longdata && nosign) {
if (x <= (double)ULONG_MAX && x >= (double)0)
printf(format, (unsigned long)x);
else
return (1);
} else if (longdata) {
if (x <= (double)LONG_MAX && x >= (double)LONG_MIN)
printf(format, (long)x);
else
return (1);
} else if (chardata || (intdata && !nosign)) {
if (x <= (double)INT_MAX && x >= (double)INT_MIN)
printf(format, (int)x);
else
return (1);
} else if (intdata) {
if (x <= (double)UINT_MAX && x >= (double)0)
printf(format, (unsigned int)x);
else
return (1);
} else
printf(format, x);
if (notlast != 0)
fputs(sepstring, stdout);
return (0);
}
static void
@ -368,7 +376,7 @@ void
getformat()
{
register char *p;
int dot, hash, space, sign, numbers, islong = 0;
int dot, hash, space, sign, numbers = 0;
char *s;
if (boring) /* no need to bother */
@ -401,18 +409,18 @@ getformat()
((*p == '+' || *p == '-') && !(numbers|dot|sign++))
|| (*p == '.' && !(dot++)))
p++;
else if (*p == '$' || *p == '*')
errx(1, "unsupported format character %c", *p);
else if (*p == '\0')
errx(1, "missing format character");
else
errx(1, "illegal format character %c", *p);
goto fmt_broken;
}
if (*p == 'l') {
longdata = 1;
if (*++p == 'l') {
if (p[1] != '\0')
p++;
goto fmt_broken;
}
}
switch (*p) {
case 'l':
islong = 1;
p++;
/* FALLTHROUGH */
case 'o': case 'u': case 'x': case 'X':
intdata = nosign = 1;
break;
@ -420,32 +428,29 @@ getformat()
intdata = 1;
break;
case 'D':
if (!islong) {
if (!longdata) {
intdata = 1;
break;
}
case 'O': case 'U':
if (!islong) {
if (!longdata) {
intdata = nosign = 1;
break;
}
case 'c':
if (!(intdata | islong)) {
if (!(intdata | longdata)) {
chardata = 1;
break;
}
case 's':
errx(1, "cannot convert numeric data to strings");
break;
case 'h': case 'n': case 'p': case 'q': case 'L':
case 'h': case 'n': case 'p': case 'q': case 's': case 'L':
case '$': case '*':
errx(1, "unsupported format character %c", *p);
/* NOTREACHED */
goto fmt_broken;
case 'f': case 'e': case 'g': case 'E': case 'G':
if (!islong)
if (!longdata)
break;
/* FALLTHROUGH */
default:
fmt_broken:
*++p = '\0';
errx(1, "illegal or unsupported format '%s'", s);
/* NOTREACHED */
@ -461,11 +466,3 @@ getformat()
}
}
}
void
arith_oflow(int sig)
{
write(STDERR_FILENO, oflowstr, oflowlen);
_exit(sig);
}