5 // Dietmar Maurer (dietmar@ximian.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // (C) Ximian, Inc. http://www.ximian.com
9 // (C) 2004,2005 Novell, Inc. (http://www.novell.com)
10 // Copyright 2013 Xamarin Inc. (http://www.xamarin.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Diagnostics;
34 using System.Runtime.CompilerServices;
35 using System.Runtime.InteropServices;
36 using System.Security;
37 using System.Security.Permissions;
42 public static partial class Console
45 private class WindowsConsole
47 public static bool ctrlHandlerAdded = false;
48 private delegate bool WindowsCancelHandler (int keyCode);
49 private static WindowsCancelHandler cancelHandler = new WindowsCancelHandler (DoWindowsConsoleCancelEvent);
51 [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
52 private static extern int GetConsoleCP ();
53 [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
54 private static extern int GetConsoleOutputCP ();
56 [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
57 private static extern bool SetConsoleCtrlHandler (WindowsCancelHandler handler, bool addHandler);
59 // Only call the event handler if Control-C was pressed (code == 0), nothing else
60 private static bool DoWindowsConsoleCancelEvent (int keyCode)
63 DoConsoleCancelEvent ();
67 [MethodImpl (MethodImplOptions.NoInlining)]
68 public static int GetInputCodePage ()
70 return GetConsoleCP ();
73 [MethodImpl (MethodImplOptions.NoInlining)]
74 public static int GetOutputCodePage ()
76 return GetConsoleOutputCP ();
79 public static void AddCtrlHandler ()
81 SetConsoleCtrlHandler (cancelHandler, true);
82 ctrlHandlerAdded = true;
85 public static void RemoveCtrlHandler ()
87 SetConsoleCtrlHandler (cancelHandler, false);
88 ctrlHandlerAdded = false;
93 internal static TextWriter stdout;
94 private static TextWriter stderr;
95 private static TextReader stdin;
100 Encoding inputEncoding;
101 Encoding outputEncoding;
104 if (Environment.IsRunningOnWindows) {
106 // On Windows, follow the Windows tradition
109 // should never happen since Moonlight does not run on windows
110 inputEncoding = outputEncoding = Encoding.Default;
113 inputEncoding = Encoding.GetEncoding (WindowsConsole.GetInputCodePage ());
114 outputEncoding = Encoding.GetEncoding (WindowsConsole.GetOutputCodePage ());
115 // ArgumentException and NotSupportedException can be thrown as well
117 // FIXME: I18N assemblies are not available when compiling mcs
118 // Use Latin 1 as it is fast and UTF-8 is never used as console code page
119 inputEncoding = outputEncoding = Encoding.Default;
124 // On Unix systems (128), do not output the
125 // UTF-8 ZWNBSP (zero-width non-breaking space).
128 EncodingHelper.InternalCodePage (ref code_page);
130 if (code_page != -1 && ((code_page & 0x0fffffff) == 3 // UTF8Encoding.UTF8_CODE_PAGE
131 || ((code_page & 0x10000000) != 0)))
132 inputEncoding = outputEncoding = EncodingHelper.UTF8Unmarked;
134 inputEncoding = outputEncoding = Encoding.Default;
137 SetupStreams (inputEncoding, outputEncoding);
140 static void SetupStreams (Encoding inputEncoding, Encoding outputEncoding)
143 if (!Environment.IsRunningOnWindows && ConsoleDriver.IsConsole) {
144 StreamWriter w = new CStreamWriter (OpenStandardOutput (0), outputEncoding, true);
146 stdout = TextWriter.Synchronized (w);
148 w = new CStreamWriter (OpenStandardOutput (0), outputEncoding, true);
150 stderr = TextWriter.Synchronized (w);
152 stdin = new CStreamReader (OpenStandardInput (0), inputEncoding);
156 stdout = new NSLogWriter ();
158 stdout = new UnexceptionalStreamWriter (OpenStandardOutput (0), outputEncoding);
159 ((StreamWriter)stdout).AutoFlush = true;
161 stdout = TextWriter.Synchronized (stdout);
164 stderr = new NSLogWriter ();
166 stderr = new UnexceptionalStreamWriter (OpenStandardError (0), outputEncoding);
167 ((StreamWriter)stderr).AutoFlush = true;
169 stderr = TextWriter.Synchronized (stderr);
171 stdin = new UnexceptionalStreamReader (OpenStandardInput (0), inputEncoding);
172 stdin = TextReader.Synchronized (stdin);
178 if (LogcatTextWriter.IsRunningOnAndroid ()) {
179 stdout = TextWriter.Synchronized (new LogcatTextWriter ("mono-stdout", stdout));
180 stderr = TextWriter.Synchronized (new LogcatTextWriter ("mono-stderr", stderr));
184 GC.SuppressFinalize (stdout);
185 GC.SuppressFinalize (stderr);
186 GC.SuppressFinalize (stdin);
189 public static TextWriter Error {
195 public static TextWriter Out {
201 public static TextReader In {
207 private static Stream Open (IntPtr handle, FileAccess access, int bufferSize)
210 // TODO: Should use __ConsoleStream from reference sources
211 return new FileStream (handle, access, false, bufferSize, false, true);
212 } catch (IOException) {
217 public static Stream OpenStandardError ()
219 return OpenStandardError (0);
222 // calling any FileStream constructor with a handle normally
223 // requires permissions UnmanagedCode permissions. In this
224 // case we assert this permission so the console can be used
225 // in partial trust (i.e. without having UnmanagedCode).
226 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
227 public static Stream OpenStandardError (int bufferSize)
229 return Open (MonoIO.ConsoleError, FileAccess.Write, bufferSize);
232 public static Stream OpenStandardInput ()
234 return OpenStandardInput (0);
237 // calling any FileStream constructor with a handle normally
238 // requires permissions UnmanagedCode permissions. In this
239 // case we assert this permission so the console can be used
240 // in partial trust (i.e. without having UnmanagedCode).
241 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
242 public static Stream OpenStandardInput (int bufferSize)
244 return Open (MonoIO.ConsoleInput, FileAccess.Read, bufferSize);
247 public static Stream OpenStandardOutput ()
249 return OpenStandardOutput (0);
252 // calling any FileStream constructor with a handle normally
253 // requires permissions UnmanagedCode permissions. In this
254 // case we assert this permission so the console can be used
255 // in partial trust (i.e. without having UnmanagedCode).
256 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
257 public static Stream OpenStandardOutput (int bufferSize)
259 return Open (MonoIO.ConsoleOutput, FileAccess.Write, bufferSize);
262 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
263 public static void SetError (TextWriter newError)
265 if (newError == null)
266 throw new ArgumentNullException ("newError");
271 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
272 public static void SetIn (TextReader newIn)
275 throw new ArgumentNullException ("newIn");
280 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
281 public static void SetOut (TextWriter newOut)
284 throw new ArgumentNullException ("newOut");
289 public static void Write (bool value)
291 stdout.Write (value);
294 public static void Write (char value)
296 stdout.Write (value);
299 public static void Write (char[] buffer)
301 stdout.Write (buffer);
304 public static void Write (decimal value)
306 stdout.Write (value);
309 public static void Write (double value)
311 stdout.Write (value);
314 public static void Write (int value)
316 stdout.Write (value);
319 public static void Write (long value)
321 stdout.Write (value);
324 public static void Write (object value)
326 stdout.Write (value);
329 public static void Write (float value)
331 stdout.Write (value);
334 public static void Write (string value)
336 stdout.Write (value);
339 [CLSCompliant (false)]
340 public static void Write (uint value)
342 stdout.Write (value);
345 [CLSCompliant (false)]
346 public static void Write (ulong value)
348 stdout.Write (value);
351 public static void Write (string format, object arg0)
353 stdout.Write (format, arg0);
356 public static void Write (string format, params object[] arg)
359 stdout.Write (format);
361 stdout.Write (format, arg);
364 public static void Write (char[] buffer, int index, int count)
366 stdout.Write (buffer, index, count);
369 public static void Write (string format, object arg0, object arg1)
371 stdout.Write (format, arg0, arg1);
374 public static void Write (string format, object arg0, object arg1, object arg2 )
376 stdout.Write (format, arg0, arg1, arg2);
379 [CLSCompliant (false)]
380 public static void Write (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
382 ArgIterator iter = new ArgIterator (__arglist);
383 int argCount = iter.GetRemainingCount();
385 object[] args = new object [argCount + 4];
390 for (int i = 0; i < argCount; i++) {
391 TypedReference typedRef = iter.GetNextArg ();
392 args [i + 4] = TypedReference.ToObject (typedRef);
395 stdout.Write (String.Format (format, args));
398 public static void WriteLine ()
403 public static void WriteLine (bool value)
405 stdout.WriteLine (value);
408 public static void WriteLine (char value)
410 stdout.WriteLine (value);
413 public static void WriteLine (char[] buffer)
415 stdout.WriteLine (buffer);
418 public static void WriteLine (decimal value)
420 stdout.WriteLine (value);
423 public static void WriteLine (double value)
425 stdout.WriteLine (value);
428 public static void WriteLine (int value)
430 stdout.WriteLine (value);
433 public static void WriteLine (long value)
435 stdout.WriteLine (value);
438 public static void WriteLine (object value)
440 stdout.WriteLine (value);
443 public static void WriteLine (float value)
445 stdout.WriteLine (value);
448 public static void WriteLine (string value)
450 stdout.WriteLine (value);
453 [CLSCompliant (false)]
454 public static void WriteLine (uint value)
456 stdout.WriteLine (value);
459 [CLSCompliant (false)]
460 public static void WriteLine (ulong value)
462 stdout.WriteLine (value);
465 public static void WriteLine (string format, object arg0)
467 stdout.WriteLine (format, arg0);
470 public static void WriteLine (string format, params object[] arg)
473 stdout.WriteLine (format);
475 stdout.WriteLine (format, arg);
478 public static void WriteLine (char[] buffer, int index, int count)
480 stdout.WriteLine (buffer, index, count);
483 public static void WriteLine (string format, object arg0, object arg1)
485 stdout.WriteLine (format, arg0, arg1);
488 public static void WriteLine (string format, object arg0, object arg1, object arg2)
490 stdout.WriteLine (format, arg0, arg1, arg2);
493 [CLSCompliant (false)]
494 public static void WriteLine (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
496 ArgIterator iter = new ArgIterator (__arglist);
497 int argCount = iter.GetRemainingCount();
499 object[] args = new object [argCount + 4];
504 for (int i = 0; i < argCount; i++) {
505 TypedReference typedRef = iter.GetNextArg ();
506 args [i + 4] = TypedReference.ToObject (typedRef);
509 stdout.WriteLine (String.Format (format, args));
513 public static int Read ()
515 if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
516 return ConsoleDriver.Read ();
518 return stdin.Read ();
522 public static string ReadLine ()
524 if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
525 return ConsoleDriver.ReadLine ();
527 return stdin.ReadLine ();
531 public static int Read ()
533 return stdin.Read ();
536 public static string ReadLine ()
538 return stdin.ReadLine ();
544 // FIXME: Console should use these encodings when changed
545 static Encoding inputEncoding;
546 static Encoding outputEncoding;
548 public static Encoding InputEncoding {
549 get { return inputEncoding; }
551 inputEncoding = value;
552 SetupStreams (inputEncoding, outputEncoding);
556 public static Encoding OutputEncoding {
557 get { return outputEncoding; }
559 outputEncoding = value;
560 SetupStreams (inputEncoding, outputEncoding);
564 public static ConsoleColor BackgroundColor {
565 get { return ConsoleDriver.BackgroundColor; }
566 set { ConsoleDriver.BackgroundColor = value; }
569 public static int BufferHeight {
570 get { return ConsoleDriver.BufferHeight; }
571 [MonoLimitation ("Implemented only on Windows")]
572 set { ConsoleDriver.BufferHeight = value; }
575 public static int BufferWidth {
576 get { return ConsoleDriver.BufferWidth; }
577 [MonoLimitation ("Implemented only on Windows")]
578 set { ConsoleDriver.BufferWidth = value; }
581 [MonoLimitation ("Implemented only on Windows")]
582 public static bool CapsLock {
583 get { return ConsoleDriver.CapsLock; }
586 public static int CursorLeft {
587 get { return ConsoleDriver.CursorLeft; }
588 set { ConsoleDriver.CursorLeft = value; }
591 public static int CursorTop {
592 get { return ConsoleDriver.CursorTop; }
593 set { ConsoleDriver.CursorTop = value; }
596 public static int CursorSize {
597 get { return ConsoleDriver.CursorSize; }
598 set { ConsoleDriver.CursorSize = value; }
601 public static bool CursorVisible {
602 get { return ConsoleDriver.CursorVisible; }
603 set { ConsoleDriver.CursorVisible = value; }
606 public static ConsoleColor ForegroundColor {
607 get { return ConsoleDriver.ForegroundColor; }
608 set { ConsoleDriver.ForegroundColor = value; }
611 public static bool KeyAvailable {
612 get { return ConsoleDriver.KeyAvailable; }
615 public static int LargestWindowHeight {
616 get { return ConsoleDriver.LargestWindowHeight; }
619 public static int LargestWindowWidth {
620 get { return ConsoleDriver.LargestWindowWidth; }
623 [MonoLimitation ("Only works on windows")]
624 public static bool NumberLock {
625 get { return ConsoleDriver.NumberLock; }
628 public static string Title {
629 get { return ConsoleDriver.Title; }
630 set { ConsoleDriver.Title = value; }
633 public static bool TreatControlCAsInput {
634 get { return ConsoleDriver.TreatControlCAsInput; }
635 set { ConsoleDriver.TreatControlCAsInput = value; }
638 [MonoLimitation ("Only works on windows")]
639 public static int WindowHeight {
640 get { return ConsoleDriver.WindowHeight; }
641 set { ConsoleDriver.WindowHeight = value; }
644 [MonoLimitation ("Only works on windows")]
645 public static int WindowLeft {
646 get { return ConsoleDriver.WindowLeft; }
647 set { ConsoleDriver.WindowLeft = value; }
650 [MonoLimitation ("Only works on windows")]
651 public static int WindowTop {
652 get { return ConsoleDriver.WindowTop; }
653 set { ConsoleDriver.WindowTop = value; }
656 [MonoLimitation ("Only works on windows")]
657 public static int WindowWidth {
658 get { return ConsoleDriver.WindowWidth; }
659 set { ConsoleDriver.WindowWidth = value; }
662 public static bool IsErrorRedirected {
664 return ConsoleDriver.IsErrorRedirected;
668 public static bool IsOutputRedirected {
670 return ConsoleDriver.IsOutputRedirected;
674 public static bool IsInputRedirected {
676 return ConsoleDriver.IsInputRedirected;
680 public static void Beep ()
685 public static void Beep (int frequency, int duration)
687 if (frequency < 37 || frequency > 32767)
688 throw new ArgumentOutOfRangeException ("frequency");
691 throw new ArgumentOutOfRangeException ("duration");
693 ConsoleDriver.Beep (frequency, duration);
696 public static void Clear ()
698 ConsoleDriver.Clear ();
701 [MonoLimitation ("Implemented only on Windows")]
702 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
703 int targetLeft, int targetTop)
705 ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop);
708 [MonoLimitation ("Implemented only on Windows")]
709 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
710 int targetLeft, int targetTop, Char sourceChar,
711 ConsoleColor sourceForeColor, ConsoleColor sourceBackColor)
713 ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop,
714 sourceChar, sourceForeColor, sourceBackColor);
717 public static ConsoleKeyInfo ReadKey ()
719 return ReadKey (false);
722 public static ConsoleKeyInfo ReadKey (bool intercept)
724 return ConsoleDriver.ReadKey (intercept);
727 public static void ResetColor ()
729 ConsoleDriver.ResetColor ();
732 [MonoLimitation ("Only works on windows")]
733 public static void SetBufferSize (int width, int height)
735 ConsoleDriver.SetBufferSize (width, height);
738 public static void SetCursorPosition (int left, int top)
740 ConsoleDriver.SetCursorPosition (left, top);
743 public static void SetWindowPosition (int left, int top)
745 ConsoleDriver.SetWindowPosition (left, top);
748 public static void SetWindowSize (int width, int height)
750 ConsoleDriver.SetWindowSize (width, height);
753 static ConsoleCancelEventHandler cancel_event;
754 public static event ConsoleCancelEventHandler CancelKeyPress {
756 if (ConsoleDriver.Initialized == false)
757 ConsoleDriver.Init ();
759 cancel_event += value;
761 if (Environment.IsRunningOnWindows && !WindowsConsole.ctrlHandlerAdded)
762 WindowsConsole.AddCtrlHandler();
765 if (ConsoleDriver.Initialized == false)
766 ConsoleDriver.Init ();
768 cancel_event -= value;
770 if (cancel_event == null && Environment.IsRunningOnWindows)
772 // Need to remove our hook if there's nothing left in the event
773 if (WindowsConsole.ctrlHandlerAdded)
774 WindowsConsole.RemoveCtrlHandler();
779 delegate void InternalCancelHandler ();
781 #pragma warning disable 414
783 // Used by console-io.c
785 static readonly InternalCancelHandler cancel_handler = new InternalCancelHandler (DoConsoleCancelEvent);
786 #pragma warning restore 414
788 internal static void DoConsoleCancelEvent ()
791 if (cancel_event != null) {
792 ConsoleCancelEventArgs args = new ConsoleCancelEventArgs (ConsoleSpecialKey.ControlC);
793 Delegate [] delegates = cancel_event.GetInvocationList ();
794 foreach (ConsoleCancelEventHandler d in delegates){
796 // Sender is always null here.
798 } catch {} // Ignore any exception.
804 Environment.Exit (58);