diff --git a/include/alisp/stream.h b/include/alisp/stream.h index c8f0a94..a2fbbd8 100644 --- a/include/alisp/stream.h +++ b/include/alisp/stream.h @@ -53,6 +53,8 @@ typedef struct stream_err_t stream_init_string(stream_t *, const char *, sv_t); stream_err_t stream_init_pipe(stream_t *, const char *, FILE *); +// NOTE: stream_init_file will attempt to read all content from the FILE +// descriptor. Use with caution. stream_err_t stream_init_file(stream_t *, const char *, FILE *); void stream_stop(stream_t *); diff --git a/src/stream.c b/src/stream.c index 1507a85..a915683 100644 --- a/src/stream.c +++ b/src/stream.c @@ -84,7 +84,18 @@ stream_err_t stream_init_file(stream_t *stream, const char *name, FILE *pipe) stream->type = STREAM_TYPE_FILE; stream->name = name; - stream->pipe.file = pipe; + stream->pipe.file = NULL; + + // NOTE: We're reading all the data from the file descriptor now. + fseek(pipe, 0, SEEK_END); + long size = ftell(pipe); + fseek(pipe, 0, SEEK_SET); + vec_ensure_free(&stream->pipe.cache, size); + int read = fread(vec_data(&stream->pipe.cache), 1, size, pipe); + + // These must be equivalent for this function. + assert(read == size); + stream->pipe.cache.size += size; return STREAM_ERR_OK; } @@ -99,11 +110,8 @@ void stream_stop(stream_t *stream) free(stream->string.data); break; case STREAM_TYPE_FILE: - // ensure we reset the FILE pointer to the start - fseek(stream->pipe.file, 0, SEEK_SET); - // fallthrough case STREAM_TYPE_PIPE: - // Must cleanup vector + // Must cleanup caching vector vec_free(&stream->pipe.cache); break; } @@ -131,10 +139,10 @@ bool stream_eoc(stream_t *stream) assert(stream); switch (stream->type) { - case STREAM_TYPE_STRING: - return stream->position >= stream->string.size; - case STREAM_TYPE_PIPE: case STREAM_TYPE_FILE: + case STREAM_TYPE_STRING: + return stream->position >= stream_size(stream); + case STREAM_TYPE_PIPE: return feof(stream->pipe.file) && stream->position >= stream->pipe.cache.size; default: @@ -148,12 +156,11 @@ bool stream_chunk(stream_t *stream) assert(stream); switch (stream->type) { + case STREAM_TYPE_FILE: case STREAM_TYPE_STRING: // nothing to chunk, hence false return false; case STREAM_TYPE_PIPE: - // fallthrough - case STREAM_TYPE_FILE: { if (feof(stream->pipe.file)) // We can't read anymore. End of the line @@ -194,10 +201,10 @@ char stream_peek(stream_t *stream) switch (stream->type) { - case STREAM_TYPE_STRING: - return stream->string.data[stream->position]; - case STREAM_TYPE_PIPE: case STREAM_TYPE_FILE: + case STREAM_TYPE_STRING: + return stream_sv(stream).data[0]; + case STREAM_TYPE_PIPE: { // Cached already? We are done. if (stream->position < stream->pipe.cache.size) @@ -306,8 +313,8 @@ sv_t stream_sv_abs(stream_t *stream) case STREAM_TYPE_STRING: sv = stream->string; break; - case STREAM_TYPE_PIPE: case STREAM_TYPE_FILE: + case STREAM_TYPE_PIPE: sv = SV((char *)vec_data(&stream->pipe.cache), stream_size(stream)); break; default: diff --git a/test/test_stream.c b/test/test_stream.c index 292fe02..3807789 100644 --- a/test/test_stream.c +++ b/test/test_stream.c @@ -113,9 +113,8 @@ void stream_test_file(void) TEST(err == STREAM_ERR_OK, "Expected initialisating to be okay: %s", stream_err_to_cstr(err)); } - TEST(stream_size(&stream) == 0, "Stream doesn't read on init: size = %lu", - stream_size(&stream)); TEST(!stream_eoc(&stream), "Stream should not be at the EoC from init."); + stream_stop(&stream); } // try to initialise the stream again but against a nonexistent file - we're