Skip to content

Commit

Permalink
sc_io_source: add feof and further checks
Browse files Browse the repository at this point in the history
We remember if we reach the end of input.
In this case, any further reading returns 0 bytes.

We add a couple documentation items and assertions.
  • Loading branch information
cburstedde committed Jan 16, 2024
1 parent e69f0ad commit e0b4e2a
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 9 deletions.
53 changes: 48 additions & 5 deletions src/sc_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,27 +213,33 @@ sc_io_source_new (int iotype, int ioencode, ...)
sc_io_source_t *source;
va_list ap;

/* verify preconditions */
SC_ASSERT (0 <= iotype && iotype < SC_IO_TYPE_LAST);
SC_ASSERT (0 <= ioencode && ioencode < SC_IO_ENCODE_LAST);

/* initialize members of source object */
source = SC_ALLOC_ZERO (sc_io_source_t, 1);
source->iotype = (sc_io_type_t) iotype;
source->encode = (sc_io_encode_t) ioencode;

/* there is at least one type-dependent argument */
va_start (ap, ioencode);
if (iotype == SC_IO_TYPE_BUFFER) {
/* the source is presented in the form of an array */
source->buffer = va_arg (ap, sc_array_t *);
}
else if (iotype == SC_IO_TYPE_FILENAME) {
const char *filename = va_arg (ap, const char *);

/* open a file on disk by name */
source->file = fopen (filename, "rb");
if (source->file == NULL) {
SC_FREE (source);
return NULL;
}
}
else if (iotype == SC_IO_TYPE_FILEFILE) {
/* read from an existing (readable) file object */
source->file = va_arg (ap, FILE *);
if (ferror (source->file)) {
SC_FREE (source);
Expand All @@ -245,6 +251,7 @@ sc_io_source_new (int iotype, int ioencode, ...)
}
va_end (ap);

/* this source can now be called for reading */
return source;
}

Expand Down Expand Up @@ -300,28 +307,60 @@ sc_io_source_read (sc_io_source_t * source, void *data,
int retval;
size_t bbytes_out;

/* basic input preconditions */
SC_ASSERT (source != NULL);
SC_ASSERT (data != NULL || bytes_avail == 0);

/* do nothing also if the end of the file has been reached */
if (bytes_avail == 0 || source->is_eof) {
if (bytes_out != NULL) {
*bytes_out = 0;
}
return SC_IO_ERROR_NONE;
}

/* do a regular read */
retval = 0;
bbytes_out = 0;

/* switch on the type of source */
if (source->iotype == SC_IO_TYPE_BUFFER) {
SC_ASSERT (source->buffer != NULL);

/* access total byte count theoretically available in input buffer */
bbytes_out = SC_ARRAY_BYTE_ALLOC (source->buffer);
SC_ASSERT (bbytes_out >= source->buffer_bytes);

/* compute how many bytes may be read now on top of the previous ones */
bbytes_out -= source->buffer_bytes;
bbytes_out = SC_MIN (bbytes_out, bytes_avail);
if (bbytes_out == 0) {
/* note end of buffer memory */
source->is_eof = 1;
}
else {
/* we may be instructed to read less bytes than available */
bbytes_out = SC_MIN (bbytes_out, bytes_avail);

if (data != NULL) {
memcpy (data, source->buffer->array + source->buffer_bytes, bbytes_out);
/* In the present code we read to the end of the buffer allocation.
* This may not be what we want: we may only read actual elements,
* which may be less.
* TO DO: look into it. */

/* read into output buffer */
if (data != NULL) {
memcpy (data, source->buffer->array + source->buffer_bytes, bbytes_out);
}
source->buffer_bytes += bbytes_out;
}
source->buffer_bytes += bbytes_out;
}
else if (source->iotype == SC_IO_TYPE_FILENAME ||
source->iotype == SC_IO_TYPE_FILEFILE) {
SC_ASSERT (source->file != NULL);
if (data != NULL) {
bbytes_out = fread (data, 1, bytes_avail, source->file);
if (bbytes_out < bytes_avail) {
retval = !feof (source->file) || ferror (source->file);
retval = !(source->is_eof = feof (source->file)) ||
ferror (source->file);
}
if (retval == SC_IO_ERROR_NONE && source->mirror != NULL) {
retval = sc_io_sink_write (source->mirror, data, bbytes_out);
Expand All @@ -332,19 +371,23 @@ sc_io_source_read (sc_io_source_t * source, void *data,
bbytes_out = bytes_avail;
}
}

/* process error conditions */
if (retval) {
return SC_IO_ERROR_FATAL;
}
if (bytes_out == NULL && bbytes_out < bytes_avail) {
return SC_IO_ERROR_FATAL;
}

/* complete and return on successful operation */
if (bytes_out != NULL) {
*bytes_out = bbytes_out;
}
source->bytes_in += bbytes_out;
source->bytes_out += bbytes_out;

/* success! */
return SC_IO_ERROR_NONE;
}

Expand Down
9 changes: 5 additions & 4 deletions src/sc_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,15 @@ typedef struct sc_io_source
sc_io_type_t iotype; /**< type of the I/O operation */
sc_io_encode_t encode; /**< encoding of data */
sc_array_t *buffer; /**< buffer for the iotype
SC_IO_TYPE_BUFFER*/
size_t buffer_bytes; /**< distinguish from array elems */
\ref SC_IO_TYPE_BUFFER */
size_t buffer_bytes; /**< distinguish from array elements */
FILE *file; /**< file pointer for iotype unequal to
SC_IO_TYPE_BUFFER */
\ref SC_IO_TYPE_BUFFER */
size_t bytes_in; /**< input bytes count */
size_t bytes_out; /**< read bytes count */
int is_eof; /**< Have we reached the end of file? */
sc_io_sink_t *mirror; /**< if activated, a sink to store the
data*/
data */
sc_array_t *mirror_buffer; /**< if activated, the buffer for the
mirror */
}
Expand Down

0 comments on commit e0b4e2a

Please sign in to comment.