2007-04-24 Jeffrey Stedfast <fejj@novell.com>
[mono.git] / mcs / class / corlib / System / TermInfoDriver.cs
1 //
2 // System.ConsoleDriver
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // (C) 2005,2006 Novell, Inc (http://www.novell.com)
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 #if NET_2_0
31 //#define DEBUG
32 using System.Collections;
33 using System.IO;
34 using System.Text;
35 using System.Runtime.InteropServices;
36 namespace System {
37         class TermInfoDriver : IConsoleDriver {
38                 /* Do not rename this field, its looked up from the runtime */
39                 static bool need_window_dimensions = true;
40                 
41                 static string [] locations = { "/etc/terminfo", "/usr/share/terminfo", "/usr/lib/terminfo" };
42
43                 TermInfoReader reader;
44                 int cursorLeft;
45                 int cursorTop;
46                 string title = String.Empty;
47                 string titleFormat = String.Empty;
48                 bool cursorVisible = true;
49                 string csrVisible;
50                 string csrInvisible;
51                 string clear;
52                 string bell;
53                 string term;
54                 StreamReader stdin;
55                 CStreamWriter stdout;
56                 internal byte verase;
57                 byte vsusp;
58                 byte intr;
59
60                 int windowWidth;
61                 int windowHeight;
62                 //int windowTop;
63                 //int windowLeft;
64                 int bufferHeight;
65                 int bufferWidth;
66
67                 char [] buffer;
68                 int readpos;
69                 int writepos;
70                 string keypadXmit, keypadLocal;
71                 bool controlCAsInput;
72                 bool inited;
73                 bool initKeys;
74                 string origPair;
75                 string origColors;
76                 string cursorAddress;
77                 ConsoleColor fgcolor = ConsoleColor.White;
78                 ConsoleColor bgcolor = ConsoleColor.Black;
79                 bool color16 = false; // terminal supports 16 colors
80                 string setlfgcolor;
81                 string setlbgcolor;
82                 string setfgcolor;
83                 string setbgcolor;
84                 bool noGetPosition;
85                 Hashtable keymap;
86                 ByteMatcher rootmap;
87                 bool home_1_1; // if true, we have to add 1 to x and y when using cursorAddress
88                 int rl_startx = -1, rl_starty = -1;
89 #if DEBUG
90                 StreamWriter logger;
91 #endif
92
93                 static string SearchTerminfo (string term)
94                 {
95                         if (term == null || term == String.Empty)
96                                 return null;
97
98                         // Ignore TERMINFO and TERMINFO_DIRS by now
99                         //string terminfo = Environment.GetEnvironmentVariable ("TERMINFO");
100                         //string terminfoDirs = Environment.GetEnvironmentVariable ("TERMINFO_DIRS");
101
102                         foreach (string dir in locations) {
103                                 if (!Directory.Exists (dir))
104                                         continue;
105
106                                 string path = Path.Combine (dir, term.Substring (0, 1));
107                                 if (!Directory.Exists (dir))
108                                         continue;
109
110                                 path = Path.Combine (path, term);
111                                 if (!File.Exists (path))
112                                         continue;
113
114                                 return path;
115                         }
116
117                         return null;
118                 }
119
120                 void WriteConsole (string str)
121                 {
122                         if (str == null)
123                                 return;
124                         
125                         stdout.InternalWriteString (str);
126                 }
127
128                 public TermInfoDriver ()
129                         : this (Environment.GetEnvironmentVariable ("TERM"))
130                 {
131                 }
132
133                 public TermInfoDriver (string term)
134                 {
135 #if DEBUG
136                         File.Delete ("console.log");
137                         logger = new StreamWriter (File.OpenWrite ("console.log"));
138 #endif
139                         this.term = term;
140
141                         if (term == "xterm") {
142                                 reader = new TermInfoReader (term, KnownTerminals.xterm);
143                                 color16 = true;
144                         } else if (term == "linux") {
145                                 reader = new TermInfoReader (term, KnownTerminals.linux);
146                                 color16 = true;
147                         } else {
148                                 string filename = SearchTerminfo (term);
149                                 if (filename != null)
150                                         reader = new TermInfoReader (term, filename);
151                         }
152
153                         if (reader == null)
154                                 reader = new TermInfoReader (term, KnownTerminals.ansi);
155
156                         if (!(Console.stdout is CStreamWriter)) {
157                                 // Application set its own stdout, we need a reference to the real stdout
158                                 stdout = new CStreamWriter (Console.OpenStandardOutput (0), Console.OutputEncoding);
159                                 ((StreamWriter) stdout).AutoFlush = true;
160                         } else {
161                                 stdout = (CStreamWriter) Console.stdout;
162                         }
163                 }
164
165                 public bool Initialized {
166                         get { return inited; }
167                 }
168
169                 public void Init ()
170                 {
171                         if (inited)
172                                 return;
173
174                         /* This should not happen any more, since it is checked for in Console */
175                         if (!ConsoleDriver.IsConsole)
176                                 throw new IOException ("Not a tty.");
177
178                         inited = true;
179
180                         ConsoleDriver.SetEcho (false);
181
182                         string endString = null;
183                         keypadXmit = reader.Get (TermInfoStrings.KeypadXmit);
184                         keypadLocal = reader.Get (TermInfoStrings.KeypadLocal);
185                         if (keypadXmit != null) {
186                                 WriteConsole (keypadXmit); // Needed to get the arrows working
187                                 if (keypadLocal != null)
188                                         endString += keypadLocal;
189                         }
190
191                         origPair = reader.Get (TermInfoStrings.OrigPair);
192                         origColors = reader.Get (TermInfoStrings.OrigColors);
193                         setfgcolor = MangleParameters (reader.Get (TermInfoStrings.SetAForeground));
194                         setbgcolor = MangleParameters (reader.Get (TermInfoStrings.SetABackground));
195                         // lighter fg colours are 90 -> 97 rather than 30 -> 37
196                         setlfgcolor = color16 ? setfgcolor.Replace ("[3", "[9") : setfgcolor;
197                         // lighter bg colours are 100 -> 107 rather than 40 -> 47
198                         setlbgcolor = color16 ? setbgcolor.Replace ("[4", "[10") : setbgcolor;
199                         string resetColors = (origColors == null) ? origPair : origColors;
200                         if (resetColors != null)
201                                 endString += resetColors;
202
203                         if (!ConsoleDriver.TtySetup (endString, out verase, out vsusp, out intr))
204                                 throw new IOException ("Error initializing terminal.");
205
206                         stdin = new StreamReader (Console.OpenStandardInput (0), Console.InputEncoding);
207                         clear = reader.Get (TermInfoStrings.ClearScreen);
208                         bell = reader.Get (TermInfoStrings.Bell);
209                         if (clear == null) {
210                                 clear = reader.Get (TermInfoStrings.CursorHome);
211                                 clear += reader.Get (TermInfoStrings.ClrEos);
212                         }
213
214                         csrVisible = reader.Get (TermInfoStrings.CursorNormal);
215                         if (csrVisible == null)
216                                 csrVisible = reader.Get (TermInfoStrings.CursorVisible);
217
218                         csrInvisible = reader.Get (TermInfoStrings.CursorInvisible);
219                         if (term == "cygwin" || term == "linux" || (term != null && term.StartsWith ("xterm")) ||
220                                 term == "rxvt" || term == "dtterm") {
221                                 titleFormat = "\x1b]0;{0}\x7"; // icon + window title
222                         } else if (term == "iris-ansi") {
223                                 titleFormat = "\x1bP1.y{0}\x1b\\"; // not tested
224                         } else if (term == "sun-cmd") {
225                                 titleFormat = "\x1b]l{0}\x1b\\"; // not tested
226                         }
227
228                         cursorAddress = reader.Get (TermInfoStrings.CursorAddress);
229                         if (cursorAddress != null) {
230                                 string result = cursorAddress.Replace ("%i", String.Empty);
231                                 home_1_1 = (cursorAddress != result);
232                                 cursorAddress = MangleParameters (result);
233                         }
234
235                         GetCursorPosition ();
236 #if DEBUG
237                         logger.WriteLine ("noGetPosition: {0} left: {1} top: {2}", noGetPosition, cursorLeft, cursorTop);
238                         logger.Flush ();
239 #endif
240                         if (noGetPosition) {
241                                 WriteConsole (clear);
242                                 cursorLeft = 0;
243                                 cursorTop = 0;
244                         }
245                 }
246
247                 static string MangleParameters (string str)
248                 {
249                         if (str == null)
250                                 return null;
251
252                         str = str.Replace ("{", "{{");
253                         str = str.Replace ("}", "}}");
254                         str = str.Replace ("%p1%d", "{0}");
255                         return str.Replace ("%p2%d", "{1}");
256                 }
257
258                 static int TranslateColor (ConsoleColor desired, out bool light)
259                 {
260                         switch (desired) {
261                         // Dark colours
262                         case ConsoleColor.Black:
263                                 light = false;
264                                 return 0;
265                         case ConsoleColor.DarkRed:
266                                 light = false;
267                                 return 1;
268                         case ConsoleColor.DarkGreen:
269                                 light = false;
270                                 return 2;
271                         case ConsoleColor.DarkYellow:
272                                 light = false;
273                                 return 3;
274                         case ConsoleColor.DarkBlue:
275                                 light = false;
276                                 return 4;
277                         case ConsoleColor.DarkMagenta:
278                                 light = false;
279                                 return 5;
280                         case ConsoleColor.DarkCyan:
281                                 light = false;
282                                 return 6;
283                         case ConsoleColor.Gray:
284                                 light = false;
285                                 return 7;
286                         // Light colours
287                         case ConsoleColor.DarkGray:
288                                 light = true;
289                                 return 0;
290                         case ConsoleColor.Red:
291                                 light = true;
292                                 return 1;
293                         case ConsoleColor.Green:
294                                 light = true;
295                                 return 2;
296                         case ConsoleColor.Yellow:
297                                 light = true;
298                                 return 3;
299                         case ConsoleColor.Blue:
300                                 light = true;
301                                 return 4;
302                         case ConsoleColor.Magenta:
303                                 light = true;
304                                 return 5;
305                         case ConsoleColor.Cyan:
306                                 light = true;
307                                 return 6;
308                         case ConsoleColor.White:
309                                 light = true;
310                                 return 7;
311                         }
312
313                         light = false;
314
315                         return 0;
316                 }
317
318                 void IncrementX ()
319                 {
320                         cursorLeft++;
321                         if (cursorLeft >= WindowWidth) {
322                                 cursorTop++;
323                                 cursorLeft = 0;
324                                 if (cursorTop >= WindowHeight) {
325                                         // Writing beyond the initial screen
326                                         if (rl_starty != -1) rl_starty--;
327                                         cursorTop--;
328                                 }
329                         }
330                 }
331
332                 // Should never get called unless inited
333                 public void WriteSpecialKey (ConsoleKeyInfo key)
334                 {
335                         switch (key.Key) {
336                         case ConsoleKey.Backspace:
337                                 if (cursorLeft > 0) {
338                                         if (cursorLeft <= rl_startx && cursorTop == rl_starty)
339                                                 break;
340                                         cursorLeft--;
341                                         SetCursorPosition (cursorLeft, cursorTop);
342                                         WriteConsole (" ");
343                                         SetCursorPosition (cursorLeft, cursorTop);
344                                 }
345 #if DEBUG
346                                 logger.WriteLine ("BS left: {0} top: {1}", cursorLeft, cursorTop);
347                                 logger.Flush ();
348 #endif
349                                 break;
350                         case ConsoleKey.Tab:
351                                 int n = 8 - (cursorLeft % 8);
352                                 for (int i = 0; i < n; i++)
353                                         IncrementX ();
354                                 break;
355                         case ConsoleKey.Clear:
356                                 break;
357                         case ConsoleKey.Enter:
358                                 break;
359                         default:
360                                 break;
361                         }
362 #if DEBUG
363                         logger.WriteLine ("left: {0} top: {1}", cursorLeft, cursorTop);
364                         logger.Flush ();
365 #endif
366                 }
367
368                 // Should never get called unless inited
369                 public void WriteSpecialKey (char c)
370                 {
371                         WriteSpecialKey (CreateKeyInfoFromInt (c));
372                 }
373
374                 public bool IsSpecialKey (ConsoleKeyInfo key)
375                 {
376                         if (!inited)
377                                 return false;
378
379                         switch (key.Key) {
380                         case ConsoleKey.Backspace:
381                                 return true;
382                         case ConsoleKey.Tab:
383                                 return true;
384                         case ConsoleKey.Clear:
385                                 return true;
386                         case ConsoleKey.Enter:
387                                 cursorLeft = 0;
388                                 cursorTop++;
389                                 if (cursorTop >= WindowHeight) {
390                                         cursorTop--;
391                                         //TODO: scroll up
392                                 }
393                                 return false;
394                         default:
395                                 // CStreamWriter will handle writing this key
396                                 IncrementX ();
397                                 return false;
398                         }
399                 }
400
401                 public bool IsSpecialKey (char c)
402                 {
403                         return IsSpecialKey (CreateKeyInfoFromInt (c));
404                 }
405
406                 public ConsoleColor BackgroundColor {
407                         get {
408                                 if (!inited) {
409                                         Init ();
410                                 }
411
412                                 return bgcolor;
413                         }
414                         set {
415                                 if (!inited) {
416                                         Init ();
417                                 }
418
419                                 bgcolor = value;
420
421                                 bool light;
422                                 int colour = TranslateColor (value, out light);
423
424                                 if (light)
425                                         WriteConsole (String.Format (setlbgcolor, colour));
426                                 else
427                                         WriteConsole (String.Format (setbgcolor, colour));
428                         }
429                 }
430
431                 public ConsoleColor ForegroundColor {
432                         get {
433                                 if (!inited) {
434                                         Init ();
435                                 }
436
437                                 return fgcolor;
438                         }
439                         set {
440                                 if (!inited) {
441                                         Init ();
442                                 }
443
444                                 fgcolor = value;
445
446                                 bool light;
447                                 int colour = TranslateColor (value, out light);
448
449                                 if (light)
450                                         WriteConsole (String.Format (setlfgcolor, colour));
451                                 else
452                                         WriteConsole (String.Format (setfgcolor, colour));
453                         }
454                 }
455
456                 void GetCursorPosition ()
457                 {
458                         int row = 0, col = 0;
459
460                         WriteConsole ("\x1b[6n");
461                         if (ConsoleDriver.InternalKeyAvailable (1000) <= 0) {
462                                 noGetPosition = true;
463                                 return;
464                         }
465
466                         int b = stdin.Read ();
467                         while (b != '\x1b') {
468                                 AddToBuffer (b);
469                                 if (ConsoleDriver.InternalKeyAvailable (100) <= 0)
470                                         return;
471                                 b = stdin.Read ();
472                         }
473
474                         b = stdin.Read ();
475                         if (b != '[') {
476                                 AddToBuffer ('\x1b');
477                                 AddToBuffer (b);
478                                 return;
479                         }
480
481                         b = stdin.Read ();
482                         if (b != ';') {
483                                 row = b - '0';
484                                 b = stdin.Read ();
485                                 while ((b >= '0') && (b <= '9')) {
486                                         row = row * 10 + b - '0';
487                                         b = stdin.Read ();
488                                 }
489                                 // Row/col is 0 based
490                                 row --;
491                         }
492
493                         b = stdin.Read ();
494                         if (b != 'R') {
495                                 col = b - '0';
496                                 b = stdin.Read ();
497                                 while ((b >= '0') && (b <= '9')) {
498                                         col = col * 10 + b - '0';
499                                         b = stdin.Read ();
500                                 }
501                                 // Row/col is 0 based
502                                 col --;
503                         }
504
505 #if DEBUG
506                         logger.WriteLine ("GetCursorPosition: {0}, {1}", col, row);
507                         logger.Flush ();
508 #endif
509
510                         cursorLeft = col;
511                         cursorTop = row;
512                 }
513
514                 public int BufferHeight {
515                         get {
516                                 if (!inited) {
517                                         Init ();
518                                 }
519
520                                 return bufferHeight;
521                         }
522                         set {
523                                 if (!inited) {
524                                         Init ();
525                                 }
526
527                                 throw new NotSupportedException ();
528                         }
529                 }
530
531                 public int BufferWidth {
532                         get {
533                                 if (!inited) {
534                                         Init ();
535                                 }
536
537                                 return bufferWidth;
538                         }
539                         set {
540                                 if (!inited) {
541                                         Init ();
542                                 }
543
544                                 throw new NotSupportedException ();
545                         }
546                 }
547
548                 public bool CapsLock {
549                         get {
550                                 if (!inited) {
551                                         Init ();
552                                 }
553
554                                 throw new NotSupportedException ();
555                         }
556                 }
557
558                 public int CursorLeft {
559                         get {
560                                 if (!inited) {
561                                         Init ();
562                                 }
563
564                                 return cursorLeft;
565                         }
566                         set {
567                                 if (!inited) {
568                                         Init ();
569                                 }
570
571                                 SetCursorPosition (value, CursorTop);
572                         }
573                 }
574
575                 public int CursorTop {
576                         get {
577                                 if (!inited) {
578                                         Init ();
579                                 }
580
581                                 return cursorTop;
582                         }
583                         set {
584                                 if (!inited) {
585                                         Init ();
586                                 }
587
588                                 SetCursorPosition (CursorLeft, value);
589                         }
590                 }
591
592                 public bool CursorVisible {
593                         get {
594                                 if (!inited) {
595                                         Init ();
596                                 }
597
598                                 return cursorVisible;
599                         }
600                         set {
601                                 if (!inited) {
602                                         Init ();
603                                 }
604
605                                 cursorVisible = value;
606                                 WriteConsole ((value ? csrVisible : csrInvisible));
607                         }
608                 }
609
610                 // we have CursorNormal vs. CursorVisible...
611                 [MonoTODO]
612                 public int CursorSize {
613                         get {
614                                 if (!inited) {
615                                         Init ();
616                                 }
617                                 return 1;
618                         }
619                         set {
620                                 if (!inited) {
621                                         Init ();
622                                 }
623                         }
624
625                 }
626
627                 public bool KeyAvailable {
628                         get {
629                                 if (!inited) {
630                                         Init ();
631                                 }
632
633                                 return (writepos > readpos || ConsoleDriver.InternalKeyAvailable (0) > 0);
634                         }
635                 }
636
637                 // We don't know these next 2 values, so return something reasonable
638                 public int LargestWindowHeight {
639                         get { return WindowHeight; }
640                 }
641
642                 public int LargestWindowWidth {
643                         get { return WindowWidth; }
644                 }
645
646                 public bool NumberLock {
647                         get {
648                                 if (!inited) {
649                                         Init ();
650                                 }
651
652                                 throw new NotSupportedException ();
653                         }
654                 }
655
656                 public string Title {
657                         get {
658                                 if (!inited) {
659                                         Init ();
660                                 }
661                                 return title;
662                         }
663                         
664                         set {
665                                 if (!inited) {
666                                         Init ();
667                                 }
668
669                                 title = value;
670                                 WriteConsole (String.Format (titleFormat, value));
671                         }
672                 }
673
674                 public bool TreatControlCAsInput {
675                         get {
676                                 if (!inited) {
677                                         Init ();
678                                 }
679                                 return controlCAsInput;
680                         }
681                         set {
682                                 if (!inited) {
683                                         Init ();
684                                 }
685
686                                 if (controlCAsInput == value)
687                                         return;
688
689                                 ConsoleDriver.SetBreak (value);
690                                 controlCAsInput = value;
691                         }
692                 }
693
694                 void GetWindowDimensions ()
695                 {
696                         /* Try the ioctl first */
697                         if (!ConsoleDriver.GetTtySize (MonoIO.ConsoleOutput, out windowWidth, out windowHeight)) {
698                                 windowWidth = reader.Get (TermInfoNumbers.Columns);
699                                 string env = Environment.GetEnvironmentVariable ("COLUMNS");
700                                 if (env != null) {
701                                         try {
702                                                 windowWidth = (int) UInt32.Parse (env);
703                                         } catch {
704                                         }
705                                 }
706
707                                 windowHeight = reader.Get (TermInfoNumbers.Lines);
708                                 env = Environment.GetEnvironmentVariable ("LINES");
709                                 if (env != null) {
710                                         try {
711                                                 windowHeight = (int) UInt32.Parse (env);
712                                         } catch {
713                                         }
714                                 }
715                         }
716
717                         bufferHeight = windowHeight;
718                         bufferWidth = windowWidth;
719                         need_window_dimensions = false;
720                 }
721
722                 public int WindowHeight {
723                         get {
724                                 if (!inited) {
725                                         Init ();
726                                 }
727
728                                 if (need_window_dimensions)
729                                         GetWindowDimensions ();
730                                 return windowHeight;
731                         }
732                         set {
733                                 if (!inited) {
734                                         Init ();
735                                 }
736
737                                 throw new NotSupportedException ();
738                         }
739                 }
740
741                 public int WindowLeft {
742                         get {
743                                 if (!inited) {
744                                         Init ();
745                                 }
746
747                                 //GetWindowDimensions ();
748                                 return 0;
749                         }
750                         set {
751                                 if (!inited) {
752                                         Init ();
753                                 }
754
755                                 throw new NotSupportedException ();
756                         }
757                 }
758
759                 public int WindowTop {
760                         get {
761                                 if (!inited) {
762                                         Init ();
763                                 }
764
765                                 //GetWindowDimensions ();
766                                 return 0;
767                         }
768                         set {
769                                 if (!inited) {
770                                         Init ();
771                                 }
772
773                                 throw new NotSupportedException ();
774                         }
775                 }
776
777                 public int WindowWidth {
778                         get {
779                                 if (!inited) {
780                                         Init ();
781                                 }
782
783                                 if (need_window_dimensions)
784                                         GetWindowDimensions ();
785                                 return windowWidth;
786                         }
787                         set {
788                                 if (!inited) {
789                                         Init ();
790                                 }
791
792                                 throw new NotSupportedException ();
793                         }
794                 }
795
796                 public void Clear ()
797                 {
798                         if (!inited) {
799                                 Init ();
800                         }
801
802                         WriteConsole (clear);
803                 }
804
805                 public void Beep (int frequency, int duration)
806                 {
807                         if (!inited) {
808                                 Init ();
809                         }
810
811                         WriteConsole (bell);
812                 }
813
814                 public void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
815                                         int targetLeft, int targetTop, Char sourceChar,
816                                         ConsoleColor sourceForeColor, ConsoleColor sourceBackColor)
817                 {
818                         if (!inited) {
819                                 Init ();
820                         }
821
822                         throw new NotImplementedException ();
823                 }
824
825                 void AddToBuffer (int b)
826                 {
827                         if (buffer == null) {
828                                 buffer = new char [1024];
829                         } else if (writepos >= buffer.Length) {
830                                 char [] newbuf = new char [buffer.Length * 2];
831                                 Buffer.BlockCopy (buffer, 0, newbuf, 0, buffer.Length);
832                                 buffer = newbuf;
833                         }
834
835                         buffer [writepos++] = (char) b;
836                 }
837
838                 void AdjustBuffer ()
839                 {
840                         if (readpos >= writepos) {
841                                 readpos = writepos = 0;
842                         }
843                 }
844
845                 ConsoleKeyInfo CreateKeyInfoFromInt (int n)
846                 {
847                         char c = (char) n;
848                         ConsoleKey key = (ConsoleKey)n;
849                         bool shift = false;
850                         bool ctrl = false;
851                         bool alt = false;
852
853                         if (n == 10) {
854                                 key = ConsoleKey.Enter;
855                         } else if (n == 8 || n == 9 || n == 12 || n == 13 || n == 19) {
856                                 /* Values in ConsoleKey */
857                         } else if (n >= 1 && n <= 26) {
858                                 // For Ctrl-a to Ctrl-z.
859                                 ctrl = true;
860                                 key = ConsoleKey.A + n - 1;
861                         } else if (n == 27) {
862                                 key = ConsoleKey.Escape;
863                         } else if (n >= 'a' && n <= 'z') {
864                                 key = ConsoleKey.A - 'a' + n;
865                         } else if (n >= 'A' && n <= 'Z') {
866                                 shift = true;
867                         } else if (n >= '0' && n <= '9') {
868                         } else {
869                                 key = 0;
870                         }
871
872                         return new ConsoleKeyInfo (c, key, shift, alt, ctrl);
873                 }
874
875                 object GetKeyFromBuffer (bool cooked)
876                 {
877                         if (readpos >= writepos)
878                                 return null;
879
880                         int next = buffer [readpos];
881                         if (!cooked || !rootmap.StartsWith (next)) {
882                                 readpos++;
883                                 AdjustBuffer ();
884                                 return CreateKeyInfoFromInt (next);
885                         }
886
887                         int used;
888                         TermInfoStrings str = rootmap.Match (buffer, readpos, writepos - readpos, out used);
889                         if ((int) str == -1)
890                                 return null;
891
892                         ConsoleKeyInfo key;
893                         if (keymap [str] != null) {
894                                 key = (ConsoleKeyInfo) keymap [str];
895                         } else {
896                                 readpos++;
897                                 AdjustBuffer ();
898                                 return CreateKeyInfoFromInt (next);
899                         }
900
901                         readpos += used;
902                         AdjustBuffer ();
903                         return key;
904                 }
905
906                 ConsoleKeyInfo ReadKeyInternal (out bool fresh)
907                 {
908                         if (!inited)
909                                 Init ();
910
911                         InitKeys ();
912
913                         object o;
914
915                         if ((o = GetKeyFromBuffer (true)) == null) {
916                                 do {
917                                         if (ConsoleDriver.InternalKeyAvailable (150) > 0) {
918                                                 do {
919                                                         AddToBuffer (stdin.Read ());
920                                                 } while (ConsoleDriver.InternalKeyAvailable (0) > 0);
921                                         } else if (stdin.Peek () != -1) {
922                                                 do {
923                                                         AddToBuffer (stdin.Read ());
924                                                 } while (stdin.Peek () != -1);
925                                         } else {                                                
926                                                 if ((o = GetKeyFromBuffer (false)) != null)
927                                                         break;
928
929                                                 AddToBuffer (stdin.Read ());
930                                         }
931                                         
932                                         o = GetKeyFromBuffer (true);
933                                 } while (o == null);
934
935                                 // freshly read character
936                                 fresh = true;
937                         } else {
938                                 // this char was pre-buffered (e.g. not fresh)
939                                 fresh = false;
940                         }
941
942                         return (ConsoleKeyInfo) o;
943                 }
944
945 #region Input echoing optimization
946                 bool InputPending ()
947                 {
948                         // check if we've got pending input we can read immediately
949                         return readpos < writepos || stdin.Peek () != -1;
950                 }
951
952                 char [] echobuf = null;
953                 int echon = 0;
954
955                 // Queues a character to be echo'd back to the console
956                 void QueueEcho (char c)
957                 {
958                         if (echobuf == null)
959                                 echobuf = new char [1024];
960
961                         echobuf[echon++] = c;
962
963                         if (echon == echobuf.Length || !InputPending ()) {
964                                 // blit our echo buffer to the console
965                                 stdout.InternalWriteChars (echobuf, echon);
966                                 echon = 0;
967                         }
968                 }
969
970                 // Queues a key to be echo'd back to the console
971                 void Echo (ConsoleKeyInfo key)
972                 {
973                         if (!IsSpecialKey (key)) {
974                                 QueueEcho (key.KeyChar);
975                                 return;
976                         }
977
978                         // flush pending echo's
979                         EchoFlush ();
980
981                         WriteSpecialKey (key);
982                 }
983
984                 // Flush the pending echo queue
985                 void EchoFlush ()
986                 {
987                         if (echon == 0)
988                                 return;
989
990                         // flush our echo buffer to the console
991                         stdout.InternalWriteChars (echobuf, echon);
992                         echon = 0;
993                 }
994 #endregion
995
996                 public int Read ([In, Out] char [] dest, int index, int count)
997                 {
998                         bool fresh, echo = false;
999                         StringBuilder sbuf;
1000                         ConsoleKeyInfo key;
1001                         int BoL = 0;  // Beginning-of-Line marker (can't backspace beyond this)
1002                         object o;
1003                         char c;
1004
1005                         sbuf = new StringBuilder ();
1006
1007                         // consume buffered keys first (do not echo, these have already been echo'd)
1008                         while (true) {
1009                                 if ((o = GetKeyFromBuffer (true)) == null)
1010                                         break;
1011
1012                                 key = (ConsoleKeyInfo) o;
1013                                 c = key.KeyChar;
1014
1015                                 if (key.Key != ConsoleKey.Backspace) {
1016                                         if (key.Key == ConsoleKey.Enter)
1017                                                 BoL = sbuf.Length;
1018
1019                                         sbuf.Append (c);
1020                                 } else if (sbuf.Length > BoL) {
1021                                         sbuf.Length--;
1022                                 }
1023                         }
1024
1025                         // continue reading until Enter is hit
1026                         rl_startx = cursorLeft;
1027                         rl_starty = cursorTop;
1028
1029                         do {
1030                                 key = ReadKeyInternal (out fresh);
1031                                 echo = echo || fresh;
1032                                 c = key.KeyChar;
1033
1034                                 if (key.Key != ConsoleKey.Backspace) {
1035                                         if (key.Key == ConsoleKey.Enter)
1036                                                 BoL = sbuf.Length;
1037
1038                                         sbuf.Append (c);
1039                                 } else if (sbuf.Length > BoL) {
1040                                         sbuf.Length--;
1041                                 } else {
1042                                         continue;
1043                                 }
1044
1045                                 // echo fresh keys back to the console
1046                                 if (echo)
1047                                         Echo (key);
1048                         } while (key.Key != ConsoleKey.Enter);
1049
1050                         EchoFlush ();
1051
1052                         rl_startx = -1;
1053                         rl_starty = -1;
1054
1055                         // copy up to count chars into dest
1056                         int nread = 0;
1057                         while (count > 0 && nread < sbuf.Length) {
1058                                 dest[index + nread] = sbuf[nread];
1059                                 nread++;
1060                                 count--;
1061                         }
1062
1063                         // put the rest back into our key buffer
1064                         for (int i = nread; i < sbuf.Length; i++)
1065                                 AddToBuffer (sbuf[i]);
1066
1067                         return nread;
1068                 }
1069
1070                 public ConsoleKeyInfo ReadKey (bool intercept)
1071                 {
1072                         bool fresh;
1073
1074                         ConsoleKeyInfo key = ReadKeyInternal (out fresh);
1075
1076                         if (!intercept && fresh) {
1077                                 // echo the fresh key back to the console
1078                                 Echo (key);
1079                                 EchoFlush ();
1080                         }
1081
1082                         return key;
1083                 }
1084
1085                 public string ReadLine ()
1086                 {
1087                         if (!inited)
1088                                 Init ();
1089
1090                         // Hack to make Iron Python work (since it goes behind our backs
1091                         // when writing to the console thus preventing us from keeping
1092                         // cursor state normally).
1093                         GetCursorPosition ();
1094
1095                         StringBuilder builder = new StringBuilder ();
1096                         bool fresh, echo = false;
1097                         ConsoleKeyInfo key;
1098                         char c;
1099
1100                         rl_startx = cursorLeft;
1101                         rl_starty = cursorTop;
1102
1103                         do {
1104                                 key = ReadKeyInternal (out fresh);
1105                                 echo = echo || fresh;
1106                                 c = key.KeyChar;
1107
1108                                 if (key.Key != ConsoleKey.Enter) {
1109                                         if (key.Key != ConsoleKey.Backspace) {
1110                                                 builder.Append (c);
1111                                         } else if (builder.Length > 0) {
1112                                                 builder.Length--;
1113                                         } else {
1114                                                 // skips over echoing the key to the console
1115                                                 continue;
1116                                         }
1117                                 }
1118
1119                                 // echo fresh keys back to the console
1120                                 if (echo)
1121                                         Echo (key);
1122                         } while (key.Key != ConsoleKey.Enter);
1123
1124                         EchoFlush ();
1125
1126                         rl_startx = -1;
1127                         rl_starty = -1;
1128
1129                         return builder.ToString ();
1130                 }
1131
1132                 public void ResetColor ()
1133                 {
1134                         if (!inited) {
1135                                 Init ();
1136                         }
1137
1138                         string str = (origPair != null) ? origPair : origColors;
1139                         WriteConsole (str);
1140                 }
1141
1142                 public void SetBufferSize (int width, int height)
1143                 {
1144                         if (!inited) {
1145                                 Init ();
1146                         }
1147
1148                         throw new NotImplementedException (String.Empty);
1149                 }
1150
1151                 public void SetCursorPosition (int left, int top)
1152                 {
1153                         if (!inited) {
1154                                 Init ();
1155                         }
1156
1157                         if (bufferWidth == 0 && need_window_dimensions)
1158                                 GetWindowDimensions ();
1159
1160                         if (left < 0 || left >= bufferWidth)
1161                                 throw new ArgumentOutOfRangeException ("left", "Value must be positive and below the buffer width.");
1162
1163                         if (top < 0 || top >= bufferHeight)
1164                                 throw new ArgumentOutOfRangeException ("top", "Value must be positive and below the buffer height.");
1165
1166                         // Either CursorAddress or nothing.
1167                         // We might want to play with up/down/left/right/home when ca is not available.
1168                         if (cursorAddress == null)
1169                                 throw new NotSupportedException ("This terminal does not suport setting the cursor position.");
1170
1171                         int one = (home_1_1 ? 1 : 0);
1172                         WriteConsole (String.Format (cursorAddress, top + one, left + one));
1173                         cursorLeft = left;
1174                         cursorTop = top;
1175                 }
1176
1177                 public void SetWindowPosition (int left, int top)
1178                 {
1179                         if (!inited) {
1180                                 Init ();
1181                         }
1182
1183                         // No need to throw exceptions here.
1184                         //throw new NotSupportedException ();
1185                 }
1186
1187                 public void SetWindowSize (int width, int height)
1188                 {
1189                         if (!inited) {
1190                                 Init ();
1191                         }
1192
1193                         // No need to throw exceptions here.
1194                         //throw new NotSupportedException ();
1195                 }
1196
1197
1198                 void CreateKeyMap ()
1199                 {
1200                         keymap = new Hashtable ();
1201                         keymap [TermInfoStrings.KeyBackspace] = new ConsoleKeyInfo ('\0', ConsoleKey.Backspace, false, false, false);
1202                         keymap [TermInfoStrings.KeyClear] = new ConsoleKeyInfo ('\0', ConsoleKey.Clear, false, false, false);
1203                         // Delete character...
1204                         keymap [TermInfoStrings.KeyDown] = new ConsoleKeyInfo ('\0', ConsoleKey.DownArrow, false, false, false);
1205                         keymap [TermInfoStrings.KeyF1] = new ConsoleKeyInfo ('\0', ConsoleKey.F1, false, false, false);
1206                         keymap [TermInfoStrings.KeyF10] = new ConsoleKeyInfo ('\0', ConsoleKey.F10, false, false, false);
1207                         keymap [TermInfoStrings.KeyF2] = new ConsoleKeyInfo ('\0', ConsoleKey.F2, false, false, false);
1208                         keymap [TermInfoStrings.KeyF3] = new ConsoleKeyInfo ('\0', ConsoleKey.F3, false, false, false);
1209                         keymap [TermInfoStrings.KeyF4] = new ConsoleKeyInfo ('\0', ConsoleKey.F4, false, false, false);
1210                         keymap [TermInfoStrings.KeyF5] = new ConsoleKeyInfo ('\0', ConsoleKey.F5, false, false, false);
1211                         keymap [TermInfoStrings.KeyF6] = new ConsoleKeyInfo ('\0', ConsoleKey.F6, false, false, false);
1212                         keymap [TermInfoStrings.KeyF7] = new ConsoleKeyInfo ('\0', ConsoleKey.F7, false, false, false);
1213                         keymap [TermInfoStrings.KeyF8] = new ConsoleKeyInfo ('\0', ConsoleKey.F8, false, false, false);
1214                         keymap [TermInfoStrings.KeyF9] = new ConsoleKeyInfo ('\0', ConsoleKey.F9, false, false, false);
1215                         keymap [TermInfoStrings.KeyHome] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, false, false, false);
1216
1217                         keymap [TermInfoStrings.KeyLeft] = new ConsoleKeyInfo ('\0', ConsoleKey.LeftArrow, false, false, false);
1218                         keymap [TermInfoStrings.KeyLl] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad1, false, false, false);
1219                         keymap [TermInfoStrings.KeyNpage] = new ConsoleKeyInfo ('\0', ConsoleKey.PageDown, false, false, false);
1220                         keymap [TermInfoStrings.KeyPpage] = new ConsoleKeyInfo ('\0', ConsoleKey.PageUp, false, false, false);
1221                         keymap [TermInfoStrings.KeyRight] = new ConsoleKeyInfo ('\0', ConsoleKey.RightArrow, false, false, false);
1222                         keymap [TermInfoStrings.KeySf] = new ConsoleKeyInfo ('\0', ConsoleKey.PageDown, false, false, false);
1223                         keymap [TermInfoStrings.KeySr] = new ConsoleKeyInfo ('\0', ConsoleKey.PageUp, false, false, false);
1224                         keymap [TermInfoStrings.KeyUp] = new ConsoleKeyInfo ('\0', ConsoleKey.UpArrow, false, false, false);
1225                         keymap [TermInfoStrings.KeyA1] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad7, false, false, false);
1226                         keymap [TermInfoStrings.KeyA3] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad9, false, false, false);
1227                         keymap [TermInfoStrings.KeyB2] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad5, false, false, false);
1228                         keymap [TermInfoStrings.KeyC1] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad1, false, false, false);
1229                         keymap [TermInfoStrings.KeyC3] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad3, false, false, false);
1230                         keymap [TermInfoStrings.KeyBtab] = new ConsoleKeyInfo ('\0', ConsoleKey.Tab, true, false, false);
1231                         keymap [TermInfoStrings.KeyBeg] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, false, false, false);
1232                         keymap [TermInfoStrings.KeyCopy] = new ConsoleKeyInfo ('C', ConsoleKey.C, false, true, false);
1233                         keymap [TermInfoStrings.KeyEnd] = new ConsoleKeyInfo ('\0', ConsoleKey.End, false, false, false);
1234                         keymap [TermInfoStrings.KeyEnter] = new ConsoleKeyInfo ('\n', ConsoleKey.Enter, false, false, false);
1235                         keymap [TermInfoStrings.KeyHelp] = new ConsoleKeyInfo ('\0', ConsoleKey.Help, false, false, false);
1236                         keymap [TermInfoStrings.KeyPrint] = new ConsoleKeyInfo ('\0', ConsoleKey.Print, false, false, false);
1237                         keymap [TermInfoStrings.KeyUndo] = new ConsoleKeyInfo ('Z', ConsoleKey.Z , false, true, false);
1238                         keymap [TermInfoStrings.KeySbeg] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, true, false, false);
1239                         keymap [TermInfoStrings.KeyScopy] = new ConsoleKeyInfo ('C', ConsoleKey.C , true, true, false);
1240                         keymap [TermInfoStrings.KeySdc] = new ConsoleKeyInfo ('\x9', ConsoleKey.Delete, true, false, false);
1241                         keymap [TermInfoStrings.KeyShelp] = new ConsoleKeyInfo ('\0', ConsoleKey.Help, true, false, false);
1242                         keymap [TermInfoStrings.KeyShome] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, true, false, false);
1243                         keymap [TermInfoStrings.KeySleft] = new ConsoleKeyInfo ('\0', ConsoleKey.LeftArrow, true, false, false);
1244                         keymap [TermInfoStrings.KeySprint] = new ConsoleKeyInfo ('\0', ConsoleKey.Print, true, false, false);
1245                         keymap [TermInfoStrings.KeySright] = new ConsoleKeyInfo ('\0', ConsoleKey.RightArrow, true, false, false);
1246                         keymap [TermInfoStrings.KeySundo] = new ConsoleKeyInfo ('Z', ConsoleKey.Z, true, false, false);
1247                         keymap [TermInfoStrings.KeyF11] = new ConsoleKeyInfo ('\0', ConsoleKey.F11, false, false, false);
1248                         keymap [TermInfoStrings.KeyF12] = new ConsoleKeyInfo ('\0', ConsoleKey.F12 , false, false, false);
1249                         keymap [TermInfoStrings.KeyF13] = new ConsoleKeyInfo ('\0', ConsoleKey.F13, false, false, false);
1250                         keymap [TermInfoStrings.KeyF14] = new ConsoleKeyInfo ('\0', ConsoleKey.F14, false, false, false);
1251                         keymap [TermInfoStrings.KeyF15] = new ConsoleKeyInfo ('\0', ConsoleKey.F15, false, false, false);
1252                         keymap [TermInfoStrings.KeyF16] = new ConsoleKeyInfo ('\0', ConsoleKey.F16, false, false, false);
1253                         keymap [TermInfoStrings.KeyF17] = new ConsoleKeyInfo ('\0', ConsoleKey.F17, false, false, false);
1254                         keymap [TermInfoStrings.KeyF18] = new ConsoleKeyInfo ('\0', ConsoleKey.F18, false, false, false);
1255                         keymap [TermInfoStrings.KeyF19] = new ConsoleKeyInfo ('\0', ConsoleKey.F19, false, false, false);
1256                         keymap [TermInfoStrings.KeyF20] = new ConsoleKeyInfo ('\0', ConsoleKey.F20, false, false, false);
1257                         keymap [TermInfoStrings.KeyF21] = new ConsoleKeyInfo ('\0', ConsoleKey.F21, false, false, false);
1258                         keymap [TermInfoStrings.KeyF22] = new ConsoleKeyInfo ('\0', ConsoleKey.F22, false, false, false);
1259                         keymap [TermInfoStrings.KeyF23] = new ConsoleKeyInfo ('\0', ConsoleKey.F23, false, false, false);
1260                         keymap [TermInfoStrings.KeyF24] = new ConsoleKeyInfo ('\0', ConsoleKey.F24, false, false, false);
1261                 }
1262
1263                 void InitKeys ()
1264                 {
1265                         if (initKeys)
1266                                 return;
1267
1268                         CreateKeyMap ();
1269                         rootmap = new ByteMatcher ();
1270                         AddStringMapping (TermInfoStrings.KeyBackspace);
1271                         AddStringMapping (TermInfoStrings.KeyClear);
1272                         AddStringMapping (TermInfoStrings.KeyDown);
1273                         AddStringMapping (TermInfoStrings.KeyF1);
1274                         AddStringMapping (TermInfoStrings.KeyF10);
1275                         AddStringMapping (TermInfoStrings.KeyF2);
1276                         AddStringMapping (TermInfoStrings.KeyF3);
1277                         AddStringMapping (TermInfoStrings.KeyF4);
1278                         AddStringMapping (TermInfoStrings.KeyF5);
1279                         AddStringMapping (TermInfoStrings.KeyF6);
1280                         AddStringMapping (TermInfoStrings.KeyF7);
1281                         AddStringMapping (TermInfoStrings.KeyF8);
1282                         AddStringMapping (TermInfoStrings.KeyF9);
1283                         AddStringMapping (TermInfoStrings.KeyHome);
1284                         AddStringMapping (TermInfoStrings.KeyLeft);
1285                         AddStringMapping (TermInfoStrings.KeyLl);
1286                         AddStringMapping (TermInfoStrings.KeyNpage);
1287                         AddStringMapping (TermInfoStrings.KeyPpage);
1288                         AddStringMapping (TermInfoStrings.KeyRight);
1289                         AddStringMapping (TermInfoStrings.KeySf);
1290                         AddStringMapping (TermInfoStrings.KeySr);
1291                         AddStringMapping (TermInfoStrings.KeyUp);
1292                         AddStringMapping (TermInfoStrings.KeyA1);
1293                         AddStringMapping (TermInfoStrings.KeyA3);
1294                         AddStringMapping (TermInfoStrings.KeyB2);
1295                         AddStringMapping (TermInfoStrings.KeyC1);
1296                         AddStringMapping (TermInfoStrings.KeyC3);
1297                         AddStringMapping (TermInfoStrings.KeyBtab);
1298                         AddStringMapping (TermInfoStrings.KeyBeg);
1299                         AddStringMapping (TermInfoStrings.KeyCopy);
1300                         AddStringMapping (TermInfoStrings.KeyEnd);
1301                         AddStringMapping (TermInfoStrings.KeyEnter);
1302                         AddStringMapping (TermInfoStrings.KeyHelp);
1303                         AddStringMapping (TermInfoStrings.KeyPrint);
1304                         AddStringMapping (TermInfoStrings.KeyUndo);
1305                         AddStringMapping (TermInfoStrings.KeySbeg);
1306                         AddStringMapping (TermInfoStrings.KeyScopy);
1307                         AddStringMapping (TermInfoStrings.KeySdc);
1308                         AddStringMapping (TermInfoStrings.KeyShelp);
1309                         AddStringMapping (TermInfoStrings.KeyShome);
1310                         AddStringMapping (TermInfoStrings.KeySleft);
1311                         AddStringMapping (TermInfoStrings.KeySprint);
1312                         AddStringMapping (TermInfoStrings.KeySright);
1313                         AddStringMapping (TermInfoStrings.KeySundo);
1314                         AddStringMapping (TermInfoStrings.KeyF11);
1315                         AddStringMapping (TermInfoStrings.KeyF12);
1316                         AddStringMapping (TermInfoStrings.KeyF13);
1317                         AddStringMapping (TermInfoStrings.KeyF14);
1318                         AddStringMapping (TermInfoStrings.KeyF15);
1319                         AddStringMapping (TermInfoStrings.KeyF16);
1320                         AddStringMapping (TermInfoStrings.KeyF17);
1321                         AddStringMapping (TermInfoStrings.KeyF18);
1322                         AddStringMapping (TermInfoStrings.KeyF19);
1323                         AddStringMapping (TermInfoStrings.KeyF20);
1324                         AddStringMapping (TermInfoStrings.KeyF21);
1325                         AddStringMapping (TermInfoStrings.KeyF22);
1326                         AddStringMapping (TermInfoStrings.KeyF23);
1327                         AddStringMapping (TermInfoStrings.KeyF24);
1328                         rootmap.Sort ();
1329                         initKeys = true;
1330                 }
1331
1332                 void AddStringMapping (TermInfoStrings s)
1333                 {
1334                         byte [] bytes = reader.GetStringBytes (s);
1335                         if (bytes == null)
1336                                 return;
1337
1338                         rootmap.AddMapping (s, bytes);
1339                 }
1340         }
1341
1342         class ByteMatcher {
1343                 Hashtable map = new Hashtable ();
1344                 Hashtable starts = new Hashtable ();
1345
1346                 public void AddMapping (TermInfoStrings key, byte [] val)
1347                 {
1348                         if (val.Length == 0)
1349                                 return;
1350
1351                         map [val] = key;
1352                         starts [(int) val [0]] = true;
1353                 }
1354
1355                 public void Sort ()
1356                 {
1357                 }
1358
1359                 public bool StartsWith (int c)
1360                 {
1361                         return (starts [c] != null);
1362                 }
1363
1364                 public TermInfoStrings Match (char [] buffer, int offset, int length, out int used)
1365                 {
1366                         foreach (byte [] bytes in map.Keys) {
1367                                 for (int i = 0; i < bytes.Length && i < length; i++) {
1368                                         if ((char) bytes [i] != buffer [offset + i])
1369                                                 break;
1370
1371                                         if (bytes.Length - 1 == i) {
1372                                                 used = bytes.Length;
1373                                                 return (TermInfoStrings) map [bytes];
1374                                         }
1375                                 }
1376                         }
1377
1378                         used = 0;
1379                         return (TermInfoStrings) (-1);
1380                 }
1381         }
1382 }
1383 #endif
1384