Home | History | Annotate | Download | only in src
      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