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.Patterns;
14 
15 private import tango.text.Regex;
16 
17 private import tango.io.model.IConduit;
18 private import tango.io.stream.Iterator;
19 
20 /*******************************************************************************
21 
22         Iterate across a set of text patterns.
23 
24         Each pattern is exposed to the client as a slice of the original
25         content, where the slice is transient. If you need to retain the
26         exposed content, then you should .dup it appropriately.
27 
28         The content exposed via an iterator is supposed to be entirely
29         read-only. All current iterators abide by this rule, but it is
30         possible a user could mutate the content through a get() slice.
31         To enforce the desired read-only aspect, the code would have to
32         introduce redundant copying or the compiler would have to support
33         read-only arrays.
34 
35         See Delimiters, Lines, Quotes.
36 
37 *******************************************************************************/
38 
39 class Patterns : Iterator!(char)
40 {
41         private Regex regex;
42         private alias char T;
43 
44         /***********************************************************************
45 
46                 Construct an uninitialized iterator. For example:
47                 ---
48                 auto lines = new Lines!(char);
49 
50                 void somefunc (InputStream stream)
51                 {
52                         foreach (line; lines.set(stream))
53                                  Cout (line).newline;
54                 }
55                 ---
56 
57                 Construct a streaming iterator upon a stream:
58                 ---
59                 void somefunc (InputStream stream)
60                 {
61                         foreach (line; new Lines!(char) (stream))
62                                  Cout (line).newline;
63                 }
64                 ---
65 
66                 Construct a streaming iterator upon a conduit:
67                 ---
68                 foreach (line; new Lines!(char) (new File ("myfile")))
69                          Cout (line).newline;
70                 ---
71 
72         ***********************************************************************/
73 
74         this (const(T)[] pattern, InputStream stream = null)
75         {
76                 regex = new Regex (pattern, "");
77                 super (stream);
78         }
79 
80         /***********************************************************************
81 
82         ***********************************************************************/
83 
84         protected override size_t scan (const(void)[] data)
85         {
86                 auto content = (cast(const(T)*) data.ptr) [0 .. data.length / T.sizeof];
87 
88                 if (regex.test (content))
89                    {
90                    int start = regex.registers_[0];
91                    int finish = regex.registers_[1];
92                    set (content.ptr, 0, start);
93                    return found (finish-1);
94                    }
95 
96                 return notFound();
97         }
98 }
99 
100 
101 /*******************************************************************************
102 
103 *******************************************************************************/
104 
105 debug(UnitTest)
106 {
107         private import tango.io.device.Array;
108 
109         unittest
110         {
111                 auto p = new Patterns ("b.*", new Array("blah".dup));
112         }
113 }