** 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.
{"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}
/* 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;
/* debugging for developers. Enables devmsg(). */
static bool dev_debug = false;
+
static inline int
default_scale_base (enum scale_type scale)
{
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);
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;
}
}
if (newline)
- putchar ('\n');
+ putchar (line_delim);
return valid_number;
}
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;
delimiter = optarg[0];
break;
+ case 'z':
+ line_delim = '\0';
+ break;
+
case SUFFIX_OPTION:
suffix = optarg;
break;
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);
{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
}
}
+# 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};