1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "crazy_linker_line_reader.h"
6 
7 #include "crazy_linker_debug.h"
8 
9 // Set to 1 to enable debug logs here.
10 #define DEBUG_LINE_READER 0
11 
12 #define LLOG(...) LOG_IF(DEBUG_LINE_READER, __VA_ARGS__)
13 
14 namespace crazy {
15 
LineReader()16 LineReader::LineReader() : fd_(), buff_(buff0_) {
17   Reset();
18   eof_ = true;
19 }
20 
LineReader(const char * path)21 LineReader::LineReader(const char* path) : fd_(), buff_(buff0_) { Open(path); }
22 
~LineReader()23 LineReader::~LineReader() { Reset(); }
24 
Open(const char * path)25 void LineReader::Open(const char* path) {
26   Reset();
27   eof_ = !fd_.OpenReadOnly(path);
28 }
29 
Reset()30 void LineReader::Reset() {
31   if (buff_ != buff0_)
32     ::free(buff_);
33 
34   eof_ = false;
35   line_start_ = 0;
36   line_len_ = 0;
37   buff_size_ = 0;
38   buff_capacity_ = sizeof buff0_;
39   buff_ = buff0_;
40 }
41 
GetNextLine()42 bool LineReader::GetNextLine() {
43   // Eat previous line.
44   line_start_ += line_len_;
45   line_len_ = 0;
46 
47   for (;;) {
48     LLOG("%s: LOOP line_start=%d buff_size=%d buff_capacity=%d\n",
49          __FUNCTION__,
50          line_start_,
51          buff_size_,
52          buff_capacity_);
53 
54     // Find the end of the current line in the current buffer.
55     const char* line = buff_ + line_start_;
56     const char* line_end = reinterpret_cast<const char*>(
57         ::memchr(line, '\n', buff_size_ - line_start_));
58     if (line_end != NULL) {
59       // Found one, return it directly.
60       line_len_ = static_cast<size_t>(line_end + 1 - line);
61       LLOG("%s: LINE line_start=%d line_len=%d '%.*s'\n",
62            __FUNCTION__,
63            line_start_,
64            line_len_,
65            line_len_,
66            buff_ + line_start_);
67       return true;
68     }
69 
70     // Eat the start of the buffer
71     if (line_start_ > 0) {
72       ::memmove(buff_, buff_ + line_start_, buff_size_ - line_start_);
73       buff_size_ -= line_start_;
74       line_start_ = 0;
75       LLOG("%s: MOVE buff_size=%d\n", __FUNCTION__, buff_size_);
76     }
77 
78     // Handle end of input now.
79     if (eof_) {
80       // If there is a last line that isn't terminated by a newline, and
81       // there is room for it in the buffer. Manually add a \n and return
82       // the line.
83       if (buff_size_ > 0 && buff_size_ < buff_capacity_) {
84         buff_[buff_size_++] = '\n';
85         line_len_ = buff_size_;
86         LLOG("%s: EOF_LINE buff_size=%d '%.*s'\n",
87              __FUNCTION__,
88              buff_size_,
89              buff_size_,
90              buff_);
91         return true;
92       }
93       // Otherwise, ignore the last line.
94       LLOG("%s: EOF\n", __FUNCTION__);
95       return false;
96     }
97 
98     // Before reading more data, grow the buffer if needed.
99     if (buff_size_ == buff_capacity_) {
100       size_t new_capacity = buff_capacity_ * 2;
101       void* old_buff = (buff_ == buff0_) ? NULL : buff_;
102       buff_ = static_cast<char*>(::realloc(old_buff, new_capacity));
103       if (old_buff != buff_)
104         ::memcpy(buff_, buff0_, buff_capacity_);
105 
106       buff_capacity_ = new_capacity;
107       LLOG("%s: GROW buff_size=%d buff_capacity=%d '%.*s'\n",
108            __FUNCTION__,
109            buff_size_,
110            buff_capacity_,
111            buff_size_,
112            buff_);
113     }
114 
115     // Try to fill the rest of buffer after current content.
116     size_t avail = buff_capacity_ - buff_size_;
117     int ret = fd_.Read(buff_ + buff_size_, avail);
118     LLOG("%s: READ buff_size=%d buff_capacity=%d avail=%d ret=%d\n",
119          __FUNCTION__,
120          buff_size_,
121          buff_capacity_,
122          avail,
123          ret);
124     if (ret <= 0) {
125       eof_ = true;
126       ret = 0;
127     }
128     buff_size_ += static_cast<size_t>(ret);
129   }
130 }
131 
line() const132 const char* LineReader::line() const { return buff_ + line_start_; }
133 
length() const134 size_t LineReader::length() const { return line_len_; }
135 
136 }  // namespace crazy
137