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;
97 #if NET_4_5 && !MOBILE
98 static TextWriter console_stdout;
99 static TextWriter console_stderr;
100 static TextReader console_stdin;
106 Encoding inputEncoding;
107 Encoding outputEncoding;
110 if (Environment.IsRunningOnWindows) {
112 // On Windows, follow the Windows tradition
115 // should never happen since Moonlight does not run on windows
116 inputEncoding = outputEncoding = Encoding.Default;
119 inputEncoding = Encoding.GetEncoding (WindowsConsole.GetInputCodePage ());
120 outputEncoding = Encoding.GetEncoding (WindowsConsole.GetOutputCodePage ());
121 // ArgumentException and NotSupportedException can be thrown as well
123 // FIXME: I18N assemblies are not available when compiling mcs
124 // Use Latin 1 as it is fast and UTF-8 is never used as console code page
125 inputEncoding = outputEncoding = Encoding.Default;
130 // On Unix systems (128), do not output the
131 // UTF-8 ZWNBSP (zero-width non-breaking space).
134 Encoding.InternalCodePage (ref code_page);
136 if (code_page != -1 && ((code_page & 0x0fffffff) == 3 // UTF8Encoding.UTF8_CODE_PAGE
137 || ((code_page & 0x10000000) != 0)))
138 inputEncoding = outputEncoding = Encoding.UTF8Unmarked;
140 inputEncoding = outputEncoding = Encoding.Default;
143 SetupStreams (inputEncoding, outputEncoding);
146 static void SetupStreams (Encoding inputEncoding, Encoding outputEncoding)
149 if (!Environment.IsRunningOnWindows && ConsoleDriver.IsConsole) {
150 StreamWriter w = new CStreamWriter (OpenStandardOutput (0), outputEncoding);
152 stdout = TextWriter.Synchronized (w, true);
154 w = new CStreamWriter (OpenStandardOutput (0), outputEncoding);
156 stderr = TextWriter.Synchronized (w, true);
158 stdin = new CStreamReader (OpenStandardInput (0), inputEncoding);
161 // FULL_AOT_RUNTIME is used (instead of MONOTOUCH) since we only want this code when running on
162 // iOS (simulator or devices) and *not* when running tools (e.g. btouch #12179) that needs to use
163 // the mscorlib.dll shipped with Xamarin.iOS
165 stdout = new NSLogWriter ();
167 stdout = new UnexceptionalStreamWriter (OpenStandardOutput (0), outputEncoding);
168 ((StreamWriter)stdout).AutoFlush = true;
170 stdout = TextWriter.Synchronized (stdout, true);
173 stderr = new NSLogWriter ();
175 stderr = new UnexceptionalStreamWriter (OpenStandardError (0), outputEncoding);
176 ((StreamWriter)stderr).AutoFlush = true;
178 stderr = TextWriter.Synchronized (stderr, true);
180 stdin = new UnexceptionalStreamReader (OpenStandardInput (0), inputEncoding);
181 stdin = TextReader.Synchronized (stdin);
186 #if NET_4_5 && !MOBILE
187 console_stderr = stderr;
188 console_stdout = stdout;
189 console_stdin = stdin;
193 if (LogcatTextWriter.IsRunningOnAndroid ()) {
194 stdout = TextWriter.Synchronized (new LogcatTextWriter ("mono-stdout", stdout));
195 stderr = TextWriter.Synchronized (new LogcatTextWriter ("mono-stderr", stderr));
199 GC.SuppressFinalize (stdout);
200 GC.SuppressFinalize (stderr);
201 GC.SuppressFinalize (stdin);
204 public static TextWriter Error {
210 public static TextWriter Out {
216 public static TextReader In {
222 private static Stream Open (IntPtr handle, FileAccess access, int bufferSize)
225 return new FileStream (handle, access, false, bufferSize, false, bufferSize == 0);
226 } catch (IOException) {
227 return new NullStream ();
231 public static Stream OpenStandardError ()
233 return OpenStandardError (0);
236 // calling any FileStream constructor with a handle normally
237 // requires permissions UnmanagedCode permissions. In this
238 // case we assert this permission so the console can be used
239 // in partial trust (i.e. without having UnmanagedCode).
240 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
241 public static Stream OpenStandardError (int bufferSize)
243 return Open (MonoIO.ConsoleError, FileAccess.Write, bufferSize);
246 public static Stream OpenStandardInput ()
248 return OpenStandardInput (0);
251 // calling any FileStream constructor with a handle normally
252 // requires permissions UnmanagedCode permissions. In this
253 // case we assert this permission so the console can be used
254 // in partial trust (i.e. without having UnmanagedCode).
255 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
256 public static Stream OpenStandardInput (int bufferSize)
258 return Open (MonoIO.ConsoleInput, FileAccess.Read, bufferSize);
261 public static Stream OpenStandardOutput ()
263 return OpenStandardOutput (0);
266 // calling any FileStream constructor with a handle normally
267 // requires permissions UnmanagedCode permissions. In this
268 // case we assert this permission so the console can be used
269 // in partial trust (i.e. without having UnmanagedCode).
270 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
271 public static Stream OpenStandardOutput (int bufferSize)
273 return Open (MonoIO.ConsoleOutput, FileAccess.Write, bufferSize);
276 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
277 public static void SetError (TextWriter newError)
279 if (newError == null)
280 throw new ArgumentNullException ("newError");
285 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
286 public static void SetIn (TextReader newIn)
289 throw new ArgumentNullException ("newIn");
294 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
295 public static void SetOut (TextWriter newOut)
298 throw new ArgumentNullException ("newOut");
303 public static void Write (bool value)
305 stdout.Write (value);
308 public static void Write (char value)
310 stdout.Write (value);
313 public static void Write (char[] buffer)
315 stdout.Write (buffer);
318 public static void Write (decimal value)
320 stdout.Write (value);
323 public static void Write (double value)
325 stdout.Write (value);
328 public static void Write (int value)
330 stdout.Write (value);
333 public static void Write (long value)
335 stdout.Write (value);
338 public static void Write (object value)
340 stdout.Write (value);
343 public static void Write (float value)
345 stdout.Write (value);
348 public static void Write (string value)
350 stdout.Write (value);
353 [CLSCompliant (false)]
354 public static void Write (uint value)
356 stdout.Write (value);
359 [CLSCompliant (false)]
360 public static void Write (ulong value)
362 stdout.Write (value);
365 public static void Write (string format, object arg0)
367 stdout.Write (format, arg0);
370 public static void Write (string format, params object[] arg)
373 stdout.Write (format);
375 stdout.Write (format, arg);
378 public static void Write (char[] buffer, int index, int count)
380 stdout.Write (buffer, index, count);
383 public static void Write (string format, object arg0, object arg1)
385 stdout.Write (format, arg0, arg1);
388 public static void Write (string format, object arg0, object arg1, object arg2 )
390 stdout.Write (format, arg0, arg1, arg2);
393 [CLSCompliant (false)]
394 public static void Write (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
396 ArgIterator iter = new ArgIterator (__arglist);
397 int argCount = iter.GetRemainingCount();
399 object[] args = new object [argCount + 4];
404 for (int i = 0; i < argCount; i++) {
405 TypedReference typedRef = iter.GetNextArg ();
406 args [i + 4] = TypedReference.ToObject (typedRef);
409 stdout.Write (String.Format (format, args));
412 public static void WriteLine ()
417 public static void WriteLine (bool value)
419 stdout.WriteLine (value);
422 public static void WriteLine (char value)
424 stdout.WriteLine (value);
427 public static void WriteLine (char[] buffer)
429 stdout.WriteLine (buffer);
432 public static void WriteLine (decimal value)
434 stdout.WriteLine (value);
437 public static void WriteLine (double value)
439 stdout.WriteLine (value);
442 public static void WriteLine (int value)
444 stdout.WriteLine (value);
447 public static void WriteLine (long value)
449 stdout.WriteLine (value);
452 public static void WriteLine (object value)
454 stdout.WriteLine (value);
457 public static void WriteLine (float value)
459 stdout.WriteLine (value);
462 public static void WriteLine (string value)
464 stdout.WriteLine (value);
467 [CLSCompliant (false)]
468 public static void WriteLine (uint value)
470 stdout.WriteLine (value);
473 [CLSCompliant (false)]
474 public static void WriteLine (ulong value)
476 stdout.WriteLine (value);
479 public static void WriteLine (string format, object arg0)
481 stdout.WriteLine (format, arg0);
484 public static void WriteLine (string format, params object[] arg)
487 stdout.WriteLine (format);
489 stdout.WriteLine (format, arg);
492 public static void WriteLine (char[] buffer, int index, int count)
494 stdout.WriteLine (buffer, index, count);
497 public static void WriteLine (string format, object arg0, object arg1)
499 stdout.WriteLine (format, arg0, arg1);
502 public static void WriteLine (string format, object arg0, object arg1, object arg2)
504 stdout.WriteLine (format, arg0, arg1, arg2);
507 [CLSCompliant (false)]
508 public static void WriteLine (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
510 ArgIterator iter = new ArgIterator (__arglist);
511 int argCount = iter.GetRemainingCount();
513 object[] args = new object [argCount + 4];
518 for (int i = 0; i < argCount; i++) {
519 TypedReference typedRef = iter.GetNextArg ();
520 args [i + 4] = TypedReference.ToObject (typedRef);
523 stdout.WriteLine (String.Format (format, args));
527 public static int Read ()
529 if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
530 return ConsoleDriver.Read ();
532 return stdin.Read ();
536 public static string ReadLine ()
538 if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
539 return ConsoleDriver.ReadLine ();
541 return stdin.ReadLine ();
545 public static int Read ()
547 return stdin.Read ();
550 public static string ReadLine ()
552 return stdin.ReadLine ();
558 // FIXME: Console should use these encodings when changed
559 static Encoding inputEncoding;
560 static Encoding outputEncoding;
562 public static Encoding InputEncoding {
563 get { return inputEncoding; }
565 inputEncoding = value;
566 SetupStreams (inputEncoding, outputEncoding);
570 public static Encoding OutputEncoding {
571 get { return outputEncoding; }
573 outputEncoding = value;
574 SetupStreams (inputEncoding, outputEncoding);
578 public static ConsoleColor BackgroundColor {
579 get { return ConsoleDriver.BackgroundColor; }
580 set { ConsoleDriver.BackgroundColor = value; }
583 public static int BufferHeight {
584 get { return ConsoleDriver.BufferHeight; }
585 [MonoLimitation ("Implemented only on Windows")]
586 set { ConsoleDriver.BufferHeight = value; }
589 public static int BufferWidth {
590 get { return ConsoleDriver.BufferWidth; }
591 [MonoLimitation ("Implemented only on Windows")]
592 set { ConsoleDriver.BufferWidth = value; }
595 [MonoLimitation ("Implemented only on Windows")]
596 public static bool CapsLock {
597 get { return ConsoleDriver.CapsLock; }
600 public static int CursorLeft {
601 get { return ConsoleDriver.CursorLeft; }
602 set { ConsoleDriver.CursorLeft = value; }
605 public static int CursorTop {
606 get { return ConsoleDriver.CursorTop; }
607 set { ConsoleDriver.CursorTop = value; }
610 public static int CursorSize {
611 get { return ConsoleDriver.CursorSize; }
612 set { ConsoleDriver.CursorSize = value; }
615 public static bool CursorVisible {
616 get { return ConsoleDriver.CursorVisible; }
617 set { ConsoleDriver.CursorVisible = value; }
620 public static ConsoleColor ForegroundColor {
621 get { return ConsoleDriver.ForegroundColor; }
622 set { ConsoleDriver.ForegroundColor = value; }
625 public static bool KeyAvailable {
626 get { return ConsoleDriver.KeyAvailable; }
629 public static int LargestWindowHeight {
630 get { return ConsoleDriver.LargestWindowHeight; }
633 public static int LargestWindowWidth {
634 get { return ConsoleDriver.LargestWindowWidth; }
637 [MonoLimitation ("Only works on windows")]
638 public static bool NumberLock {
639 get { return ConsoleDriver.NumberLock; }
642 public static string Title {
643 get { return ConsoleDriver.Title; }
644 set { ConsoleDriver.Title = value; }
647 public static bool TreatControlCAsInput {
648 get { return ConsoleDriver.TreatControlCAsInput; }
649 set { ConsoleDriver.TreatControlCAsInput = value; }
652 [MonoLimitation ("Only works on windows")]
653 public static int WindowHeight {
654 get { return ConsoleDriver.WindowHeight; }
655 set { ConsoleDriver.WindowHeight = value; }
658 [MonoLimitation ("Only works on windows")]
659 public static int WindowLeft {
660 get { return ConsoleDriver.WindowLeft; }
661 set { ConsoleDriver.WindowLeft = value; }
664 [MonoLimitation ("Only works on windows")]
665 public static int WindowTop {
666 get { return ConsoleDriver.WindowTop; }
667 set { ConsoleDriver.WindowTop = value; }
670 [MonoLimitation ("Only works on windows")]
671 public static int WindowWidth {
672 get { return ConsoleDriver.WindowWidth; }
673 set { ConsoleDriver.WindowWidth = value; }
677 public static bool IsErrorRedirected {
679 return stderr != console_stderr || ConsoleDriver.IsErrorRedirected;
683 public static bool IsOutputRedirected {
685 return stdout != console_stdout || ConsoleDriver.IsOutputRedirected;
689 public static bool IsInputRedirected {
691 return stdin != console_stdin || ConsoleDriver.IsInputRedirected;
696 public static void Beep ()
701 public static void Beep (int frequency, int duration)
703 if (frequency < 37 || frequency > 32767)
704 throw new ArgumentOutOfRangeException ("frequency");
707 throw new ArgumentOutOfRangeException ("duration");
709 ConsoleDriver.Beep (frequency, duration);
712 public static void Clear ()
714 ConsoleDriver.Clear ();
717 [MonoLimitation ("Implemented only on Windows")]
718 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
719 int targetLeft, int targetTop)
721 ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop);
724 [MonoLimitation ("Implemented only on Windows")]
725 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
726 int targetLeft, int targetTop, Char sourceChar,
727 ConsoleColor sourceForeColor, ConsoleColor sourceBackColor)
729 ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop,
730 sourceChar, sourceForeColor, sourceBackColor);
733 public static ConsoleKeyInfo ReadKey ()
735 return ReadKey (false);
738 public static ConsoleKeyInfo ReadKey (bool intercept)
740 return ConsoleDriver.ReadKey (intercept);
743 public static void ResetColor ()
745 ConsoleDriver.ResetColor ();
748 [MonoLimitation ("Only works on windows")]
749 public static void SetBufferSize (int width, int height)
751 ConsoleDriver.SetBufferSize (width, height);
754 public static void SetCursorPosition (int left, int top)
756 ConsoleDriver.SetCursorPosition (left, top);
759 public static void SetWindowPosition (int left, int top)
761 ConsoleDriver.SetWindowPosition (left, top);
764 public static void SetWindowSize (int width, int height)
766 ConsoleDriver.SetWindowSize (width, height);
769 static ConsoleCancelEventHandler cancel_event;
770 public static event ConsoleCancelEventHandler CancelKeyPress {
772 if (ConsoleDriver.Initialized == false)
773 ConsoleDriver.Init ();
775 cancel_event += value;
777 if (Environment.IsRunningOnWindows && !WindowsConsole.ctrlHandlerAdded)
778 WindowsConsole.AddCtrlHandler();
781 if (ConsoleDriver.Initialized == false)
782 ConsoleDriver.Init ();
784 cancel_event -= value;
786 if (cancel_event == null && Environment.IsRunningOnWindows)
788 // Need to remove our hook if there's nothing left in the event
789 if (WindowsConsole.ctrlHandlerAdded)
790 WindowsConsole.RemoveCtrlHandler();
795 delegate void InternalCancelHandler ();
797 #pragma warning disable 414
799 // Used by console-io.c
801 static readonly InternalCancelHandler cancel_handler = new InternalCancelHandler (DoConsoleCancelEvent);
802 #pragma warning restore 414
804 internal static void DoConsoleCancelEvent ()
807 if (cancel_event != null) {
808 ConsoleCancelEventArgs args = new ConsoleCancelEventArgs (ConsoleSpecialKey.ControlC);
809 Delegate [] delegates = cancel_event.GetInvocationList ();
810 foreach (ConsoleCancelEventHandler d in delegates){
812 // Sender is always null here.
814 } catch {} // Ignore any exception.
820 Environment.Exit (58);