#include <sys/types.h>
#include "system.h"
#include "error.h"
+#include "ftoastr.h"
#include "quote.h"
#include "xfreopen.h"
#include "xprintf.h"
#define AUTHORS proper_name ("Jim Meyering")
-#include <float.h>
-
/* The default number of input bytes per output line. */
#define DEFAULT_BYTES_PER_BLOCK 16
-/* The number of decimal digits of precision in a float. */
-#ifndef FLT_DIG
-# define FLT_DIG 7
-#endif
-
-/* The number of decimal digits of precision in a double. */
-#ifndef DBL_DIG
-# define DBL_DIG 15
-#endif
-
#if HAVE_UNSIGNED_LONG_LONG_INT
typedef unsigned long long int unsigned_long_long_int;
#else
enum
{
FMT_BYTES_ALLOCATED =
- MAX ((sizeof "%*.99" - 1
+ (sizeof "%*.99" - 1
+ MAX (sizeof "ld",
MAX (sizeof PRIdMAX,
MAX (sizeof PRIoMAX,
MAX (sizeof PRIuMAX,
- sizeof PRIxMAX))))),
- sizeof "%*.99Le")
+ sizeof PRIxMAX)))))
};
/* Ensure that our choice for FMT_BYTES_ALLOCATED is reasonable. */
-verify (LDBL_DIG <= 99);
verify (MAX_INTEGRAL_TYPE_SIZE * CHAR_BIT / 3 <= 99);
/* Each output format specification (from `-t spec' or from
/* Define the print functions. */
-#define PRINT_TYPE(N, T) \
+#define PRINT_FIELDS(N, T, FMT_STRING, ACTION) \
static void \
N (size_t fields, size_t blank, void const *block, \
- char const *fmt_string, int width, int pad) \
+ char const *FMT_STRING, int width, int pad) \
{ \
T const *p = block; \
size_t i; \
for (i = fields; blank < i; i--) \
{ \
int next_pad = pad * (i - 1) / fields; \
- xprintf (fmt_string, pad_remaining - next_pad + width, *p++); \
+ int adjusted_width = pad_remaining - next_pad + width; \
+ T x = *p++; \
+ ACTION; \
pad_remaining = next_pad; \
} \
}
+#define PRINT_TYPE(N, T) \
+ PRINT_FIELDS (N, T, fmt_string, xprintf (fmt_string, adjusted_width, x))
+
+#define PRINT_FLOATTYPE(N, T, FTOASTR, BUFSIZE) \
+ PRINT_FIELDS (N, T, fmt_string ATTRIBUTE_UNUSED, \
+ char buf[BUFSIZE]; \
+ FTOASTR (buf, sizeof buf, 0, 0, x); \
+ xprintf ("%*s", adjusted_width, buf))
+
PRINT_TYPE (print_s_char, signed char)
PRINT_TYPE (print_char, unsigned char)
PRINT_TYPE (print_s_short, short int)
PRINT_TYPE (print_int, unsigned int)
PRINT_TYPE (print_long, unsigned long int)
PRINT_TYPE (print_long_long, unsigned_long_long_int)
-PRINT_TYPE (print_float, float)
-PRINT_TYPE (print_double, double)
-PRINT_TYPE (print_long_double, long double)
+
+PRINT_FLOATTYPE (print_float, float, ftoastr, FLT_BUFSIZE_BOUND)
+PRINT_FLOATTYPE (print_double, double, dtoastr, DBL_BUFSIZE_BOUND)
+PRINT_FLOATTYPE (print_long_double, long double, ldtoastr, LDBL_BUFSIZE_BOUND)
#undef PRINT_TYPE
+#undef PRINT_FLOATTYPE
static void
dump_hexl_mode_trailer (size_t n_bytes, const char *block)
enum size_spec size_spec;
unsigned long int size;
enum output_format fmt;
- const char *pre_fmt_string;
void (*print_function) (size_t, size_t, void const *, char const *,
int, int);
const char *p;
char c;
int field_width;
- int precision;
assert (tspec != NULL);
}
size_spec = fp_type_size[size];
+ struct lconv const *locale = localeconv ();
+ size_t decimal_point_len =
+ (locale->decimal_point[0] ? strlen (locale->decimal_point) : 1);
+
switch (size_spec)
{
case FLOAT_SINGLE:
print_function = print_float;
- /* FIXME - should we use %g instead of %e? */
- pre_fmt_string = "%%*.%de";
- precision = FLT_DIG;
+ field_width = FLT_STRLEN_BOUND_L (decimal_point_len);
break;
case FLOAT_DOUBLE:
print_function = print_double;
- pre_fmt_string = "%%*.%de";
- precision = DBL_DIG;
+ field_width = DBL_STRLEN_BOUND_L (decimal_point_len);
break;
case FLOAT_LONG_DOUBLE:
print_function = print_long_double;
- pre_fmt_string = "%%*.%dLe";
- precision = LDBL_DIG;
+ field_width = LDBL_STRLEN_BOUND_L (decimal_point_len);
break;
default:
abort ();
}
- field_width = precision + 8;
- sprintf (tspec->fmt_string, pre_fmt_string, precision);
- assert (strlen (tspec->fmt_string) < FMT_BYTES_ALLOCATED);
break;
case 'a':
--- /dev/null
+#!/bin/sh
+# Test od on floating-point values.
+
+# Copyright (C) 2010 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/init.sh"; path_prepend_ ../src
+print_ver_ od
+
+export LC_ALL=C
+
+# Test for a bug in coreutils up through 8.7: od was losing
+# information when asked to parse floating-point values. The numeric
+# tests are valid only on Intel-like hosts, but that should be good
+# enough to detect regressions, as they are designed to succeed on
+# non-Intel-like hosts. Also, test for another bug in coreutils 8.7
+# on x86: sometimes there was no space between the columns.
+
+set x $(echo aaaabaaa | tr ab '\376\377' | od -t fF) ||
+ framework_failure
+case "$*" in
+*0-*) fail=1;;
+esac
+case $3,$4 in
+-1.694740e+38,-1.694740e+38) fail=1;;
+esac
+
+set x $(echo aaaaaaaabaaaaaaa | tr ab '\376\377' | od -t fD) ||
+ framework_failure
+case "$*" in
+*0-*) fail=1;;
+esac
+case $3,$4 in
+-5.314010372517808e+303,-5.314010372517808e+303) fail=1;;
+esac
+
+set x $(echo aaaaaaaaaaaaaaaabaaaaaaaaaaaaaaa | tr ab '\376\377' | od -t fL) ||
+ framework_failure
+case "$*" in
+*0-*) fail=1;;
+esac
+case $3,$4 in
+-1.023442870282055988e+4855,-1.023442870282055988e+4855) fail=1;;
+esac
+
+Exit $fail