SHEL5
[efi/shell/.git] / shellenv / conio.c
1 /*++
2
3 Copyright (c) 2005, Intel Corporation                                                         
4 All rights reserved. This program and the accompanying materials                          
5 are licensed and made available under the terms and conditions of the BSD License         
6 which accompanies this distribution. The full text of the license may be found at         
7 http://opensource.org/licenses/bsd-license.php                                            
8                                                                                           
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
11
12 Module Name:
13
14   conio.c
15   
16 Abstract: 
17
18   Shell Environment driver
19
20 Revision History
21
22 --*/
23
24 #include "shelle.h"
25 #include "shellenvguid.h"
26
27 //
28 //
29 //
30 #define MAX_HISTORY           20
31
32 #define MODE_MIN_COLUMN       80
33 #define MODE_MIN_ROW          25
34
35 #define INPUT_LINE_SIGNATURE  EFI_SIGNATURE_32 ('i', 's', 'i', 'g')
36
37 //
38 // add this line to aVOID record keyboard history as memory leak
39 //
40 #undef AllocateZeroPool
41
42 typedef struct {
43   UINTN           Signature;
44   EFI_LIST_ENTRY  Link;
45   CHAR16          *Buffer;
46 } INPUT_LINE;
47
48 //
49 // Globals
50 //
51 STATIC BOOLEAN        SEnvInsertMode;
52 STATIC EFI_LIST_ENTRY SEnvLineHistory;
53 STATIC UINTN          SEnvNoHistory;
54
55 //
56 //
57 //
58 VOID
59 SEnvConIoInitDosKey (
60   VOID
61   )
62 /*++
63
64 Routine Description:
65
66 Arguments:
67
68 Returns:
69
70 --*/
71 {
72   InitializeListHead (&SEnvLineHistory);
73   SEnvInsertMode  = TRUE;
74   SEnvNoHistory   = 0;
75 }
76
77 EFI_STATUS
78 EFIAPI
79 SEnvConIoOpen (
80   IN EFI_FILE                   *File,
81   OUT EFI_FILE                  **NewHandle,
82   IN CHAR16                     *FileName,
83   IN UINT64                     OpenMode,
84   IN UINT64                     Attributes
85   )
86 /*++
87
88 Routine Description:
89
90   Functions used to access the console interface via a file handle
91   Used if the console is not being redirected to a file
92
93 Arguments:
94
95   File       - The file
96   NewHandle  - The new handle
97   FileName   - The file name
98   OpenMode   - The open mode
99   Attributes - Attributes
100
101 Returns:
102
103   EFI_NOT_FOUND - Not found
104 --*/
105 {
106   return EFI_NOT_FOUND;
107 }
108
109 EFI_STATUS
110 EFIAPI
111 SEnvConIoNop (
112   IN EFI_FILE  *File
113   )
114 /*++
115
116 Routine Description:
117
118 Arguments:
119
120   File - The file
121
122 Returns:
123
124   EFI_SUCCESS - Success
125
126 --*/
127 {
128   return EFI_SUCCESS;
129 }
130
131 EFI_STATUS
132 EFIAPI
133 SEnvConIoGetPosition (
134   IN EFI_FILE                   *File,
135   OUT UINT64                    *Position
136   )
137 /*++
138
139 Routine Description:
140
141 Arguments:
142
143   File     - The file
144   Position - Position
145   
146 Returns:
147
148   EFI_UNSUPPORTED - Unsupported
149
150 --*/
151 {
152   return EFI_UNSUPPORTED;
153 }
154
155 EFI_STATUS
156 EFIAPI
157 SEnvConIoSetPosition (
158   IN EFI_FILE                   *File,
159   OUT UINT64                    Position
160   )
161 /*++
162
163 Routine Description:
164
165 Arguments:
166
167   File     - The file
168   Position - THe position
169
170 Returns:
171
172   EFI_UNSUPPORTED - add return value to function comment
173
174 --*/
175 {
176   return EFI_UNSUPPORTED;
177 }
178
179 EFI_STATUS
180 EFIAPI
181 SEnvConIoGetInfo (
182   IN EFI_FILE                   *File,
183   IN EFI_GUID                   *InformationType,
184   IN OUT UINTN                  *BufferSize,
185   OUT VOID                      *Buffer
186   )
187 /*++
188
189 Routine Description:
190
191 Arguments:
192
193   File            - The file
194   InformationType - The infomation type
195   BufferSize      - The buffer size
196   Buffer          - The buffer
197
198 Returns:
199
200   EFI_UNSUPPORTED - Unsupported
201   
202 --*/
203 {
204   return EFI_UNSUPPORTED;
205 }
206
207 EFI_STATUS
208 EFIAPI
209 SEnvConIoSetInfo (
210   IN EFI_FILE                   *File,
211   IN EFI_GUID                   *InformationType,
212   IN UINTN                      BufferSize,
213   OUT VOID                      *Buffer
214   )
215 /*++
216
217 Routine Description:
218
219 Arguments:
220
221   File            - The file
222   InformationType - The infomation type
223   BufferSize      - The buffer size
224   Buffer          - The buffer
225
226 Returns:
227
228   EFI_UNSUPPORTED - Unsupported
229
230 --*/
231 {
232   return EFI_UNSUPPORTED;
233 }
234
235 EFI_STATUS
236 EFIAPI
237 SEnvConIoWrite (
238   IN EFI_FILE                   *File,
239   IN OUT UINTN                  *BufferSize,
240   IN VOID                       *Buffer
241   )
242 /*++
243
244 Routine Description:
245
246 Arguments:
247
248   File       - The file
249   BufferSize - The buffer size
250   Buffer     - The buffer
251
252 Returns:
253   EFI_SUCCESS - Success
254
255 --*/
256 {
257   PrintToken (STRING_TOKEN (STR_SHELLENV_CONIO_ONE_VAR_S_PTR), HiiEnvHandle, *BufferSize, Buffer);
258   return EFI_SUCCESS;
259 }
260
261 EFI_STATUS
262 EFIAPI
263 SEnvErrIoWrite (
264   IN EFI_FILE                   *File,
265   IN OUT UINTN                  *BufferSize,
266   IN VOID                       *Buffer
267   )
268 /*++
269
270 Routine Description:
271
272 Arguments:
273
274   File       - The file
275   BufferSize - The buffer size
276   Buffer     - The buffer
277
278 Returns:
279   EFI_SUCCESS - Success
280
281 --*/
282 {
283   IPrint (ST->StdErr, L"%.*s", *BufferSize, Buffer);
284   return EFI_SUCCESS;
285 }
286
287 EFI_STATUS
288 EFIAPI
289 SEnvErrIoRead (
290   IN EFI_FILE                   *File,
291   IN OUT UINTN                  *BufferSize,
292   IN VOID                       *Buffer
293   )
294 /*++
295
296 Routine Description:
297
298 Arguments:
299
300   File       - The file
301   BufferSize - The buffer size
302   Buffer     - The buffer
303
304 Returns:
305   EFI_UNSUPPORTED - Unsupported
306
307 --*/
308 {
309   return EFI_UNSUPPORTED;
310 }
311
312 VOID
313 SEnvPrintHistory (
314   VOID
315   )
316 /*++
317
318 Routine Description:
319
320 Arguments:
321
322 Returns:
323
324 --*/
325 {
326   EFI_LIST_ENTRY  *Link;
327   INPUT_LINE      *Line;
328   UINTN           Index;
329   UINTN           LineNumber;
330   UINTN           StartColumn;
331   UINTN           LineLength;
332   UINTN           TotalRow;
333   UINTN           LineCount;
334   CHAR16          InputStr[1];
335
336   Print (L"\n");
337   Index       = 0;
338   LineNumber  = 0;
339   StartColumn = 4;
340   ST->ConOut->QueryMode (
341                 ST->ConOut,
342                 ST->ConOut->Mode->Mode,
343                 &LineLength,
344                 &TotalRow
345                 );
346
347   //
348   // Print history
349   //
350   for (Link = SEnvLineHistory.Flink; Link != &SEnvLineHistory; Link = Link->Flink) {
351     Index += 1;
352     Line      = CR (Link, INPUT_LINE, Link, INPUT_LINE_SIGNATURE);
353     LineCount = (StrLen (Line->Buffer) + StartColumn + 1) / LineLength + 1;
354
355     if (LineNumber + LineCount >= TotalRow) {
356       PrintToken (STRING_TOKEN (STR_SHELLENV_CONIO_ENTER_CONTINUE), HiiEnvHandle);
357       Input (NULL, InputStr, 1);
358       Print (L"\n");
359       LineNumber = 0;
360     }
361
362     PrintToken (STRING_TOKEN (STR_SHELLENV_CONIO_TWO_VARS_D_S), HiiEnvHandle, Index, Line->Buffer);
363     LineNumber += LineCount;
364   }
365 }
366
367 VOID
368 MoveCursorBackward (
369   IN     UINTN                   LineLength,
370   IN OUT UINTN                   *Column,
371   IN OUT UINTN                   *Row
372   )
373 /*++
374
375 Routine Description:
376   Move the cursor position one character backward.
377
378 Arguments:
379   LineLength       Length of a line. Get it by calling QueryMode
380   Column           Current column of the cursor position
381   Row              Current row of the cursor position
382
383 Returns:
384
385 --*/
386 {
387   //
388   // If current column is 0, move to the last column of the previous line,
389   // otherwise, just decrement column.
390   //
391   if (*Column == 0) {
392     (*Column) = LineLength - 1;
393     if (*Row > 0) {
394       (*Row)--;
395     }
396   } else {
397     (*Column)--;
398   }
399 }
400
401 VOID
402 MoveCursorForward (
403   IN     UINTN                   LineLength,
404   IN     UINTN                   TotalRow,
405   IN OUT UINTN                   *Column,
406   IN OUT UINTN                   *Row
407   )
408 /*++
409
410 Routine Description:
411   Move the cursor position one character backward.
412
413 Arguments:
414   LineLength       Length of a line. Get it by calling QueryMode
415   TotalRow         Total row of a screen, get by calling QueryMode
416   Column           Current column of the cursor position
417   Row              Current row of the cursor position
418
419 Returns:
420
421 --*/
422 {
423   //
424   // If current column is at line end, move to the first column of the nest
425   // line, otherwise, just increment column.
426   //
427   (*Column)++;
428   if (*Column >= LineLength) {
429     (*Column) = 0;
430     if ((*Row) < TotalRow - 1) {
431       (*Row)++;
432     }
433   }
434 }
435
436 EFI_STATUS
437 EFIAPI
438 SEnvConIoRead (
439   IN EFI_FILE                       *File,
440   IN OUT UINTN                      *BufferSize,
441   IN VOID                           *Buffer
442   )
443 /*++
444
445 Routine Description:
446   Get a line from the console.
447
448 Arguments:
449   File             File handle, actually not used in this function
450   BufferSize       Size of the buffer
451   Buffer           Buffer to hold the line from console
452
453 Returns:
454   EFI_SUCCESS      The function finished successfully
455   EFI_OUT_OF_RESOURCES Out of resources
456   
457 --*/
458 {
459   CHAR16                        *Str;
460   BOOLEAN                       Done;
461   UINTN                         Column;
462   UINTN                         Row;
463   UINTN                         StartColumn;
464   UINTN                         Update;
465   UINTN                         Delete;
466   UINTN                         Len;
467   UINTN                         StrPos;
468   UINTN                         MaxStr;
469   UINTN                         Index;
470   UINTN                         LineLength;
471   UINTN                         TotalRow;
472   UINTN                         SkipLength;
473   UINTN                         OutputLength;
474   UINTN                         TailRow;
475   UINTN                         TailColumn;
476   EFI_INPUT_KEY                 Key;
477   EFI_SIMPLE_TEXT_OUT_PROTOCOL  *ConOut;
478   EFI_SIMPLE_TEXT_IN_PROTOCOL   *ConIn;
479   INPUT_LINE                    *NewLine;
480   INPUT_LINE                    *LineCmd;
481   EFI_LIST_ENTRY                *LinePos;
482   EFI_LIST_ENTRY                *NewPos;
483   BOOLEAN                       InScrolling;
484
485   ConOut            = ST->ConOut;
486   ConIn             = ST->ConIn;
487   Str               = Buffer;
488   Len               = 0;
489   StrPos            = 0;
490   OutputLength      = 0;
491   Update            = 0;
492   Delete            = 0;
493   LinePos           = NewPos = &SEnvLineHistory;
494
495   InScrolling       = FALSE;
496
497   //
498   // If buffer is not large enough to hold a CHAR16, do nothing.
499   //
500   if (*BufferSize < sizeof (CHAR16) * 2) {
501     *BufferSize = 0;
502     return EFI_SUCCESS;
503   }
504   //
505   // Get the screen setting and the current cursor location
506   //
507   StartColumn = ConOut->Mode->CursorColumn;
508   Column      = StartColumn;
509   Row         = ConOut->Mode->CursorRow;
510   ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &LineLength, &TotalRow);
511
512   //
513   // Limit the line length to the buffer size or the minimun size of the
514   // screen. (The smaller takes effect)
515   //
516   MaxStr = LineLength * (TotalRow - 1) - StartColumn;
517   if (MaxStr > *BufferSize / sizeof (CHAR16)) {
518     MaxStr = *BufferSize / sizeof (CHAR16);
519   }
520
521   ZeroMem (Str, MaxStr * sizeof (CHAR16));
522   Done = FALSE;
523   do {
524     //
525     // Read a key
526     //
527     WaitForSingleEvent (ConIn->WaitForKey, 0);
528     ConIn->ReadKeyStroke (ConIn, &Key);
529
530     //
531     // Press PageUp or PageDown to scroll the history screen up or down.
532     // Press any other key to quit scrolling.
533     //
534     if (Key.UnicodeChar == 0 && (Key.ScanCode == SCAN_PAGE_UP || Key.ScanCode == SCAN_PAGE_DOWN)) {
535       if (Key.ScanCode == SCAN_PAGE_UP) {
536         SEnvConOutHistoryScrollBack (NULL);
537       } else if (Key.ScanCode == SCAN_PAGE_DOWN) {
538         SEnvConOutHistoryScrollForward (NULL);
539       }
540
541       InScrolling = TRUE;
542     } else {
543       if (InScrolling) {
544         SEnvConOutHistoryQuitScroll ();
545         InScrolling = FALSE;
546       }
547     }
548
549     switch (Key.UnicodeChar) {
550     case CHAR_CARRIAGE_RETURN:
551       //
552       // All done, print a newline at the end of the string
553       //
554       TailRow     = Row + (Len - StrPos + Column) / LineLength;
555       TailColumn  = (Len - StrPos + Column) % LineLength;
556       PrintAt (TailColumn, TailRow, L"%N\n");
557       Done = TRUE;
558       break;
559
560     case CHAR_BACKSPACE:
561       if (StrPos) {
562         //
563         // If not move back beyond string beginning, move all characters behind
564         // the current position one character forward
565         //
566         StrPos -= 1;
567         Update  = StrPos;
568         Delete  = 1;
569         CopyMem (Str + StrPos, Str + StrPos + 1, sizeof (CHAR16) * (Len - StrPos));
570
571         //
572         // Adjust the current column and row
573         //
574         MoveCursorBackward (LineLength, &Column, &Row);
575       }
576       break;
577
578     default:
579       if (Key.UnicodeChar >= ' ') {
580         //
581         // If we are at the buffer's end, drop the key
582         //
583         if (Len == MaxStr - 1 && (SEnvInsertMode || StrPos == Len)) {
584           break;
585         }
586         //
587         // If in insert mode, move all characters behind the current position
588         // one character backward to make space for this character. Then store
589         // the character.
590         //
591         if (SEnvInsertMode) {
592           for (Index = Len; Index > StrPos; Index -= 1) {
593             Str[Index] = Str[Index - 1];
594           }
595         }
596
597         Str[StrPos] = Key.UnicodeChar;
598         Update      = StrPos;
599
600         StrPos += 1;
601         OutputLength = 1;
602       }
603       break;
604
605     case 0:
606       switch (Key.ScanCode) {
607       case SCAN_DELETE:
608         //
609         // Move characters behind current position one character forward
610         //
611         if (Len) {
612           Update  = StrPos;
613           Delete  = 1;
614           CopyMem (Str + StrPos, Str + StrPos + 1, sizeof (CHAR16) * (Len - StrPos));
615         }
616         break;
617
618       case SCAN_UP:
619         //
620         // Prepare to print the previous command
621         //
622         NewPos = LinePos->Blink;
623         if (NewPos == &SEnvLineHistory) {
624           NewPos = NewPos->Blink;
625         }
626         break;
627
628       case SCAN_DOWN:
629         //
630         // Prepare to print the next command
631         //
632         NewPos = LinePos->Flink;
633         if (NewPos == &SEnvLineHistory) {
634           NewPos = NewPos->Flink;
635         }
636         break;
637
638       case SCAN_LEFT:
639         //
640         // Adjust current cursor position
641         //
642         if (StrPos) {
643           StrPos -= 1;
644           MoveCursorBackward (LineLength, &Column, &Row);
645         }
646         break;
647
648       case SCAN_RIGHT:
649         //
650         // Adjust current cursor position
651         //
652         if (StrPos < Len) {
653           StrPos += 1;
654           MoveCursorForward (LineLength, TotalRow, &Column, &Row);
655         }
656         break;
657
658       case SCAN_HOME:
659         //
660         // Move current cursor position to the beginning of the command line
661         //
662         Row -= (StrPos + StartColumn) / LineLength;
663         Column  = StartColumn;
664         StrPos  = 0;
665         break;
666
667       case SCAN_END:
668         //
669         // Move current cursor position to the end of the command line
670         //
671         TailRow     = Row + (Len - StrPos + Column) / LineLength;
672         TailColumn  = (Len - StrPos + Column) % LineLength;
673         Row         = TailRow;
674         Column      = TailColumn;
675         StrPos      = Len;
676         break;
677
678       case SCAN_ESC:
679         //
680         // Prepare to clear the current command line
681         //
682         Str[0]  = 0;
683         Update  = 0;
684         Delete  = Len;
685         Row -= (StrPos + StartColumn) / LineLength;
686         Column        = StartColumn;
687         OutputLength  = 0;
688         break;
689
690       case SCAN_INSERT:
691         //
692         // Toggle the SEnvInsertMode flag
693         //
694         SEnvInsertMode = (BOOLEAN)!SEnvInsertMode;
695         break;
696
697       case SCAN_F7:
698         //
699         // Print command history
700         //
701         SEnvPrintHistory ();
702         *Str  = 0;
703         Done  = TRUE;
704         break;
705       }
706     }
707
708     if (Done) {
709       break;
710     }
711     //
712     // If we have a new position, we are preparing to print a previous or next
713     // command.
714     //
715     if (NewPos != &SEnvLineHistory) {
716       Column = StartColumn;
717       Row -= (StrPos + StartColumn) / LineLength;
718
719       LineCmd       = CR (NewPos, INPUT_LINE, Link, INPUT_LINE_SIGNATURE);
720       LinePos       = NewPos;
721       NewPos        = &SEnvLineHistory;
722
723       OutputLength  = StrLen (LineCmd->Buffer) < MaxStr - 1 ? StrLen (LineCmd->Buffer) : MaxStr - 1;
724       CopyMem (Str, LineCmd->Buffer, OutputLength * sizeof (CHAR16));
725       Str[OutputLength] = 0;
726
727       StrPos            = OutputLength;
728
729       //
730       // Draw new input string
731       //
732       Update = 0;
733       if (Len > OutputLength) {
734         //
735         // If old string was longer, blank its tail
736         //
737         Delete = Len - OutputLength;
738       }
739     }
740     //
741     // If we need to update the output do so now
742     //
743     if (Update != -1) {
744       PrintAt (Column, Row, L"%s%.*s", Str + Update, Delete, L"");
745       Len = StrLen (Str);
746
747       if (Delete) {
748         SetMem (Str + Len, Delete * sizeof (CHAR16), 0x00);
749       }
750
751       if (StrPos > Len) {
752         StrPos = Len;
753       }
754
755       Update = (UINTN) -1;
756
757       //
758       // After using print to reflect newly updates, if we're not using
759       // BACKSPACE and DELETE, we need to move the cursor position forward,
760       // so adjust row and column here.
761       //
762       if (Key.UnicodeChar != CHAR_BACKSPACE && !(Key.UnicodeChar == 0 && Key.ScanCode == SCAN_DELETE)) {
763         //
764         // Calulate row and column of the tail of current string
765         //
766         TailRow     = Row + (Len - StrPos + Column + OutputLength) / LineLength;
767         TailColumn  = (Len - StrPos + Column + OutputLength) % LineLength;
768
769         //
770         // If the tail of string reaches screen end, screen rolls up, so if
771         // Row does not equal TailRow, Row should be decremented
772         //
773         // (if we are recalling commands using UPPER and DOWN key, and if the
774         // old command is too long to fit the screen, TailColumn must be 79.
775         //
776         if (TailColumn == 0 && TailRow >= TotalRow && Row != TailRow) {
777           Row--;
778         }
779         //
780         // Calculate the cursor position after current operation. If cursor
781         // reaches line end, update both row and column, otherwise, only
782         // column will be changed.
783         //
784         if (Column + OutputLength >= LineLength) {
785           SkipLength = OutputLength - (LineLength - Column);
786
787           Row += SkipLength / LineLength + 1;
788           if (Row > TotalRow - 1) {
789             Row = TotalRow - 1;
790           }
791
792           Column = SkipLength % LineLength;
793         } else {
794           Column += OutputLength;
795         }
796       }
797
798       Delete = 0;
799     }
800     //
801     // Set the cursor position for this key
802     //
803     ConOut->SetCursorPosition (ConOut, Column, Row);
804   } while (!Done);
805
806   //
807   // Copy the line to the history buffer
808   //
809   if (Str[0]) {
810     //
811     // Allocate and initalize a new key entry for command history
812     //
813     NewLine = AllocateZeroPool (sizeof (INPUT_LINE));
814     if (!NewLine) {
815       return EFI_OUT_OF_RESOURCES;
816     }
817
818     NewLine->Signature  = INPUT_LINE_SIGNATURE;
819     NewLine->Buffer     = AllocateZeroPool ((Len + 1) * sizeof (CHAR16));
820     if (NewLine->Buffer == NULL) {
821       FreePool (NewLine);
822       return EFI_OUT_OF_RESOURCES;
823     }
824
825     StrCpy (NewLine->Buffer, Str);
826     InsertTailList (&SEnvLineHistory, &NewLine->Link);
827     SEnvNoHistory++;
828   }
829   //
830   // If there's too much in the history buffer free an entry
831   //
832   if (SEnvNoHistory > MAX_HISTORY) {
833     LineCmd = CR (
834                 SEnvLineHistory.Flink,
835                 INPUT_LINE,
836                 Link,
837                 INPUT_LINE_SIGNATURE
838                 );
839     RemoveEntryList (&LineCmd->Link);
840     SEnvNoHistory--;
841     if (LineCmd->Buffer) {
842       FreePool (LineCmd->Buffer);
843     }
844
845     FreePool (LineCmd);
846   }
847   //
848   // Return the data to the caller
849   //
850   *BufferSize = Len * sizeof (CHAR16);
851   return EFI_SUCCESS;
852 }
853 //
854 //
855 //
856 EFI_STATUS
857 EFIAPI
858 SEnvReset (
859   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL     *This,
860   IN BOOLEAN                          ExtendedVerification
861   )
862 /*++
863
864 Routine Description:
865
866 Arguments:
867
868    This - This protocol
869    ExtendedVerification - To extended verification
870
871 Returns:
872   EFI_SUCCESS Success
873
874 --*/
875 {
876   return EFI_SUCCESS;
877 }
878
879 EFI_STATUS
880 EFIAPI
881 SEnvOutputString (
882   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
883   IN CHAR16                       *String
884   )
885 /*++
886
887 Routine Description:
888
889 Arguments:
890
891   This - This protocol
892   String - The string
893
894 Returns:
895
896 --*/
897 {
898   EFI_STATUS                    Status;
899   ENV_SHELL_REDIR_FILE          *Redir;
900   UINTN                         Len;
901   UINTN                         Size;
902   UINTN                         WriteSize;
903   UINTN                         Index;
904   UINTN                         Start;
905   CHAR8                         Buffer[100];
906   CHAR16                        UnicodeBuffer[100];
907   BOOLEAN                       InvalidChar;
908
909   EFI_SIMPLE_TEXT_IN_PROTOCOL   *TextIn;
910   EFI_SIMPLE_TEXT_OUT_PROTOCOL  *TextOut;
911
912   TextIn  = NULL;
913   TextOut = NULL;
914
915   //
916   // Get Shell redirection device
917   //
918   Redir = CR (This, ENV_SHELL_REDIR_FILE, Out, ENV_REDIR_SIGNATURE);
919   if (EFI_ERROR (Redir->WriteError)) {
920     return Redir->WriteError;
921   }
922
923   Status      = EFI_SUCCESS;
924   InvalidChar = FALSE;
925
926   if (Redir->Ascii) {
927     //
928     // Handle for ASCII
929     //
930     Start = 0;
931     Len   = StrLen (String);
932     while (Len) {
933       Size = Len > sizeof (Buffer) ? sizeof (Buffer) : Len;
934       for (Index = 0; Index < Size; Index += 1) {
935         if (String[Start + Index] > 0xff) {
936           Buffer[Index] = '_';
937           InvalidChar   = TRUE;
938         } else {
939           Buffer[Index] = (CHAR8) String[Start + Index];
940         }
941       }
942
943       WriteSize = Size;
944       if (WriteSize > 0) {
945         Status = Redir->File->Write (Redir->File, &WriteSize, Buffer);
946         if (EFI_ERROR (Status)) {
947           break;
948         }
949       }
950
951       Len -= Size;
952       Start += Size;
953     }
954
955   } else {
956     //
957     // Unicode
958     //
959     Len = StrSize (String) - sizeof (CHAR16);
960     if (Len > 0) {
961       Status = Redir->File->Write (Redir->File, &Len, String);
962     }
963   }
964   //
965   // Error check
966   //
967   if (EFI_ERROR (Status)) {
968     Redir->WriteError = Status;
969     SEnvBatchGetConsole (&TextIn, &TextOut);
970     SPrint (UnicodeBuffer, 100, L"write error: %r\n\r", Status);
971     Status = TextOut->OutputString (TextOut, UnicodeBuffer);
972   }
973
974   if (InvalidChar && !EFI_ERROR (Status)) {
975     Status = EFI_WARN_UNKNOWN_GLYPH;
976   }
977
978   return Status;
979 }
980
981 EFI_STATUS
982 EFIAPI
983 SEnvTestString (
984   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
985   IN CHAR16                       *String
986   )
987 /*++
988
989 Routine Description:
990
991 Arguments:
992
993   This - This protocol
994   String - The string
995
996 Returns:
997
998 --*/
999 {
1000   EFI_STATUS            Status;
1001   ENV_SHELL_REDIR_FILE  *Redir;
1002
1003   Redir   = CR (This, ENV_SHELL_REDIR_FILE, Out, ENV_REDIR_SIGNATURE);
1004   Status  = ST->ConOut->TestString (ST->ConOut, String);
1005
1006   //
1007   // Test String
1008   //
1009   if (!EFI_ERROR (Status) && Redir->Ascii) {
1010     while (*String && *String < 0x100) {
1011       String += 1;
1012     }
1013
1014     if (*String > 0xff) {
1015       Status = EFI_UNSUPPORTED;
1016     }
1017   }
1018
1019   return Status;
1020 }
1021
1022 EFI_STATUS
1023 EFIAPI
1024 SEnvQueryMode (
1025   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
1026   IN UINTN                        ModeNumber,
1027   OUT UINTN                       *Columns,
1028   OUT UINTN                       *Rows
1029   )
1030 /*++
1031
1032 Routine Description:
1033
1034 Arguments:
1035
1036   This       - This       
1037   ModeNumber - ModeNumber 
1038   Columns    - Columns    
1039   Rows       - Rows       
1040
1041 Returns:
1042   EFI_INVALID_PARAMETER - Invalid parameter
1043   EFI_SUCCESS - Success
1044
1045 --*/
1046 {
1047   if (ModeNumber > 0) {
1048     return EFI_INVALID_PARAMETER;
1049   }
1050
1051   *Columns  = 0;
1052   *Rows     = 0;
1053   return EFI_SUCCESS;
1054 }
1055
1056 EFI_STATUS
1057 EFIAPI
1058 SEnvSetMode (
1059   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
1060   IN UINTN                        ModeNumber
1061   )
1062 /*++
1063
1064 Routine Description:
1065
1066 Arguments:
1067
1068   This - This protocol
1069   ModeNumber - ModeNumber
1070
1071 Returns:
1072
1073 --*/
1074 {
1075   return ModeNumber > 0 ? EFI_INVALID_PARAMETER : EFI_SUCCESS;
1076 }
1077
1078 EFI_STATUS
1079 EFIAPI
1080 SEnvSetAttribute (
1081   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL     *This,
1082   IN UINTN                            Attribute
1083   )
1084 /*++
1085
1086 Routine Description:
1087
1088 Arguments:
1089
1090   This - This protocol
1091   Attribute - The attribute
1092
1093 Returns:
1094
1095   EFI_SUCCESS - Success
1096
1097 --*/
1098 {
1099   This->Mode->Attribute = (UINT32) Attribute;
1100   return EFI_SUCCESS;
1101 }
1102
1103 EFI_STATUS
1104 EFIAPI
1105 SEnvClearScreen (
1106   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This
1107   )
1108 /*++
1109
1110 Routine Description:
1111
1112 Arguments:
1113
1114   This - This protocol
1115
1116 Returns:
1117
1118   EFI_SUCCESS - Success
1119   
1120 --*/
1121 {
1122   return EFI_SUCCESS;
1123 }
1124
1125 EFI_STATUS
1126 EFIAPI
1127 SEnvSetCursorPosition (
1128   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
1129   IN UINTN                        Column,
1130   IN UINTN                        Row
1131   )
1132 /*++
1133
1134 Routine Description:
1135
1136 Arguments:
1137
1138   This   - This protocol
1139   Column - The column
1140   Row    - The row
1141
1142 Returns:
1143
1144   EFI_UNSUPPORTED - Unsupported
1145
1146 --*/
1147 {
1148   return EFI_UNSUPPORTED;
1149 }
1150
1151 EFI_STATUS
1152 EFIAPI
1153 SEnvEnableCursor (
1154   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
1155   IN BOOLEAN                      Enable
1156   )
1157 /*++
1158
1159 Routine Description:
1160
1161 Arguments:
1162
1163   This - This protcol
1164   Enable - Enable the cursor
1165   
1166 Returns:
1167
1168   EFI_SUCCESS - Success
1169   
1170 --*/
1171 {
1172   This->Mode->CursorVisible = Enable;
1173   return EFI_SUCCESS;
1174 }
1175
1176 EFI_STATUS
1177 EFIAPI
1178 SEnvDummyReset (
1179   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL     *This,
1180   IN BOOLEAN                          ExtendedVerification
1181   )
1182 /*++
1183
1184 Routine Description:
1185
1186 Arguments:
1187
1188   This - This protocol
1189   ExtendedVerification - Extended verification
1190
1191 Returns:
1192
1193   EFI_SUCCESS - Success
1194   
1195 --*/
1196 {
1197   return EFI_SUCCESS;
1198 }
1199
1200 EFI_STATUS
1201 EFIAPI
1202 SEnvDummyOutputString (
1203   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
1204   IN CHAR16                       *String
1205   )
1206 /*++
1207
1208 Routine Description:
1209
1210 Arguments:
1211
1212   This - This protocol
1213   String - The string
1214
1215 Returns:
1216
1217   EFI_SUCCESS  - Success
1218 --*/
1219 {
1220   return EFI_SUCCESS;
1221 }
1222
1223 EFI_STATUS
1224 EFIAPI
1225 SEnvDummyTestString (
1226   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
1227   IN CHAR16                       *String
1228   )
1229 /*++
1230
1231 Routine Description:
1232
1233 Arguments:
1234
1235   This - This protocol
1236   String - The string
1237
1238 Returns:
1239
1240   EFI_SUCCESS  - Success
1241 --*/
1242 {
1243   return EFI_SUCCESS;
1244 }
1245
1246 EFI_STATUS
1247 EFIAPI
1248 SEnvDummyQueryMode (
1249   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
1250   IN UINTN                        ModeNumber,
1251   OUT UINTN                       *Columns,
1252   OUT UINTN                       *Rows
1253   )
1254 /*++
1255
1256 Routine Description:
1257
1258 Arguments:
1259
1260   This       - This protocol
1261   ModeNumber - The mode number
1262   Columns    - The Columns
1263   Rows       - The Rows
1264
1265 Returns:
1266
1267   EFI_SUCCESS  - Success
1268 --*/
1269 {
1270   return EFI_SUCCESS;
1271 }
1272
1273 EFI_STATUS
1274 EFIAPI
1275 SEnvDummySetMode (
1276   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
1277   IN UINTN                        ModeNumber
1278   )
1279 /*++
1280
1281 Routine Description:
1282
1283 Arguments:
1284   
1285   This - This protocol
1286   ModeNumber - Mode number
1287   
1288 Returns:
1289
1290   EFI_SUCCESS - Success
1291   
1292 --*/
1293 {
1294   return EFI_SUCCESS;
1295 }
1296
1297 EFI_STATUS
1298 EFIAPI
1299 SEnvDummySetAttribute (
1300   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL     *This,
1301   IN UINTN                            Attribute
1302   )
1303 /*++
1304
1305 Routine Description:
1306
1307 Arguments:
1308
1309   This - This protocol
1310   Attribute - The attribute
1311
1312 Returns:
1313
1314   EFI_SUCCESS  - Success
1315
1316 --*/
1317 {
1318   return EFI_SUCCESS;
1319 }
1320
1321 EFI_STATUS
1322 EFIAPI
1323 SEnvDummyClearScreen (
1324   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This
1325   )
1326 /*++
1327
1328 Routine Description:
1329
1330 Arguments:
1331
1332   This - This protocol
1333
1334 Returns:
1335
1336   EFI_SUCCESS - Success
1337
1338 --*/
1339 {
1340   return EFI_SUCCESS;
1341 }
1342
1343 EFI_STATUS
1344 EFIAPI
1345 SEnvDummySetCursorPosition (
1346   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
1347   IN UINTN                        Column,
1348   IN UINTN                        Row
1349   )
1350 /*++
1351
1352 Routine Description:
1353
1354 Arguments:
1355
1356   This   - This protocol
1357   Column - The column
1358   Row    - The row
1359
1360 Returns:
1361
1362   EFI_UNSUPPORTED  Unsupported
1363
1364 --*/
1365 {
1366   return EFI_UNSUPPORTED;
1367 }
1368
1369 EFI_STATUS
1370 EFIAPI
1371 SEnvDummyEnableCursor (
1372   IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *This,
1373   IN BOOLEAN                      Enable
1374   )
1375 /*++
1376
1377 Routine Description:
1378
1379 Arguments:
1380
1381   This - This protocol
1382   Enable - Enable the Cursor
1383
1384 Returns:
1385
1386   EFI_SUCCESS Success
1387
1388 --*/
1389 {
1390   return EFI_SUCCESS;
1391 }