Merge pull request #2152 from joelmartinez/mdoc-preserver
[mono.git] / mcs / class / corlib / System / Console.cs
1 //
2 // System.Console.cs
3 //
4 // Author:
5 //      Dietmar Maurer (dietmar@ximian.com)
6 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //
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)
11
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:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
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.
30 //
31
32 using System.Diagnostics;
33 using System.IO;
34 using System.Runtime.CompilerServices;
35 using System.Runtime.InteropServices;
36 using System.Security;
37 using System.Security.Permissions;
38 using System.Text;
39
40 namespace System
41 {
42         public static partial class Console
43         {
44 #if !NET_2_1
45                 private class WindowsConsole
46                 {
47                         public static bool ctrlHandlerAdded = false;
48                         private delegate bool WindowsCancelHandler (int keyCode);
49                         private static WindowsCancelHandler cancelHandler = new WindowsCancelHandler (DoWindowsConsoleCancelEvent);
50
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 ();
55
56                         [DllImport ("kernel32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
57                         private static extern bool SetConsoleCtrlHandler (WindowsCancelHandler handler, bool addHandler);
58
59                         // Only call the event handler if Control-C was pressed (code == 0), nothing else
60                         private static bool DoWindowsConsoleCancelEvent (int keyCode)
61                         {
62                                 if (keyCode == 0)
63                                         DoConsoleCancelEvent ();
64                                 return keyCode == 0;
65                         }
66
67                         [MethodImpl (MethodImplOptions.NoInlining)]
68                         public static int GetInputCodePage ()
69                         {
70                                 return GetConsoleCP ();
71                         }
72
73                         [MethodImpl (MethodImplOptions.NoInlining)]
74                         public static int GetOutputCodePage ()
75                         {
76                                 return GetConsoleOutputCP ();
77                         }
78
79                         public static void AddCtrlHandler ()
80                         {
81                                 SetConsoleCtrlHandler (cancelHandler, true);
82                                 ctrlHandlerAdded = true;
83                         }
84                         
85                         public static void RemoveCtrlHandler ()
86                         {
87                                 SetConsoleCtrlHandler (cancelHandler, false);
88                                 ctrlHandlerAdded = false;
89                         }
90                 }
91 #endif
92
93                 internal static TextWriter stdout;
94                 private static TextWriter stderr;
95                 private static TextReader stdin;
96
97                 static Console ()
98                 {
99 #if NET_2_1
100                         Encoding inputEncoding;
101                         Encoding outputEncoding;
102 #endif
103
104                         if (Environment.IsRunningOnWindows) {
105                                 //
106                                 // On Windows, follow the Windows tradition
107                                 //
108 #if NET_2_1
109                                 // should never happen since Moonlight does not run on windows
110                                 inputEncoding = outputEncoding = Encoding.Default;
111 #else                   
112                                 try {
113                                         inputEncoding = Encoding.GetEncoding (WindowsConsole.GetInputCodePage ());
114                                         outputEncoding = Encoding.GetEncoding (WindowsConsole.GetOutputCodePage ());
115                                         // ArgumentException and NotSupportedException can be thrown as well
116                                 } catch {
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;
120                                 }
121 #endif
122                         } else {
123                                 //
124                                 // On Unix systems (128), do not output the
125                                 // UTF-8 ZWNBSP (zero-width non-breaking space).
126                                 //
127                                 int code_page = 0;
128                                 EncodingHelper.InternalCodePage (ref code_page);
129
130                                 if (code_page != -1 && ((code_page & 0x0fffffff) == 3 // UTF8Encoding.UTF8_CODE_PAGE
131                                         || ((code_page & 0x10000000) != 0)))
132                                         inputEncoding = outputEncoding = EncodingHelper.UTF8Unmarked;
133                                 else
134                                         inputEncoding = outputEncoding = Encoding.Default;
135                         }
136
137                         SetupStreams (inputEncoding, outputEncoding);
138                 }
139
140                 static void SetupStreams (Encoding inputEncoding, Encoding outputEncoding)
141                 {
142 #if !NET_2_1
143                         if (!Environment.IsRunningOnWindows && ConsoleDriver.IsConsole) {
144                                 StreamWriter w = new CStreamWriter (OpenStandardOutput (0), outputEncoding, true);
145                                 w.AutoFlush = true;
146                                 stdout = TextWriter.Synchronized (w);
147
148                                 w = new CStreamWriter (OpenStandardOutput (0), outputEncoding, true);
149                                 w.AutoFlush = true;
150                                 stderr = TextWriter.Synchronized (w);
151                                 
152                                 stdin = new CStreamReader (OpenStandardInput (0), inputEncoding);
153                         } else {
154 #endif
155 #if MONOTOUCH
156                                 stdout = new NSLogWriter ();
157 #else
158                                 stdout = new UnexceptionalStreamWriter (OpenStandardOutput (0), outputEncoding);
159                                 ((StreamWriter)stdout).AutoFlush = true;
160 #endif
161                                 stdout = TextWriter.Synchronized (stdout);
162
163 #if MONOTOUCH
164                                 stderr = new NSLogWriter ();
165 #else
166                                 stderr = new UnexceptionalStreamWriter (OpenStandardError (0), outputEncoding); 
167                                 ((StreamWriter)stderr).AutoFlush = true;
168 #endif
169                                 stderr = TextWriter.Synchronized (stderr);
170
171                                 stdin = new UnexceptionalStreamReader (OpenStandardInput (0), inputEncoding);
172                                 stdin = TextReader.Synchronized (stdin);
173 #if !NET_2_1
174                         }
175 #endif
176
177 #if MONODROID
178                         if (LogcatTextWriter.IsRunningOnAndroid ()) {
179                                 stdout = TextWriter.Synchronized (new LogcatTextWriter ("mono-stdout", stdout));
180                                 stderr = TextWriter.Synchronized (new LogcatTextWriter ("mono-stderr", stderr));
181                         }
182 #endif  // MONODROID
183
184                         GC.SuppressFinalize (stdout);
185                         GC.SuppressFinalize (stderr);
186                         GC.SuppressFinalize (stdin);
187                 }
188
189                 public static TextWriter Error {
190                         get {
191                                 return stderr;
192                         }
193                 }
194
195                 public static TextWriter Out {
196                         get {
197                                 return stdout;
198                         }
199                 }
200
201                 public static TextReader In {
202                         get {
203                                 return stdin;
204                         }
205                 }
206
207                 private static Stream Open (IntPtr handle, FileAccess access, int bufferSize)
208                 {
209                         try {
210                                 // TODO: Should use __ConsoleStream from reference sources
211                                 return new FileStream (handle, access, false, bufferSize, false, true);
212                         } catch (IOException) {
213                                 return Stream.Null;
214                         }
215                 }
216
217                 public static Stream OpenStandardError ()
218                 {
219                         return OpenStandardError (0);
220                 }
221
222                 // calling any FileStream constructor with a handle normally
223                 // requires permissions UnmanagedCode permissions. In this 
224                 // case we assert this permission so the console can be used
225                 // in partial trust (i.e. without having UnmanagedCode).
226                 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
227                 public static Stream OpenStandardError (int bufferSize)
228                 {
229                         return Open (MonoIO.ConsoleError, FileAccess.Write, bufferSize);
230                 }
231
232                 public static Stream OpenStandardInput ()
233                 {
234                         return OpenStandardInput (0);
235                 }
236
237                 // calling any FileStream constructor with a handle normally
238                 // requires permissions UnmanagedCode permissions. In this 
239                 // case we assert this permission so the console can be used
240                 // in partial trust (i.e. without having UnmanagedCode).
241                 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
242                 public static Stream OpenStandardInput (int bufferSize)
243                 {
244                         return Open (MonoIO.ConsoleInput, FileAccess.Read, bufferSize);
245                 }
246
247                 public static Stream OpenStandardOutput ()
248                 {
249                         return OpenStandardOutput (0);
250                 }
251
252                 // calling any FileStream constructor with a handle normally
253                 // requires permissions UnmanagedCode permissions. In this 
254                 // case we assert this permission so the console can be used
255                 // in partial trust (i.e. without having UnmanagedCode).
256                 [SecurityPermission (SecurityAction.Assert, UnmanagedCode = true)]
257                 public static Stream OpenStandardOutput (int bufferSize)
258                 {
259                         return Open (MonoIO.ConsoleOutput, FileAccess.Write, bufferSize);
260                 }
261
262                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
263                 public static void SetError (TextWriter newError)
264                 {
265                         if (newError == null)
266                                 throw new ArgumentNullException ("newError");
267
268                         stderr = newError;
269                 }
270
271                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
272                 public static void SetIn (TextReader newIn)
273                 {
274                         if (newIn == null)
275                                 throw new ArgumentNullException ("newIn");
276
277                         stdin = newIn;
278                 }
279
280                 [SecurityPermission (SecurityAction.Demand, UnmanagedCode = true)]
281                 public static void SetOut (TextWriter newOut)
282                 {
283                         if (newOut == null)
284                                 throw new ArgumentNullException ("newOut");
285
286                         stdout = newOut;
287                 }
288
289                 public static void Write (bool value)
290                 {
291                         stdout.Write (value);
292                 }
293
294                 public static void Write (char value)
295                 {
296                         stdout.Write (value);
297                 }
298
299                 public static void Write (char[] buffer)
300                 {
301                         stdout.Write (buffer);
302                 }
303
304                 public static void Write (decimal value)
305                 {
306                         stdout.Write (value);
307                 }
308                 
309                 public static void Write (double value)
310                 {
311                         stdout.Write (value);
312                 }
313
314                 public static void Write (int value)
315                 {
316                         stdout.Write (value);
317                 }
318
319                 public static void Write (long value)
320                 {
321                         stdout.Write (value);
322                 }
323
324                 public static void Write (object value)
325                 {
326                         stdout.Write (value);
327                 }
328
329                 public static void Write (float value)
330                 {
331                         stdout.Write (value);
332                 }
333
334                 public static void Write (string value)
335                 {
336                         stdout.Write (value);
337                 }
338
339                 [CLSCompliant (false)]
340                 public static void Write (uint value)
341                 {
342                         stdout.Write (value);
343                 }
344
345                 [CLSCompliant (false)]
346                 public static void Write (ulong value)
347                 {
348                         stdout.Write (value);
349                 }
350
351                 public static void Write (string format, object arg0)
352                 {
353                         stdout.Write (format, arg0);
354                 }
355
356                 public static void Write (string format, params object[] arg)
357                 {
358                         if (arg == null)
359                                 stdout.Write (format);
360                         else
361                                 stdout.Write (format, arg);
362                 }
363
364                 public static void Write (char[] buffer, int index, int count)
365                 {
366                         stdout.Write (buffer, index, count);
367                 }
368
369                 public static void Write (string format, object arg0, object arg1)
370                 {
371                         stdout.Write (format, arg0, arg1);
372                 }
373
374                 public static void Write (string format, object arg0, object arg1, object arg2 )
375                 {
376                         stdout.Write (format, arg0, arg1, arg2);
377                 }
378
379                 [CLSCompliant (false)]
380                 public static void Write (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
381                 {
382                         ArgIterator iter = new ArgIterator (__arglist);
383                         int argCount = iter.GetRemainingCount();
384
385                         object[] args = new object [argCount + 4];
386                         args [0] = arg0;
387                         args [1] = arg1;
388                         args [2] = arg2;
389                         args [3] = arg3;
390                         for (int i = 0; i < argCount; i++) {
391                                 TypedReference typedRef = iter.GetNextArg ();
392                                 args [i + 4] = TypedReference.ToObject (typedRef);
393                         }
394
395                         stdout.Write (String.Format (format, args));
396                 }
397
398                 public static void WriteLine ()
399                 {
400                         stdout.WriteLine ();
401                 }
402
403                 public static void WriteLine (bool value)
404                 {
405                         stdout.WriteLine (value);
406                 }
407
408                 public static void WriteLine (char value)
409                 {
410                         stdout.WriteLine (value);
411                 }
412
413                 public static void WriteLine (char[] buffer)
414                 {
415                         stdout.WriteLine (buffer);
416                 }
417
418                 public static void WriteLine (decimal value)
419                 {
420                         stdout.WriteLine (value);
421                 }
422
423                 public static void WriteLine (double value)
424                 {
425                         stdout.WriteLine (value);
426                 }
427
428                 public static void WriteLine (int value)
429                 {
430                         stdout.WriteLine (value);
431                 }
432
433                 public static void WriteLine (long value)
434                 {
435                         stdout.WriteLine (value);
436                 }
437
438                 public static void WriteLine (object value)
439                 {
440                         stdout.WriteLine (value);
441                 }
442
443                 public static void WriteLine (float value)
444                 {
445                         stdout.WriteLine (value);
446                 }
447
448                 public static void WriteLine (string value)
449                 {
450                         stdout.WriteLine (value);
451                 }
452
453                 [CLSCompliant (false)]
454                 public static void WriteLine (uint value)
455                 {
456                         stdout.WriteLine (value);
457                 }
458
459                 [CLSCompliant (false)]
460                 public static void WriteLine (ulong value)
461                 {
462                         stdout.WriteLine (value);
463                 }
464
465                 public static void WriteLine (string format, object arg0)
466                 {
467                         stdout.WriteLine (format, arg0);
468                 }
469
470                 public static void WriteLine (string format, params object[] arg)
471                 {
472                         if (arg == null)
473                                 stdout.WriteLine (format);
474                         else
475                                 stdout.WriteLine (format, arg);
476                 }
477
478                 public static void WriteLine (char[] buffer, int index, int count)
479                 {
480                         stdout.WriteLine (buffer, index, count);
481                 }
482
483                 public static void WriteLine (string format, object arg0, object arg1)
484                 {
485                         stdout.WriteLine (format, arg0, arg1);
486                 }
487
488                 public static void WriteLine (string format, object arg0, object arg1, object arg2)
489                 {
490                         stdout.WriteLine (format, arg0, arg1, arg2);
491                 }
492
493                 [CLSCompliant (false)]
494                 public static void WriteLine (string format, object arg0, object arg1, object arg2, object arg3, __arglist)
495                 {
496                         ArgIterator iter = new ArgIterator (__arglist);
497                         int argCount = iter.GetRemainingCount();
498
499                         object[] args = new object [argCount + 4];
500                         args [0] = arg0;
501                         args [1] = arg1;
502                         args [2] = arg2;
503                         args [3] = arg3;
504                         for (int i = 0; i < argCount; i++) {
505                                 TypedReference typedRef = iter.GetNextArg ();
506                                 args [i + 4] = TypedReference.ToObject (typedRef);
507                         }
508
509                         stdout.WriteLine (String.Format (format, args));
510                 }
511
512 #if !NET_2_1
513                 public static int Read ()
514                 {
515                         if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
516                                 return ConsoleDriver.Read ();
517                         } else {
518                                 return stdin.Read ();
519                         }
520                 }
521
522                 public static string ReadLine ()
523                 {
524                         if ((stdin is CStreamReader) && ConsoleDriver.IsConsole) {
525                                 return ConsoleDriver.ReadLine ();
526                         } else {
527                                 return stdin.ReadLine ();
528                         }
529                 }
530 #else
531                 public static int Read ()
532                 {
533                         return stdin.Read ();
534                 }
535
536                 public static string ReadLine ()
537                 {
538                         return stdin.ReadLine ();
539                 }
540
541 #endif
542
543 #if !NET_2_1
544                 // FIXME: Console should use these encodings when changed
545                 static Encoding inputEncoding;
546                 static Encoding outputEncoding;
547
548                 public static Encoding InputEncoding {
549                         get { return inputEncoding; }
550                         set {
551                                 inputEncoding = value;
552                                 SetupStreams (inputEncoding, outputEncoding);
553                         }
554                 }
555
556                 public static Encoding OutputEncoding {
557                         get { return outputEncoding; }
558                         set {
559                                 outputEncoding = value;
560                                 SetupStreams (inputEncoding, outputEncoding);
561                         }
562                 }
563
564                 public static ConsoleColor BackgroundColor {
565                         get { return ConsoleDriver.BackgroundColor; }
566                         set { ConsoleDriver.BackgroundColor = value; }
567                 }
568
569                 public static int BufferHeight {
570                         get { return ConsoleDriver.BufferHeight; }
571                         [MonoLimitation ("Implemented only on Windows")]
572                         set { ConsoleDriver.BufferHeight = value; }
573                 }
574
575                 public static int BufferWidth {
576                         get { return ConsoleDriver.BufferWidth; }
577                         [MonoLimitation ("Implemented only on Windows")]
578                         set { ConsoleDriver.BufferWidth = value; }
579                 }
580
581                 [MonoLimitation ("Implemented only on Windows")]
582                 public static bool CapsLock {
583                         get { return ConsoleDriver.CapsLock; }
584                 }
585
586                 public static int CursorLeft {
587                         get { return ConsoleDriver.CursorLeft; }
588                         set { ConsoleDriver.CursorLeft = value; }
589                 }
590
591                 public static int CursorTop {
592                         get { return ConsoleDriver.CursorTop; }
593                         set { ConsoleDriver.CursorTop = value; }
594                 }
595
596                 public static int CursorSize {
597                         get { return ConsoleDriver.CursorSize; }
598                         set { ConsoleDriver.CursorSize = value; }
599                 }
600
601                 public static bool CursorVisible {
602                         get { return ConsoleDriver.CursorVisible; }
603                         set { ConsoleDriver.CursorVisible = value; }
604                 }
605
606                 public static ConsoleColor ForegroundColor {
607                         get { return ConsoleDriver.ForegroundColor; }
608                         set { ConsoleDriver.ForegroundColor = value; }
609                 }
610
611                 public static bool KeyAvailable {
612                         get { return ConsoleDriver.KeyAvailable; }
613                 }
614
615                 public static int LargestWindowHeight {
616                         get { return ConsoleDriver.LargestWindowHeight; }
617                 }
618
619                 public static int LargestWindowWidth {
620                         get { return ConsoleDriver.LargestWindowWidth; }
621                 }
622
623                 [MonoLimitation ("Only works on windows")]
624                 public static bool NumberLock {
625                         get { return ConsoleDriver.NumberLock; }
626                 }
627
628                 public static string Title {
629                         get { return ConsoleDriver.Title; }
630                         set { ConsoleDriver.Title = value; }
631                 }
632
633                 public static bool TreatControlCAsInput {
634                         get { return ConsoleDriver.TreatControlCAsInput; }
635                         set { ConsoleDriver.TreatControlCAsInput = value; }
636                 }
637
638                 [MonoLimitation ("Only works on windows")]
639                 public static int WindowHeight {
640                         get { return ConsoleDriver.WindowHeight; }
641                         set { ConsoleDriver.WindowHeight = value; }
642                 }
643
644                 [MonoLimitation ("Only works on windows")]
645                 public static int WindowLeft {
646                         get { return ConsoleDriver.WindowLeft; }
647                         set { ConsoleDriver.WindowLeft = value; }
648                 }
649
650                 [MonoLimitation ("Only works on windows")]
651                 public static int WindowTop {
652                         get { return ConsoleDriver.WindowTop; }
653                         set { ConsoleDriver.WindowTop = value; }
654                 }
655
656                 [MonoLimitation ("Only works on windows")]
657                 public static int WindowWidth {
658                         get { return ConsoleDriver.WindowWidth; }
659                         set { ConsoleDriver.WindowWidth = value; }
660                 }
661
662                 public static bool IsErrorRedirected {
663                         get {
664                                 return ConsoleDriver.IsErrorRedirected;
665                         }
666                 }
667
668                 public static bool IsOutputRedirected {
669                         get {
670                                 return ConsoleDriver.IsOutputRedirected;
671                         }
672                 }
673
674                 public static bool IsInputRedirected {
675                         get {
676                                 return ConsoleDriver.IsInputRedirected;
677                         }
678                 }
679
680                 public static void Beep ()
681                 {
682                         Beep (1000, 500);
683                 }
684
685                 public static void Beep (int frequency, int duration)
686                 {
687                         if (frequency < 37 || frequency > 32767)
688                                 throw new ArgumentOutOfRangeException ("frequency");
689
690                         if (duration <= 0)
691                                 throw new ArgumentOutOfRangeException ("duration");
692
693                         ConsoleDriver.Beep (frequency, duration);
694                 }
695
696                 public static void Clear ()
697                 {
698                         ConsoleDriver.Clear ();
699                 }
700
701                 [MonoLimitation ("Implemented only on Windows")]
702                 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
703                                                 int targetLeft, int targetTop)
704                 {
705                         ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop);
706                 }
707
708                 [MonoLimitation ("Implemented only on Windows")]
709                 public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
710                                                 int targetLeft, int targetTop, Char sourceChar,
711                                                 ConsoleColor sourceForeColor, ConsoleColor sourceBackColor)
712                 {
713                         ConsoleDriver.MoveBufferArea (sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop,
714                                                         sourceChar, sourceForeColor, sourceBackColor);
715                 }
716
717                 public static ConsoleKeyInfo ReadKey ()
718                 {
719                         return ReadKey (false);
720                 }
721
722                 public static ConsoleKeyInfo ReadKey (bool intercept)
723                 {
724                         return ConsoleDriver.ReadKey (intercept);
725                 }
726
727                 public static void ResetColor ()
728                 {
729                         ConsoleDriver.ResetColor ();
730                 }
731
732                 [MonoLimitation ("Only works on windows")]
733                 public static void SetBufferSize (int width, int height)
734                 {
735                         ConsoleDriver.SetBufferSize (width, height);
736                 }
737
738                 public static void SetCursorPosition (int left, int top)
739                 {
740                         ConsoleDriver.SetCursorPosition (left, top);
741                 }
742
743                 public static void SetWindowPosition (int left, int top)
744                 {
745                         ConsoleDriver.SetWindowPosition (left, top);
746                 }
747
748                 public static void SetWindowSize (int width, int height)
749                 {
750                         ConsoleDriver.SetWindowSize (width, height);
751                 }
752
753                 static ConsoleCancelEventHandler cancel_event;
754                 public static event ConsoleCancelEventHandler CancelKeyPress {
755                         add {
756                                 if (ConsoleDriver.Initialized == false)
757                                         ConsoleDriver.Init ();
758
759                                 cancel_event += value;
760
761                                 if (Environment.IsRunningOnWindows && !WindowsConsole.ctrlHandlerAdded)
762                                         WindowsConsole.AddCtrlHandler();
763                         }
764                         remove {
765                                 if (ConsoleDriver.Initialized == false)
766                                         ConsoleDriver.Init ();
767
768                                 cancel_event -= value;
769
770                                 if (cancel_event == null && Environment.IsRunningOnWindows)
771                                 {
772                                         // Need to remove our hook if there's nothing left in the event
773                                         if (WindowsConsole.ctrlHandlerAdded)
774                                                 WindowsConsole.RemoveCtrlHandler();
775                                 }
776                         }
777                 }
778
779                 delegate void InternalCancelHandler ();
780                 
781 #pragma warning disable 414
782                 //
783                 // Used by console-io.c
784                 //
785                 static readonly InternalCancelHandler cancel_handler = new InternalCancelHandler (DoConsoleCancelEvent);
786 #pragma warning restore 414             
787
788                 internal static void DoConsoleCancelEvent ()
789                 {
790                         bool exit = true;
791                         if (cancel_event != null) {
792                                 ConsoleCancelEventArgs args = new ConsoleCancelEventArgs (ConsoleSpecialKey.ControlC);
793                                 Delegate [] delegates = cancel_event.GetInvocationList ();
794                                 foreach (ConsoleCancelEventHandler d in delegates){
795                                         try {
796                                                 // Sender is always null here.
797                                                 d (null, args);
798                                         } catch {} // Ignore any exception.
799                                 }
800                                 exit = !args.Cancel;
801                         }
802
803                         if (exit)
804                                 Environment.Exit (58);
805                 }
806 #endif
807         }
808 }
809