1 /*******************************************************************************
2 
3         copyright:      Copyright (c) 2007 Kris Bell. All rights reserved
4 
5         license:        BSD style: $(LICENSE)
6 
7         version:        Initial release: Oct 2007
8 
9         author:         Kris
10 
11 *******************************************************************************/
12 
13 module tango.io.stream.Snoop;
14 
15 private import  tango.io.Console,
16                 tango.io.device.Conduit;
17 
18 private import  tango.text.convert.Format;
19 
20 version(DigitalMars)
21 {
22     private import tango.core.Vararg;
23 }else version (GNU)
24     private import tango.core.Vararg;
25 
26 private alias void delegate(const(char)[]) Snoop;
27 
28 /*******************************************************************************
29 
30         Stream to expose call behaviour. By default, activity trace is
31         sent to Cerr.
32 
33 *******************************************************************************/
34 
35 class SnoopInput : InputStream
36 {
37         private InputStream     host;
38         private Snoop           snoop;
39 
40         /***********************************************************************
41 
42                 Attach to the provided stream.
43 
44         ***********************************************************************/
45 
46         this (InputStream host, Snoop snoop = null)
47         {
48                 assert (host);
49                 this.host = host;
50                 this.snoop = snoop ? snoop : &snooper;
51         }
52 
53         /***********************************************************************
54 
55                 Return the upstream host of this filter.
56 
57         ***********************************************************************/
58 
59         InputStream input ()
60         {
61                 return host;
62         }
63 
64         /***********************************************************************
65 
66                 Return the hosting conduit.
67 
68         ***********************************************************************/
69 
70         final IConduit conduit ()
71         {
72                 return host.conduit;
73         }
74 
75         /***********************************************************************
76 
77                 Read from conduit into a target array. The provided dst
78                 will be populated with content from the conduit.
79 
80                 Returns the number of bytes read, which may be less than
81                 requested in dst.
82 
83         ***********************************************************************/
84 
85         final size_t read (void[] dst)
86         {
87                 auto x = host.read (dst);
88                 trace ("{}: read {} bytes", host.conduit, x is -1 ? 0 : x);
89                 return x;
90         }
91 
92         /***********************************************************************
93 
94                 Load the bits from a stream, and return them all in an
95                 array. The dst array can be provided as an option, which
96                 will be expanded as necessary to consume the input.
97 
98                 Returns an array representing the content, and throws
99                 IOException on error.
100 
101         ***********************************************************************/
102 
103         void[] load (size_t max=-1)
104         {
105                 auto x = host.load (max);
106                 trace ("{}: loaded {} bytes", x.length);
107                 return x;
108         }
109 
110         /***********************************************************************
111 
112                 Clear any buffered content.
113 
114         ***********************************************************************/
115 
116         final InputStream flush ()
117         {
118                 host.flush();
119                 trace ("{}: flushed/cleared", host.conduit);
120                 return this;
121         }
122 
123         /***********************************************************************
124 
125                 Close the input.
126 
127         ***********************************************************************/
128 
129         final void close ()
130         {
131                 host.close();
132                 trace ("{}: closed", host.conduit);
133         }
134 
135         /***********************************************************************
136 
137                 Seek on this stream. Target conduits that don't support
138                 seeking will throw an IOException.
139 
140         ***********************************************************************/
141 
142         final long seek (long offset, Anchor anchor = Anchor.Begin)
143         {
144                 auto s = host.seek (offset, anchor);
145                 trace ("{}: seek at offset {} from anchor {}", host.conduit, offset, anchor);
146                 return s;
147         }
148 
149         /***********************************************************************
150 
151                 Internal trace handler.
152 
153         ***********************************************************************/
154 
155         private void snooper (const(char)[] x)
156         {
157                 Cerr(x).newline;
158         }
159 
160         /***********************************************************************
161 
162                 Internal trace handler.
163 
164         ***********************************************************************/
165 
166         private void trace (const(char)[] format, ...)
167         {
168                 char[256] tmp = void;
169                 snoop (Format.vprint (tmp, format, _arguments, _argptr));
170         }
171 }
172 
173 
174 /*******************************************************************************
175 
176         Stream to expose call behaviour. By default, activity trace is
177         sent to Cerr.
178 
179 *******************************************************************************/
180 
181 class SnoopOutput : OutputStream
182 {
183         private OutputStream    host;
184         private Snoop           snoop;
185 
186         /***********************************************************************
187 
188                 Attach to the provided stream.
189 
190         ***********************************************************************/
191 
192         this (OutputStream host, Snoop snoop = null)
193         {
194                 assert (host);
195                 this.host = host;
196                 this.snoop = snoop ? snoop : &snooper;
197         }
198 
199         /***********************************************************************
200 
201                 Return the upstream host of this filter.
202 
203         ***********************************************************************/
204 
205         OutputStream output ()
206         {
207                 return host;
208         }
209 
210         /***********************************************************************
211 
212                 Write to conduit from a source array. The provided src
213                 content will be written to the conduit.
214 
215                 Returns the number of bytes written from src, which may
216                 be less than the quantity provided.
217 
218         ***********************************************************************/
219 
220         final size_t write (const(void)[] src)
221         {
222                 auto x = host.write (src);
223                 trace ("{}: wrote {} bytes", host.conduit, x is -1 ? 0 : x);
224                 return x;
225         }
226 
227         /***********************************************************************
228 
229                 Return the hosting conduit.
230 
231         ***********************************************************************/
232 
233         final IConduit conduit ()
234         {
235                 return host.conduit;
236         }
237 
238         /***********************************************************************
239 
240                 Emit/purge buffered content.
241 
242         ***********************************************************************/
243 
244         final OutputStream flush ()
245         {
246                 host.flush();
247                 trace ("{}: flushed", host.conduit);
248                 return this;
249         }
250 
251         /***********************************************************************
252 
253                 Close the output.
254 
255         ***********************************************************************/
256 
257         final void close ()
258         {
259                 host.close();
260                 trace ("{}: closed", host.conduit);
261         }
262 
263         /***********************************************************************
264 
265                 Transfer the content of another conduit to this one. Returns
266                 a reference to this class, or throws IOException on failure.
267 
268         ***********************************************************************/
269 
270         final OutputStream copy (InputStream src, size_t max=-1)
271         {
272                 host.copy (src, max);
273                 trace("{}: copied from {}", host.conduit, src.conduit);
274                 return this;
275         }
276 
277         /***********************************************************************
278 
279                 Seek on this stream. Target conduits that don't support
280                 seeking will throw an IOException.
281 
282         ***********************************************************************/
283 
284         final long seek (long offset, Anchor anchor = Anchor.Begin)
285         {
286                 auto s = host.seek (offset, anchor);
287                 trace ("{}: seek at offset {} from anchor {}", host.conduit, offset, anchor);
288                 return s;
289         }
290 
291         /***********************************************************************
292 
293                 Internal trace handler.
294 
295         ***********************************************************************/
296 
297         private void snooper (const(char)[] x)
298         {
299                 Cerr(x).newline;
300         }
301 
302         /***********************************************************************
303 
304                 Internal trace handler.
305 
306         ***********************************************************************/
307 
308         private void trace (const(char)[] format, ...)
309         {
310                 char[256] tmp = void;
311                 snoop (Format.vprint (tmp, format, _arguments, _argptr));
312         }
313 }
314 
315 
316 
317 debug (Snoop)
318 {
319         void main()
320         {
321                 auto s = new SnoopInput (null);
322                 auto o = new SnoopOutput (null);
323         }
324 }