blob: b2c48ba6df30510ae39d505ab7c570fe6ff646af [file] [log] [blame]
Guillaume Chatelet439d3712018-02-01 10:03:09 +01001// Copyright 2017 Google Inc.
2//
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"
16#include "internal/filesystem.h"
17
18#include <assert.h>
19#include <errno.h>
20#include <stdio.h>
21
22void StackLineReader_Initialize(StackLineReader* reader, int fd) {
23 reader->view.ptr = reader->buffer;
24 reader->view.size = 0;
25 reader->skip_mode = false;
26 reader->fd = fd;
27}
28
29// Replaces the content of buffer with bytes from the file.
30static int LoadFullBuffer(StackLineReader* reader) {
Arvid Gerstmannd9689912018-05-04 09:32:17 +020031 const int read = CpuFeatures_ReadFile(reader->fd, reader->buffer,
32 STACK_LINE_READER_BUFFER_SIZE);
Guillaume Chatelet439d3712018-02-01 10:03:09 +010033 assert(read >= 0);
34 reader->view.ptr = reader->buffer;
35 reader->view.size = read;
36 return read;
37}
38
39// Appends with bytes from the file to buffer, filling the remaining space.
40static int LoadMore(StackLineReader* reader) {
41 char* const ptr = reader->buffer + reader->view.size;
42 const size_t size_to_read = STACK_LINE_READER_BUFFER_SIZE - reader->view.size;
Arvid Gerstmanna1ffdcb2018-04-26 10:31:03 +020043 const int read = CpuFeatures_ReadFile(reader->fd, ptr, size_to_read);
Guillaume Chatelet439d3712018-02-01 10:03:09 +010044 assert(read >= 0);
45 assert(read <= (int)size_to_read);
46 reader->view.size += read;
47 return read;
48}
49
50static int IndexOfEol(StackLineReader* reader) {
Arvid Gerstmanna1ffdcb2018-04-26 10:31:03 +020051 return CpuFeatures_StringView_IndexOfChar(reader->view, '\n');
Guillaume Chatelet439d3712018-02-01 10:03:09 +010052}
53
54// Relocate buffer's pending bytes at the beginning of the array and fills the
55// remaining space with bytes from the file.
56static int BringToFrontAndLoadMore(StackLineReader* reader) {
57 if (reader->view.size && reader->view.ptr != reader->buffer) {
58 memmove(reader->buffer, reader->view.ptr, reader->view.size);
59 }
60 reader->view.ptr = reader->buffer;
61 return LoadMore(reader);
62}
63
64// Loads chunks of buffer size from disks until it contains a newline character
65// or end of file.
66static void SkipToNextLine(StackLineReader* reader) {
67 for (;;) {
68 const int read = LoadFullBuffer(reader);
69 if (read == 0) {
70 break;
71 } else {
72 const int eol_index = IndexOfEol(reader);
73 if (eol_index >= 0) {
Arvid Gerstmannd9689912018-05-04 09:32:17 +020074 reader->view =
75 CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
Guillaume Chatelet439d3712018-02-01 10:03:09 +010076 break;
77 }
78 }
79 }
80}
81
82static LineResult CreateLineResult(bool eof, bool full_line, StringView view) {
83 LineResult result;
84 result.eof = eof;
85 result.full_line = full_line;
86 result.line = view;
87 return result;
88}
89
90// Helper methods to provide clearer semantic in StackLineReader_NextLine.
91static LineResult CreateEOFLineResult(StringView view) {
92 return CreateLineResult(true, true, view);
93}
94
95static LineResult CreateTruncatedLineResult(StringView view) {
96 return CreateLineResult(false, false, view);
97}
98
99static LineResult CreateValidLineResult(StringView view) {
100 return CreateLineResult(false, true, view);
101}
102
103LineResult StackLineReader_NextLine(StackLineReader* reader) {
104 if (reader->skip_mode) {
105 SkipToNextLine(reader);
106 reader->skip_mode = false;
107 }
108 {
109 const bool can_load_more =
110 reader->view.size < STACK_LINE_READER_BUFFER_SIZE;
111 int eol_index = IndexOfEol(reader);
112 if (eol_index < 0 && can_load_more) {
113 const int read = BringToFrontAndLoadMore(reader);
114 if (read == 0) {
115 return CreateEOFLineResult(reader->view);
116 }
117 eol_index = IndexOfEol(reader);
118 }
119 if (eol_index < 0) {
120 reader->skip_mode = true;
121 return CreateTruncatedLineResult(reader->view);
122 }
123 {
Arvid Gerstmannd9689912018-05-04 09:32:17 +0200124 StringView line =
125 CpuFeatures_StringView_KeepFront(reader->view, eol_index);
126 reader->view =
127 CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
Guillaume Chatelet439d3712018-02-01 10:03:09 +0100128 return CreateValidLineResult(line);
129 }
130 }
131}