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 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. 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 132 const char* LineReader::line() const { return buff_ + line_start_; } 133 134 size_t LineReader::length() const { return line_len_; } 135 136 } // namespace crazy 137