summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/head.c28
-rwxr-xr-xtests/misc/head-c.sh9
2 files changed, 29 insertions, 8 deletions
diff --git a/src/head.c b/src/head.c
index d79d5f7de..00e1be17c 100644
--- a/src/head.c
+++ b/src/head.c
@@ -196,7 +196,7 @@ copy_fd (int src_fd, FILE *o_stream, uintmax_t n_bytes)
return COPY_FD_OK;
}
-/* Print all but the last N_ELIDE lines from the input available via
+/* Print all but the last N_ELIDE bytes from the input available via
the non-seekable file descriptor FD. Return true upon success.
Give a diagnostic and return false upon error. */
static bool
@@ -313,18 +313,34 @@ elide_tail_bytes_pipe (const char *filename, int fd, uintmax_t n_elide_0)
size_t n_read;
bool buffered_enough;
size_t i, i_next;
- char **b;
+ char **b = NULL;
/* Round n_elide up to a multiple of READ_BUFSIZE. */
size_t rem = READ_BUFSIZE - (n_elide % READ_BUFSIZE);
size_t n_elide_round = n_elide + rem;
size_t n_bufs = n_elide_round / READ_BUFSIZE + 1;
- b = xcalloc (n_bufs, sizeof *b);
+ size_t n_alloc = 0;
+ size_t n_array_alloc = 0;
buffered_enough = false;
for (i = 0, i_next = 1; !eof; i = i_next, i_next = (i_next + 1) % n_bufs)
{
- if (b[i] == NULL)
- b[i] = xmalloc (READ_BUFSIZE);
+ if (n_array_alloc == i)
+ {
+ /* reallocate between 16 and n_bufs entries. */
+ if (n_array_alloc == 0)
+ n_array_alloc = MIN (n_bufs, 16);
+ else if (n_array_alloc <= n_bufs / 2)
+ n_array_alloc *= 2;
+ else
+ n_array_alloc = n_bufs;
+ b = xnrealloc (b, n_array_alloc, sizeof *b);
+ }
+
+ if (! buffered_enough)
+ {
+ b[i] = xmalloc (READ_BUFSIZE);
+ n_alloc = i + 1;
+ }
n_read = full_read (fd, b[i], READ_BUFSIZE);
if (n_read < READ_BUFSIZE)
{
@@ -388,7 +404,7 @@ elide_tail_bytes_pipe (const char *filename, int fd, uintmax_t n_elide_0)
}
free_mem:
- for (i = 0; i < n_bufs; i++)
+ for (i = 0; i < n_alloc; i++)
free (b[i]);
free (b);
diff --git a/tests/misc/head-c.sh b/tests/misc/head-c.sh
index 6807c4d5a..eada8d550 100755
--- a/tests/misc/head-c.sh
+++ b/tests/misc/head-c.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# exercise the fix of 2001-08-18, based on test case from Ian Bruce
+# exercise head -c
# Copyright (C) 2001-2013 Free Software Foundation, Inc.
@@ -19,12 +19,17 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ head
+# exercise the fix of 2001-08-18, based on test case from Ian Bruce
echo abc > in || framework_failure_
-
(head -c1; head -c1) < in > out || fail=1
case "$(cat out)" in
ab) ;;
*) fail=1 ;;
esac
+# Only allocate memory as needed.
+# Coreutils <= 8.21 would allocate memory up front
+# based on the value passed to -c
+(ulimit -v 20000; head --bytes=-E < /dev/null) || fail=1
+
Exit $fail