1 // Copyright 2014 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 16 LineReader::LineReader() : fd_(), buff_(buff0_) { 17 Reset(); 18 eof_ = true; 19 } 20 21 LineReader::LineReader(const char* path) : fd_(), buff_(buff0_) { Open(path); } 22 23 LineReader::~LineReader() { Reset(); } 24 25 void LineReader::Open(const char* path) { 26 Reset(); 27 eof_ = !fd_.OpenReadOnly(path); 28 } 29 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 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. The result 55 // of memchr(_,_,0) is undefined, treated as not-found. 56 const char* line = buff_ + line_start_; 57 const size_t range = buff_size_ - line_start_; 58 const char* line_end; 59 if (range > 0) 60 line_end = reinterpret_cast<const char*>(::memchr(line, '\n', range)); 61 else 62 line_end = NULL; 63 if (line_end != NULL) { 64 // Found one, return it directly. 65 line_len_ = static_cast<size_t>(line_end + 1 - line); 66 LLOG("%s: LINE line_start=%d line_len=%d '%.*s'\n", 67 __FUNCTION__, 68 line_start_, 69 line_len_, 70 line_len_, 71 buff_ + line_start_); 72 return true; 73 } 74 75 // Eat the start of the buffer 76 if (line_start_ > 0) { 77 ::memmove(buff_, buff_ + line_start_, buff_size_ - line_start_); 78 buff_size_ -= line_start_; 79 line_start_ = 0; 80 LLOG("%s: MOVE buff_size=%d\n", __FUNCTION__, buff_size_); 81 } 82 83 // Handle end of input now. 84 if (eof_) { 85 // If there is a last line that isn't terminated by a newline, and 86 // there is room for it in the buffer. Manually add a \n and return 87 // the line. 88 if (buff_size_ > 0 && buff_size_ < buff_capacity_) { 89 buff_[buff_size_++] = '\n'; 90 line_len_ = buff_size_; 91 LLOG("%s: EOF_LINE buff_size=%d '%.*s'\n", 92 __FUNCTION__, 93 buff_size_, 94 buff_size_, 95 buff_); 96 return true; 97 } 98 // Otherwise, ignore the last line. 99 LLOG("%s: EOF\n", __FUNCTION__); 100 return false; 101 } 102 103 // Before reading more data, grow the buffer if needed. 104 if (buff_size_ == buff_capacity_) { 105 size_t new_capacity = buff_capacity_ * 2; 106 void* old_buff = (buff_ == buff0_) ? NULL : buff_; 107 buff_ = static_cast<char*>(::realloc(old_buff, new_capacity)); 108 if (old_buff != buff_) 109 ::memcpy(buff_, buff0_, buff_capacity_); 110 111 buff_capacity_ = new_capacity; 112 LLOG("%s: GROW buff_size=%d buff_capacity=%d '%.*s'\n", 113 __FUNCTION__, 114 buff_size_, 115 buff_capacity_, 116 buff_size_, 117 buff_); 118 } 119 120 // Try to fill the rest of buffer after current content. 121 size_t avail = buff_capacity_ - buff_size_; 122 int ret = fd_.Read(buff_ + buff_size_, avail); 123 LLOG("%s: READ buff_size=%d buff_capacity=%d avail=%d ret=%d\n", 124 __FUNCTION__, 125 buff_size_, 126 buff_capacity_, 127 avail, 128 ret); 129 if (ret <= 0) { 130 eof_ = true; 131 ret = 0; 132 } 133 buff_size_ += static_cast<size_t>(ret); 134 } 135 } 136 137 const char* LineReader::line() const { return buff_ + line_start_; } 138 139 size_t LineReader::length() const { return line_len_; } 140 141 } // namespace crazy 142