summaryrefslogtreecommitdiffstats
path: root/usr.bin/printf
diff options
context:
space:
mode:
authordas <das@FreeBSD.org>2005-03-21 08:01:09 +0000
committerdas <das@FreeBSD.org>2005-03-21 08:01:09 +0000
commitf5e55fd6043735ac328d3781c369fad18a4473a7 (patch)
tree587be6da68e9def7bd60577e5323789d902df796 /usr.bin/printf
parent79d24f2484be4474682749ca0ad8fcc097aea491 (diff)
downloadFreeBSD-src-f5e55fd6043735ac328d3781c369fad18a4473a7.zip
FreeBSD-src-f5e55fd6043735ac328d3781c369fad18a4473a7.tar.gz
Support the L modifier for floating-point values as an extension.
When L is omitted, double precision is used, so printf(1) gives reproducable results. When L is specified, long double precision is used, which may improve precision, depending on the machine.
Diffstat (limited to 'usr.bin/printf')
-rw-r--r--usr.bin/printf/printf.110
-rw-r--r--usr.bin/printf/printf.c40
2 files changed, 44 insertions, 6 deletions
diff --git a/usr.bin/printf/printf.1 b/usr.bin/printf/printf.1
index 445c7aa..01360a4 100644
--- a/usr.bin/printf/printf.1
+++ b/usr.bin/printf/printf.1
@@ -197,6 +197,11 @@ A character which indicates the type of format to use (one of
.Cm diouxXfFeEgGaAcsb ) .
The uppercase formats differ from their lowercase counterparts only in
that the output of the former is entirely in uppercase.
+The floating-point format specifiers
+.Cm ( fFeEgGaA )
+may be prefixed by an
+.Cm L
+to request that additional precision be used, if available.
.El
.Pp
A field width or precision may be
@@ -326,6 +331,11 @@ Since the floating point numbers are translated from
.Tn ASCII
to floating-point and
then back again, floating-point precision may be lost.
+(By default, the number is translated to an IEEE-754 double-precision
+value before being printed.
+The
+.Cm L
+modifier may produce additional precision, depending on the hardware platform.)
.Pp
.Tn ANSI
hexadecimal character constants were deliberately not provided.
diff --git a/usr.bin/printf/printf.c b/usr.bin/printf/printf.c
index 2dcf4f4..64206a4 100644
--- a/usr.bin/printf/printf.c
+++ b/usr.bin/printf/printf.c
@@ -91,7 +91,7 @@ static const char rcsid[] =
static int asciicode(void);
static int escape(char *, int);
static int getchr(void);
-static int getdouble(double *);
+static int getfloating(long double *, int);
static int getint(int *);
static int getquads(quad_t *, u_quad_t *, int);
static const char
@@ -110,6 +110,7 @@ main(int argc, char *argv[])
{
static const char *skip1, *skip2;
int ch, chopped, end, fieldwidth, haveprec, havewidth, precision, rval;
+ int mod_ldbl;
char convch, nextch, *format, *fmt, *start;
#ifndef BUILTIN
@@ -211,6 +212,27 @@ next: for (start = fmt;; ++fmt) {
return (1);
}
+ /*
+ * Look for a length modifier. POSIX doesn't have these, so
+ * we only support them for floating-point conversions, which
+ * are extensions. This is useful because the L modifier can
+ * be used to gain extra range and precision, while omitting
+ * it is more likely to produce consistent results on different
+ * architectures. This is not so important for integers
+ * because overflow is the only bad thing that can happen to
+ * them, but consider the command printf %a 1.1
+ */
+ if (*fmt == 'L') {
+ mod_ldbl = 1;
+ fmt++;
+ if (!strchr("aAeEfFgG", *fmt)) {
+ warnx2("bad modifier L for %%%c", *fmt, NULL);
+ return (1);
+ }
+ } else {
+ mod_ldbl = 0;
+ }
+
convch = *fmt;
nextch = *++fmt;
*fmt = '\0';
@@ -276,11 +298,14 @@ next: for (start = fmt;; ++fmt) {
case 'f': case 'F':
case 'g': case 'G':
case 'a': case 'A': {
- double p;
+ long double p;
- if (getdouble(&p))
+ if (getfloating(&p, mod_ldbl))
rval = 1;
- PF(start, p);
+ if (mod_ldbl)
+ PF(start, p);
+ else
+ PF(start, (double)p);
break;
}
default:
@@ -465,7 +490,7 @@ getquads(quad_t *qp, u_quad_t *uqp, int signedconv)
}
static int
-getdouble(double *dp)
+getfloating(long double *dp, int mod_ldbl)
{
char *ep;
int rval;
@@ -478,7 +503,10 @@ getdouble(double *dp)
}
rval = 0;
errno = 0;
- *dp = strtod(*gargv, &ep);
+ if (mod_ldbl)
+ *dp = strtold(*gargv, &ep);
+ else
+ *dp = strtod(*gargv, &ep);
if (ep == *gargv) {
warnx2("%s: expected numeric value", *gargv, NULL);
rval = 1;
OpenPOWER on IntegriCloud