1 /*******************************************************************************
2 
3         Copyright:
4             Copyright (c) 2007 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: Oct 2007
13 
14         Authors: Kris
15 
16 *******************************************************************************/
17 
18 module ocean.io.stream.Format;
19 
20 import ocean.meta.types.Qualifiers;
21 
22 import ocean.core.Verify;
23 
24 import ocean.io.device.Conduit;
25 
26 import ocean.text.convert.Formatter;
27 
28 
29 /*******************************************************************************
30 
31         A bridge between a Layout instance and a stream. This is used for
32         the Stdout & Stderr globals, but can be used for general purpose
33         buffer-formatting as desired.
34 
35         FormatOutput exposes this style of usage:
36         ---
37         auto print = new FormatOutput(...);
38 
39         print.format ("abc {}", 1);         // => abc 1
40         print.format ("abc {}:{}", 1, 2);   // => abc 1:2
41         print.format ("abc {1}:{0}", 1, 2); // => abc 2:1
42         print.format ("abc ", 1);           // => abc
43         ---
44 
45         Note that the last example does not throw an exception. There
46         are several use-cases where dropping an argument is legitimate,
47         so we're currently not enforcing any particular trap mechanism.
48 
49         Flushing the output is achieved through the flush() method:
50         ---
51         print.format ("hello {}", "world").flush;
52         ---
53 
54         Special character sequences, such as "\n", are written directly to
55         the output without any translation (though an output-filter could
56         be inserted to perform translation as required). Platform-specific
57         newlines are generated instead via the newline() method, which also
58         flushes the output when configured to do so:
59         ---
60         print.format ("hello {}", "world").newline;
61         print.formatln ("hello {}", "world");
62         ---
63 
64         Note that FormatOutput is *not* intended to be thread-safe.
65 
66 *******************************************************************************/
67 
68 class FormatOutput : OutputFilter
69 {
70         public  alias OutputFilter.flush flush;
71 
72         private cstring         eol;
73         private bool            flushLines;
74 
75         public alias newline    nl;             /// nl -> newline
76 
77         protected static immutable Eol = "\n";
78 
79         /**********************************************************************
80 
81                 Construct a FormatOutput instance, tying the provided stream
82                 to a layout formatter.
83 
84         **********************************************************************/
85 
86         this (OutputStream output, cstring eol = Eol)
87         {
88             this.eol = eol;
89             super (output);
90 
91         }
92 
93         /**********************************************************************
94 
95             Format the provided arguments to the stream according to the format
96             string
97 
98             Params:
99                 Args = Variadic template arguments
100                 fmt  = Format string to use (see `ocean.text.convert.Formatter`
101                 args = Arguments to format
102 
103             Returns:
104                 `this`, for easy chaining
105 
106         **********************************************************************/
107 
108         public typeof(this) format (Args...) (cstring fmt, Args args)
109         {
110             sformat(&this.emit, fmt, args);
111             return this;
112         }
113 
114         /**********************************************************************
115 
116             Format the provided arguments to the stream according to the format
117             string, and append a newline to the output.
118 
119             Params:
120                 Args = Variadic template arguments
121                 fmt  = Format string to use (see `ocean.text.convert.Formatter`
122                 args = Arguments to format
123 
124             Returns:
125                 `this`, for easy chaining
126 
127         **********************************************************************/
128 
129         public typeof(this) formatln (Args...) (cstring fmt, Args args)
130         {
131             sformat(&this.emit, fmt, args);
132             this.newline;
133             return this;
134         }
135 
136         /***********************************************************************
137 
138                 Output a newline and optionally flush.
139 
140         ***********************************************************************/
141 
142         final FormatOutput newline ()
143         {
144                 sink.write (eol);
145                 if (flushLines)
146                     sink.flush;
147                 return this;
148         }
149 
150         /**********************************************************************
151 
152                 Control implicit flushing of newline(), where true enables
153                 flushing. An explicit flush() will always flush the output.
154 
155         **********************************************************************/
156 
157         final FormatOutput flush (bool yes)
158         {
159                 flushLines = yes;
160                 return this;
161         }
162 
163         /**********************************************************************
164 
165                 Return the associated output stream.
166 
167         **********************************************************************/
168 
169         final OutputStream stream ()
170         {
171                 return sink;
172         }
173 
174         /**********************************************************************
175 
176                 Set the associated output stream.
177 
178         **********************************************************************/
179 
180         final FormatOutput stream (OutputStream output)
181         {
182                 sink = output;
183                 return this;
184         }
185 
186         /**********************************************************************
187 
188                 Sink for passing to the formatter.
189 
190         **********************************************************************/
191 
192         protected void emit (cstring s)
193         {
194                 auto count = sink.write (s);
195                 if (count is Eof)
196                     conduit.error ("FormatOutput :: unexpected Eof");
197         }
198 }