X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FSystem%2FConsole.cs;h=fe0f229e396b169123983fdb3292b672d18c83d3;hb=e2b2d181084848f3c5dde2788370db1b79893c69;hp=c963158ce6109dae73bca6591df708a2e60ad61b;hpb=a54a7a5ad5187cbde76eddcbbf94050910d78fbc;p=mono.git diff --git a/mcs/class/corlib/System/Console.cs b/mcs/class/corlib/System/Console.cs index c963158ce61..fe0f229e396 100644 --- a/mcs/class/corlib/System/Console.cs +++ b/mcs/class/corlib/System/Console.cs @@ -29,29 +29,41 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System.Diagnostics; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Security; using System.Security.Permissions; using System.Text; namespace System { - public -#if NET_2_0 - static -#else - sealed -#endif - class Console + public static class Console { +#if !NET_2_1 private class WindowsConsole { + public static bool ctrlHandlerAdded = false; + private delegate bool WindowsCancelHandler (int keyCode); + private static WindowsCancelHandler cancelHandler = new WindowsCancelHandler (DoWindowsConsoleCancelEvent); + [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)] private static extern int GetConsoleCP (); [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)] private static extern int GetConsoleOutputCP (); + [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)] + private static extern bool SetConsoleCtrlHandler (WindowsCancelHandler handler, bool addHandler); + + // Only call the event handler if Control-C was pressed (code == 0), nothing else + private static bool DoWindowsConsoleCancelEvent (int keyCode) + { + if (keyCode == 0) + DoConsoleCancelEvent (); + return keyCode == 0; + } + [MethodImpl (MethodImplOptions.NoInlining)] public static int GetInputCodePage () { @@ -63,15 +75,34 @@ namespace System { return GetConsoleOutputCP (); } + + public static void AddCtrlHandler () + { + SetConsoleCtrlHandler (cancelHandler, true); + ctrlHandlerAdded = true; + } + + public static void RemoveCtrlHandler () + { + SetConsoleCtrlHandler (cancelHandler, false); + ctrlHandlerAdded = false; + } } +#endif - private static TextWriter stdout; + internal static TextWriter stdout; private static TextWriter stderr; private static TextReader stdin; +#if NET_4_5 + static TextWriter console_stdout; + static TextWriter console_stderr; + static TextReader console_stdin; +#endif + static Console () { -#if !NET_2_0 +#if NET_2_1 Encoding inputEncoding; Encoding outputEncoding; #endif @@ -80,6 +111,10 @@ namespace System // // On Windows, follow the Windows tradition // +#if NET_2_1 + // should never happen since Moonlight does not run on windows + inputEncoding = outputEncoding = Encoding.Default; +#else try { inputEncoding = Encoding.GetEncoding (WindowsConsole.GetInputCodePage ()); outputEncoding = Encoding.GetEncoding (WindowsConsole.GetOutputCodePage ()); @@ -87,8 +122,9 @@ namespace System } catch { // FIXME: I18N assemblies are not available when compiling mcs // Use Latin 1 as it is fast and UTF-8 is never used as console code page - inputEncoding = outputEncoding = Encoding.GetEncoding (28591); + inputEncoding = outputEncoding = Encoding.Default; } +#endif } else { // // On Unix systems (128), do not output the @@ -104,27 +140,65 @@ namespace System inputEncoding = outputEncoding = Encoding.Default; } - stderr = new UnexceptionalStreamWriter (OpenStandardError (0), outputEncoding); - ((StreamWriter)stderr).AutoFlush = true; - stderr = TextWriter.Synchronized (stderr, true); + SetupStreams (inputEncoding, outputEncoding); + } + + static void SetupStreams (Encoding inputEncoding, Encoding outputEncoding) + { +#if !NET_2_1 + if (!Environment.IsRunningOnWindows && ConsoleDriver.IsConsole) { + StreamWriter w = new CStreamWriter (OpenStandardOutput (0), outputEncoding); + w.AutoFlush = true; + stdout = TextWriter.Synchronized (w, true); + + w = new CStreamWriter (OpenStandardOutput (0), outputEncoding); + w.AutoFlush = true; + stderr = TextWriter.Synchronized (w, true); + + stdin = new CStreamReader (OpenStandardInput (0), inputEncoding); + } else { +#endif +#if FULL_AOT_RUNTIME + Type nslogwriter = Type.GetType ("MonoTouch.Foundation.NSLogWriter, monotouch, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"); + stdout = (TextWriter) Activator.CreateInstance (nslogwriter); +#else + stdout = new UnexceptionalStreamWriter (OpenStandardOutput (0), outputEncoding); + ((StreamWriter)stdout).AutoFlush = true; +#endif + stdout = TextWriter.Synchronized (stdout, true); + +#if FULL_AOT_RUNTIME + stderr = (TextWriter) Activator.CreateInstance (nslogwriter); +#else + stderr = new UnexceptionalStreamWriter (OpenStandardError (0), outputEncoding); + ((StreamWriter)stderr).AutoFlush = true; +#endif + stderr = TextWriter.Synchronized (stderr, true); + + stdin = new UnexceptionalStreamReader (OpenStandardInput (0), inputEncoding); + stdin = TextReader.Synchronized (stdin); +#if !NET_2_1 + } +#endif + +#if NET_4_5 + console_stderr = stderr; + console_stdout = stdout; + console_stdin = stdin; +#endif - stdout = new UnexceptionalStreamWriter (OpenStandardOutput (0), outputEncoding); - ((StreamWriter)stdout).AutoFlush = true; - stdout = TextWriter.Synchronized (stdout, true); +#if MONODROID + if (LogcatTextWriter.IsRunningOnAndroid ()) { + stdout = TextWriter.Synchronized (new LogcatTextWriter ("mono-stdout", stdout)); + stderr = TextWriter.Synchronized (new LogcatTextWriter ("mono-stderr", stderr)); + } +#endif // MONODROID - stdin = new UnexceptionalStreamReader (OpenStandardInput (0), inputEncoding); - stdin = TextReader.Synchronized (stdin); GC.SuppressFinalize (stdout); GC.SuppressFinalize (stderr); GC.SuppressFinalize (stdin); } -#if !NET_2_0 - private Console () - { - } -#endif - public static TextWriter Error { get { return stderr; @@ -143,23 +217,52 @@ namespace System } } +#if NET_4_5 + public static bool IsErrorRedirected { + get { + return stderr != console_stderr || ConsoleDriver.IsErrorRedirected; + } + } + + public static bool IsOutputRedirected { + get { + return stdout != console_stdout || ConsoleDriver.IsOutputRedirected; + } + } + + public static bool IsInputRedirected { + get { + return stdin != console_stdin || ConsoleDriver.IsInputRedirected; + } + } +#endif + + private static Stream Open (IntPtr handle, FileAccess access, int bufferSize) + { +#if MOONLIGHT + if (SecurityManager.SecurityEnabled && !Debugger.IsAttached && Environment.GetEnvironmentVariable ("MOONLIGHT_ENABLE_CONSOLE") == null) + return new NullStream (); +#endif + try { + return new FileStream (handle, access, false, bufferSize, false, bufferSize == 0); + } catch (IOException) { + return new NullStream (); + } + } + public static Stream OpenStandardError () { return OpenStandardError (0); } - // calling any FileStream constructor with an handle normally + // calling any FileStream constructor with a handle normally // requires permissions UnmanagedCode permissions. In this // case we assert this permission so the console can be used // in partial trust (i.e. without having UnmanagedCode). [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)] public static Stream OpenStandardError (int bufferSize) { - try { - return new FileStream (MonoIO.ConsoleError, FileAccess.Write, false, bufferSize, false, bufferSize == 0); - } catch (IOException) { - return new NullStream (); - } + return Open (MonoIO.ConsoleError, FileAccess.Write, bufferSize); } public static Stream OpenStandardInput () @@ -167,18 +270,14 @@ namespace System return OpenStandardInput (0); } - // calling any FileStream constructor with an handle normally + // calling any FileStream constructor with a handle normally // requires permissions UnmanagedCode permissions. In this // case we assert this permission so the console can be used // in partial trust (i.e. without having UnmanagedCode). [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)] public static Stream OpenStandardInput (int bufferSize) { - try { - return new FileStream (MonoIO.ConsoleInput, FileAccess.Read, false, bufferSize, false, bufferSize == 0); - } catch (IOException) { - return new NullStream (); - } + return Open (MonoIO.ConsoleInput, FileAccess.Read, bufferSize); } public static Stream OpenStandardOutput () @@ -186,18 +285,14 @@ namespace System return OpenStandardOutput (0); } - // calling any FileStream constructor with an handle normally + // calling any FileStream constructor with a handle normally // requires permissions UnmanagedCode permissions. In this // case we assert this permission so the console can be used // in partial trust (i.e. without having UnmanagedCode). [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)] public static Stream OpenStandardOutput (int bufferSize) { - try { - return new FileStream (MonoIO.ConsoleOutput, FileAccess.Write, false, bufferSize, false, bufferSize == 0); - } catch (IOException) { - return new NullStream (); - } + return Open (MonoIO.ConsoleOutput, FileAccess.Write, bufferSize); } [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)] @@ -237,9 +332,9 @@ namespace System stdout.Write (value); } - public static void Write (char[] value) + public static void Write (char[] buffer) { - stdout.Write (value); + stdout.Write (buffer); } public static void Write (decimal value) @@ -296,7 +391,10 @@ namespace System public static void Write (string format, params object[] arg) { - stdout.Write (format, arg); + if (arg == null) + stdout.Write (format); + else + stdout.Write (format, arg); } public static void Write (char[] buffer, int index, int count) @@ -314,7 +412,6 @@ namespace System stdout.Write (format, arg0, arg1, arg2); } -#if ! BOOTSTRAP_WITH_OLDLIB [CLSCompliant (false)] public static void Write (string format, object arg0, object arg1, object arg2, object arg3, __arglist) { @@ -333,7 +430,6 @@ namespace System stdout.Write (String.Format (format, args)); } -#endif public static void WriteLine () { @@ -350,9 +446,9 @@ namespace System stdout.WriteLine (value); } - public static void WriteLine (char[] value) + public static void WriteLine (char[] buffer) { - stdout.WriteLine (value); + stdout.WriteLine (buffer); } public static void WriteLine (decimal value) @@ -409,7 +505,10 @@ namespace System public static void WriteLine (string format, params object[] arg) { - stdout.WriteLine (format, arg); + if (arg == null) + stdout.WriteLine (format); + else + stdout.WriteLine (format, arg); } public static void WriteLine (char[] buffer, int index, int count) @@ -427,7 +526,6 @@ namespace System stdout.WriteLine (format, arg0, arg1, arg2); } -#if ! BOOTSTRAP_WITH_OLDLIB [CLSCompliant (false)] public static void WriteLine (string format, object arg0, object arg1, object arg2, object arg3, __arglist) { @@ -446,29 +544,31 @@ namespace System stdout.WriteLine (String.Format (format, args)); } -#endif +#if !NET_2_1 public static int Read () { - return stdin.Read (); + if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) { + return ConsoleDriver.Read (); + } else { + return stdin.Read (); + } } -#if NET_2_0 public static string ReadLine () { - bool prevEcho = false; - if (ConsoleDriver.Initialized) { - prevEcho = ConsoleDriver.Echo; - ConsoleDriver.Echo = true; + if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) { + return ConsoleDriver.ReadLine (); + } else { + return stdin.ReadLine (); } - - string ret = stdin.ReadLine (); - if (ConsoleDriver.Initialized) - ConsoleDriver.Echo = prevEcho; - - return ret; } #else + public static int Read () + { + return stdin.Read (); + } + public static string ReadLine () { return stdin.ReadLine (); @@ -476,19 +576,25 @@ namespace System #endif -#if NET_2_0 +#if !NET_2_1 // FIXME: Console should use these encodings when changed static Encoding inputEncoding; static Encoding outputEncoding; public static Encoding InputEncoding { get { return inputEncoding; } - set { inputEncoding = value; } + set { + inputEncoding = value; + SetupStreams (inputEncoding, outputEncoding); + } } public static Encoding OutputEncoding { get { return outputEncoding; } - set { outputEncoding = value; } + set { + outputEncoding = value; + SetupStreams (inputEncoding, outputEncoding); + } } public static ConsoleColor BackgroundColor { @@ -498,14 +604,21 @@ namespace System public static int BufferHeight { get { return ConsoleDriver.BufferHeight; } + [MonoLimitation ("Implemented only on Windows")] set { ConsoleDriver.BufferHeight = value; } } public static int BufferWidth { get { return ConsoleDriver.BufferWidth; } + [MonoLimitation ("Implemented only on Windows")] set { ConsoleDriver.BufferWidth = value; } } + [MonoLimitation ("Implemented only on Windows")] + public static bool CapsLock { + get { return ConsoleDriver.CapsLock; } + } + public static int CursorLeft { get { return ConsoleDriver.CursorLeft; } set { ConsoleDriver.CursorLeft = value; } @@ -516,6 +629,11 @@ namespace System set { ConsoleDriver.CursorTop = value; } } + public static int CursorSize { + get { return ConsoleDriver.CursorSize; } + set { ConsoleDriver.CursorSize = value; } + } + public static bool CursorVisible { get { return ConsoleDriver.CursorVisible; } set { ConsoleDriver.CursorVisible = value; } @@ -530,6 +648,19 @@ namespace System get { return ConsoleDriver.KeyAvailable; } } + public static int LargestWindowHeight { + get { return ConsoleDriver.LargestWindowHeight; } + } + + public static int LargestWindowWidth { + get { return ConsoleDriver.LargestWindowWidth; } + } + + [MonoLimitation ("Only works on windows")] + public static bool NumberLock { + get { return ConsoleDriver.NumberLock; } + } + public static string Title { get { return ConsoleDriver.Title; } set { ConsoleDriver.Title = value; } @@ -540,21 +671,25 @@ namespace System set { ConsoleDriver.TreatControlCAsInput = value; } } + [MonoLimitation ("Only works on windows")] public static int WindowHeight { get { return ConsoleDriver.WindowHeight; } set { ConsoleDriver.WindowHeight = value; } } + [MonoLimitation ("Only works on windows")] public static int WindowLeft { get { return ConsoleDriver.WindowLeft; } set { ConsoleDriver.WindowLeft = value; } } + [MonoLimitation ("Only works on windows")] public static int WindowTop { get { return ConsoleDriver.WindowTop; } set { ConsoleDriver.WindowTop = value; } } + [MonoLimitation ("Only works on windows")] public static int WindowWidth { get { return ConsoleDriver.WindowWidth; } set { ConsoleDriver.WindowWidth = value; } @@ -581,19 +716,20 @@ namespace System ConsoleDriver.Clear (); } - [MonoTODO] + [MonoLimitation ("Implemented only on Windows")] public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight, int targetLeft, int targetTop) { - throw new NotImplementedException (); + ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop); } - [MonoTODO] + [MonoLimitation ("Implemented only on Windows")] public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight, int targetLeft, int targetTop, Char sourceChar, ConsoleColor sourceForeColor, ConsoleColor sourceBackColor) { - throw new NotImplementedException (); + ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop, + sourceChar, sourceForeColor, sourceBackColor); } public static ConsoleKeyInfo ReadKey () @@ -611,6 +747,7 @@ namespace System ConsoleDriver.ResetColor (); } + [MonoLimitation ("Only works on windows")] public static void SetBufferSize (int width, int height) { ConsoleDriver.SetBufferSize (width, height); @@ -631,8 +768,60 @@ namespace System ConsoleDriver.SetWindowSize (width, height); } - [MonoTODO ("Implement add/remove hooks")] - public static event ConsoleCancelEventHandler CancelKeyPress; + static ConsoleCancelEventHandler cancel_event; + public static event ConsoleCancelEventHandler CancelKeyPress { + add { + if (ConsoleDriver.Initialized == false) + ConsoleDriver.Init (); + + cancel_event += value; + + if (Environment.IsRunningOnWindows && !WindowsConsole.ctrlHandlerAdded) + WindowsConsole.AddCtrlHandler(); + } + remove { + if (ConsoleDriver.Initialized == false) + ConsoleDriver.Init (); + + cancel_event -= value; + + if (cancel_event == null && Environment.IsRunningOnWindows) + { + // Need to remove our hook if there's nothing left in the event + if (WindowsConsole.ctrlHandlerAdded) + WindowsConsole.RemoveCtrlHandler(); + } + } + } + + delegate void InternalCancelHandler (); + +#pragma warning disable 414 + // + // Used by console-io.c + // + static readonly InternalCancelHandler cancel_handler = new InternalCancelHandler (DoConsoleCancelEvent); +#pragma warning restore 414 + + internal static void DoConsoleCancelEvent () + { + bool exit = true; + if (cancel_event != null) { + ConsoleCancelEventArgs args = new ConsoleCancelEventArgs (ConsoleSpecialKey.ControlC); + Delegate [] delegates = cancel_event.GetInvocationList (); + foreach (ConsoleCancelEventHandler d in delegates){ + try { + // Sender is always null here. + d (null, args); + } catch {} // Ignore any exception. + } + exit = !args.Cancel; + } + + if (exit) + Environment.Exit (58); + } #endif } } +