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