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