#include "system/stacktrace.h" #include #include #include #include #include #include "line_stream.h" #include "lt.h" #include "lt_adapters.h" #include "system/nth_alloc.h" #include "system/log.h" #include "system/str.h" struct LineStream { Lt *lt; FILE *stream; char *buffer; size_t capacity; bool unfinished; }; // TODO(#905): create_line_stream probably does not need mode // Because LineStream interface doesn't even have anything // for writing to files. So we can just hardcode the mode // inside of the ctor. LineStream *create_line_stream(const char *filename, const char *mode, size_t capacity) { trace_assert(filename); trace_assert(mode); Lt *lt = create_lt(); LineStream *line_stream = PUSH_LT( lt, nth_calloc(1, sizeof(LineStream)), free); if (line_stream == NULL) { RETURN_LT(lt, NULL); } line_stream->lt = lt; line_stream->stream = PUSH_LT( lt, fopen(filename, mode), fclose_lt); if (line_stream->stream == NULL) { log_fail("Could not open file '%s': %s\n", filename, strerror(errno)); RETURN_LT(lt, NULL); } line_stream->buffer = PUSH_LT( lt, nth_calloc(1, sizeof(char) * capacity), free); if (line_stream->buffer == NULL) { RETURN_LT(lt, NULL); } line_stream->capacity = capacity; line_stream->unfinished = false; return line_stream; } void destroy_line_stream(LineStream *line_stream) { trace_assert(line_stream); RETURN_LT0(line_stream->lt); } const char *line_stream_next_chunk(LineStream *line_stream) { trace_assert(line_stream); const char *s = fgets(line_stream->buffer, (int) line_stream->capacity, line_stream->stream); if (s == NULL) { return NULL; } size_t n = strlen(s); line_stream->unfinished = s[n - 1] != '\n'; return s; } const char *line_stream_next(LineStream *line_stream) { trace_assert(line_stream); while (line_stream->unfinished) { line_stream_next_chunk(line_stream); } return line_stream_next_chunk(line_stream); } char *line_stream_collect_n_lines(LineStream *line_stream, size_t n) { char *result = string_append(NULL, ""); for (size_t i = 0; i < n; ++i) { const char *line = line_stream_next(line_stream); if (line == NULL) { free(result); return NULL; } result = string_append(result,line); } return result; } char *line_stream_collect_until_end(LineStream *line_stream) { char *result = string_append(NULL, ""); const char *line = line_stream_next(line_stream); /* TODO(#906): line_stream_collect_until_end does not distinguish between EOF and error during reading */ while (line != NULL) { result = string_append(result, line); line = line_stream_next(line_stream); } return result; }