Handle numbers larger than QUAD_MAX for unsigned conversions correctly.
Exit with nonzero status if a conversion failed. Play nice if used as a shell builtin (currently disabled). Submitted by: bde (partially) Approved by: mike
This commit is contained in:
parent
04a3d10ee5
commit
bacab7d655
@ -71,7 +71,7 @@ static const char rcsid[] =
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
#define PF(f, func) { \
|
||||
#define PF(f, func) do { \
|
||||
char *b = NULL; \
|
||||
if (fieldwidth) \
|
||||
if (precision) \
|
||||
@ -86,16 +86,17 @@ static const char rcsid[] =
|
||||
(void)fputs(b, stdout); \
|
||||
free(b); \
|
||||
} \
|
||||
}
|
||||
} while (0)
|
||||
|
||||
static int asciicode(void);
|
||||
static int escape(char *);
|
||||
static int getchr(void);
|
||||
static double getdouble(void);
|
||||
static int getdouble(double *);
|
||||
static int getint(int *);
|
||||
static int getquad(quad_t *);
|
||||
static const char *getstr(void);
|
||||
static char *mklong(char *, int);
|
||||
static int getquads(quad_t *, u_quad_t *, int);
|
||||
static const char
|
||||
*getstr(void);
|
||||
static char *mkquad(char *, int);
|
||||
static void usage(void);
|
||||
|
||||
static char **gargv;
|
||||
@ -110,7 +111,7 @@ main(argc, argv)
|
||||
char *argv[];
|
||||
{
|
||||
static const char *skip1, *skip2;
|
||||
int ch, chopped, end, fieldwidth, precision;
|
||||
int ch, chopped, end, fieldwidth, precision, rval;
|
||||
char convch, nextch, *format, *fmt, *start;
|
||||
|
||||
#ifndef BUILTIN
|
||||
@ -143,6 +144,7 @@ main(argc, argv)
|
||||
skip2 = "0123456789";
|
||||
|
||||
chopped = escape(fmt = format = *argv); /* backslash interpretation */
|
||||
rval = 0;
|
||||
gargv = ++argv;
|
||||
for (;;) {
|
||||
end = 0;
|
||||
@ -152,7 +154,7 @@ next: for (start = fmt;; ++fmt) {
|
||||
/* avoid infinite loop */
|
||||
if (chopped) {
|
||||
(void)printf("%s", start);
|
||||
return (0);
|
||||
return (rval);
|
||||
}
|
||||
if (end == 1) {
|
||||
warnx1("missing format character",
|
||||
@ -163,7 +165,7 @@ next: for (start = fmt;; ++fmt) {
|
||||
if (fmt > start)
|
||||
(void)printf("%s", start);
|
||||
if (!*gargv)
|
||||
return (0);
|
||||
return (rval);
|
||||
fmt = format;
|
||||
goto next;
|
||||
}
|
||||
@ -217,15 +219,26 @@ next: for (start = fmt;; ++fmt) {
|
||||
char *p;
|
||||
int getout;
|
||||
|
||||
if ((p = strdup(getstr())) == NULL)
|
||||
err(1, NULL);
|
||||
#ifdef SHELL
|
||||
p = savestr(getstr());
|
||||
#else
|
||||
p = strdup(getstr());
|
||||
#endif
|
||||
if (p == NULL) {
|
||||
warnx2("%s", strerror(ENOMEM), NULL);
|
||||
return (1);
|
||||
}
|
||||
getout = escape(p);
|
||||
*(fmt - 1) = 's';
|
||||
PF(start, p)
|
||||
PF(start, p);
|
||||
*(fmt - 1) = 'b';
|
||||
#ifdef SHELL
|
||||
ckfree(p);
|
||||
#else
|
||||
free(p);
|
||||
#endif
|
||||
if (getout)
|
||||
return (0);
|
||||
return (rval);
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
@ -243,19 +256,27 @@ next: for (start = fmt;; ++fmt) {
|
||||
break;
|
||||
}
|
||||
case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
|
||||
quad_t p;
|
||||
char *f;
|
||||
quad_t val;
|
||||
u_quad_t uval;
|
||||
int signedconv;
|
||||
|
||||
if ((f = mklong(start, convch)) != NULL &&
|
||||
!getquad(&p)) {
|
||||
PF(f, p);
|
||||
}
|
||||
signedconv = (convch == 'd' || convch == 'i');
|
||||
if ((f = mkquad(start, convch)) == NULL)
|
||||
return (1);
|
||||
if (getquads(&val, &uval, signedconv))
|
||||
rval = 1;
|
||||
if (signedconv)
|
||||
PF(f, val);
|
||||
else
|
||||
PF(f, uval);
|
||||
break;
|
||||
}
|
||||
case 'e': case 'E': case 'f': case 'g': case 'G': {
|
||||
double p;
|
||||
|
||||
p = getdouble();
|
||||
if (getdouble(&p))
|
||||
rval = 1;
|
||||
PF(start, p);
|
||||
break;
|
||||
}
|
||||
@ -269,14 +290,14 @@ next: for (start = fmt;; ++fmt) {
|
||||
}
|
||||
|
||||
static char *
|
||||
mklong(str, ch)
|
||||
mkquad(str, ch)
|
||||
char *str;
|
||||
int ch;
|
||||
{
|
||||
static char *copy;
|
||||
static size_t copy_size;
|
||||
size_t len, newlen;
|
||||
char *newcopy;
|
||||
size_t len, newlen;
|
||||
|
||||
len = strlen(str) + 2;
|
||||
if (len > copy_size) {
|
||||
@ -286,7 +307,10 @@ mklong(str, ch)
|
||||
#else
|
||||
if ((newcopy = realloc(copy, newlen)) == NULL)
|
||||
#endif
|
||||
{
|
||||
warnx2("%s", strerror(ENOMEM), NULL);
|
||||
return (NULL);
|
||||
}
|
||||
copy = newcopy;
|
||||
copy_size = newlen;
|
||||
}
|
||||
@ -384,69 +408,91 @@ getint(ip)
|
||||
int *ip;
|
||||
{
|
||||
quad_t val;
|
||||
u_quad_t uval;
|
||||
int rval;
|
||||
|
||||
if (getquad(&val))
|
||||
if (getquads(&val, &uval, 1))
|
||||
return (1);
|
||||
if (val < INT_MIN || val > INT_MAX)
|
||||
rval = 0;
|
||||
if (val < INT_MIN || val > INT_MAX) {
|
||||
warnx3("%s: %s", *gargv, strerror(ERANGE));
|
||||
rval = 1;
|
||||
}
|
||||
*ip = (int)val;
|
||||
return (0);
|
||||
return (rval);
|
||||
}
|
||||
|
||||
static int
|
||||
getquad(lp)
|
||||
quad_t *lp;
|
||||
getquads(qp, uqp, signedconv)
|
||||
quad_t *qp;
|
||||
u_quad_t *uqp;
|
||||
int signedconv;
|
||||
{
|
||||
quad_t val;
|
||||
char *ep;
|
||||
int rval;
|
||||
|
||||
if (!*gargv) {
|
||||
*lp = 0;
|
||||
*qp = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (**gargv == '"' || **gargv == '\'') {
|
||||
*lp = (quad_t)asciicode();
|
||||
if (signedconv)
|
||||
*qp = asciicode();
|
||||
else
|
||||
*uqp = asciicode();
|
||||
return (0);
|
||||
}
|
||||
|
||||
rval = 0;
|
||||
errno = 0;
|
||||
val = strtoq(*gargv, &ep, 0);
|
||||
if (ep == *gargv)
|
||||
if (signedconv)
|
||||
*qp = strtoq(*gargv, &ep, 0);
|
||||
else
|
||||
*uqp = strtouq(*gargv, &ep, 0);
|
||||
if (ep == *gargv) {
|
||||
warnx2("%s: expected numeric value", *gargv, NULL);
|
||||
else if (*ep != '\0')
|
||||
rval = 1;
|
||||
}
|
||||
else if (*ep != '\0') {
|
||||
warnx2("%s: not completely converted", *gargv, NULL);
|
||||
if (errno == ERANGE)
|
||||
rval = 1;
|
||||
}
|
||||
if (errno == ERANGE) {
|
||||
warnx3("%s: %s", *gargv, strerror(ERANGE));
|
||||
*lp = val;
|
||||
rval = 1;
|
||||
}
|
||||
++gargv;
|
||||
return (0);
|
||||
return (rval);
|
||||
}
|
||||
|
||||
static double
|
||||
getdouble()
|
||||
static int
|
||||
getdouble(dp)
|
||||
double *dp;
|
||||
{
|
||||
double val;
|
||||
char *ep;
|
||||
int rval;
|
||||
|
||||
if (!*gargv)
|
||||
return ((double)0);
|
||||
|
||||
return (0);
|
||||
if (**gargv == '"' || **gargv == '\'') {
|
||||
val = (double)asciicode();
|
||||
return (val);
|
||||
*dp = asciicode();
|
||||
return (0);
|
||||
}
|
||||
|
||||
rval = 1;
|
||||
errno = 0;
|
||||
val = strtod(*gargv, &ep);
|
||||
if (ep == *gargv)
|
||||
*dp = strtod(*gargv, &ep);
|
||||
if (ep == *gargv) {
|
||||
warnx2("%s: expected numeric value", *gargv, NULL);
|
||||
else if (*ep != '\0')
|
||||
rval = 1;
|
||||
} else if (*ep != '\0') {
|
||||
warnx2("%s: not completely converted", *gargv, NULL);
|
||||
if (errno == ERANGE)
|
||||
rval = 1;
|
||||
}
|
||||
if (errno == ERANGE) {
|
||||
warnx3("%s: %s", *gargv, strerror(ERANGE));
|
||||
rval = 1;
|
||||
}
|
||||
++gargv;
|
||||
return (val);
|
||||
return (rval);
|
||||
}
|
||||
|
||||
static int
|
||||
|
Loading…
Reference in New Issue
Block a user