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;
99 if (Environment.IsRunningOnWindows) {
101 // On Windows, follow the Windows tradition
104 // should never happen since Moonlight does not run on windows
105 inputEncoding = outputEncoding = Encoding.Default;
108 inputEncoding = Encoding.GetEncoding (WindowsConsole.GetInputCodePage ());
109 outputEncoding = Encoding.GetEncoding (WindowsConsole.GetOutputCodePage ());
110 // ArgumentException and NotSupportedException can be thrown as well
112 // FIXME: I18N assemblies are not available when compiling mcs
113 // Use Latin 1 as it is fast and UTF-8 is never used as console code page
114 inputEncoding = outputEncoding = Encoding.Default;
119 // On Unix systems (128), do not output the
120 // UTF-8 ZWNBSP (zero-width non-breaking space).
123 EncodingHelper.InternalCodePage (ref code_page);
125 if (code_page != -1 && ((code_page & 0x0fffffff) == 3 // UTF8Encoding.UTF8_CODE_PAGE
126 || ((code_page & 0x10000000) != 0)))
127 inputEncoding = outputEncoding = EncodingHelper.UTF8Unmarked;
129 inputEncoding = outputEncoding = Encoding.Default;
132 SetupStreams (inputEncoding, outputEncoding);
135 static void SetupStreams (Encoding inputEncoding, Encoding outputEncoding)
138 if (!Environment.IsRunningOnWindows && ConsoleDriver.IsConsole) {
139 stdin = new CStreamReader (OpenStandardInput (0), inputEncoding);
140 stdout = TextWriter.Synchronized (new CStreamWriter (OpenStandardOutput (0), outputEncoding, true) { AutoFlush = true });
141 stderr = TextWriter.Synchronized (new CStreamWriter (OpenStandardError (0), outputEncoding, true) { AutoFlush = true });
145 stdin = TextReader.Synchronized (new UnexceptionalStreamReader (OpenStandardInput (0), inputEncoding));
148 stdout = new NSLogWriter ();
149 stderr = new NSLogWriter ();
151 stdout = TextWriter.Synchronized (new UnexceptionalStreamWriter (OpenStandardOutput (0), outputEncoding) { AutoFlush = true });
152 stderr = TextWriter.Synchronized (new UnexceptionalStreamWriter (OpenStandardError (0), outputEncoding) { AutoFlush = true });
155 if (LogcatTextWriter.IsRunningOnAndroid ()) {
156 stdout = TextWriter.Synchronized (new LogcatTextWriter ("mono-stdout", stdout));
157 stderr = TextWriter.Synchronized (new LogcatTextWriter ("mono-stderr", stderr));
163 GC.SuppressFinalize (stdout);
164 GC.SuppressFinalize (stderr);
165 GC.SuppressFinalize (stdin);
168 public static TextWriter Error {
174 public static TextWriter Out {
180 public static TextReader In {
186 private static Stream Open (IntPtr handle, FileAccess access, int bufferSize)
189 // TODO: Should use __ConsoleStream from reference sources
190 return new FileStream (handle, access, false, bufferSize, false, true);
191 } catch (IOException) {
196 public static Stream OpenStandardError ()
198 return OpenStandardError (0);
201 // calling any FileStream constructor with a handle normally
202 // requires permissions UnmanagedCode permissions. In this
203 // case we assert this permission so the console can be used
204 // in partial trust (i.e. without having UnmanagedCode).
205 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
206 public static Stream OpenStandardError (int bufferSize)
208 return Open (MonoIO.ConsoleError, FileAccess.Write, bufferSize);
211 public static Stream OpenStandardInput ()
213 return OpenStandardInput (0);
216 // calling any FileStream constructor with a handle normally
217 // requires permissions UnmanagedCode permissions. In this
218 // case we assert this permission so the console can be used
219 // in partial trust (i.e. without having UnmanagedCode).
220 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
221 public static Stream OpenStandardInput (int bufferSize)
223 return Open (MonoIO.ConsoleInput, FileAccess.Read, bufferSize);
226 public static Stream OpenStandardOutput ()
228 return OpenStandardOutput (0);
231 // calling any FileStream constructor with a handle normally
232 // requires permissions UnmanagedCode permissions. In this
233 // case we assert this permission so the console can be used
234 // in partial trust (i.e. without having UnmanagedCode).
235 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
236 public static Stream OpenStandardOutput (int bufferSize)
238 return Open (MonoIO.ConsoleOutput, FileAccess.Write, bufferSize);
241 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
242 public static void SetError (TextWriter newError)
244 if (newError == null)
245 throw new ArgumentNullException ("newError");
250 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
251 public static void SetIn (TextReader newIn)
254 throw new ArgumentNullException ("newIn");
259 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
260 public static void SetOut (TextWriter newOut)
263 throw new ArgumentNullException ("newOut");
268 public static void Write (bool value)
270 stdout.Write (value);
273 public static void Write (char value)
275 stdout.Write (value);
278 public static void Write (char[] buffer)
280 stdout.Write (buffer);
283 public static void Write (decimal value)
285 stdout.Write (value);
288 public static void Write (double value)
290 stdout.Write (value);
293 public static void Write (int value)
295 stdout.Write (value);
298 public static void Write (long value)
300 stdout.Write (value);
303 public static void Write (object value)
305 stdout.Write (value);
308 public static void Write (float value)
310 stdout.Write (value);
313 public static void Write (string value)
315 stdout.Write (value);
318 [CLSCompliant (false)]
319 public static void Write (uint value)
321 stdout.Write (value);
324 [CLSCompliant (false)]
325 public static void Write (ulong value)
327 stdout.Write (value);
330 public static void Write (string format, object arg0)
332 stdout.Write (format, arg0);
335 public static void Write (string format, params object[] arg)
338 stdout.Write (format);
340 stdout.Write (format, arg);
343 public static void Write (char[] buffer, int index, int count)
345 stdout.Write (buffer, index, count);
348 public static void Write (string format, object arg0, object arg1)
350 stdout.Write (format, arg0, arg1);
353 public static void Write (string format, object arg0, object arg1, object arg2 )
355 stdout.Write (format, arg0, arg1, arg2);
358 [CLSCompliant (false)]
359 public static void Write (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
361 ArgIterator iter = new ArgIterator (__arglist);
362 int argCount = iter.GetRemainingCount();
364 object[] args = new object [argCount + 4];
369 for (int i = 0; i < argCount; i++) {
370 TypedReference typedRef = iter.GetNextArg ();
371 args [i + 4] = TypedReference.ToObject (typedRef);
374 stdout.Write (String.Format (format, args));
377 public static void WriteLine ()
382 public static void WriteLine (bool value)
384 stdout.WriteLine (value);
387 public static void WriteLine (char value)
389 stdout.WriteLine (value);
392 public static void WriteLine (char[] buffer)
394 stdout.WriteLine (buffer);
397 public static void WriteLine (decimal value)
399 stdout.WriteLine (value);
402 public static void WriteLine (double value)
404 stdout.WriteLine (value);
407 public static void WriteLine (int value)
409 stdout.WriteLine (value);
412 public static void WriteLine (long value)
414 stdout.WriteLine (value);
417 public static void WriteLine (object value)
419 stdout.WriteLine (value);
422 public static void WriteLine (float value)
424 stdout.WriteLine (value);
427 public static void WriteLine (string value)
429 stdout.WriteLine (value);
432 [CLSCompliant (false)]
433 public static void WriteLine (uint value)
435 stdout.WriteLine (value);
438 [CLSCompliant (false)]
439 public static void WriteLine (ulong value)
441 stdout.WriteLine (value);
444 public static void WriteLine (string format, object arg0)
446 stdout.WriteLine (format, arg0);
449 public static void WriteLine (string format, params object[] arg)
452 stdout.WriteLine (format);
454 stdout.WriteLine (format, arg);
457 public static void WriteLine (char[] buffer, int index, int count)
459 stdout.WriteLine (buffer, index, count);
462 public static void WriteLine (string format, object arg0, object arg1)
464 stdout.WriteLine (format, arg0, arg1);
467 public static void WriteLine (string format, object arg0, object arg1, object arg2)
469 stdout.WriteLine (format, arg0, arg1, arg2);
472 [CLSCompliant (false)]
473 public static void WriteLine (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
475 ArgIterator iter = new ArgIterator (__arglist);
476 int argCount = iter.GetRemainingCount();
478 object[] args = new object [argCount + 4];
483 for (int i = 0; i < argCount; i++) {
484 TypedReference typedRef = iter.GetNextArg ();
485 args [i + 4] = TypedReference.ToObject (typedRef);
488 stdout.WriteLine (String.Format (format, args));
492 public static int Read ()
494 if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
495 return ConsoleDriver.Read ();
497 return stdin.Read ();
501 public static string ReadLine ()
503 if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
504 return ConsoleDriver.ReadLine ();
506 return stdin.ReadLine ();
510 public static int Read ()
512 return stdin.Read ();
515 public static string ReadLine ()
517 return stdin.ReadLine ();
522 // FIXME: Console should use these encodings when changed
523 static Encoding inputEncoding;
524 static Encoding outputEncoding;
526 public static Encoding InputEncoding {
527 get { return inputEncoding; }
529 inputEncoding = value;
530 SetupStreams (inputEncoding, outputEncoding);
534 public static Encoding OutputEncoding {
535 get { return outputEncoding; }
537 outputEncoding = value;
538 SetupStreams (inputEncoding, outputEncoding);
543 public static ConsoleColor BackgroundColor {
544 get { return ConsoleDriver.BackgroundColor; }
545 set { ConsoleDriver.BackgroundColor = value; }
548 public static int BufferHeight {
549 get { return ConsoleDriver.BufferHeight; }
550 [MonoLimitation ("Implemented only on Windows")]
551 set { ConsoleDriver.BufferHeight = value; }
554 public static int BufferWidth {
555 get { return ConsoleDriver.BufferWidth; }
556 [MonoLimitation ("Implemented only on Windows")]
557 set { ConsoleDriver.BufferWidth = value; }
560 [MonoLimitation ("Implemented only on Windows")]
561 public static bool CapsLock {
562 get { return ConsoleDriver.CapsLock; }
565 public static int CursorLeft {
566 get { return ConsoleDriver.CursorLeft; }
567 set { ConsoleDriver.CursorLeft = value; }
570 public static int CursorTop {
571 get { return ConsoleDriver.CursorTop; }
572 set { ConsoleDriver.CursorTop = value; }
575 public static int CursorSize {
576 get { return ConsoleDriver.CursorSize; }
577 set { ConsoleDriver.CursorSize = value; }
580 public static bool CursorVisible {
581 get { return ConsoleDriver.CursorVisible; }
582 set { ConsoleDriver.CursorVisible = value; }
585 public static ConsoleColor ForegroundColor {
586 get { return ConsoleDriver.ForegroundColor; }
587 set { ConsoleDriver.ForegroundColor = value; }
590 public static bool KeyAvailable {
591 get { return ConsoleDriver.KeyAvailable; }
594 public static int LargestWindowHeight {
595 get { return ConsoleDriver.LargestWindowHeight; }
598 public static int LargestWindowWidth {
599 get { return ConsoleDriver.LargestWindowWidth; }
602 [MonoLimitation ("Only works on windows")]
603 public static bool NumberLock {
604 get { return ConsoleDriver.NumberLock; }
607 public static string Title {
608 get { return ConsoleDriver.Title; }
609 set { ConsoleDriver.Title = value; }
612 public static bool TreatControlCAsInput {
613 get { return ConsoleDriver.TreatControlCAsInput; }
614 set { ConsoleDriver.TreatControlCAsInput = value; }
617 [MonoLimitation ("Only works on windows")]
618 public static int WindowHeight {
619 get { return ConsoleDriver.WindowHeight; }
620 set { ConsoleDriver.WindowHeight = value; }
623 [MonoLimitation ("Only works on windows")]
624 public static int WindowLeft {
625 get { return ConsoleDriver.WindowLeft; }
626 set { ConsoleDriver.WindowLeft = value; }
629 [MonoLimitation ("Only works on windows")]
630 public static int WindowTop {
631 get { return ConsoleDriver.WindowTop; }
632 set { ConsoleDriver.WindowTop = value; }
635 [MonoLimitation ("Only works on windows")]
636 public static int WindowWidth {
637 get { return ConsoleDriver.WindowWidth; }
638 set { ConsoleDriver.WindowWidth = value; }
641 public static bool IsErrorRedirected {
643 return ConsoleDriver.IsErrorRedirected;
647 public static bool IsOutputRedirected {
649 return ConsoleDriver.IsOutputRedirected;
653 public static bool IsInputRedirected {
655 return ConsoleDriver.IsInputRedirected;
659 public static void Beep ()
664 public static void Beep (int frequency, int duration)
666 if (frequency < 37 || frequency > 32767)
667 throw new ArgumentOutOfRangeException ("frequency");
670 throw new ArgumentOutOfRangeException ("duration");
672 ConsoleDriver.Beep (frequency, duration);
675 public static void Clear ()
677 ConsoleDriver.Clear ();
680 [MonoLimitation ("Implemented only on Windows")]
681 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
682 int targetLeft, int targetTop)
684 ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop);
687 [MonoLimitation ("Implemented only on Windows")]
688 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
689 int targetLeft, int targetTop, Char sourceChar,
690 ConsoleColor sourceForeColor, ConsoleColor sourceBackColor)
692 ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop,
693 sourceChar, sourceForeColor, sourceBackColor);
696 public static ConsoleKeyInfo ReadKey ()
698 return ReadKey (false);
701 public static ConsoleKeyInfo ReadKey (bool intercept)
703 return ConsoleDriver.ReadKey (intercept);
706 public static void ResetColor ()
708 ConsoleDriver.ResetColor ();
711 [MonoLimitation ("Only works on windows")]
712 public static void SetBufferSize (int width, int height)
714 ConsoleDriver.SetBufferSize (width, height);
717 public static void SetCursorPosition (int left, int top)
719 ConsoleDriver.SetCursorPosition (left, top);
722 public static void SetWindowPosition (int left, int top)
724 ConsoleDriver.SetWindowPosition (left, top);
727 public static void SetWindowSize (int width, int height)
729 ConsoleDriver.SetWindowSize (width, height);
732 static ConsoleCancelEventHandler cancel_event;
733 public static event ConsoleCancelEventHandler CancelKeyPress {
735 if (ConsoleDriver.Initialized == false)
736 ConsoleDriver.Init ();
738 cancel_event += value;
740 if (Environment.IsRunningOnWindows && !WindowsConsole.ctrlHandlerAdded)
741 WindowsConsole.AddCtrlHandler();
744 if (ConsoleDriver.Initialized == false)
745 ConsoleDriver.Init ();
747 cancel_event -= value;
749 if (cancel_event == null && Environment.IsRunningOnWindows)
751 // Need to remove our hook if there's nothing left in the event
752 if (WindowsConsole.ctrlHandlerAdded)
753 WindowsConsole.RemoveCtrlHandler();
758 delegate void InternalCancelHandler ();
760 #pragma warning disable 414
762 // Used by console-io.c
764 static readonly InternalCancelHandler cancel_handler = new InternalCancelHandler (DoConsoleCancelEvent);
765 #pragma warning restore 414
767 internal static void DoConsoleCancelEvent ()
770 if (cancel_event != null) {
771 ConsoleCancelEventArgs args = new ConsoleCancelEventArgs (ConsoleSpecialKey.ControlC);
772 Delegate [] delegates = cancel_event.GetInvocationList ();
773 foreach (ConsoleCancelEventHandler d in delegates){
775 // Sender is always null here.
777 } catch {} // Ignore any exception.
783 Environment.Exit (58);