summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--doc/coreutils.texi3
-rw-r--r--src/numfmt.c31
-rwxr-xr-xtests/misc/numfmt.pl29
4 files changed, 56 insertions, 9 deletions
diff --git a/NEWS b/NEWS
index 9f48415de..1c214d520 100644
--- a/NEWS
+++ b/NEWS
@@ -33,7 +33,7 @@ GNU coreutils NEWS -*- outline -*-
** New features
- comm, cut, head, paste, tail now have the -z,--zero-terminated option, and
+ comm,cut,head,numfmt,paste,tail now have the -z,--zero-terminated option, and
tac --separator accepts an empty argument, to work with NUL delimited items.
dd now summarizes sizes in --human-readable format too, not just --si.
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 01d76ec2c..f7bdc4274 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -17171,6 +17171,9 @@ the output numbers represent other units (e.g. to represent @samp{4,000,000}
bytes in blocks of 1KB, use @samp{--to=si --to-unit=1000}).
Suffixes are handled as with @samp{--from=auto}.
+@optZeroTerminated
+@newlineFieldSeparator
+
@end table
@subsection Possible @var{unit}s:
diff --git a/src/numfmt.c b/src/numfmt.c
index 5d38cbdcf..223f2a26b 100644
--- a/src/numfmt.c
+++ b/src/numfmt.c
@@ -147,6 +147,7 @@ static struct option const longopts[] =
{"header", optional_argument, NULL, HEADER_OPTION},
{"format", required_argument, NULL, FORMAT_OPTION},
{"invalid", required_argument, NULL, INVALID_OPTION},
+ {"zero-terminated", no_argument, NULL, 'z'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
@@ -189,8 +190,13 @@ static int conv_exit_code = EXIT_CONVERSION_WARNINGS;
/* auto-pad each line based on skipped whitespace. */
static int auto_padding = 0;
static mbs_align_t padding_alignment = MBS_ALIGN_RIGHT;
+
+/* field delimiter */
static int delimiter = DELIMITER_DEFAULT;
+/* line delimiter. */
+static unsigned char line_delim = '\n';
+
/* if non-zero, the first 'header' lines from STDIN are skipped. */
static uintmax_t header = 0;
@@ -205,6 +211,7 @@ static int decimal_point_length;
/* debugging for developers. Enables devmsg(). */
static bool dev_debug = false;
+
static inline int
default_scale_base (enum scale_type scale)
{
@@ -934,7 +941,9 @@ Reformat NUMBER(s), or the numbers from standard input if none are specified.\n\
fputs (_("\
--to-unit=N the output unit size (instead of the default 1)\n\
"), stdout);
-
+ fputs (_("\
+ -z, --zero-terminated line delimiter is NUL, not newline\n\
+"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -1329,10 +1338,10 @@ next_field (char **line)
else
{
/* keep any space prefix in the returned field */
- while (*field_end && isblank (to_uchar (*field_end)))
+ while (*field_end && field_sep (*field_end))
++field_end;
- while (*field_end && !isblank (to_uchar (*field_end)))
+ while (*field_end && ! field_sep (*field_end))
++field_end;
}
@@ -1420,7 +1429,7 @@ process_line (char *line, bool newline)
}
if (newline)
- putchar ('\n');
+ putchar (line_delim);
return valid_number;
}
@@ -1451,7 +1460,7 @@ main (int argc, char **argv)
while (true)
{
- int c = getopt_long (argc, argv, "d:", longopts, NULL);
+ int c = getopt_long (argc, argv, "d:z", longopts, NULL);
if (c == -1)
break;
@@ -1512,6 +1521,10 @@ main (int argc, char **argv)
delimiter = optarg[0];
break;
+ case 'z':
+ line_delim = '\0';
+ break;
+
case SUFFIX_OPTION:
suffix = optarg;
break;
@@ -1599,12 +1612,14 @@ main (int argc, char **argv)
size_t line_allocated = 0;
ssize_t len;
- while (header-- && getline (&line, &line_allocated, stdin) > 0)
+ while (header-- && getdelim (&line, &line_allocated,
+ line_delim, stdin) > 0)
fputs (line, stdout);
- while ((len = getline (&line, &line_allocated, stdin)) > 0)
+ while ((len = getdelim (&line, &line_allocated,
+ line_delim, stdin)) > 0)
{
- bool newline = line[len - 1] == '\n';
+ bool newline = line[len - 1] == line_delim;
if (newline)
line[len - 1] = '\0';
valid_numbers &= process_line (line, newline);
diff --git a/tests/misc/numfmt.pl b/tests/misc/numfmt.pl
index 451bb34ab..3f2d6cc66 100755
--- a/tests/misc/numfmt.pl
+++ b/tests/misc/numfmt.pl
@@ -804,6 +804,32 @@ my @Tests =
{EXIT => 2}],
);
+# test null-terminated lines
+my @NullDelim_Tests =
+ (
+ # Input from STDIN
+ ['z1', '-z --to=iec',
+ {IN_PIPE => "1025\x002048\x00"}, {OUT=>"1.1K\x002.0K\x00"}],
+
+ # Input from the commandline - terminated by NULL vs NL
+ ['z3', ' --to=iec 1024', {OUT=>"1.0K\n"}],
+ ['z2', '-z --to=iec 1024', {OUT=>"1.0K\x00"}],
+
+ # Input from STDIN, with fields
+ ['z4', '-z --field=3 --to=si',
+ {IN_PIPE => "A B 1001 C\x00" .
+ "D E 2002 F\x00"},
+ {OUT => "A B 1.1K C\x00" .
+ "D E 2.1K F\x00"}],
+
+ # Input from STDIN, with fields and embedded NL
+ ['z5', '-z --field=3 --to=si',
+ {IN_PIPE => "A\nB 1001 C\x00" .
+ "D E\n2002 F\x00"},
+ {OUT => "A B 1.1K C\x00" .
+ "D E 2.1K F\x00"}],
+ );
+
my @Limit_Tests =
(
# Large Values
@@ -1080,6 +1106,9 @@ foreach $t (@Tests)
}
}
+# Add test for null-terminated lines (after adjusting the OUT string, above).
+push @Tests, @NullDelim_Tests;
+
my $save_temps = $ENV{SAVE_TEMPS};
my $verbose = $ENV{VERBOSE};