1 /******************************************************************************* 2 3 copyright: Copyright (c) 2009 Kris Bell. All rights reserved 4 5 license: BSD style: $(LICENSE) 6 7 version: rewritten: Nov 2009 8 9 Various low-level console oriented utilities 10 11 *******************************************************************************/ 12 13 module tango.core.util.console; 14 15 private import tango.core.util.string; 16 17 /******************************************************************************* 18 19 External functions 20 21 *******************************************************************************/ 22 23 version (Windows) 24 { 25 enum {UTF8 = 65001}; 26 private extern (Windows) int GetStdHandle (int); 27 private extern (Windows) int WriteFile (int, in char*, int, int*, void*); 28 private extern (Windows) bool GetConsoleMode (int, int*); 29 private extern (Windows) bool WriteConsoleW (int, in wchar*, int, int*, void*); 30 private extern (Windows) int MultiByteToWideChar (int, int, in char*, int, wchar*, int); 31 } 32 else 33 version (Posix) 34 extern(C) ptrdiff_t write (int, in void*, size_t); 35 36 37 /******************************************************************************* 38 39 Emit an integer to the console 40 41 *******************************************************************************/ 42 43 extern(C) void consoleInteger (ulong i) 44 { 45 char[25] tmp = void; 46 47 consoleString (ulongToUtf8 (tmp, i)); 48 } 49 50 /******************************************************************************* 51 52 Emit a utf8 string to the console. Codepages are not supported 53 54 *******************************************************************************/ 55 56 extern(C) void consoleString (const(char)[] s) 57 { 58 version (Windows) 59 { 60 int mode, count; 61 auto handle = GetStdHandle (0xfffffff5); 62 63 if (handle != -1 && GetConsoleMode (handle, &mode)) 64 { 65 wchar[512] utf; 66 while (s.length) 67 { 68 // crop to last complete utf8 sequence 69 auto t = crop (s[0 .. (s.length > utf.length) ? utf.length : s.length]); 70 71 // convert into output buffer and emit 72 auto i = MultiByteToWideChar (UTF8, 0, s.ptr, t.length, utf.ptr, utf.length); 73 WriteConsoleW (handle, utf.ptr, i, &count, null); 74 75 // process next chunk 76 s = s [t.length .. $]; 77 } 78 } 79 else 80 // output is probably redirected (we assume utf8 output) 81 WriteFile (handle, s.ptr, s.length, &count, null); 82 } 83 84 version (Posix) 85 write (2, s.ptr, s.length); 86 } 87 88 /******************************************************************************* 89 90 Support for chained console (pseudo formatting) output 91 92 *******************************************************************************/ 93 94 struct Console 95 { 96 alias newline opCall; 97 alias emit opCall; 98 99 /// emit a utf8 string to the console 100 Console emit (const(char)[] s) 101 { 102 consoleString (s); 103 return this; 104 } 105 106 /// emit an unsigned integer to the console 107 Console emit (ulong i) 108 { 109 consoleInteger (i); 110 return this; 111 } 112 113 /// emit a newline to the console 114 Console newline () 115 { 116 version (Windows) 117 const eol = "\r\n"; 118 version (Posix) 119 const eol = "\n"; 120 121 return emit (eol); 122 } 123 } 124 125 public Console console; 126 127 128 version (Windows) 129 { 130 /******************************************************************************* 131 132 Adjust the content such that no partial encodings exist on the 133 right side of the provided text. 134 135 Returns a slice of the input 136 137 *******************************************************************************/ 138 139 private inout(char)[] crop (inout(char)[] s) 140 { 141 if (s.length) 142 { 143 auto i = s.length - 1; 144 while (i && (s[i] & 0x80)) 145 if ((s[i] & 0xc0) is 0xc0) 146 { 147 // located the first byte of a sequence 148 ubyte b = s[i]; 149 int d = s.length - i; 150 151 // is it a 3 byte sequence? 152 if (b & 0x20) 153 --d; 154 155 // or a four byte sequence? 156 if (b & 0x10) 157 --d; 158 159 // is the sequence complete? 160 if (d is 2) 161 i = s.length; 162 return s [0..i]; 163 } 164 else 165 --i; 166 } 167 return s; 168 } 169 } 170 171 172 /******************************************************************************* 173 174 *******************************************************************************/ 175 176 debug (console) 177 { 178 void main() 179 { 180 console ("hello world \u263a")(); 181 } 182 }