Home | History | Annotate | Download | only in Support
      1 //===- LineIterator.cpp - Implementation of line iteration ----------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "llvm/Support/LineIterator.h"
     11 #include "llvm/Support/MemoryBuffer.h"
     12 
     13 using namespace llvm;
     14 
     15 static bool isAtLineEnd(const char *P) {
     16   if (*P == '\n')
     17     return true;
     18   if (*P == '\r' && *(P + 1) == '\n')
     19     return true;
     20   return false;
     21 }
     22 
     23 static bool skipIfAtLineEnd(const char *&P) {
     24   if (*P == '\n') {
     25     ++P;
     26     return true;
     27   }
     28   if (*P == '\r' && *(P + 1) == '\n') {
     29     P += 2;
     30     return true;
     31   }
     32   return false;
     33 }
     34 
     35 line_iterator::line_iterator(const MemoryBuffer &Buffer, bool SkipBlanks,
     36                              char CommentMarker)
     37     : Buffer(Buffer.getBufferSize() ? &Buffer : nullptr),
     38       CommentMarker(CommentMarker), SkipBlanks(SkipBlanks), LineNumber(1),
     39       CurrentLine(Buffer.getBufferSize() ? Buffer.getBufferStart() : nullptr,
     40                   0) {
     41   // Ensure that if we are constructed on a non-empty memory buffer that it is
     42   // a null terminated buffer.
     43   if (Buffer.getBufferSize()) {
     44     assert(Buffer.getBufferEnd()[0] == '\0');
     45     // Make sure we don't skip a leading newline if we're keeping blanks
     46     if (SkipBlanks || !isAtLineEnd(Buffer.getBufferStart()))
     47       advance();
     48   }
     49 }
     50 
     51 void line_iterator::advance() {
     52   assert(Buffer && "Cannot advance past the end!");
     53 
     54   const char *Pos = CurrentLine.end();
     55   assert(Pos == Buffer->getBufferStart() || isAtLineEnd(Pos) || *Pos == '\0');
     56 
     57   if (skipIfAtLineEnd(Pos))
     58     ++LineNumber;
     59   if (!SkipBlanks && isAtLineEnd(Pos)) {
     60     // Nothing to do for a blank line.
     61   } else if (CommentMarker == '\0') {
     62     // If we're not stripping comments, this is simpler.
     63     while (skipIfAtLineEnd(Pos))
     64       ++LineNumber;
     65   } else {
     66     // Skip comments and count line numbers, which is a bit more complex.
     67     for (;;) {
     68       if (isAtLineEnd(Pos) && !SkipBlanks)
     69         break;
     70       if (*Pos == CommentMarker)
     71         do {
     72           ++Pos;
     73         } while (*Pos != '\0' && !isAtLineEnd(Pos));
     74       if (!skipIfAtLineEnd(Pos))
     75         break;
     76       ++LineNumber;
     77     }
     78   }
     79 
     80   if (*Pos == '\0') {
     81     // We've hit the end of the buffer, reset ourselves to the end state.
     82     Buffer = nullptr;
     83     CurrentLine = StringRef();
     84     return;
     85   }
     86 
     87   // Measure the line.
     88   size_t Length = 0;
     89   while (Pos[Length] != '\0' && !isAtLineEnd(&Pos[Length])) {
     90     ++Length;
     91   }
     92 
     93   CurrentLine = StringRef(Pos, Length);
     94 }
     95