diff options
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | doc/coreutils.texi | 2 | ||||
-rw-r--r-- | src/paste.c | 26 | ||||
-rwxr-xr-x | tests/misc/paste.pl | 10 |
4 files changed, 31 insertions, 9 deletions
@@ -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. diff --git a/doc/coreutils.texi b/doc/coreutils.texi index 157ce0e12..01d76ec2c 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -6004,6 +6004,8 @@ $ paste -d '%_' num2 let3 num2 %c_ @end example +@optZeroTerminated + @end table @exitstatus diff --git a/src/paste.c b/src/paste.c index a5acecd90..bf99fe028 100644 --- a/src/paste.c +++ b/src/paste.c @@ -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)) { @@ -447,6 +450,9 @@ each FILE, separated by TABs, to standard output.\n\ -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); /* FIXME: add a couple of examples. */ @@ -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); diff --git a/tests/misc/paste.pl b/tests/misc/paste.pl index b4409e779..7c9559700 100755 --- a/tests/misc/paste.pl +++ b/tests/misc/paste.pl @@ -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}, |