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 : line_iterator(Buffer.getMemBufferRef(), SkipBlanks, CommentMarker) {} 37 38 line_iterator::line_iterator(const MemoryBufferRef &Buffer, bool SkipBlanks, 39 char CommentMarker) 40 : Buffer(Buffer.getBufferSize() ? std::optional<MemoryBufferRef>(Buffer) 41 : std::nullopt), 42 CommentMarker(CommentMarker), SkipBlanks(SkipBlanks), 43 CurrentLine(Buffer.getBufferSize() ? Buffer.getBufferStart() : nullptr, 44 0) { 45 // Ensure that if we are constructed on a non-empty memory buffer that it is 46 // a null terminated buffer. 47 if (Buffer.getBufferSize()) { 48 assert(Buffer.getBufferEnd()[0] == '\0'); 49 // Make sure we don't skip a leading newline if we're keeping blanks 50 if (SkipBlanks || !isAtLineEnd(Buffer.getBufferStart())) 51 advance(); 52 } 53 } 54 55 void line_iterator::advance() { 56 assert(Buffer && "Cannot advance past the end!"); 57 58 const char *Pos = CurrentLine.end(); 59 assert(Pos == Buffer->getBufferStart() || isAtLineEnd(Pos) || *Pos == '\0'); 60 61 if (skipIfAtLineEnd(Pos)) 62 ++LineNumber; 63 if (!SkipBlanks && isAtLineEnd(Pos)) { 64 // Nothing to do for a blank line. 65 } else if (CommentMarker == '\0') { 66 // If we're not stripping comments, this is simpler. 67 while (skipIfAtLineEnd(Pos)) 68 ++LineNumber; 69 } else { 70 // Skip comments and count line numbers, which is a bit more complex. 71 for (;;) { 72 if (isAtLineEnd(Pos) && !SkipBlanks) 73 break; 74 if (*Pos == CommentMarker) 75 do { 76 ++Pos; 77 } while (*Pos != '\0' && !isAtLineEnd(Pos)); 78 if (!skipIfAtLineEnd(Pos)) 79 break; 80 ++LineNumber; 81 } 82 } 83 84 if (*Pos == '\0') { 85 // We've hit the end of the buffer, reset ourselves to the end state. 86 Buffer = std::nullopt; 87 CurrentLine = StringRef(); 88 return; 89 } 90 91 // Measure the line. 92 size_t Length = 0; 93 while (Pos[Length] != '\0' && !isAtLineEnd(&Pos[Length])) { 94 ++Length; 95 } 96 97 CurrentLine = StringRef(Pos, Length); 98 } 99