blob: ffc778d31597913cb254248d6ee34c4f395a037d [file] [log] [blame]
Guillaume Chatelet3cc8f312020-10-12 08:55:20 +00001// Copyright 2017 Google LLC
Guillaume Chatelet439d3712018-02-01 10:03:09 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "internal/stack_line_reader.h"
Guillaume Chatelet439d3712018-02-01 10:03:09 +010016
17#include <assert.h>
18#include <errno.h>
19#include <stdio.h>
20
Guillaume Chatelet22a53622020-09-23 11:52:20 +020021#include "internal/filesystem.h"
22
Guillaume Chatelet439d3712018-02-01 10:03:09 +010023void StackLineReader_Initialize(StackLineReader* reader, int fd) {
24 reader->view.ptr = reader->buffer;
25 reader->view.size = 0;
26 reader->skip_mode = false;
27 reader->fd = fd;
28}
29
30// Replaces the content of buffer with bytes from the file.
31static int LoadFullBuffer(StackLineReader* reader) {
Arvid Gerstmannd9689912018-05-04 09:32:17 +020032 const int read = CpuFeatures_ReadFile(reader->fd, reader->buffer,
33 STACK_LINE_READER_BUFFER_SIZE);
Guillaume Chatelet439d3712018-02-01 10:03:09 +010034 assert(read >= 0);
35 reader->view.ptr = reader->buffer;
36 reader->view.size = read;
37 return read;
38}
39
40// Appends with bytes from the file to buffer, filling the remaining space.
41static int LoadMore(StackLineReader* reader) {
42 char* const ptr = reader->buffer + reader->view.size;
43 const size_t size_to_read = STACK_LINE_READER_BUFFER_SIZE - reader->view.size;
Arvid Gerstmanna1ffdcb2018-04-26 10:31:03 +020044 const int read = CpuFeatures_ReadFile(reader->fd, ptr, size_to_read);
Guillaume Chatelet439d3712018-02-01 10:03:09 +010045 assert(read >= 0);
46 assert(read <= (int)size_to_read);
47 reader->view.size += read;
48 return read;
49}
50
51static int IndexOfEol(StackLineReader* reader) {
Arvid Gerstmanna1ffdcb2018-04-26 10:31:03 +020052 return CpuFeatures_StringView_IndexOfChar(reader->view, '\n');
Guillaume Chatelet439d3712018-02-01 10:03:09 +010053}
54
55// Relocate buffer's pending bytes at the beginning of the array and fills the
56// remaining space with bytes from the file.
57static int BringToFrontAndLoadMore(StackLineReader* reader) {
58 if (reader->view.size && reader->view.ptr != reader->buffer) {
59 memmove(reader->buffer, reader->view.ptr, reader->view.size);
60 }
61 reader->view.ptr = reader->buffer;
62 return LoadMore(reader);
63}
64
65// Loads chunks of buffer size from disks until it contains a newline character
66// or end of file.
67static void SkipToNextLine(StackLineReader* reader) {
68 for (;;) {
69 const int read = LoadFullBuffer(reader);
70 if (read == 0) {
71 break;
72 } else {
73 const int eol_index = IndexOfEol(reader);
74 if (eol_index >= 0) {
Arvid Gerstmannd9689912018-05-04 09:32:17 +020075 reader->view =
76 CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
Guillaume Chatelet439d3712018-02-01 10:03:09 +010077 break;
78 }
79 }
80 }
81}
82
83static LineResult CreateLineResult(bool eof, bool full_line, StringView view) {
84 LineResult result;
85 result.eof = eof;
86 result.full_line = full_line;
87 result.line = view;
88 return result;
89}
90
91// Helper methods to provide clearer semantic in StackLineReader_NextLine.
92static LineResult CreateEOFLineResult(StringView view) {
93 return CreateLineResult(true, true, view);
94}
95
96static LineResult CreateTruncatedLineResult(StringView view) {
97 return CreateLineResult(false, false, view);
98}
99
100static LineResult CreateValidLineResult(StringView view) {
101 return CreateLineResult(false, true, view);
102}
103
104LineResult StackLineReader_NextLine(StackLineReader* reader) {
105 if (reader->skip_mode) {
106 SkipToNextLine(reader);
107 reader->skip_mode = false;
108 }
109 {
110 const bool can_load_more =
111 reader->view.size < STACK_LINE_READER_BUFFER_SIZE;
112 int eol_index = IndexOfEol(reader);
113 if (eol_index < 0 && can_load_more) {
114 const int read = BringToFrontAndLoadMore(reader);
115 if (read == 0) {
116 return CreateEOFLineResult(reader->view);
117 }
118 eol_index = IndexOfEol(reader);
119 }
120 if (eol_index < 0) {
121 reader->skip_mode = true;
122 return CreateTruncatedLineResult(reader->view);
123 }
124 {
Arvid Gerstmannd9689912018-05-04 09:32:17 +0200125 StringView line =
126 CpuFeatures_StringView_KeepFront(reader->view, eol_index);
127 reader->view =
128 CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
Guillaume Chatelet439d3712018-02-01 10:03:09 +0100129 return CreateValidLineResult(line);
130 }
131 }
132}