@item --format=@var{format}
@opindex --format
Use printf-style floating FORMAT string. The @var{format} string must contain
-one @samp{%f} directive, optionally with @samp{'}, @samp{-}, @samp{0}, or width
-modifiers. The @samp{'} modifier will enable @option{--grouping}, the @samp{-}
-modifier will enable left-aligned @option{--padding} and the width modifier will
-enable right-aligned @option{--padding}. The @samp{0} width modifier
-(without the @samp{-} modifier) will generate leading zeros on the number,
-up to the specified width.
+one @samp{%f} directive, optionally with @samp{'}, @samp{-}, @samp{0}, width
+or precision modifiers. The @samp{'} modifier will enable @option{--grouping},
+the @samp{-} modifier will enable left-aligned @option{--padding} and the width
+modifier will enable right-aligned @option{--padding}. The @samp{0} width
+modifier (without the @samp{-} modifier) will generate leading zeros on the
+number, up to the specified width. A precision specification like @samp{%.1f}
+will override the precision determined from the input data or set due to
+@option{--to} option auto scaling.
@item --from=@var{unit}
@opindex --from
static size_t padding_buffer_size = 0;
static long int padding_width = 0;
static long int zero_padding_width = 0;
+static long int user_precision = -1;
static const char *format_str = NULL;
static char *format_str_prefix = NULL;
static char *format_str_suffix = NULL;
devmsg (" scaled value to %Lf * %0.f ^ %u\n", val, scale_base, power);
/* Perform rounding. */
- int ten_or_less = 0;
- if (absld (val) < 10)
+ unsigned int power_adjust = 0;
+ if (user_precision != -1)
+ power_adjust = MIN (power * 3, user_precision);
+ else if (absld (val) < 10)
{
/* for values less than 10, we allow one decimal-point digit,
so adjust before rounding. */
- ten_or_less = 1;
- val *= 10;
+ power_adjust = 1;
}
+
+ val *= powerld (10, power_adjust);
val = simple_round (val, round);
+ val /= powerld (10, power_adjust);
+
/* two special cases after rounding:
1. a "999.99" can turn into 1000 - so scale down
2. a "9.99" can turn into 10 - so don't display decimal-point. */
val /= scale_base;
power++;
}
- if (ten_or_less)
- val /= 10;
/* should "7.0" be printed as "7" ?
if removing the ".0" is preferred, enable the fourth condition. */
devmsg (" after rounding, value=%Lf * %0.f ^ %u\n", val, scale_base, power);
- stpcpy (pfmt, show_decimal_point ? ".1Lf%s" : ".0Lf%s");
+ stpcpy (pfmt, ".*Lf%s");
+
+ int prec = user_precision == -1 ? show_decimal_point : user_precision;
/* buf_size - 1 used here to ensure place for possible scale_IEC_I suffix. */
- num_size = snprintf (buf, buf_size - 1, fmt, val, suffix_power_char (power));
+ num_size = snprintf (buf, buf_size - 1, fmt, val, prec,
+ suffix_power_char (power));
if (num_size < 0 || num_size >= (int) buf_size - 1)
error (EXIT_FAILURE, 0,
_("failed to prepare value '%Lf' for printing"), val);
Optional quote (%'f) will enable --grouping (if supported by current locale).\n\
Optional width value (%10f) will pad output. Optional zero (%010f) width\n\
will zero pad the number. Optional negative values (%-10f) will left align.\n\
+Optional precision (%.1f) will override the input determined precision.\n\
"), stdout);
printf (_("\n\
Only a limited subset of printf(3) syntax is supported.
TODO:
- support .precision
support %e %g etc. rather than just %f
NOTES:
if (fmt[i] == '\0')
error (EXIT_FAILURE, 0, _("format %s ends in %%"), quote (fmt));
+ if (fmt[i] == '.')
+ {
+ i++;
+ errno = 0;
+ user_precision = strtol (fmt + i, &endptr, 10);
+ if (errno == ERANGE || user_precision < 0 || SIZE_MAX < user_precision
+ || isblank (fmt[i]) || fmt[i] == '+')
+ {
+ /* Note we disallow negative user_precision to be
+ consistent with printf(1). POSIX states that
+ negative precision is only supported (and ignored)
+ when used with '.*f'. glibc at least will malform
+ output when passed a direct negative precision. */
+ error (EXIT_FAILURE, 0,
+ _("invalid precision in format %s"), quote (fmt));
+ }
+ i = endptr - fmt;
+ }
+
if (fmt[i] != 'f')
error (EXIT_FAILURE, 0, _("invalid format %s,"
- " directive must be %%[0]['][-][N]f"),
+ " directive must be %%[0]['][-][N][.][N]f"),
quote (fmt));
i++;
suffix_pos = i;
return 0;
}
- double_to_human (val, precision, buf, sizeof (buf), scale_to, grouping,
- round_style);
+ double_to_human (val, user_precision == -1 ? precision : user_precision, buf,
+ sizeof (buf), scale_to, grouping, round_style);
if (suffix)
strncat (buf, suffix, sizeof (buf) - strlen (buf) -1);
"(cannot handle values > 999Y)\n"},
{EXIT => 2}],
+ # precision override
+ ['precision-1','--format=%.4f 9991239123 --to=si', {OUT=>"9.9913G"}],
+ ['precision-2','--format=%.1f 9991239123 --to=si', {OUT=>"10.0G"}],
+ ['precision-3','--format=%.1f 1', {OUT=>"1.0"}],
+ ['precision-4','--format=%.1f 1.12', {OUT=>"1.2"}],
+ ['precision-5','--format=%.1f 9991239123 --to-unit=G', {OUT=>"10.0"}],
+ ['precision-6','--format="% .1f" 9991239123 --to-unit=G', {OUT=>"10.0"}],
+ ['precision-7','--format=%.-1f 1.1',
+ {ERR => "$prog: invalid precision in format '%.-1f'\n"},
+ {EXIT => 1}],
+ ['precision-8','--format=%.+1f 1.1',
+ {ERR => "$prog: invalid precision in format '%.+1f'\n"},
+ {EXIT => 1}],
+ ['precision-9','--format="%. 1f" 1.1',
+ {ERR => "$prog: invalid precision in format '%. 1f'\n"},
+ {EXIT => 1}],
+
# debug warnings
['debug-1', '--debug 4096', {OUT=>"4096"},
{ERR=>"$prog: no conversion option specified\n"}],
{EXIT=>1}],
['fmt-err-4', '--format "%d"',
{ERR=>"$prog: invalid format '%d', " .
- "directive must be %[0]['][-][N]f\n"},
+ "directive must be %[0]['][-][N][.][N]f\n"},
{EXIT=>1}],
['fmt-err-5', '--format "% -43 f"',
{ERR=>"$prog: invalid format '% -43 f', " .
- "directive must be %[0]['][-][N]f\n"},
+ "directive must be %[0]['][-][N][.][N]f\n"},
{EXIT=>1}],
['fmt-err-6', '--format "%f %f"',
{ERR=>"$prog: format '%f %f' has too many % directives\n"},