summaryrefslogtreecommitdiffstats
path: root/usr.bin/printf
diff options
context:
space:
mode:
authortjr <tjr@FreeBSD.org>2002-04-25 01:10:11 +0000
committertjr <tjr@FreeBSD.org>2002-04-25 01:10:11 +0000
commit12a8faa64a26e5dcfde6ae295040e0fe4aa5afe1 (patch)
tree1a55803f8f822577ed318c786a6ee89af797889f /usr.bin/printf
parentd2d34844656f57922ed98df7f946c141ae1c16c1 (diff)
downloadFreeBSD-src-12a8faa64a26e5dcfde6ae295040e0fe4aa5afe1.zip
FreeBSD-src-12a8faa64a26e5dcfde6ae295040e0fe4aa5afe1.tar.gz
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
Diffstat (limited to 'usr.bin/printf')
-rw-r--r--usr.bin/printf/printf.c146
1 files changed, 96 insertions, 50 deletions
diff --git a/usr.bin/printf/printf.c b/usr.bin/printf/printf.c
index e8d7b3c..e0d1591 100644
--- a/usr.bin/printf/printf.c
+++ b/usr.bin/printf/printf.c
@@ -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
OpenPOWER on IntegriCloud