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