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);
155 // FULL_AOT_RUNTIME is used (instead of MONOTOUCH) since we only want this code when running on
156 // iOS (simulator or devices) and *not* when running tools (e.g. btouch #12179) that needs to use
157 // the mscorlib.dll shipped with Xamarin.iOS
158 #if MONOTOUCH && FULL_AOT_RUNTIME
159 stdout = new NSLogWriter ();
161 stdout = new UnexceptionalStreamWriter (OpenStandardOutput (0), outputEncoding);
162 ((StreamWriter)stdout).AutoFlush = true;
164 stdout = TextWriter.Synchronized (stdout);
166 #if MONOTOUCH && FULL_AOT_RUNTIME
167 stderr = new NSLogWriter ();
169 stderr = new UnexceptionalStreamWriter (OpenStandardError (0), outputEncoding);
170 ((StreamWriter)stderr).AutoFlush = true;
172 stderr = TextWriter.Synchronized (stderr);
174 stdin = new UnexceptionalStreamReader (OpenStandardInput (0), inputEncoding);
175 stdin = TextReader.Synchronized (stdin);
181 if (LogcatTextWriter.IsRunningOnAndroid ()) {
182 stdout = TextWriter.Synchronized (new LogcatTextWriter ("mono-stdout", stdout));
183 stderr = TextWriter.Synchronized (new LogcatTextWriter ("mono-stderr", stderr));
187 GC.SuppressFinalize (stdout);
188 GC.SuppressFinalize (stderr);
189 GC.SuppressFinalize (stdin);
192 public static TextWriter Error {
198 public static TextWriter Out {
204 public static TextReader In {
210 private static Stream Open (IntPtr handle, FileAccess access, int bufferSize)
213 // TODO: Should use __ConsoleStream from reference sources
214 return new FileStream (handle, access, false, bufferSize, false, true);
215 } catch (IOException) {
220 public static Stream OpenStandardError ()
222 return OpenStandardError (0);
225 // calling any FileStream constructor with a handle normally
226 // requires permissions UnmanagedCode permissions. In this
227 // case we assert this permission so the console can be used
228 // in partial trust (i.e. without having UnmanagedCode).
229 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
230 public static Stream OpenStandardError (int bufferSize)
232 return Open (MonoIO.ConsoleError, FileAccess.Write, bufferSize);
235 public static Stream OpenStandardInput ()
237 return OpenStandardInput (0);
240 // calling any FileStream constructor with a handle normally
241 // requires permissions UnmanagedCode permissions. In this
242 // case we assert this permission so the console can be used
243 // in partial trust (i.e. without having UnmanagedCode).
244 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
245 public static Stream OpenStandardInput (int bufferSize)
247 return Open (MonoIO.ConsoleInput, FileAccess.Read, bufferSize);
250 public static Stream OpenStandardOutput ()
252 return OpenStandardOutput (0);
255 // calling any FileStream constructor with a handle normally
256 // requires permissions UnmanagedCode permissions. In this
257 // case we assert this permission so the console can be used
258 // in partial trust (i.e. without having UnmanagedCode).
259 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
260 public static Stream OpenStandardOutput (int bufferSize)
262 return Open (MonoIO.ConsoleOutput, FileAccess.Write, bufferSize);
265 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
266 public static void SetError (TextWriter newError)
268 if (newError == null)
269 throw new ArgumentNullException ("newError");
274 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
275 public static void SetIn (TextReader newIn)
278 throw new ArgumentNullException ("newIn");
283 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
284 public static void SetOut (TextWriter newOut)
287 throw new ArgumentNullException ("newOut");
292 public static void Write (bool value)
294 stdout.Write (value);
297 public static void Write (char value)
299 stdout.Write (value);
302 public static void Write (char[] buffer)
304 stdout.Write (buffer);
307 public static void Write (decimal value)
309 stdout.Write (value);
312 public static void Write (double value)
314 stdout.Write (value);
317 public static void Write (int value)
319 stdout.Write (value);
322 public static void Write (long value)
324 stdout.Write (value);
327 public static void Write (object value)
329 stdout.Write (value);
332 public static void Write (float value)
334 stdout.Write (value);
337 public static void Write (string value)
339 stdout.Write (value);
342 [CLSCompliant (false)]
343 public static void Write (uint value)
345 stdout.Write (value);
348 [CLSCompliant (false)]
349 public static void Write (ulong value)
351 stdout.Write (value);
354 public static void Write (string format, object arg0)
356 stdout.Write (format, arg0);
359 public static void Write (string format, params object[] arg)
362 stdout.Write (format);
364 stdout.Write (format, arg);
367 public static void Write (char[] buffer, int index, int count)
369 stdout.Write (buffer, index, count);
372 public static void Write (string format, object arg0, object arg1)
374 stdout.Write (format, arg0, arg1);
377 public static void Write (string format, object arg0, object arg1, object arg2 )
379 stdout.Write (format, arg0, arg1, arg2);
382 [CLSCompliant (false)]
383 public static void Write (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
385 ArgIterator iter = new ArgIterator (__arglist);
386 int argCount = iter.GetRemainingCount();
388 object[] args = new object [argCount + 4];
393 for (int i = 0; i < argCount; i++) {
394 TypedReference typedRef = iter.GetNextArg ();
395 args [i + 4] = TypedReference.ToObject (typedRef);
398 stdout.Write (String.Format (format, args));
401 public static void WriteLine ()
406 public static void WriteLine (bool value)
408 stdout.WriteLine (value);
411 public static void WriteLine (char value)
413 stdout.WriteLine (value);
416 public static void WriteLine (char[] buffer)
418 stdout.WriteLine (buffer);
421 public static void WriteLine (decimal value)
423 stdout.WriteLine (value);
426 public static void WriteLine (double value)
428 stdout.WriteLine (value);
431 public static void WriteLine (int value)
433 stdout.WriteLine (value);
436 public static void WriteLine (long value)
438 stdout.WriteLine (value);
441 public static void WriteLine (object value)
443 stdout.WriteLine (value);
446 public static void WriteLine (float value)
448 stdout.WriteLine (value);
451 public static void WriteLine (string value)
453 stdout.WriteLine (value);
456 [CLSCompliant (false)]
457 public static void WriteLine (uint value)
459 stdout.WriteLine (value);
462 [CLSCompliant (false)]
463 public static void WriteLine (ulong value)
465 stdout.WriteLine (value);
468 public static void WriteLine (string format, object arg0)
470 stdout.WriteLine (format, arg0);
473 public static void WriteLine (string format, params object[] arg)
476 stdout.WriteLine (format);
478 stdout.WriteLine (format, arg);
481 public static void WriteLine (char[] buffer, int index, int count)
483 stdout.WriteLine (buffer, index, count);
486 public static void WriteLine (string format, object arg0, object arg1)
488 stdout.WriteLine (format, arg0, arg1);
491 public static void WriteLine (string format, object arg0, object arg1, object arg2)
493 stdout.WriteLine (format, arg0, arg1, arg2);
496 [CLSCompliant (false)]
497 public static void WriteLine (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
499 ArgIterator iter = new ArgIterator (__arglist);
500 int argCount = iter.GetRemainingCount();
502 object[] args = new object [argCount + 4];
507 for (int i = 0; i < argCount; i++) {
508 TypedReference typedRef = iter.GetNextArg ();
509 args [i + 4] = TypedReference.ToObject (typedRef);
512 stdout.WriteLine (String.Format (format, args));
516 public static int Read ()
518 if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
519 return ConsoleDriver.Read ();
521 return stdin.Read ();
525 public static string ReadLine ()
527 if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
528 return ConsoleDriver.ReadLine ();
530 return stdin.ReadLine ();
534 public static int Read ()
536 return stdin.Read ();
539 public static string ReadLine ()
541 return stdin.ReadLine ();
547 // FIXME: Console should use these encodings when changed
548 static Encoding inputEncoding;
549 static Encoding outputEncoding;
551 public static Encoding InputEncoding {
552 get { return inputEncoding; }
554 inputEncoding = value;
555 SetupStreams (inputEncoding, outputEncoding);
559 public static Encoding OutputEncoding {
560 get { return outputEncoding; }
562 outputEncoding = value;
563 SetupStreams (inputEncoding, outputEncoding);
567 public static ConsoleColor BackgroundColor {
568 get { return ConsoleDriver.BackgroundColor; }
569 set { ConsoleDriver.BackgroundColor = value; }
572 public static int BufferHeight {
573 get { return ConsoleDriver.BufferHeight; }
574 [MonoLimitation ("Implemented only on Windows")]
575 set { ConsoleDriver.BufferHeight = value; }
578 public static int BufferWidth {
579 get { return ConsoleDriver.BufferWidth; }
580 [MonoLimitation ("Implemented only on Windows")]
581 set { ConsoleDriver.BufferWidth = value; }
584 [MonoLimitation ("Implemented only on Windows")]
585 public static bool CapsLock {
586 get { return ConsoleDriver.CapsLock; }
589 public static int CursorLeft {
590 get { return ConsoleDriver.CursorLeft; }
591 set { ConsoleDriver.CursorLeft = value; }
594 public static int CursorTop {
595 get { return ConsoleDriver.CursorTop; }
596 set { ConsoleDriver.CursorTop = value; }
599 public static int CursorSize {
600 get { return ConsoleDriver.CursorSize; }
601 set { ConsoleDriver.CursorSize = value; }
604 public static bool CursorVisible {
605 get { return ConsoleDriver.CursorVisible; }
606 set { ConsoleDriver.CursorVisible = value; }
609 public static ConsoleColor ForegroundColor {
610 get { return ConsoleDriver.ForegroundColor; }
611 set { ConsoleDriver.ForegroundColor = value; }
614 public static bool KeyAvailable {
615 get { return ConsoleDriver.KeyAvailable; }
618 public static int LargestWindowHeight {
619 get { return ConsoleDriver.LargestWindowHeight; }
622 public static int LargestWindowWidth {
623 get { return ConsoleDriver.LargestWindowWidth; }
626 [MonoLimitation ("Only works on windows")]
627 public static bool NumberLock {
628 get { return ConsoleDriver.NumberLock; }
631 public static string Title {
632 get { return ConsoleDriver.Title; }
633 set { ConsoleDriver.Title = value; }
636 public static bool TreatControlCAsInput {
637 get { return ConsoleDriver.TreatControlCAsInput; }
638 set { ConsoleDriver.TreatControlCAsInput = value; }
641 [MonoLimitation ("Only works on windows")]
642 public static int WindowHeight {
643 get { return ConsoleDriver.WindowHeight; }
644 set { ConsoleDriver.WindowHeight = value; }
647 [MonoLimitation ("Only works on windows")]
648 public static int WindowLeft {
649 get { return ConsoleDriver.WindowLeft; }
650 set { ConsoleDriver.WindowLeft = value; }
653 [MonoLimitation ("Only works on windows")]
654 public static int WindowTop {
655 get { return ConsoleDriver.WindowTop; }
656 set { ConsoleDriver.WindowTop = value; }
659 [MonoLimitation ("Only works on windows")]
660 public static int WindowWidth {
661 get { return ConsoleDriver.WindowWidth; }
662 set { ConsoleDriver.WindowWidth = value; }
665 public static bool IsErrorRedirected {
667 return ConsoleDriver.IsErrorRedirected;
671 public static bool IsOutputRedirected {
673 return ConsoleDriver.IsOutputRedirected;
677 public static bool IsInputRedirected {
679 return ConsoleDriver.IsInputRedirected;
683 public static void Beep ()
688 public static void Beep (int frequency, int duration)
690 if (frequency < 37 || frequency > 32767)
691 throw new ArgumentOutOfRangeException ("frequency");
694 throw new ArgumentOutOfRangeException ("duration");
696 ConsoleDriver.Beep (frequency, duration);
699 public static void Clear ()
701 ConsoleDriver.Clear ();
704 [MonoLimitation ("Implemented only on Windows")]
705 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
706 int targetLeft, int targetTop)
708 ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop);
711 [MonoLimitation ("Implemented only on Windows")]
712 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
713 int targetLeft, int targetTop, Char sourceChar,
714 ConsoleColor sourceForeColor, ConsoleColor sourceBackColor)
716 ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop,
717 sourceChar, sourceForeColor, sourceBackColor);
720 public static ConsoleKeyInfo ReadKey ()
722 return ReadKey (false);
725 public static ConsoleKeyInfo ReadKey (bool intercept)
727 return ConsoleDriver.ReadKey (intercept);
730 public static void ResetColor ()
732 ConsoleDriver.ResetColor ();
735 [MonoLimitation ("Only works on windows")]
736 public static void SetBufferSize (int width, int height)
738 ConsoleDriver.SetBufferSize (width, height);
741 public static void SetCursorPosition (int left, int top)
743 ConsoleDriver.SetCursorPosition (left, top);
746 public static void SetWindowPosition (int left, int top)
748 ConsoleDriver.SetWindowPosition (left, top);
751 public static void SetWindowSize (int width, int height)
753 ConsoleDriver.SetWindowSize (width, height);
756 static ConsoleCancelEventHandler cancel_event;
757 public static event ConsoleCancelEventHandler CancelKeyPress {
759 if (ConsoleDriver.Initialized == false)
760 ConsoleDriver.Init ();
762 cancel_event += value;
764 if (Environment.IsRunningOnWindows && !WindowsConsole.ctrlHandlerAdded)
765 WindowsConsole.AddCtrlHandler();
768 if (ConsoleDriver.Initialized == false)
769 ConsoleDriver.Init ();
771 cancel_event -= value;
773 if (cancel_event == null && Environment.IsRunningOnWindows)
775 // Need to remove our hook if there's nothing left in the event
776 if (WindowsConsole.ctrlHandlerAdded)
777 WindowsConsole.RemoveCtrlHandler();
782 delegate void InternalCancelHandler ();
784 #pragma warning disable 414
786 // Used by console-io.c
788 static readonly InternalCancelHandler cancel_handler = new InternalCancelHandler (DoConsoleCancelEvent);
789 #pragma warning restore 414
791 internal static void DoConsoleCancelEvent ()
794 if (cancel_event != null) {
795 ConsoleCancelEventArgs args = new ConsoleCancelEventArgs (ConsoleSpecialKey.ControlC);
796 Delegate [] delegates = cancel_event.GetInvocationList ();
797 foreach (ConsoleCancelEventHandler d in delegates){
799 // Sender is always null here.
801 } catch {} // Ignore any exception.
807 Environment.Exit (58);