diff options
author | Richard Russon <rich@flatcap.org> | 2015-09-26 14:22:26 +0100 |
---|---|---|
committer | Pádraig Brady <P@draigBrady.com> | 2016-01-13 10:59:55 +0000 |
commit | bc94551f63cfc4c05a56628dfcb386707d9e98cb (patch) | |
tree | 8e22511edca165d3603b13762ff2063801543c27 /src | |
parent | b2eadd109c3a508011705761dfe24a35180d925d (diff) | |
download | coreutils-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.c | 31 | ||||
-rw-r--r-- | src/tail.c | 26 |
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; |