// SPDX-FileCopyrightText: 2017 Google Inc. // SPDX-License-Identifier: Apache-2.0 #include "internal/stack_line_reader.h" #include "internal/filesystem.h" #include #include #include void StackLineReader_Initialize(StackLineReader* reader, int fd) { reader->view.ptr = reader->buffer; reader->view.size = 0; reader->skip_mode = false; reader->fd = fd; } // Replaces the content of buffer with bytes from the file. static int LoadFullBuffer(StackLineReader* reader) { const int read = CpuFeatures_ReadFile(reader->fd, reader->buffer, STACK_LINE_READER_BUFFER_SIZE); assert(read >= 0); reader->view.ptr = reader->buffer; reader->view.size = read; return read; } // Appends with bytes from the file to buffer, filling the remaining space. static int LoadMore(StackLineReader* reader) { char* const ptr = reader->buffer + reader->view.size; const size_t size_to_read = STACK_LINE_READER_BUFFER_SIZE - reader->view.size; const int read = CpuFeatures_ReadFile(reader->fd, ptr, size_to_read); assert(read >= 0); assert(read <= (int)size_to_read); reader->view.size += read; return read; } static int IndexOfEol(StackLineReader* reader) { return CpuFeatures_StringView_IndexOfChar(reader->view, '\n'); } // Relocate buffer's pending bytes at the beginning of the array and fills the // remaining space with bytes from the file. static int BringToFrontAndLoadMore(StackLineReader* reader) { if (reader->view.size && reader->view.ptr != reader->buffer) { memmove(reader->buffer, reader->view.ptr, reader->view.size); } reader->view.ptr = reader->buffer; return LoadMore(reader); } // Loads chunks of buffer size from disks until it contains a newline character // or end of file. static void SkipToNextLine(StackLineReader* reader) { for (;;) { const int read = LoadFullBuffer(reader); if (read == 0) { break; } else { const int eol_index = IndexOfEol(reader); if (eol_index >= 0) { reader->view = CpuFeatures_StringView_PopFront(reader->view, eol_index + 1); break; } } } } static LineResult CreateLineResult(bool eof, bool full_line, StringView view) { LineResult result; result.eof = eof; result.full_line = full_line; result.line = view; return result; } // Helper methods to provide clearer semantic in StackLineReader_NextLine. static LineResult CreateEOFLineResult(StringView view) { return CreateLineResult(true, true, view); } static LineResult CreateTruncatedLineResult(StringView view) { return CreateLineResult(false, false, view); } static LineResult CreateValidLineResult(StringView view) { return CreateLineResult(false, true, view); } LineResult StackLineReader_NextLine(StackLineReader* reader) { if (reader->skip_mode) { SkipToNextLine(reader); reader->skip_mode = false; } { const bool can_load_more = reader->view.size < STACK_LINE_READER_BUFFER_SIZE; int eol_index = IndexOfEol(reader); if (eol_index < 0 && can_load_more) { const int read = BringToFrontAndLoadMore(reader); if (read == 0) { return CreateEOFLineResult(reader->view); } eol_index = IndexOfEol(reader); } if (eol_index < 0) { reader->skip_mode = true; return CreateTruncatedLineResult(reader->view); } { StringView line = CpuFeatures_StringView_KeepFront(reader->view, eol_index); reader->view = CpuFeatures_StringView_PopFront(reader->view, eol_index + 1); return CreateValidLineResult(line); } } }