mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-07-26 02:30:35 +02:00
cut: ensure responsive input processing
* gl/lib/mbbuf.h (fill_buf): Switch from fread() to read() as the former retries read() internally to fill the buffer. * src/cut.c: Adjust accordingly, and avoid getc() interface entirely. * bootstrap.h: Depend explicitly on fseterr. This is already depended on transitively, so should not introduce new build portability issues.
This commit is contained in:
@@ -119,6 +119,7 @@ gnulib_modules="
|
||||
freopen
|
||||
freopen-safer
|
||||
fseeko
|
||||
fseterr
|
||||
fstatat
|
||||
fsusage
|
||||
fsync
|
||||
|
||||
+22
-4
@@ -25,7 +25,9 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "fseterr.h"
|
||||
#include "mcel.h"
|
||||
#include "idx.h"
|
||||
|
||||
@@ -47,6 +49,7 @@ typedef struct
|
||||
idx_t size; /* Number of bytes allocated for BUFFER. */
|
||||
idx_t length; /* Number of bytes with data in BUFFER. */
|
||||
idx_t offset; /* Current position in BUFFER. */
|
||||
bool eof; /* Whether at End Of File. */
|
||||
} mbbuf_t;
|
||||
|
||||
MBBUF_INLINE idx_t
|
||||
@@ -68,16 +71,19 @@ mbbuf_init (mbbuf_t *mbbuf, char *buffer, idx_t size, FILE *fp)
|
||||
mbbuf->size = size;
|
||||
mbbuf->length = 0;
|
||||
mbbuf->offset = 0;
|
||||
mbbuf->eof = false;
|
||||
}
|
||||
|
||||
/* Fill the input buffer with at least MCEL_LEN_MAX bytes if possible.
|
||||
Return the number of bytes available from the current offset. */
|
||||
Return the number of bytes available from the current offset.
|
||||
At end of file, MBBUF.EOF is set, and zero will eventually be returned.
|
||||
Note feof() will _NOT_ be set on the MBBUF.FP. */
|
||||
MBBUF_INLINE idx_t
|
||||
mbbuf_fill (mbbuf_t *mbbuf)
|
||||
{
|
||||
idx_t available = mbbuf_avail (mbbuf);
|
||||
|
||||
if (available < MCEL_LEN_MAX && ! feof (mbbuf->fp))
|
||||
if (available < MCEL_LEN_MAX && ! mbbuf->eof)
|
||||
{
|
||||
idx_t start;
|
||||
if (!(0 < available))
|
||||
@@ -87,8 +93,20 @@ mbbuf_fill (mbbuf_t *mbbuf)
|
||||
memmove (mbbuf->buffer, mbbuf->buffer + mbbuf->offset, available);
|
||||
start = available;
|
||||
}
|
||||
mbbuf->length = fread (mbbuf->buffer + start, 1, mbbuf->size - start,
|
||||
mbbuf->fp) + start;
|
||||
ssize_t read_ret = read (fileno (mbbuf->fp), mbbuf->buffer + start,
|
||||
mbbuf->size - start);
|
||||
if (read_ret < 0)
|
||||
{
|
||||
fseterr (mbbuf->fp);
|
||||
mbbuf->eof = true; /* Avoid any more reads(). */
|
||||
mbbuf->length = start;
|
||||
}
|
||||
else
|
||||
{
|
||||
mbbuf->eof = read_ret == 0;
|
||||
mbbuf->length = read_ret + start;
|
||||
}
|
||||
|
||||
mbbuf->offset = 0;
|
||||
available = mbbuf_avail (mbbuf);
|
||||
}
|
||||
|
||||
@@ -727,17 +727,22 @@ reset_field_line (uintmax_t *field_idx, bool *found_any_selected_field,
|
||||
callers to hand off mid-line. */
|
||||
|
||||
static void
|
||||
cut_bytes_buffered (FILE *stream, uintmax_t *byte_idx, bool *print_delimiter)
|
||||
cut_bytes (FILE *stream)
|
||||
{
|
||||
static char bytes_in[IO_BUFSIZE];
|
||||
uintmax_t byte_idx = 0;
|
||||
bool print_delimiter = false;
|
||||
|
||||
current_rp = frp;
|
||||
|
||||
while (true)
|
||||
{
|
||||
idx_t available = fread (bytes_in, sizeof *bytes_in, sizeof bytes_in,
|
||||
stream);
|
||||
if (available == 0)
|
||||
idx_t available = read (fileno (stream), bytes_in, sizeof bytes_in);
|
||||
if (available <= 0)
|
||||
{
|
||||
write_pending_line_delim (*byte_idx);
|
||||
if (available < 0)
|
||||
fseterr (stream);
|
||||
write_pending_line_delim (byte_idx);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -754,22 +759,22 @@ cut_bytes_buffered (FILE *stream, uintmax_t *byte_idx, bool *print_delimiter)
|
||||
|
||||
while (p < end)
|
||||
{
|
||||
sync_byte_selection (*byte_idx);
|
||||
sync_byte_selection (byte_idx);
|
||||
|
||||
if (*byte_idx + 1 < current_rp->lo)
|
||||
if (byte_idx + 1 < current_rp->lo)
|
||||
{
|
||||
idx_t skip = MIN (end - p, current_rp->lo - (*byte_idx + 1));
|
||||
idx_t skip = MIN (end - p, current_rp->lo - (byte_idx + 1));
|
||||
p += skip;
|
||||
*byte_idx += skip;
|
||||
byte_idx += skip;
|
||||
}
|
||||
else
|
||||
{
|
||||
idx_t n = MIN (end - p, current_rp->hi - *byte_idx);
|
||||
write_selected_item (print_delimiter,
|
||||
is_range_start_index (*byte_idx + 1),
|
||||
idx_t n = MIN (end - p, current_rp->hi - byte_idx);
|
||||
write_selected_item (&print_delimiter,
|
||||
is_range_start_index (byte_idx + 1),
|
||||
p, n);
|
||||
p += n;
|
||||
*byte_idx += n;
|
||||
byte_idx += n;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -777,49 +782,7 @@ cut_bytes_buffered (FILE *stream, uintmax_t *byte_idx, bool *print_delimiter)
|
||||
if (line_end)
|
||||
{
|
||||
processed++;
|
||||
reset_item_line (byte_idx, print_delimiter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Read from stream STREAM, printing to standard output any selected bytes.
|
||||
This avoids data copies and function calls for short lines,
|
||||
and will defer to cut_bytes_buffered() once a longer line is encountered. */
|
||||
|
||||
static void
|
||||
cut_bytes (FILE *stream)
|
||||
{
|
||||
uintmax_t byte_idx = 0;
|
||||
bool print_delimiter = false;
|
||||
|
||||
current_rp = frp;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int c = getc (stream);
|
||||
|
||||
if (c == line_delim)
|
||||
reset_item_line (&byte_idx, &print_delimiter);
|
||||
else if (c == EOF)
|
||||
{
|
||||
write_pending_line_delim (byte_idx);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
next_item (&byte_idx);
|
||||
if (print_kth (byte_idx))
|
||||
{
|
||||
char ch = c;
|
||||
write_selected_item (&print_delimiter,
|
||||
is_range_start_index (byte_idx), &ch, 1);
|
||||
}
|
||||
|
||||
if (SMALL_BYTE_THRESHOLD < byte_idx)
|
||||
{
|
||||
cut_bytes_buffered (stream, &byte_idx, &print_delimiter);
|
||||
break;
|
||||
reset_item_line (&byte_idx, &print_delimiter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1023,7 +986,7 @@ cut_fields_bytesearch (FILE *stream)
|
||||
idx_t safe = mbbuf_fill (&mbbuf);
|
||||
if (safe == 0)
|
||||
break;
|
||||
search.at_eof = feof (mbbuf.fp);
|
||||
search.at_eof = mbbuf.eof;
|
||||
search.line_end_known = false;
|
||||
|
||||
char *chunk = mbbuf.buffer + mbbuf.offset;
|
||||
|
||||
Reference in New Issue
Block a user