1 /******************************************************************************* 2 3 copyright: Copyright (c) 2004 Kris Bell. All rights reserved 4 5 license: BSD style: $(LICENSE) 6 7 version: Initial release: January 2006 8 9 author: Kris 10 11 *******************************************************************************/ 12 13 module tango.io.stream.Lines; 14 15 private import tango.io.stream.Iterator; 16 17 /******************************************************************************* 18 19 Iterate across a set of text patterns. 20 21 Each pattern is exposed to the client as a slice of the original 22 content, where the slice is transient. If you need to retain the 23 exposed content, then you should .dup it appropriately. 24 25 The content exposed via an iterator is supposed to be entirely 26 read-only. All current iterators abide by this rule, but it is 27 possible a user could mutate the content through a get() slice. 28 To enforce the desired read-only aspect, the code would have to 29 introduce redundant copying or the compiler would have to support 30 read-only arrays. 31 32 See Delimiters, Patterns, Quotes. 33 34 *******************************************************************************/ 35 36 class Lines(T) : Iterator!(T) 37 { 38 /*********************************************************************** 39 40 Construct an uninitialized iterator. For example: 41 --- 42 auto lines = new Lines!(char); 43 44 void somefunc (InputStream stream) 45 { 46 foreach (line; lines.set(stream)) 47 Cout (line).newline; 48 } 49 --- 50 51 Construct a streaming iterator upon a stream: 52 --- 53 void somefunc (InputStream stream) 54 { 55 foreach (line; new Lines!(char) (stream)) 56 Cout (line).newline; 57 } 58 --- 59 60 Construct a streaming iterator upon a conduit: 61 --- 62 foreach (line; new Lines!(char) (new File ("myfile"))) 63 Cout (line).newline; 64 --- 65 66 ***********************************************************************/ 67 68 this (InputStream stream = null) 69 { 70 super (stream); 71 } 72 73 /*********************************************************************** 74 75 Read a line of text, and return false when there's no 76 further content available. 77 78 ***********************************************************************/ 79 80 final bool readln (ref const(T)[] content) 81 { 82 content = super.next; 83 return content.ptr !is null; 84 } 85 86 /*********************************************************************** 87 88 Scanner implementation for this iterator. Find a '\n', 89 and eat any immediately preceeding '\r'. 90 91 ***********************************************************************/ 92 93 protected override size_t scan (const(void)[] data) 94 { 95 auto content = (cast(const(T)*) data.ptr) [0 .. data.length / T.sizeof]; 96 97 foreach (int i, T c; content) 98 if (c is '\n') 99 { 100 int slice = i; 101 if (i && content[i-1] is '\r') 102 --slice; 103 set (content.ptr, 0, slice, i); 104 return found (i); 105 } 106 107 return notFound(); 108 } 109 } 110 111 112 113 /******************************************************************************* 114 115 *******************************************************************************/ 116 117 debug(UnitTest) 118 { 119 private import tango.io.device.Array; 120 121 unittest 122 { 123 auto p = new Lines!(char) (new Array("blah".dup)); 124 } 125 } 126 127 128 /******************************************************************************* 129 130 *******************************************************************************/ 131 132 debug (Lines) 133 { 134 import tango.io.Console; 135 import tango.io.device.Array; 136 137 void main() 138 { 139 auto lines = new Lines!(char)(new Array("one\ntwo\r\nthree".dup)); 140 foreach (i, line, delim; lines) 141 Cout (line) (delim); 142 } 143 }