summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRichard Russon <rich@flatcap.org>2015-09-26 14:22:26 +0100
committerPádraig Brady <P@draigBrady.com>2016-01-13 10:59:55 +0000
commitbc94551f63cfc4c05a56628dfcb386707d9e98cb (patch)
tree8e22511edca165d3603b13762ff2063801543c27 /src
parentb2eadd109c3a508011705761dfe24a35180d925d (diff)
downloadcoreutils-bc94551f63cfc4c05a56628dfcb386707d9e98cb.tar.xz
head,tail: add the -z,--zero-terminated option
* doc/coreutils.texi: Reference the option description. * src/head.c: Parameterize the delimiter character. * src/tail.c: Likewise. * tests/misc/head.pl: Add test case. * tests/misc/tail.pl: Likewise. * NEWS: Mention the new feature.
Diffstat (limited to 'src')
-rw-r--r--src/head.c31
-rw-r--r--src/tail.c26
2 files changed, 43 insertions, 14 deletions
diff --git a/src/head.c b/src/head.c
index a5405aae6..282c2ea8d 100644
--- a/src/head.c
+++ b/src/head.c
@@ -58,6 +58,9 @@ static bool presume_input_pipe;
/* If true, print filename headers. */
static bool print_headers;
+/* Character to split lines by. */
+static char line_end;
+
/* When to print the filename banners. */
enum header_mode
{
@@ -90,6 +93,7 @@ static struct option const long_options[] =
{"quiet", no_argument, NULL, 'q'},
{"silent", no_argument, NULL, 'q'},
{"verbose", no_argument, NULL, 'v'},
+ {"zero-terminated", no_argument, NULL, 'z'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
@@ -126,6 +130,9 @@ With more than one FILE, precede each with a header giving the file name.\n\
-q, --quiet, --silent never print headers giving file names\n\
-v, --verbose always print headers giving file names\n\
"), stdout);
+ fputs (_("\
+ -z, --zero-terminated line delimiter is NUL, not newline\n\
+"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
@@ -532,7 +539,7 @@ elide_tail_lines_pipe (const char *filename, int fd, uintmax_t n_elide,
{
char const *buffer_end = tmp->buffer + n_read;
char const *p = tmp->buffer;
- while ((p = memchr (p, '\n', buffer_end - p)))
+ while ((p = memchr (p, line_end, buffer_end - p)))
{
++p;
++tmp->nlines;
@@ -581,7 +588,7 @@ elide_tail_lines_pipe (const char *filename, int fd, uintmax_t n_elide,
/* If we read any bytes at all, count the incomplete line
on files that don't end with a newline. */
- if (last->nbytes && last->buffer[last->nbytes - 1] != '\n')
+ if (last->nbytes && last->buffer[last->nbytes - 1] != line_end)
{
++last->nlines;
++total_lines;
@@ -600,7 +607,7 @@ elide_tail_lines_pipe (const char *filename, int fd, uintmax_t n_elide,
size_t n = total_lines - n_elide;
char const *buffer_end = tmp->buffer + tmp->nbytes;
char const *p = tmp->buffer;
- while (n && (p = memchr (p, '\n', buffer_end - p)))
+ while (n && (p = memchr (p, line_end, buffer_end - p)))
{
++p;
++tmp->nlines;
@@ -664,7 +671,7 @@ elide_tail_lines_seekable (const char *pretty_filename, int fd,
const bool all_lines = !n_lines;
/* Count the incomplete line on files that don't end with a newline. */
- if (n_lines && bytes_read && buffer[bytes_read - 1] != '\n')
+ if (n_lines && bytes_read && buffer[bytes_read - 1] != line_end)
--n_lines;
while (1)
@@ -679,7 +686,7 @@ elide_tail_lines_seekable (const char *pretty_filename, int fd,
else
{
char const *nl;
- nl = memrchr (buffer, '\n', n);
+ nl = memrchr (buffer, line_end, n);
if (nl == NULL)
break;
n = nl - buffer;
@@ -804,7 +811,7 @@ head_lines (const char *filename, int fd, uintmax_t lines_to_write)
if (bytes_read == 0)
break;
while (bytes_to_write < bytes_read)
- if (buffer[bytes_to_write++] == '\n' && --lines_to_write == 0)
+ if (buffer[bytes_to_write++] == line_end && --lines_to_write == 0)
{
off_t n_bytes_past_EOL = bytes_read - bytes_to_write;
/* If we have read more data than that on the specified number
@@ -942,6 +949,8 @@ main (int argc, char **argv)
print_headers = false;
+ line_end = '\n';
+
if (1 < argc && argv[1][0] == '-' && ISDIGIT (argv[1][1]))
{
char *a = argv[1];
@@ -986,6 +995,10 @@ main (int argc, char **argv)
header_mode = always;
break;
+ case 'z':
+ line_end = '\0';
+ break;
+
default:
error (0, 0, _("invalid trailing option -- %c"), *a);
usage (EXIT_FAILURE);
@@ -1006,7 +1019,7 @@ main (int argc, char **argv)
argc--;
}
- while ((c = getopt_long (argc, argv, "c:n:qv0123456789", long_options, NULL))
+ while ((c = getopt_long (argc, argv, "c:n:qvz0123456789", long_options, NULL))
!= -1)
{
switch (c)
@@ -1039,6 +1052,10 @@ main (int argc, char **argv)
header_mode = always;
break;
+ case 'z':
+ line_end = '\0';
+ break;
+
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
diff --git a/src/tail.c b/src/tail.c
index 9007888fc..781adf200 100644
--- a/src/tail.c
+++ b/src/tail.c
@@ -180,6 +180,9 @@ static bool from_start;
/* If true, print filename headers. */
static bool print_headers;
+/* Character to split lines by. */
+static char line_end;
+
/* When to print the filename banners. */
enum header_mode
{
@@ -238,6 +241,7 @@ static struct option const long_options[] =
{"silent", no_argument, NULL, 'q'},
{"sleep-interval", required_argument, NULL, 's'},
{"verbose", no_argument, NULL, 'v'},
+ {"zero-terminated", no_argument, NULL, 'z'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
@@ -297,6 +301,9 @@ With more than one FILE, precede each with a header giving the file name.\n\
least once every N seconds\n\
-v, --verbose always output headers giving file names\n\
"), stdout);
+ fputs (_("\
+ -z, --zero-terminated line delimiter is NUL, not newline\n\
+"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
@@ -499,7 +506,7 @@ file_lines (const char *pretty_filename, int fd, uintmax_t n_lines,
*read_pos = pos + bytes_read;
/* Count the incomplete line on files that don't end with a newline. */
- if (bytes_read && buffer[bytes_read - 1] != '\n')
+ if (bytes_read && buffer[bytes_read - 1] != line_end)
--n_lines;
do
@@ -510,7 +517,7 @@ file_lines (const char *pretty_filename, int fd, uintmax_t n_lines,
while (n)
{
char const *nl;
- nl = memrchr (buffer, '\n', n);
+ nl = memrchr (buffer, line_end, n);
if (nl == NULL)
break;
n = nl - buffer;
@@ -595,7 +602,7 @@ pipe_lines (const char *pretty_filename, int fd, uintmax_t n_lines,
{
char const *buffer_end = tmp->buffer + n_read;
char const *p = tmp->buffer;
- while ((p = memchr (p, '\n', buffer_end - p)))
+ while ((p = memchr (p, line_end, buffer_end - p)))
{
++p;
++tmp->nlines;
@@ -649,7 +656,7 @@ pipe_lines (const char *pretty_filename, int fd, uintmax_t n_lines,
goto free_lbuffers;
/* Count the incomplete line on files that don't end with a newline. */
- if (last->buffer[last->nbytes - 1] != '\n')
+ if (last->buffer[last->nbytes - 1] != line_end)
{
++last->nlines;
++total_lines;
@@ -671,7 +678,7 @@ pipe_lines (const char *pretty_filename, int fd, uintmax_t n_lines,
size_t j;
for (j = total_lines - n_lines; j; --j)
{
- beg = memchr (beg, '\n', buffer_end - beg);
+ beg = memchr (beg, line_end, buffer_end - beg);
assert (beg);
++beg;
}
@@ -857,7 +864,7 @@ start_lines (const char *pretty_filename, int fd, uintmax_t n_lines,
*read_pos += bytes_read;
char *p = buffer;
- while ((p = memchr (p, '\n', buffer_end - p)))
+ while ((p = memchr (p, line_end, buffer_end - p)))
{
++p;
if (--n_lines == 0)
@@ -2047,7 +2054,7 @@ parse_options (int argc, char **argv,
{
int c;
- while ((c = getopt_long (argc, argv, "c:n:fFqs:v0123456789",
+ while ((c = getopt_long (argc, argv, "c:n:fFqs:vz0123456789",
long_options, NULL))
!= -1)
{
@@ -2124,6 +2131,10 @@ parse_options (int argc, char **argv,
*header_mode = always;
break;
+ case 'z':
+ line_end = '\0';
+ break;
+
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
@@ -2221,6 +2232,7 @@ main (int argc, char **argv)
count_lines = true;
forever = from_start = print_headers = false;
+ line_end = '\n';
obsolete_option = parse_obsolete_option (argc, argv, &n_units);
argc -= obsolete_option;
argv += obsolete_option;