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 }