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