paste: add the -z,--zero-terminated option

* doc/coreutils.texi (paste invocation): Reference -z description.
* src/paste.c (main): Parameterize the use of '\n'.
* tests/misc/paste.pl: Add test cases.
* NEWS: Mention the new feature.
This commit is contained in:
Pádraig Brady 2016-01-08 15:57:06 +00:00
parent 0e46753d7c
commit 8297568ec6
4 changed files with 31 additions and 9 deletions

2
NEWS
View File

@ -33,7 +33,7 @@ GNU coreutils NEWS -*- outline -*-
** New features
comm, cut, head, tail now have the -z,--zero-terminated option, and
comm, cut, head, 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.

View File

@ -6004,6 +6004,8 @@ $ paste -d '%_' num2 let3 num2
%c_
@end example
@optZeroTerminated
@end table
@exitstatus

View File

@ -67,10 +67,13 @@ static char *delims;
/* A pointer to the character after the end of 'delims'. */
static char const *delim_end;
static unsigned char line_delim = '\n';
static struct option const longopts[] =
{
{"serial", no_argument, NULL, 's'},
{"delimiters", required_argument, NULL, 'd'},
{"zero-terminated", no_argument, NULL, 'z'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
@ -250,7 +253,7 @@ paste_parallel (size_t nfiles, char **fnamptr)
while (chr != EOF)
{
sometodo = true;
if (chr == '\n')
if (chr == line_delim)
break;
xputchar (chr);
chr = getc (fileptr[i]);
@ -295,7 +298,7 @@ paste_parallel (size_t nfiles, char **fnamptr)
write_error ();
delims_saved = 0;
}
xputchar ('\n');
xputchar (line_delim);
}
continue; /* Next read of files, or exit. */
}
@ -316,7 +319,7 @@ paste_parallel (size_t nfiles, char **fnamptr)
/* Except for last file, replace last newline with delim. */
if (i + 1 != nfiles)
{
if (chr != '\n' && chr != EOF)
if (chr != line_delim && chr != EOF)
xputchar (chr);
if (*delimptr != EMPTY_DELIM)
xputchar (*delimptr);
@ -327,7 +330,7 @@ paste_parallel (size_t nfiles, char **fnamptr)
{
/* If the last line of the last file lacks a newline,
print one anyhow. POSIX requires this. */
char c = (chr == EOF ? '\n' : chr);
char c = (chr == EOF ? line_delim : chr);
xputchar (c);
}
}
@ -386,7 +389,7 @@ paste_serial (size_t nfiles, char **fnamptr)
while ((charnew = getc (fileptr)) != EOF)
{
/* Process the old character. */
if (charold == '\n')
if (charold == line_delim)
{
if (*delimptr != EMPTY_DELIM)
xputchar (*delimptr);
@ -405,8 +408,8 @@ paste_serial (size_t nfiles, char **fnamptr)
xputchar (charold);
}
if (charold != '\n')
xputchar ('\n');
if (charold != line_delim)
xputchar (line_delim);
if (ferror (fileptr))
{
@ -446,6 +449,9 @@ each FILE, separated by TABs, to standard output.\n\
fputs (_("\
-d, --delimiters=LIST reuse characters from LIST instead of TABs\n\
-s, --serial paste one file at a time instead of in parallel\n\
"), stdout);
fputs (_("\
-z, --zero-terminated line delimiter is NUL, not newline\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
@ -473,7 +479,7 @@ main (int argc, char **argv)
have_read_stdin = false;
serial_merge = false;
while ((optc = getopt_long (argc, argv, "d:s", longopts, NULL)) != -1)
while ((optc = getopt_long (argc, argv, "d:sz", longopts, NULL)) != -1)
{
switch (optc)
{
@ -486,6 +492,10 @@ main (int argc, char **argv)
serial_merge = true;
break;
case 'z':
line_delim = '\0';
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);

View File

@ -34,6 +34,11 @@ my @Tests =
['no-nl-3', {IN=>"a"}, {IN=>"b\n"}, {OUT=>"a\tb\n"}],
['no-nl-4', {IN=>"a\n"}, {IN=>"b\n"}, {OUT=>"a\tb\n"}],
['zno-nl-1', '-z', {IN=>"a"}, {IN=>"b"}, {OUT=>"a\tb\0"}],
['zno-nl-2', '-z', {IN=>"a\0"}, {IN=>"b"}, {OUT=>"a\tb\0"}],
['zno-nl-3', '-z', {IN=>"a"}, {IN=>"b\0"}, {OUT=>"a\tb\0"}],
['zno-nl-4', '-z', {IN=>"a\0"}, {IN=>"b\0"}, {OUT=>"a\tb\0"}],
# Same as above, but with a two lines in each input file and
# the addition of the -d option to make SPACE be the output delimiter.
['no-nla1', '-d" "', {IN=>"1\na"}, {IN=>"2\nb"}, {OUT=>"1 2\na b\n"}],
@ -41,6 +46,11 @@ my @Tests =
['no-nla3', '-d" "', {IN=>"1\na"}, {IN=>"2\nb\n"}, {OUT=>"1 2\na b\n"}],
['no-nla4', '-d" "', {IN=>"1\na\n"}, {IN=>"2\nb\n"}, {OUT=>"1 2\na b\n"}],
['zno-nla1', '-zd" "', {IN=>"1\0a"}, {IN=>"2\0b"}, {OUT=>"1 2\0a b\0"}],
['zno-nla2', '-zd" "', {IN=>"1\0a\0"}, {IN=>"2\0b"}, {OUT=>"1 2\0a b\0"}],
['zno-nla3', '-zd" "', {IN=>"1\0a"}, {IN=>"2\0b\0"}, {OUT=>"1 2\0a b\0"}],
['zno-nla4', '-zd" "', {IN=>"1\0a\0"}, {IN=>"2\0b\0"}, {OUT=>"1 2\0a b\0"}],
# Specifying a delimiter with a trailing backslash would overrun a
# malloc'd buffer.
['delim-bs1', q!-d'\'!, {IN=>{'a'x50=>''}}, {EXIT => 1},