00001 /******************************************************************************* 00002 00003 @file DisplayWriter.d 00004 00005 Copyright (c) 2004 Kris Bell 00006 00007 This software is provided 'as-is', without any express or implied 00008 warranty. In no event will the authors be held liable for damages 00009 of any kind arising from the use of this software. 00010 00011 Permission is hereby granted to anyone to use this software for any 00012 purpose, including commercial applications, and to alter it and/or 00013 redistribute it freely, subject to the following restrictions: 00014 00015 1. The origin of this software must not be misrepresented; you must 00016 not claim that you wrote the original software. If you use this 00017 software in a product, an acknowledgment within documentation of 00018 said product would be appreciated but is not required. 00019 00020 2. Altered source versions must be plainly marked as such, and must 00021 not be misrepresented as being the original software. 00022 00023 3. This notice may not be removed or altered from any distribution 00024 of the source. 00025 00026 4. Derivative works are permitted, but they must carry this notice 00027 in full and credit the original source. 00028 00029 00030 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00031 00032 00033 @version Initial version; March 2004 00034 Changed from sprintf() to mango.format; March 2005 00035 00036 @author Kris 00037 Anders F Bjorklund (Darwin patches) 00038 00039 00040 *******************************************************************************/ 00041 00042 module mango.io.DisplayWriter; 00043 00044 public import mango.io.Writer; 00045 00046 private import mango.format.Int, 00047 mango.format.Long, 00048 mango.format.Double, 00049 mango.format.Number; 00050 00051 00052 /******************************************************************************* 00053 00054 Format output suitable for presentation. There is no corresponding 00055 reader, since there are no explicit delimiters emitted to isolate 00056 each formatted item. One can use TextReader to read input from the 00057 console (or from some other input buffer). 00058 00059 *******************************************************************************/ 00060 00061 class DisplayWriter : Writer 00062 { 00063 alias Number.Radix Radix; 00064 00065 // temporary buffer space for encoding 00066 private char[64] tmp; 00067 00068 private char fill; 00069 00070 // number of floating-point digits to write 00071 private uint digits = 2; 00072 00073 // how to print unsigned ints and unsigned longs 00074 private int width = tmp.length; 00075 private Radix radix = Radix.Decimal; 00076 00077 /*********************************************************************** 00078 00079 Construct a DisplayWriter upon the specified IBuffer 00080 00081 ***********************************************************************/ 00082 00083 this (IBuffer buffer) 00084 { 00085 super (buffer); 00086 00087 // disable array length output (for strings and so on) 00088 enableArrayPrefix (false); 00089 00090 encode.int1 = &int1; 00091 encode.int8 = &int8; 00092 encode.int8u = &int8u; 00093 encode.int16 = &int16; 00094 encode.int16u = &int16u; 00095 encode.int32 = &int32; 00096 encode.int32u = &int32u; 00097 encode.int64 = &int64; 00098 encode.int64u = &int64u; 00099 00100 encode.float32 = &float32; 00101 encode.float64 = &float64; 00102 encode.float80 = &float80; 00103 } 00104 00105 /*********************************************************************** 00106 00107 Construct a DisplayWriter upon the specified IConduit 00108 00109 ***********************************************************************/ 00110 00111 this (IConduit conduit) 00112 { 00113 this (conduit.createBuffer); 00114 } 00115 00116 /*********************************************************************** 00117 00118 Set the number of floating point digits 00119 00120 ***********************************************************************/ 00121 00122 void setPrecision (uint digits) 00123 { 00124 this.digits = digits; 00125 } 00126 00127 /*********************************************************************** 00128 00129 ***********************************************************************/ 00130 00131 void setRadix (Radix radix) 00132 { 00133 this.radix = radix; 00134 } 00135 00136 /*********************************************************************** 00137 00138 ***********************************************************************/ 00139 00140 void setFill (uint width, char fill = ' ') 00141 { 00142 assert (width <= tmp.length); 00143 this.width = width; 00144 this.fill = fill; 00145 } 00146 00147 /*********************************************************************** 00148 00149 ***********************************************************************/ 00150 00151 private void formatInt (uint i, bool sign) 00152 { 00153 if (sign) 00154 put (Int.format (tmp, i)); 00155 else 00156 put (Int.format (tmp[0..width], i, radix, fill)); 00157 } 00158 00159 /*********************************************************************** 00160 00161 ***********************************************************************/ 00162 00163 private void formatLong (ulong i, bool sign) 00164 { 00165 if (sign) 00166 put (Long.format (tmp, i)); 00167 else 00168 put (Long.format (tmp[0..width], i, radix, fill)); 00169 } 00170 00171 /*********************************************************************** 00172 00173 ***********************************************************************/ 00174 00175 private void int8f (ubyte* src, uint count, bool sign) 00176 { 00177 while (count) 00178 { 00179 // sign extend! 00180 int i = *src; 00181 formatInt (i, sign); 00182 00183 ++src; 00184 --count; 00185 } 00186 } 00187 00188 /*********************************************************************** 00189 00190 ***********************************************************************/ 00191 00192 private void int16f (ushort* src, uint count, bool sign) 00193 { 00194 while (count) 00195 { 00196 // sign extend! 00197 int i = *src; 00198 formatInt (i, sign); 00199 00200 ++src; 00201 count -= 2; 00202 } 00203 } 00204 00205 /*********************************************************************** 00206 00207 ***********************************************************************/ 00208 00209 private void int32f (uint* src, uint count, bool sign) 00210 { 00211 while (count) 00212 { 00213 uint i = *src; 00214 formatInt (i, sign); 00215 00216 ++src; 00217 count -= 4; 00218 } 00219 } 00220 00221 /*********************************************************************** 00222 00223 ***********************************************************************/ 00224 00225 private void int64f (ulong* src, uint count, bool sign) 00226 { 00227 while (count) 00228 { 00229 ulong i = *src; 00230 formatLong (i, sign); 00231 00232 ++src; 00233 count -= 8; 00234 } 00235 } 00236 00237 /*********************************************************************** 00238 00239 ***********************************************************************/ 00240 00241 private void fformat (void* src, uint count, uint width) 00242 { 00243 double x; 00244 00245 while (count) 00246 { 00247 if (width == float.sizeof) 00248 x = *cast(float*) src; 00249 else 00250 if (width == double.sizeof) 00251 x = *cast(double*) src; 00252 else 00253 x = *cast(real*) src; 00254 00255 put (Double.format (tmp, x, digits)); 00256 00257 count -= width; 00258 src += width; 00259 } 00260 } 00261 00262 /*********************************************************************** 00263 00264 ***********************************************************************/ 00265 00266 final void int1 (void* src, uint count) 00267 { 00268 while (count) 00269 { 00270 if (*cast(ubyte *) src) 00271 encode.char8 (cast(char*) "true", 4); 00272 else 00273 encode.char8 (cast(char*) "false", 5); 00274 00275 ++src; 00276 --count; 00277 } 00278 } 00279 00280 /*********************************************************************** 00281 00282 ***********************************************************************/ 00283 00284 final void int8 (void* src, uint count) 00285 { 00286 int8f (cast(ubyte*) src, count, true); 00287 } 00288 00289 /*********************************************************************** 00290 00291 ***********************************************************************/ 00292 00293 final void int8u (void* src, uint count) 00294 { 00295 int8f (cast(ubyte*) src, count, false); 00296 } 00297 00298 /*********************************************************************** 00299 00300 ***********************************************************************/ 00301 00302 final void int16 (void* src, uint count) 00303 { 00304 int16f (cast(ushort*) src, count, true); 00305 } 00306 00307 /*********************************************************************** 00308 00309 ***********************************************************************/ 00310 00311 final void int16u (void* src, uint count) 00312 { 00313 int16f (cast(ushort*) src, count, false); 00314 } 00315 00316 /*********************************************************************** 00317 00318 ***********************************************************************/ 00319 00320 final void int32 (void* src, uint count) 00321 { 00322 int32f (cast(uint*) src, count, true); 00323 } 00324 00325 /*********************************************************************** 00326 00327 ***********************************************************************/ 00328 00329 final void int32u (void* src, uint count) 00330 { 00331 int32f (cast(uint*) src, count, false); 00332 } 00333 00334 /*********************************************************************** 00335 00336 ***********************************************************************/ 00337 00338 final void int64 (void* src, uint count) 00339 { 00340 int64f (cast(ulong*) src, count, true); 00341 } 00342 00343 /*********************************************************************** 00344 00345 ***********************************************************************/ 00346 00347 final void int64u (void* src, uint count) 00348 { 00349 int64f (cast(ulong*) src, count, false); 00350 } 00351 00352 /*********************************************************************** 00353 00354 ***********************************************************************/ 00355 00356 final void float32 (void* src, uint count) 00357 { 00358 fformat (src, count, float.sizeof); 00359 } 00360 00361 /*********************************************************************** 00362 00363 ***********************************************************************/ 00364 00365 final void float64 (void* src, uint count) 00366 { 00367 fformat (src, count, double.sizeof); 00368 } 00369 00370 /*********************************************************************** 00371 00372 ***********************************************************************/ 00373 00374 final void float80 (void* src, uint count) 00375 { 00376 fformat (src, count, real.sizeof); 00377 } 00378 } 00379 00380 00381 00382 /******************************************************************************* 00383 00384 Subclass to support automatic flushing. This can be used for 00385 Stdout, Stderr, and other related conduits. 00386 00387 *******************************************************************************/ 00388 00389 class FlushWriter : DisplayWriter 00390 { 00391 alias DisplayWriter.put put; 00392 00393 /*********************************************************************** 00394 00395 Construct a FlushWriter upon the specified IBuffer 00396 00397 ***********************************************************************/ 00398 00399 this (IBuffer buffer) 00400 { 00401 super (buffer); 00402 } 00403 00404 /*********************************************************************** 00405 00406 Construct a FlushWriter upon the specified IConduit 00407 00408 ***********************************************************************/ 00409 00410 this (IConduit conduit) 00411 { 00412 this (conduit.createBuffer); 00413 } 00414 00415 /********************************************************************** 00416 00417 Intercept the IWritable method to catch newlines, and 00418 flush the buffer whenever one is emitted 00419 00420 ***********************************************************************/ 00421 00422 override IWriter put (IWritable x) 00423 { 00424 // have superclass handle the IWritable 00425 super.put (x); 00426 00427 // flush output when we see a newline 00428 if (cast(INewlineWriter) x) 00429 flush (); 00430 00431 return this; 00432 } 00433 } 00434