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