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 stdin = new CStreamReader (OpenStandardInput (0), inputEncoding);
145 stdout = TextWriter.Synchronized (new CStreamWriter (OpenStandardOutput (0), outputEncoding, true) { AutoFlush = true });
146 stderr = TextWriter.Synchronized (new CStreamWriter (OpenStandardError (0), outputEncoding, true) { AutoFlush = true });
150 stdin = TextReader.Synchronized (new UnexceptionalStreamReader (OpenStandardInput (0), inputEncoding));
153 stdout = new NSLogWriter ();
154 stderr = new NSLogWriter ();
156 stdout = TextWriter.Synchronized (new UnexceptionalStreamWriter (OpenStandardOutput (0), outputEncoding) { AutoFlush = true });
157 stderr = TextWriter.Synchronized (new UnexceptionalStreamWriter (OpenStandardError (0), outputEncoding) { AutoFlush = true });
160 if (LogcatTextWriter.IsRunningOnAndroid ()) {
161 stdout = TextWriter.Synchronized (new LogcatTextWriter ("mono-stdout", stdout));
162 stderr = TextWriter.Synchronized (new LogcatTextWriter ("mono-stderr", stderr));
168 GC.SuppressFinalize (stdout);
169 GC.SuppressFinalize (stderr);
170 GC.SuppressFinalize (stdin);
173 public static TextWriter Error {
179 public static TextWriter Out {
185 public static TextReader In {
191 private static Stream Open (IntPtr handle, FileAccess access, int bufferSize)
194 // TODO: Should use __ConsoleStream from reference sources
195 return new FileStream (handle, access, false, bufferSize, false, true);
196 } catch (IOException) {
201 public static Stream OpenStandardError ()
203 return OpenStandardError (0);
206 // calling any FileStream constructor with a handle normally
207 // requires permissions UnmanagedCode permissions. In this
208 // case we assert this permission so the console can be used
209 // in partial trust (i.e. without having UnmanagedCode).
210 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
211 public static Stream OpenStandardError (int bufferSize)
213 return Open (MonoIO.ConsoleError, FileAccess.Write, bufferSize);
216 public static Stream OpenStandardInput ()
218 return OpenStandardInput (0);
221 // calling any FileStream constructor with a handle normally
222 // requires permissions UnmanagedCode permissions. In this
223 // case we assert this permission so the console can be used
224 // in partial trust (i.e. without having UnmanagedCode).
225 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
226 public static Stream OpenStandardInput (int bufferSize)
228 return Open (MonoIO.ConsoleInput, FileAccess.Read, bufferSize);
231 public static Stream OpenStandardOutput ()
233 return OpenStandardOutput (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 OpenStandardOutput (int bufferSize)
243 return Open (MonoIO.ConsoleOutput, FileAccess.Write, bufferSize);
246 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
247 public static void SetError (TextWriter newError)
249 if (newError == null)
250 throw new ArgumentNullException ("newError");
255 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
256 public static void SetIn (TextReader newIn)
259 throw new ArgumentNullException ("newIn");
264 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
265 public static void SetOut (TextWriter newOut)
268 throw new ArgumentNullException ("newOut");
273 public static void Write (bool value)
275 stdout.Write (value);
278 public static void Write (char value)
280 stdout.Write (value);
283 public static void Write (char[] buffer)
285 stdout.Write (buffer);
288 public static void Write (decimal value)
290 stdout.Write (value);
293 public static void Write (double value)
295 stdout.Write (value);
298 public static void Write (int value)
300 stdout.Write (value);
303 public static void Write (long value)
305 stdout.Write (value);
308 public static void Write (object value)
310 stdout.Write (value);
313 public static void Write (float value)
315 stdout.Write (value);
318 public static void Write (string value)
320 stdout.Write (value);
323 [CLSCompliant (false)]
324 public static void Write (uint value)
326 stdout.Write (value);
329 [CLSCompliant (false)]
330 public static void Write (ulong value)
332 stdout.Write (value);
335 public static void Write (string format, object arg0)
337 stdout.Write (format, arg0);
340 public static void Write (string format, params object[] arg)
343 stdout.Write (format);
345 stdout.Write (format, arg);
348 public static void Write (char[] buffer, int index, int count)
350 stdout.Write (buffer, index, count);
353 public static void Write (string format, object arg0, object arg1)
355 stdout.Write (format, arg0, arg1);
358 public static void Write (string format, object arg0, object arg1, object arg2 )
360 stdout.Write (format, arg0, arg1, arg2);
363 [CLSCompliant (false)]
364 public static void Write (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
366 ArgIterator iter = new ArgIterator (__arglist);
367 int argCount = iter.GetRemainingCount();
369 object[] args = new object [argCount + 4];
374 for (int i = 0; i < argCount; i++) {
375 TypedReference typedRef = iter.GetNextArg ();
376 args [i + 4] = TypedReference.ToObject (typedRef);
379 stdout.Write (String.Format (format, args));
382 public static void WriteLine ()
387 public static void WriteLine (bool value)
389 stdout.WriteLine (value);
392 public static void WriteLine (char value)
394 stdout.WriteLine (value);
397 public static void WriteLine (char[] buffer)
399 stdout.WriteLine (buffer);
402 public static void WriteLine (decimal value)
404 stdout.WriteLine (value);
407 public static void WriteLine (double value)
409 stdout.WriteLine (value);
412 public static void WriteLine (int value)
414 stdout.WriteLine (value);
417 public static void WriteLine (long value)
419 stdout.WriteLine (value);
422 public static void WriteLine (object value)
424 stdout.WriteLine (value);
427 public static void WriteLine (float value)
429 stdout.WriteLine (value);
432 public static void WriteLine (string value)
434 stdout.WriteLine (value);
437 [CLSCompliant (false)]
438 public static void WriteLine (uint value)
440 stdout.WriteLine (value);
443 [CLSCompliant (false)]
444 public static void WriteLine (ulong value)
446 stdout.WriteLine (value);
449 public static void WriteLine (string format, object arg0)
451 stdout.WriteLine (format, arg0);
454 public static void WriteLine (string format, params object[] arg)
457 stdout.WriteLine (format);
459 stdout.WriteLine (format, arg);
462 public static void WriteLine (char[] buffer, int index, int count)
464 stdout.WriteLine (buffer, index, count);
467 public static void WriteLine (string format, object arg0, object arg1)
469 stdout.WriteLine (format, arg0, arg1);
472 public static void WriteLine (string format, object arg0, object arg1, object arg2)
474 stdout.WriteLine (format, arg0, arg1, arg2);
477 [CLSCompliant (false)]
478 public static void WriteLine (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
480 ArgIterator iter = new ArgIterator (__arglist);
481 int argCount = iter.GetRemainingCount();
483 object[] args = new object [argCount + 4];
488 for (int i = 0; i < argCount; i++) {
489 TypedReference typedRef = iter.GetNextArg ();
490 args [i + 4] = TypedReference.ToObject (typedRef);
493 stdout.WriteLine (String.Format (format, args));
497 public static int Read ()
499 if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
500 return ConsoleDriver.Read ();
502 return stdin.Read ();
506 public static string ReadLine ()
508 if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
509 return ConsoleDriver.ReadLine ();
511 return stdin.ReadLine ();
515 public static int Read ()
517 return stdin.Read ();
520 public static string ReadLine ()
522 return stdin.ReadLine ();
528 // FIXME: Console should use these encodings when changed
529 static Encoding inputEncoding;
530 static Encoding outputEncoding;
532 public static Encoding InputEncoding {
533 get { return inputEncoding; }
535 inputEncoding = value;
536 SetupStreams (inputEncoding, outputEncoding);
540 public static Encoding OutputEncoding {
541 get { return outputEncoding; }
543 outputEncoding = value;
544 SetupStreams (inputEncoding, outputEncoding);
548 public static ConsoleColor BackgroundColor {
549 get { return ConsoleDriver.BackgroundColor; }
550 set { ConsoleDriver.BackgroundColor = value; }
553 public static int BufferHeight {
554 get { return ConsoleDriver.BufferHeight; }
555 [MonoLimitation ("Implemented only on Windows")]
556 set { ConsoleDriver.BufferHeight = value; }
559 public static int BufferWidth {
560 get { return ConsoleDriver.BufferWidth; }
561 [MonoLimitation ("Implemented only on Windows")]
562 set { ConsoleDriver.BufferWidth = value; }
565 [MonoLimitation ("Implemented only on Windows")]
566 public static bool CapsLock {
567 get { return ConsoleDriver.CapsLock; }
570 public static int CursorLeft {
571 get { return ConsoleDriver.CursorLeft; }
572 set { ConsoleDriver.CursorLeft = value; }
575 public static int CursorTop {
576 get { return ConsoleDriver.CursorTop; }
577 set { ConsoleDriver.CursorTop = value; }
580 public static int CursorSize {
581 get { return ConsoleDriver.CursorSize; }
582 set { ConsoleDriver.CursorSize = value; }
585 public static bool CursorVisible {
586 get { return ConsoleDriver.CursorVisible; }
587 set { ConsoleDriver.CursorVisible = value; }
590 public static ConsoleColor ForegroundColor {
591 get { return ConsoleDriver.ForegroundColor; }
592 set { ConsoleDriver.ForegroundColor = value; }
595 public static bool KeyAvailable {
596 get { return ConsoleDriver.KeyAvailable; }
599 public static int LargestWindowHeight {
600 get { return ConsoleDriver.LargestWindowHeight; }
603 public static int LargestWindowWidth {
604 get { return ConsoleDriver.LargestWindowWidth; }
607 [MonoLimitation ("Only works on windows")]
608 public static bool NumberLock {
609 get { return ConsoleDriver.NumberLock; }
612 public static string Title {
613 get { return ConsoleDriver.Title; }
614 set { ConsoleDriver.Title = value; }
617 public static bool TreatControlCAsInput {
618 get { return ConsoleDriver.TreatControlCAsInput; }
619 set { ConsoleDriver.TreatControlCAsInput = value; }
622 [MonoLimitation ("Only works on windows")]
623 public static int WindowHeight {
624 get { return ConsoleDriver.WindowHeight; }
625 set { ConsoleDriver.WindowHeight = value; }
628 [MonoLimitation ("Only works on windows")]
629 public static int WindowLeft {
630 get { return ConsoleDriver.WindowLeft; }
631 set { ConsoleDriver.WindowLeft = value; }
634 [MonoLimitation ("Only works on windows")]
635 public static int WindowTop {
636 get { return ConsoleDriver.WindowTop; }
637 set { ConsoleDriver.WindowTop = value; }
640 [MonoLimitation ("Only works on windows")]
641 public static int WindowWidth {
642 get { return ConsoleDriver.WindowWidth; }
643 set { ConsoleDriver.WindowWidth = value; }
646 public static bool IsErrorRedirected {
648 return ConsoleDriver.IsErrorRedirected;
652 public static bool IsOutputRedirected {
654 return ConsoleDriver.IsOutputRedirected;
658 public static bool IsInputRedirected {
660 return ConsoleDriver.IsInputRedirected;
664 public static void Beep ()
669 public static void Beep (int frequency, int duration)
671 if (frequency < 37 || frequency > 32767)
672 throw new ArgumentOutOfRangeException ("frequency");
675 throw new ArgumentOutOfRangeException ("duration");
677 ConsoleDriver.Beep (frequency, duration);
680 public static void Clear ()
682 ConsoleDriver.Clear ();
685 [MonoLimitation ("Implemented only on Windows")]
686 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
687 int targetLeft, int targetTop)
689 ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop);
692 [MonoLimitation ("Implemented only on Windows")]
693 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
694 int targetLeft, int targetTop, Char sourceChar,
695 ConsoleColor sourceForeColor, ConsoleColor sourceBackColor)
697 ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop,
698 sourceChar, sourceForeColor, sourceBackColor);
701 public static ConsoleKeyInfo ReadKey ()
703 return ReadKey (false);
706 public static ConsoleKeyInfo ReadKey (bool intercept)
708 return ConsoleDriver.ReadKey (intercept);
711 public static void ResetColor ()
713 ConsoleDriver.ResetColor ();
716 [MonoLimitation ("Only works on windows")]
717 public static void SetBufferSize (int width, int height)
719 ConsoleDriver.SetBufferSize (width, height);
722 public static void SetCursorPosition (int left, int top)
724 ConsoleDriver.SetCursorPosition (left, top);
727 public static void SetWindowPosition (int left, int top)
729 ConsoleDriver.SetWindowPosition (left, top);
732 public static void SetWindowSize (int width, int height)
734 ConsoleDriver.SetWindowSize (width, height);
737 static ConsoleCancelEventHandler cancel_event;
738 public static event ConsoleCancelEventHandler CancelKeyPress {
740 if (ConsoleDriver.Initialized == false)
741 ConsoleDriver.Init ();
743 cancel_event += value;
745 if (Environment.IsRunningOnWindows && !WindowsConsole.ctrlHandlerAdded)
746 WindowsConsole.AddCtrlHandler();
749 if (ConsoleDriver.Initialized == false)
750 ConsoleDriver.Init ();
752 cancel_event -= value;
754 if (cancel_event == null && Environment.IsRunningOnWindows)
756 // Need to remove our hook if there's nothing left in the event
757 if (WindowsConsole.ctrlHandlerAdded)
758 WindowsConsole.RemoveCtrlHandler();
763 delegate void InternalCancelHandler ();
765 #pragma warning disable 414
767 // Used by console-io.c
769 static readonly InternalCancelHandler cancel_handler = new InternalCancelHandler (DoConsoleCancelEvent);
770 #pragma warning restore 414
772 internal static void DoConsoleCancelEvent ()
775 if (cancel_event != null) {
776 ConsoleCancelEventArgs args = new ConsoleCancelEventArgs (ConsoleSpecialKey.ControlC);
777 Delegate [] delegates = cancel_event.GetInvocationList ();
778 foreach (ConsoleCancelEventHandler d in delegates){
780 // Sender is always null here.
782 } catch {} // Ignore any exception.
788 Environment.Exit (58);