ShellPkg/[hex]edit: use SimpleTextInEx to read console
[mirror_edk2.git] / ShellPkg / Library / UefiShellDebug1CommandsLib / Edit / MainTextEditor.c
1 /** @file
2 Implements editor interface functions.
3
4 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved. <BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "TextEditor.h"
16 #include "EditStatusBar.h"
17 #include "EditInputBar.h"
18 #include "EditMenuBar.h"
19
20 //
21 // the first time editor launch
22 //
23 BOOLEAN EditorFirst;
24
25 //
26 // it's time editor should exit
27 //
28 BOOLEAN EditorExit;
29
30 BOOLEAN EditorMouseAction;
31
32 extern EFI_EDITOR_FILE_BUFFER FileBuffer;
33
34 extern BOOLEAN FileBufferNeedRefresh;
35
36 extern BOOLEAN FileBufferOnlyLineNeedRefresh;
37
38 extern BOOLEAN FileBufferMouseNeedRefresh;
39
40 extern EFI_EDITOR_FILE_BUFFER FileBufferBackupVar;
41
42 EFI_EDITOR_GLOBAL_EDITOR MainEditor;
43
44
45 /**
46 Load a file from disk to editor
47
48 @retval EFI_SUCCESS The operation was successful.
49 @retval EFI_LOAD_ERROR A load error occured.
50 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
51 **/
52 EFI_STATUS
53 MainCommandOpenFile (
54 VOID
55 );
56
57 /**
58 Switch a file from ASCII to UNICODE or vise-versa.
59
60 @retval EFI_SUCCESS The switch was ok or a warning was presented.
61 **/
62 EFI_STATUS
63 MainCommandSwitchFileType (
64 VOID
65 );
66
67 /**
68 move cursor to specified lines
69
70 @retval EFI_SUCCESS The operation was successful.
71 **/
72 EFI_STATUS
73 MainCommandGotoLine (
74 VOID
75 );
76
77 /**
78 Save current file to disk, you can save to current file name or
79 save to another file name.
80
81 @retval EFI_SUCCESS The file was saved correctly.
82 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
83 @retval EFI_LOAD_ERROR A file access error occured.
84 **/
85 EFI_STATUS
86 MainCommandSaveFile (
87 VOID
88 );
89
90 /**
91 Show help information for the editor.
92
93 @retval EFI_SUCCESS The operation was successful.
94 **/
95 EFI_STATUS
96 MainCommandDisplayHelp (
97 VOID
98 );
99
100 /**
101 exit editor
102
103 @retval EFI_SUCCESS The operation was successful.
104 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
105 @retval EFI_LOAD_ERROR A load error occured.
106 **/
107 EFI_STATUS
108 MainCommandExit (
109 VOID
110 );
111
112 /**
113 search string in file buffer
114
115 @retval EFI_SUCCESS The operation was successful.
116 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
117 @retval EFI_LOAD_ERROR A load error occured.
118 **/
119 EFI_STATUS
120 MainCommandSearch (
121 VOID
122 );
123
124 /**
125 search string in file buffer, and replace it with another str
126
127 @retval EFI_SUCCESS The operation was successful.
128 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
129 @retval EFI_LOAD_ERROR A load error occured.
130 **/
131 EFI_STATUS
132 MainCommandSearchReplace (
133 VOID
134 );
135
136 /**
137 cut current line to clipboard
138
139 @retval EFI_SUCCESS The operation was successful.
140 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
141 @retval EFI_LOAD_ERROR A load error occured.
142 **/
143 EFI_STATUS
144 MainCommandCutLine (
145 VOID
146 );
147
148 /**
149 paste line to file buffer.
150
151 @retval EFI_SUCCESS The operation was successful.
152 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
153 @retval EFI_LOAD_ERROR A load error occured.
154 **/
155 EFI_STATUS
156 MainCommandPasteLine (
157 VOID
158 );
159
160 /**
161 Help info that will be displayed.
162 **/
163 EFI_STRING_ID MainMenuHelpInfo[] = {
164 STRING_TOKEN(STR_EDIT_HELP_TITLE),
165 STRING_TOKEN(STR_EDIT_HELP_BLANK),
166 STRING_TOKEN(STR_EDIT_HELP_LIST_TITLE),
167 STRING_TOKEN(STR_EDIT_HELP_DIV),
168 STRING_TOKEN(STR_EDIT_HELP_GO_TO_LINE),
169 STRING_TOKEN(STR_EDIT_HELP_SAVE_FILE),
170 STRING_TOKEN(STR_EDIT_HELP_EXIT),
171 STRING_TOKEN(STR_EDIT_HELP_SEARCH),
172 STRING_TOKEN(STR_EDIT_HELP_SEARCH_REPLACE),
173 STRING_TOKEN(STR_EDIT_HELP_CUT_LINE),
174 STRING_TOKEN(STR_EDIT_HELP_PASTE_LINE),
175 STRING_TOKEN(STR_EDIT_HELP_OPEN_FILE),
176 STRING_TOKEN(STR_EDIT_HELP_FILE_TYPE),
177 STRING_TOKEN(STR_EDIT_HELP_BLANK),
178 STRING_TOKEN(STR_EDIT_HELP_EXIT_HELP),
179 STRING_TOKEN(STR_EDIT_HELP_BLANK),
180 STRING_TOKEN(STR_EDIT_HELP_BLANK),
181 STRING_TOKEN(STR_EDIT_HELP_BLANK),
182 STRING_TOKEN(STR_EDIT_HELP_BLANK),
183 STRING_TOKEN(STR_EDIT_HELP_BLANK),
184 STRING_TOKEN(STR_EDIT_HELP_BLANK),
185 STRING_TOKEN(STR_EDIT_HELP_BLANK),
186 STRING_TOKEN(STR_EDIT_HELP_DIV),
187 0
188 };
189
190 MENU_ITEM_FUNCTION MainControlBasedMenuFunctions[] = {
191 NULL,
192 NULL, /* Ctrl - A */
193 NULL, /* Ctrl - B */
194 NULL, /* Ctrl - C */
195 NULL, /* Ctrl - D */
196 MainCommandDisplayHelp, /* Ctrl - E */
197 MainCommandSearch, /* Ctrl - F */
198 MainCommandGotoLine, /* Ctrl - G */
199 NULL, /* Ctrl - H */
200 NULL, /* Ctrl - I */
201 NULL, /* Ctrl - J */
202 MainCommandCutLine, /* Ctrl - K */
203 NULL, /* Ctrl - L */
204 NULL, /* Ctrl - M */
205 NULL, /* Ctrl - N */
206 MainCommandOpenFile, /* Ctrl - O */
207 NULL, /* Ctrl - P */
208 MainCommandExit, /* Ctrl - Q */
209 MainCommandSearchReplace, /* Ctrl - R */
210 MainCommandSaveFile, /* Ctrl - S */
211 MainCommandSwitchFileType, /* Ctrl - T */
212 MainCommandPasteLine, /* Ctrl - U */
213 NULL, /* Ctrl - V */
214 NULL, /* Ctrl - W */
215 NULL, /* Ctrl - X */
216 NULL, /* Ctrl - Y */
217 NULL, /* Ctrl - Z */
218 };
219
220 EDITOR_MENU_ITEM MainMenuItems[] = {
221 {
222 STRING_TOKEN(STR_EDIT_LIBMENUBAR_GO_TO_LINE),
223 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F1),
224 MainCommandGotoLine
225 },
226 {
227 STRING_TOKEN(STR_EDIT_LIBMENUBAR_SAVE_FILE),
228 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F2),
229 MainCommandSaveFile
230 },
231 {
232 STRING_TOKEN(STR_EDIT_LIBMENUBAR_EXIT),
233 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F3),
234 MainCommandExit
235 },
236
237 {
238 STRING_TOKEN(STR_EDIT_LIBMENUBAR_SEARCH),
239 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F4),
240 MainCommandSearch
241 },
242 {
243 STRING_TOKEN(STR_EDIT_LIBMENUBAR_SEARCH_REPLACE),
244 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F5),
245 MainCommandSearchReplace
246 },
247 {
248 STRING_TOKEN(STR_EDIT_LIBMENUBAR_CUT_LINE),
249 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F6),
250 MainCommandCutLine
251 },
252 {
253 STRING_TOKEN(STR_EDIT_LIBMENUBAR_PASTE_LINE),
254 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F7),
255 MainCommandPasteLine
256 },
257
258 {
259 STRING_TOKEN(STR_EDIT_LIBMENUBAR_OPEN_FILE),
260 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F8),
261 MainCommandOpenFile
262 },
263 {
264 STRING_TOKEN(STR_EDIT_LIBMENUBAR_FILE_TYPE),
265 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F9),
266 MainCommandSwitchFileType
267 },
268 {
269 STRING_TOKEN(STR_EDIT_LIBMENUBAR_FILE_TYPE),
270 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F11),
271 MainCommandSwitchFileType
272 },
273
274 {
275 0,
276 0,
277 NULL
278 }
279 };
280
281
282 /**
283 Load a file from disk to editor
284
285 @retval EFI_SUCCESS The operation was successful.
286 @retval EFI_LOAD_ERROR A load error occured.
287 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
288 **/
289 EFI_STATUS
290 MainCommandOpenFile (
291 VOID
292 )
293 {
294 BOOLEAN Done;
295 EFI_STATUS Status;
296
297 //
298 // This command will open a file from current working directory.
299 // Read-only file can also be opened. But it can not be modified.
300 // Below is the scenario of Open File command:
301 // 1.IF currently opened file has not been modIFied, directly go to step .
302 // IF currently opened file has been modified,
303 // an Input Bar will be prompted as :
304 // "File Modified. Save ( Yes/No/Cancel) ?"
305 // IF user press 'y' or 'Y', currently opened file will be saved.
306 // IF user press 'n' or 'N', currently opened file will
307 // not be saved.
308 // IF user press 'c' or 'C' or ESC, Open File command ends and
309 // currently opened file is still opened.
310 //
311 // 2. An Input Bar will be prompted as : "File Name to Open: "
312 // IF user press ESC, Open File command ends and
313 // currently opened file is still opened.
314 // Any other inputs with a Return will
315 // cause currently opened file close.
316 //
317 // 3. IF user input file name is an existing file , this file will be read
318 // and opened.
319 // IF user input file name is a new file, this file will be created
320 // and opened. This file's type ( UNICODE or ASCII ) is the same
321 // with the old file.
322 // if current file is modified, so you need to choose
323 // whether to save it first.
324 //
325 if (MainEditor.FileBuffer->FileModified) {
326
327 Status = InputBarSetPrompt (L"File modified. Save (Yes/No/Cancel) ? ");
328 if (EFI_ERROR (Status)) {
329 return Status;
330 }
331 //
332 // the answer is just one character
333 //
334 Status = InputBarSetStringSize (1);
335 if (EFI_ERROR (Status)) {
336 return Status;
337 }
338 //
339 // loop for user's answer
340 // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C'
341 //
342 Done = FALSE;
343 while (!Done) {
344 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
345 StatusBarSetRefresh();
346
347 //
348 // ESC pressed
349 //
350 if (Status == EFI_NOT_READY) {
351 return EFI_SUCCESS;
352 }
353
354 switch (InputBarGetString()[0]) {
355 case L'y':
356 case L'Y':
357 //
358 // want to save this file first
359 //
360 Status = FileBufferSave (MainEditor.FileBuffer->FileName);
361 if (EFI_ERROR (Status)) {
362 return Status;
363 }
364
365 MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row, 0, 0);
366 FileBufferRestorePosition ();
367 Done = TRUE;
368 break;
369
370 case L'n':
371 case L'N':
372 //
373 // the file won't be saved
374 //
375 Done = TRUE;
376 break;
377
378 case L'c':
379 case L'C':
380 return EFI_SUCCESS;
381 }
382 }
383 }
384 //
385 // TO get the open file name
386 //
387 Status = InputBarSetPrompt (L"File Name to Open: ");
388 if (EFI_ERROR (Status)) {
389 FileBufferRead (MainEditor.FileBuffer->FileName, TRUE);
390 return Status;
391 }
392
393 Status = InputBarSetStringSize (100);
394 if (EFI_ERROR (Status)) {
395 FileBufferRead (MainEditor.FileBuffer->FileName, TRUE);
396 return Status;
397 }
398
399 while (1) {
400 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
401 StatusBarSetRefresh();
402
403 //
404 // ESC pressed
405 //
406 if (Status == EFI_NOT_READY) {
407 return EFI_SUCCESS;
408 }
409 //
410 // The input string length should > 0
411 //
412 if (StrLen (InputBarGetString()) > 0) {
413 //
414 // CHECK if filename is valid
415 //
416 if (!IsValidFileName (InputBarGetString())) {
417 FileBufferRead (MainEditor.FileBuffer->FileName, TRUE);
418 StatusBarSetStatusString (L"Invalid File Name");
419 return EFI_SUCCESS;
420 }
421
422 break;
423 }
424 }
425 //
426 // read from disk
427 //
428 Status = FileBufferRead (InputBarGetString(), FALSE);
429
430 if (EFI_ERROR (Status)) {
431 FileBufferRead (MainEditor.FileBuffer->FileName, TRUE);
432 return EFI_LOAD_ERROR;
433 }
434
435 return EFI_SUCCESS;
436 }
437
438 /**
439 Switch a file from ASCII to UNICODE or vise-versa.
440
441 @retval EFI_SUCCESS The switch was ok or a warning was presented.
442 **/
443 EFI_STATUS
444 MainCommandSwitchFileType (
445 VOID
446 )
447 {
448 //
449 // Below is the scenario of File Type command:
450 // After File Type is executed, file type will be changed to another type
451 // if file is read-only, can not be modified
452 //
453 if (MainEditor.FileBuffer->ReadOnly) {
454 StatusBarSetStatusString (L"Read Only File Can Not Be Modified");
455 return EFI_SUCCESS;
456 }
457
458 if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {
459 MainEditor.FileBuffer->FileType = FileTypeAscii;
460 } else {
461 MainEditor.FileBuffer->FileType = FileTypeUnicode;
462 }
463
464 MainEditor.FileBuffer->FileModified = TRUE;
465
466 return EFI_SUCCESS;
467 }
468
469 /**
470 cut current line to clipboard
471
472 @retval EFI_SUCCESS The operation was successful.
473 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
474 @retval EFI_LOAD_ERROR A load error occured.
475 **/
476 EFI_STATUS
477 MainCommandCutLine (
478 VOID
479 )
480 {
481 EFI_STATUS Status;
482 EFI_EDITOR_LINE *Line;
483
484 //
485 // This command will cut current line ( where cursor is on ) to clip board.
486 // And cursor will move to the beginning of next line.
487 // Below is the scenario of Cut Line command:
488 // 1. IF cursor is on valid line, current line will be cut to clip board.
489 // IF cursor is not on valid line, an Status String will be prompted :
490 // "Nothing to Cut".
491 //
492 Line = NULL;
493 Status = FileBufferCutLine (&Line);
494 if (Status == EFI_NOT_FOUND) {
495 return EFI_SUCCESS;
496 }
497
498 if (EFI_ERROR (Status)) {
499 return Status;
500 }
501
502 MainEditor.CutLine = Line;
503
504 return EFI_SUCCESS;
505 }
506
507 /**
508 paste line to file buffer.
509
510 @retval EFI_SUCCESS The operation was successful.
511 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
512 @retval EFI_LOAD_ERROR A load error occured.
513 **/
514 EFI_STATUS
515 MainCommandPasteLine (
516 VOID
517 )
518 {
519 EFI_STATUS Status;
520
521 //
522 // Below is the scenario of Paste Line command:
523 // 1. IF nothing is on clipboard, a Status String will be prompted :
524 // "No Line to Paste" and Paste Line command ends.
525 // IF something is on clipboard, insert it above current line.
526 // nothing on clipboard
527 //
528 if (MainEditor.CutLine == NULL) {
529 StatusBarSetStatusString (L"No Line to Paste");
530 return EFI_SUCCESS;
531 }
532
533 Status = FileBufferPasteLine ();
534
535 return Status;
536 }
537
538
539 /**
540 search string in file buffer
541
542 @retval EFI_SUCCESS The operation was successful.
543 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
544 @retval EFI_LOAD_ERROR A load error occured.
545 **/
546 EFI_STATUS
547 MainCommandSearch (
548 VOID
549 )
550 {
551 EFI_STATUS Status;
552 CHAR16 *Buffer;
553 BOOLEAN Done;
554 UINTN Offset;
555
556 //
557 // Below is the scenario of Search command:
558 // 1. An Input Bar will be prompted : "Enter Search String:".
559 // IF user press ESC, Search command ends.
560 // IF user just press Enter, Search command ends.
561 // IF user inputs the search string, do Step 2.
562 //
563 // 2. IF input search string is found, cursor will move to the first
564 // occurrence and do Step 3.
565 // IF input search string is not found, a Status String
566 // "Search String Not Found" will be prompted and Search command ends.
567 //
568 // 3. An Input Bar will be prompted: "Find Next (Yes/No/Cancel ) ?".
569 // IF user press ESC, Search command ends.
570 // IF user press 'y' or 'Y', do Step 2.
571 // IF user press 'n' or 'N', Search command ends.
572 // IF user press 'c' or 'C', Search command ends.
573 //
574 Status = InputBarSetPrompt (L"Enter Search String: ");
575 if (EFI_ERROR (Status)) {
576 return Status;
577 }
578
579 Status = InputBarSetStringSize (40);
580 if (EFI_ERROR (Status)) {
581 return Status;
582 }
583
584 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
585 StatusBarSetRefresh();
586
587 //
588 // ESC
589 //
590 if (Status == EFI_NOT_READY) {
591 return EFI_SUCCESS;
592 }
593 //
594 // just enter pressed
595 //
596 if (StrLen (InputBarGetString()) == 0) {
597 return EFI_SUCCESS;
598 }
599
600 Buffer = CatSPrint (NULL, L"%s", InputBarGetString());
601 if (Buffer == NULL) {
602 return EFI_OUT_OF_RESOURCES;
603 }
604 //
605 // the first time , search from current position
606 //
607 Offset = 0;
608 do {
609 //
610 // since search may be continued to search multiple times
611 // so we need to backup editor each time
612 //
613 MainEditorBackup ();
614
615 Status = FileBufferSearch (Buffer, Offset);
616
617 if (Status == EFI_NOT_FOUND) {
618 break;
619 }
620 //
621 // Find next
622 //
623 Status = InputBarSetPrompt (L"Find Next (Yes/No) ?");
624 if (EFI_ERROR (Status)) {
625 FreePool (Buffer);
626 return Status;
627 }
628
629 Status = InputBarSetStringSize (1);
630 if (EFI_ERROR (Status)) {
631 FreePool (Buffer);
632 return Status;
633 }
634
635 Done = FALSE;
636 while (!Done) {
637 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
638 StatusBarSetRefresh();
639
640 //
641 // ESC pressed
642 //
643 if (Status == EFI_NOT_READY) {
644 FreePool (Buffer);
645 return EFI_SUCCESS;
646 }
647
648 switch (InputBarGetString()[0]) {
649 case L'y':
650 case L'Y':
651 Done = TRUE;
652 break;
653
654 case L'n':
655 case L'N':
656 FreePool (Buffer);
657 return EFI_SUCCESS;
658
659 }
660 //
661 // end of which
662 //
663 }
664 //
665 // end of while !Done
666 // for search second, third time, search from current position + strlen
667 //
668 Offset = StrLen (Buffer);
669
670 } while (1);
671 //
672 // end of do
673 //
674 FreePool (Buffer);
675 StatusBarSetStatusString (L"Search String Not Found");
676
677 return EFI_SUCCESS;
678 }
679
680 /**
681 Search string in file buffer, and replace it with another str.
682
683 @retval EFI_SUCCESS The operation was successful.
684 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
685 @retval EFI_LOAD_ERROR A load error occured.
686 **/
687 EFI_STATUS
688 MainCommandSearchReplace (
689 VOID
690 )
691 {
692 EFI_STATUS Status;
693 CHAR16 *Search;
694 CHAR16 *Replace;
695 BOOLEAN Done;
696 BOOLEAN First;
697 BOOLEAN ReplaceOption;
698 UINTN SearchLen;
699 UINTN ReplaceLen;
700 BOOLEAN ReplaceAll;
701
702 ReplaceOption = FALSE;
703
704 //
705 // Below is the scenario of Search/Replace command:
706 // 1. An Input Bar is prompted : "Enter Search String:".
707 // IF user press ESC, Search/Replace command ends.
708 // IF user just press Enter, Search/Replace command ends.
709 // IF user inputs the search string S, do Step 2.
710 //
711 // 2. An Input Bar is prompted: "Replace With:".
712 // IF user press ESC, Search/Replace command ends.
713 // IF user inputs the replace string R, do Step 3.
714 //
715 // 3. IF input search string is not found, an Status String
716 // "Search String Not Found" will be prompted
717 // and Search/Replace command ends
718 // IF input search string is found, do Step 4.
719 //
720 // 4. An Input Bar will be prompted: "Replace ( Yes/No/All/Cancel )?"
721 // IF user press 'y' or 'Y', S will be replaced with R and do Step 5
722 // IF user press 'n' or 'N', S will not be replaced and do Step 5.
723 // IF user press 'a' or 'A', all the S from file current position on
724 // will be replaced with R and Search/Replace command ends.
725 // IF user press 'c' or 'C' or ESC, Search/Replace command ends.
726 //
727 // 5. An Input Bar will be prompted: "Find Next (Yes/No/Cancel) ?".
728 // IF user press ESC, Search/Replace command ends.
729 // IF user press 'y' or 'Y', do Step 3.
730 // IF user press 'n' or 'N', Search/Replace command ends.
731 // IF user press 'c' or 'C', Search/Replace command ends.
732 // input search string
733 //
734 Status = InputBarSetPrompt (L"Enter Search String: ");
735 if (EFI_ERROR (Status)) {
736 return Status;
737 }
738
739 Status = InputBarSetStringSize (40);
740 if (EFI_ERROR (Status)) {
741 return Status;
742 }
743
744 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
745 StatusBarSetRefresh();
746
747 //
748 // ESC
749 //
750 if (Status == EFI_NOT_READY) {
751 return EFI_SUCCESS;
752 }
753 //
754 // if just pressed enter
755 //
756 if (StrLen (InputBarGetString()) == 0) {
757 return EFI_SUCCESS;
758 }
759
760 Search = CatSPrint (NULL, L"%s", InputBarGetString());
761 if (Search == NULL) {
762 return EFI_OUT_OF_RESOURCES;
763 }
764
765 SearchLen = StrLen (Search);
766
767 //
768 // input replace string
769 //
770 Status = InputBarSetPrompt (L"Replace With: ");
771 if (EFI_ERROR (Status)) {
772 return Status;
773 }
774
775 Status = InputBarSetStringSize (40);
776 if (EFI_ERROR (Status)) {
777 return Status;
778 }
779
780 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
781 StatusBarSetRefresh();
782
783 //
784 // ESC
785 //
786 if (Status == EFI_NOT_READY) {
787 return EFI_SUCCESS;
788 }
789
790 Replace = CatSPrint (NULL, L"%s", InputBarGetString());
791 if (Replace == NULL) {
792 FreePool (Search);
793 return EFI_OUT_OF_RESOURCES;
794 }
795
796 ReplaceLen = StrLen (Replace);
797
798 First = TRUE;
799 ReplaceAll = FALSE;
800 do {
801 //
802 // since search may be continued to search multiple times
803 // so we need to backup editor each time
804 //
805 MainEditorBackup ();
806
807 if (First) {
808 Status = FileBufferSearch (Search, 0);
809 } else {
810 //
811 // if just replace, so skip this replace string
812 // if replace string is an empty string, so skip to next character
813 //
814 if (ReplaceOption) {
815 Status = FileBufferSearch (Search, (ReplaceLen == 0) ? 1 : ReplaceLen);
816 } else {
817 Status = FileBufferSearch (Search, SearchLen);
818 }
819 }
820
821 if (Status == EFI_NOT_FOUND) {
822 break;
823 }
824 //
825 // replace or not?
826 //
827 Status = InputBarSetPrompt (L"Replace (Yes/No/All/Cancel) ?");
828
829 if (EFI_ERROR (Status)) {
830 FreePool (Search);
831 FreePool (Replace);
832 return Status;
833 }
834
835 Status = InputBarSetStringSize (1);
836 if (EFI_ERROR (Status)) {
837 FreePool (Search);
838 FreePool (Replace);
839 return Status;
840 }
841
842 Done = FALSE;
843 while (!Done) {
844 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
845 StatusBarSetRefresh();
846
847 //
848 // ESC pressed
849 //
850 if (Status == EFI_NOT_READY) {
851 FreePool (Search);
852 FreePool (Replace);
853 return EFI_SUCCESS;
854 }
855
856 switch (InputBarGetString()[0]) {
857 case L'y':
858 case L'Y':
859 Done = TRUE;
860 ReplaceOption = TRUE;
861 break;
862
863 case L'n':
864 case L'N':
865 Done = TRUE;
866 ReplaceOption = FALSE;
867 break;
868
869 case L'a':
870 case L'A':
871 Done = TRUE;
872 ReplaceOption = TRUE;
873 ReplaceAll = TRUE;
874 break;
875
876 case L'c':
877 case L'C':
878 FreePool (Search);
879 FreePool (Replace);
880 return EFI_SUCCESS;
881
882 }
883 //
884 // end of which
885 //
886 }
887 //
888 // end of while !Done
889 // Decide to Replace
890 //
891 if (ReplaceOption) {
892 //
893 // file is read-only
894 //
895 if (MainEditor.FileBuffer->ReadOnly) {
896 StatusBarSetStatusString (L"Read Only File Can Not Be Modified");
897 return EFI_SUCCESS;
898 }
899 //
900 // replace all
901 //
902 if (ReplaceAll) {
903 Status = FileBufferReplaceAll (Search, Replace, 0);
904 FreePool (Search);
905 FreePool (Replace);
906 return Status;
907 }
908 //
909 // replace
910 //
911 Status = FileBufferReplace (Replace, SearchLen);
912 if (EFI_ERROR (Status)) {
913 FreePool (Search);
914 FreePool (Replace);
915 return Status;
916 }
917 }
918 //
919 // Find next
920 //
921 Status = InputBarSetPrompt (L"Find Next (Yes/No) ?");
922 if (EFI_ERROR (Status)) {
923 FreePool (Search);
924 FreePool (Replace);
925 return Status;
926 }
927
928 Status = InputBarSetStringSize (1);
929 if (EFI_ERROR (Status)) {
930 FreePool (Search);
931 FreePool (Replace);
932 return Status;
933 }
934
935 Done = FALSE;
936 while (!Done) {
937 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
938 StatusBarSetRefresh();
939
940 //
941 // ESC pressed
942 //
943 if (Status == EFI_NOT_READY) {
944 FreePool (Search);
945 FreePool (Replace);
946 return EFI_SUCCESS;
947 }
948
949 switch (InputBarGetString()[0]) {
950 case L'y':
951 case L'Y':
952 Done = TRUE;
953 break;
954
955 case L'n':
956 case L'N':
957 FreePool (Search);
958 FreePool (Replace);
959 return EFI_SUCCESS;
960
961 }
962 //
963 // end of which
964 //
965 }
966 //
967 // end of while !Done
968 //
969 First = FALSE;
970
971 } while (1);
972 //
973 // end of do
974 //
975 FreePool (Search);
976 FreePool (Replace);
977
978 StatusBarSetStatusString (L"Search String Not Found");
979
980 return EFI_SUCCESS;
981 }
982
983 /**
984 exit editor
985
986 @retval EFI_SUCCESS The operation was successful.
987 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
988 @retval EFI_LOAD_ERROR A load error occured.
989 **/
990 EFI_STATUS
991 MainCommandExit (
992 VOID
993 )
994 {
995 EFI_STATUS Status;
996
997 //
998 // Below is the scenario of Exit command:
999 // 1. IF currently opened file is not modified, exit the editor and
1000 // Exit command ends.
1001 // IF currently opened file is modified, do Step 2
1002 //
1003 // 2. An Input Bar will be prompted:
1004 // "File modified. Save ( Yes/No/Cancel )?"
1005 // IF user press 'y' or 'Y', currently opened file will be saved
1006 // and Editor exits
1007 // IF user press 'n' or 'N', currently opened file will not be saved
1008 // and Editor exits.
1009 // IF user press 'c' or 'C' or ESC, Exit command ends.
1010 // if file has been modified, so will prompt user whether to save the changes
1011 //
1012 if (MainEditor.FileBuffer->FileModified) {
1013
1014 Status = InputBarSetPrompt (L"File modified. Save (Yes/No/Cancel) ? ");
1015 if (EFI_ERROR (Status)) {
1016 return Status;
1017 }
1018
1019 Status = InputBarSetStringSize (1);
1020 if (EFI_ERROR (Status)) {
1021 return Status;
1022 }
1023
1024 while (1) {
1025 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
1026 StatusBarSetRefresh();
1027
1028 //
1029 // ESC pressed
1030 //
1031 if (Status == EFI_NOT_READY) {
1032 return EFI_SUCCESS;
1033 }
1034
1035 switch (InputBarGetString()[0]) {
1036 case L'y':
1037 case L'Y':
1038 //
1039 // write file back to disk
1040 //
1041 Status = FileBufferSave (MainEditor.FileBuffer->FileName);
1042 if (!EFI_ERROR (Status)) {
1043 EditorExit = TRUE;
1044 }
1045
1046 return Status;
1047
1048 case L'n':
1049 case L'N':
1050 EditorExit = TRUE;
1051 return EFI_SUCCESS;
1052
1053 case L'c':
1054 case L'C':
1055 return EFI_SUCCESS;
1056
1057 }
1058 }
1059 }
1060
1061 EditorExit = TRUE;
1062 return EFI_SUCCESS;
1063
1064 }
1065
1066 /**
1067 move cursor to specified lines
1068
1069 @retval EFI_SUCCESS The operation was successful.
1070 **/
1071 EFI_STATUS
1072 MainCommandGotoLine (
1073 VOID
1074 )
1075 {
1076 EFI_STATUS Status;
1077 UINTN Row;
1078
1079 //
1080 // Below is the scenario of Go To Line command:
1081 // 1. An Input Bar will be prompted : "Go To Line:".
1082 // IF user press ESC, Go To Line command ends.
1083 // IF user just press Enter, cursor remains unchanged.
1084 // IF user inputs line number, do Step 2.
1085 //
1086 // 2. IF input line number is valid, move cursor to the beginning
1087 // of specified line and Go To Line command ends.
1088 // IF input line number is invalid, a Status String will be prompted:
1089 // "No Such Line" and Go To Line command ends.
1090 //
1091 Status = InputBarSetPrompt (L"Go To Line: ");
1092 if (EFI_ERROR (Status)) {
1093 return Status;
1094 }
1095 //
1096 // line number's digit <= 6
1097 //
1098 Status = InputBarSetStringSize (6);
1099 if (EFI_ERROR (Status)) {
1100 return Status;
1101 }
1102
1103 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
1104 StatusBarSetRefresh();
1105
1106 //
1107 // press ESC
1108 //
1109 if (Status == EFI_NOT_READY) {
1110 return EFI_SUCCESS;
1111 }
1112 //
1113 // if JUST press enter
1114 //
1115 if (StrLen (InputBarGetString()) == 0) {
1116 return EFI_SUCCESS;
1117 }
1118
1119 Row = ShellStrToUintn (InputBarGetString());
1120
1121 //
1122 // invalid line number
1123 //
1124 if (Row > MainEditor.FileBuffer->NumLines || Row <= 0) {
1125 StatusBarSetStatusString (L"No Such Line");
1126 return EFI_SUCCESS;
1127 }
1128 //
1129 // move cursor to that line's start
1130 //
1131 FileBufferMovePosition (Row, 1);
1132
1133 return EFI_SUCCESS;
1134 }
1135
1136 /**
1137 Save current file to disk, you can save to current file name or
1138 save to another file name.
1139
1140 @retval EFI_SUCCESS The file was saved correctly.
1141 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1142 @retval EFI_LOAD_ERROR A file access error occured.
1143 **/
1144 EFI_STATUS
1145 MainCommandSaveFile (
1146 VOID
1147 )
1148 {
1149 EFI_STATUS Status;
1150 CHAR16 *FileName;
1151 BOOLEAN OldFile;
1152 CHAR16 *Str;
1153 SHELL_FILE_HANDLE FileHandle;
1154 EFI_FILE_INFO *Info;
1155
1156 //
1157 // This command will save currently opened file to disk.
1158 // You can choose save to another file name or just save to
1159 // current file name.
1160 // Below is the scenario of Save File command:
1161 // ( Suppose the old file name is A )
1162 // 1. An Input Bar will be prompted: "File To Save: [ old file name]"
1163 // IF user press ESC, Save File command ends .
1164 // IF user press Enter, input file name will be A.
1165 // IF user inputs a new file name B, input file name will be B.
1166 //
1167 // 2. IF input file name is A, go to do Step 3.
1168 // IF input file name is B, go to do Step 4.
1169 //
1170 // 3. IF A is read only, Status Bar will show "Access Denied" and
1171 // Save File commands ends.
1172 // IF A is not read only, save file buffer to disk and remove modified
1173 // flag in Title Bar , then Save File command ends.
1174 //
1175 // 4. IF B does not exist, create this file and save file buffer to it.
1176 // Go to do Step 7.
1177 // IF B exits, do Step 5.
1178 //
1179 // 5.An Input Bar will be prompted:
1180 // "File Exists. Overwrite ( Yes/No/Cancel )?"
1181 // IF user press 'y' or 'Y', do Step 6.
1182 // IF user press 'n' or 'N', Save File commands ends.
1183 // IF user press 'c' or 'C' or ESC, Save File commands ends.
1184 //
1185 // 6. IF B is a read-only file, Status Bar will show "Access Denied" and
1186 // Save File commands ends.
1187 // IF B can be read and write, save file buffer to B.
1188 //
1189 // 7. Update File Name field in Title Bar to B and remove the modified
1190 // flag in Title Bar.
1191 //
1192 Str = CatSPrint (NULL, L"File to Save: [%s]", MainEditor.FileBuffer->FileName);
1193 if (Str == NULL) {
1194 return EFI_OUT_OF_RESOURCES;
1195 }
1196
1197 if (StrLen (Str) >= 50) {
1198 //
1199 // replace the long file name with "..."
1200 //
1201 Str[46] = L'.';
1202 Str[47] = L'.';
1203 Str[48] = L'.';
1204 Str[49] = L']';
1205 Str[50] = CHAR_NULL;
1206 }
1207
1208 Status = InputBarSetPrompt (Str);
1209 FreePool(Str);
1210
1211 if (EFI_ERROR (Status)) {
1212 return Status;
1213 }
1214
1215
1216 Status = InputBarSetStringSize (100);
1217 if (EFI_ERROR (Status)) {
1218 return Status;
1219 }
1220 //
1221 // get new file name
1222 //
1223 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
1224 StatusBarSetRefresh();
1225
1226 //
1227 // if user pressed ESC
1228 //
1229 if (Status == EFI_NOT_READY) {
1230 return EFI_SUCCESS;
1231 }
1232
1233 //
1234 // if just enter pressed, so think save to current file name
1235 //
1236 if (StrLen (InputBarGetString()) == 0) {
1237 FileName = CatSPrint (NULL, L"%s", MainEditor.FileBuffer->FileName);
1238 } else {
1239 FileName = CatSPrint (NULL, L"%s", InputBarGetString());
1240 }
1241
1242 if (FileName == NULL) {
1243 return EFI_OUT_OF_RESOURCES;
1244 }
1245
1246 if (!IsValidFileName (FileName)) {
1247 StatusBarSetStatusString (L"Invalid File Name");
1248 FreePool (FileName);
1249 return EFI_SUCCESS;
1250 }
1251
1252 OldFile = FALSE;
1253
1254 //
1255 // save to the old file
1256 //
1257 if (StringNoCaseCompare (&FileName, &MainEditor.FileBuffer->FileName) == 0) {
1258 OldFile = TRUE;
1259 }
1260
1261 if (OldFile) {
1262 //
1263 // if the file is read only, so can not write back to it.
1264 //
1265 if (MainEditor.FileBuffer->ReadOnly == TRUE) {
1266 StatusBarSetStatusString (L"Access Denied");
1267 FreePool (FileName);
1268 return EFI_SUCCESS;
1269 }
1270 } else {
1271 //
1272 // if the file exists
1273 //
1274 if (ShellFileExists(FileName) != EFI_NOT_FOUND) {
1275 //
1276 // check for read only
1277 //
1278 Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ, 0);
1279 if (EFI_ERROR(Status)) {
1280 StatusBarSetStatusString (L"Open Failed");
1281 FreePool (FileName);
1282 return EFI_SUCCESS;
1283 }
1284
1285 Info = ShellGetFileInfo(FileHandle);
1286 if (Info == NULL) {
1287 StatusBarSetStatusString (L"Access Denied");
1288 FreePool (FileName);
1289 return (EFI_SUCCESS);
1290 }
1291
1292 if (Info->Attribute & EFI_FILE_READ_ONLY) {
1293 StatusBarSetStatusString (L"Access Denied - Read Only");
1294 FreePool (Info);
1295 FreePool (FileName);
1296 return (EFI_SUCCESS);
1297 }
1298 FreePool (Info);
1299
1300 //
1301 // ask user whether to overwrite this file
1302 //
1303 Status = InputBarSetPrompt (L"File exists. Overwrite (Yes/No/Cancel) ? ");
1304 if (EFI_ERROR (Status)) {
1305 SHELL_FREE_NON_NULL (FileName);
1306 return Status;
1307 }
1308
1309 Status = InputBarSetStringSize (1);
1310 if (EFI_ERROR (Status)) {
1311 SHELL_FREE_NON_NULL (FileName);
1312 return Status;
1313 }
1314
1315 while (TRUE) {
1316 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
1317 StatusBarSetRefresh();
1318
1319 //
1320 // ESC pressed
1321 //
1322 if (Status == EFI_NOT_READY) {
1323 SHELL_FREE_NON_NULL (FileName);
1324 return EFI_SUCCESS;
1325 }
1326
1327 switch (InputBarGetString()[0]) {
1328 case L'y':
1329 case L'Y':
1330 break;
1331
1332 case L'n':
1333 case L'N':
1334 case L'c':
1335 case L'C':
1336 SHELL_FREE_NON_NULL (FileName);
1337 return EFI_SUCCESS;
1338 } // end switch
1339 } // while (!done)
1340 } // file does exist
1341 } // if old file name same
1342
1343 //
1344 // save file to disk with specified name
1345 //
1346 FileBufferSetModified();
1347 Status = FileBufferSave (FileName);
1348 SHELL_FREE_NON_NULL (FileName);
1349
1350 return Status;
1351 }
1352
1353 /**
1354 Show help information for the editor.
1355
1356 @retval EFI_SUCCESS The operation was successful.
1357 **/
1358 EFI_STATUS
1359 MainCommandDisplayHelp (
1360 VOID
1361 )
1362 {
1363 INT32 CurrentLine;
1364 CHAR16 *InfoString;
1365 EFI_KEY_DATA KeyData;
1366 EFI_STATUS Status;
1367 UINTN EventIndex;
1368
1369 //
1370 // print helpInfo
1371 //
1372 for (CurrentLine = 0; 0 != MainMenuHelpInfo[CurrentLine]; CurrentLine++) {
1373 InfoString = HiiGetString(gShellDebug1HiiHandle, MainMenuHelpInfo[CurrentLine], NULL);
1374 ShellPrintEx (0, CurrentLine+1, L"%E%s%N", InfoString);
1375 }
1376
1377 //
1378 // scan for ctrl+w
1379 //
1380 while (TRUE) {
1381 Status = gBS->WaitForEvent (1, &MainEditor.TextInputEx->WaitForKeyEx, &EventIndex);
1382 if (EFI_ERROR (Status) || (EventIndex != 0)) {
1383 continue;
1384 }
1385 Status = MainEditor.TextInputEx->ReadKeyStrokeEx (MainEditor.TextInputEx, &KeyData);
1386 if (EFI_ERROR (Status)) {
1387 continue;
1388 }
1389
1390 if ((KeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) == 0) {
1391 //
1392 // For consoles that don't support shift state reporting,
1393 // CTRL+W is translated to L'W' - L'A' + 1.
1394 //
1395 if (KeyData.Key.UnicodeChar == L'W' - L'A' + 1) {
1396 break;
1397 }
1398 } else if (((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) &&
1399 ((KeyData.KeyState.KeyShiftState & ~(EFI_SHIFT_STATE_VALID | EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) == 0)) {
1400 //
1401 // For consoles that supports shift state reporting,
1402 // make sure that only CONTROL shift key is pressed.
1403 //
1404 if ((KeyData.Key.UnicodeChar == 'w') || (KeyData.Key.UnicodeChar == 'W')) {
1405 break;
1406 }
1407 }
1408 }
1409 //
1410 // update screen with file buffer's info
1411 //
1412 FileBufferRestorePosition ();
1413 FileBufferNeedRefresh = TRUE;
1414 FileBufferOnlyLineNeedRefresh = FALSE;
1415 FileBufferRefresh ();
1416
1417 return EFI_SUCCESS;
1418 }
1419
1420 EFI_EDITOR_COLOR_ATTRIBUTES OriginalColors;
1421 INTN OriginalMode;
1422
1423
1424 //
1425 // basic initialization for MainEditor
1426 //
1427 EFI_EDITOR_GLOBAL_EDITOR MainEditorConst = {
1428 &FileBuffer,
1429 {
1430 {0, 0}
1431 },
1432 {
1433 0,
1434 0
1435 },
1436 NULL,
1437 NULL,
1438 FALSE,
1439 NULL
1440 };
1441
1442 /**
1443 The initialization function for MainEditor.
1444
1445 @retval EFI_SUCCESS The operation was successful.
1446 @retval EFI_LOAD_ERROR A load error occured.
1447 **/
1448 EFI_STATUS
1449 MainEditorInit (
1450 VOID
1451 )
1452 {
1453 EFI_STATUS Status;
1454 EFI_HANDLE *HandleBuffer;
1455 UINTN HandleCount;
1456 UINTN Index;
1457
1458 //
1459 // basic initialization
1460 //
1461 CopyMem (&MainEditor, &MainEditorConst, sizeof (MainEditor));
1462
1463 //
1464 // set screen attributes
1465 //
1466 MainEditor.ColorAttributes.Colors.Foreground = gST->ConOut->Mode->Attribute & 0x000000ff;
1467
1468 MainEditor.ColorAttributes.Colors.Background = (UINT8) (gST->ConOut->Mode->Attribute >> 4);
1469 OriginalColors = MainEditor.ColorAttributes.Colors;
1470
1471 OriginalMode = gST->ConOut->Mode->Mode;
1472
1473 //
1474 // query screen size
1475 //
1476 gST->ConOut->QueryMode (
1477 gST->ConOut,
1478 gST->ConOut->Mode->Mode,
1479 &(MainEditor.ScreenSize.Column),
1480 &(MainEditor.ScreenSize.Row)
1481 );
1482
1483 //
1484 // Find TextInEx in System Table ConsoleInHandle
1485 // Per UEFI Spec, TextInEx is required for a console capable platform.
1486 //
1487 Status = gBS->HandleProtocol (
1488 gST->ConsoleInHandle,
1489 &gEfiSimpleTextInputExProtocolGuid,
1490 (VOID**)&MainEditor.TextInputEx
1491 );
1492 if (EFI_ERROR (Status)) {
1493 return Status;
1494 }
1495
1496 //
1497 // Find mouse in System Table ConsoleInHandle
1498 //
1499 Status = gBS->HandleProtocol (
1500 gST->ConIn,
1501 &gEfiSimplePointerProtocolGuid,
1502 (VOID**)&MainEditor.MouseInterface
1503 );
1504 if (EFI_ERROR (Status)) {
1505 //
1506 // If there is no Simple Pointer Protocol on System Table
1507 //
1508 HandleBuffer = NULL;
1509 MainEditor.MouseInterface = NULL;
1510 Status = gBS->LocateHandleBuffer (
1511 ByProtocol,
1512 &gEfiSimplePointerProtocolGuid,
1513 NULL,
1514 &HandleCount,
1515 &HandleBuffer
1516 );
1517 if (!EFI_ERROR (Status) && HandleCount > 0) {
1518 //
1519 // Try to find the first available mouse device
1520 //
1521 for (Index = 0; Index < HandleCount; Index++) {
1522 Status = gBS->HandleProtocol (
1523 HandleBuffer[Index],
1524 &gEfiSimplePointerProtocolGuid,
1525 (VOID**)&MainEditor.MouseInterface
1526 );
1527 if (!EFI_ERROR (Status)) {
1528 break;
1529 }
1530 }
1531 }
1532 if (HandleBuffer != NULL) {
1533 FreePool (HandleBuffer);
1534 }
1535 }
1536
1537 if (!EFI_ERROR (Status) && MainEditor.MouseInterface != NULL) {
1538 MainEditor.MouseAccumulatorX = 0;
1539 MainEditor.MouseAccumulatorY = 0;
1540 MainEditor.MouseSupported = TRUE;
1541 }
1542
1543 //
1544 // below will call the five components' init function
1545 //
1546 Status = MainTitleBarInit (L"UEFI EDIT");
1547 if (EFI_ERROR (Status)) {
1548 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_TITLEBAR), gShellDebug1HiiHandle);
1549 return EFI_LOAD_ERROR;
1550 }
1551
1552 Status = ControlHotKeyInit (MainControlBasedMenuFunctions);
1553 Status = MenuBarInit (MainMenuItems);
1554 if (EFI_ERROR (Status)) {
1555 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_MAINMENU), gShellDebug1HiiHandle);
1556 return EFI_LOAD_ERROR;
1557 }
1558
1559 Status = StatusBarInit ();
1560 if (EFI_ERROR (Status)) {
1561 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_STATUSBAR), gShellDebug1HiiHandle);
1562 return EFI_LOAD_ERROR;
1563 }
1564
1565 InputBarInit (MainEditor.TextInputEx);
1566
1567 Status = FileBufferInit ();
1568 if (EFI_ERROR (Status)) {
1569 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER), gShellDebug1HiiHandle);
1570 return EFI_LOAD_ERROR;
1571 }
1572 //
1573 // clear whole screen and enable cursor
1574 //
1575 gST->ConOut->ClearScreen (gST->ConOut);
1576 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
1577
1578 //
1579 // initialize EditorFirst and EditorExit
1580 //
1581 EditorFirst = TRUE;
1582 EditorExit = FALSE;
1583 EditorMouseAction = FALSE;
1584
1585 return EFI_SUCCESS;
1586 }
1587
1588 /**
1589 The cleanup function for MainEditor.
1590
1591 @retval EFI_SUCCESS The operation was successful.
1592 @retval EFI_LOAD_ERROR A load error occured.
1593 **/
1594 EFI_STATUS
1595 MainEditorCleanup (
1596 VOID
1597 )
1598 {
1599 EFI_STATUS Status;
1600
1601 //
1602 // call the five components' cleanup function
1603 // if error, do not exit
1604 // just print some warning
1605 //
1606 MainTitleBarCleanup();
1607 StatusBarCleanup();
1608 InputBarCleanup();
1609 MenuBarCleanup ();
1610
1611 Status = FileBufferCleanup ();
1612 if (EFI_ERROR (Status)) {
1613 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER_CLEANUP), gShellDebug1HiiHandle);
1614 }
1615 //
1616 // restore old mode
1617 //
1618 if (OriginalMode != gST->ConOut->Mode->Mode) {
1619 gST->ConOut->SetMode (gST->ConOut, OriginalMode);
1620 }
1621 //
1622 // restore old screen color
1623 //
1624 gST->ConOut->SetAttribute (
1625 gST->ConOut,
1626 EFI_TEXT_ATTR (OriginalColors.Foreground, OriginalColors.Background)
1627 );
1628
1629 gST->ConOut->ClearScreen (gST->ConOut);
1630
1631 return EFI_SUCCESS;
1632 }
1633
1634 /**
1635 Refresh the main editor component.
1636 **/
1637 VOID
1638 MainEditorRefresh (
1639 VOID
1640 )
1641 {
1642 //
1643 // The Stall value is from experience. NOT from spec. avoids 'flicker'
1644 //
1645 gBS->Stall (50);
1646
1647 //
1648 // call the components refresh function
1649 //
1650 if (EditorFirst
1651 || StrCmp (FileBufferBackupVar.FileName, FileBuffer.FileName) != 0
1652 || FileBufferBackupVar.FileType != FileBuffer.FileType
1653 || FileBufferBackupVar.FileModified != FileBuffer.FileModified
1654 || FileBufferBackupVar.ReadOnly != FileBuffer.ReadOnly) {
1655
1656 MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row, 0, 0);
1657 FileBufferRestorePosition ();
1658 }
1659
1660 if (EditorFirst
1661 || FileBufferBackupVar.FilePosition.Row != FileBuffer.FilePosition.Row
1662 || FileBufferBackupVar.FilePosition.Column != FileBuffer.FilePosition.Column
1663 || FileBufferBackupVar.ModeInsert != FileBuffer.ModeInsert
1664 || StatusBarGetRefresh()) {
1665
1666 StatusBarRefresh (EditorFirst, MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column, MainEditor.FileBuffer->FilePosition.Row, MainEditor.FileBuffer->FilePosition.Column, MainEditor.FileBuffer->ModeInsert);
1667 FileBufferRestorePosition ();
1668 }
1669
1670 if (EditorFirst) {
1671 FileBufferRestorePosition ();
1672 }
1673
1674 FileBufferRefresh ();
1675
1676 //
1677 // EditorFirst is now set to FALSE
1678 //
1679 EditorFirst = FALSE;
1680 }
1681
1682 /**
1683 Get's the resultant location of the cursor based on the relative movement of the Mouse.
1684
1685 @param[in] GuidX The relative mouse movement.
1686
1687 @return The X location of the mouse.
1688 **/
1689 INT32
1690 GetTextX (
1691 IN INT32 GuidX
1692 )
1693 {
1694 INT32 Gap;
1695
1696 MainEditor.MouseAccumulatorX += GuidX;
1697 Gap = (MainEditor.MouseAccumulatorX * (INT32) MainEditor.ScreenSize.Column) / (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionX);
1698 MainEditor.MouseAccumulatorX = (MainEditor.MouseAccumulatorX * (INT32) MainEditor.ScreenSize.Column) % (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionX);
1699 MainEditor.MouseAccumulatorX = MainEditor.MouseAccumulatorX / (INT32) MainEditor.ScreenSize.Column;
1700 return Gap;
1701 }
1702
1703 /**
1704 Get's the resultant location of the cursor based on the relative movement of the Mouse.
1705
1706 @param[in] GuidY The relative mouse movement.
1707
1708 @return The Y location of the mouse.
1709 **/
1710 INT32
1711 GetTextY (
1712 IN INT32 GuidY
1713 )
1714 {
1715 INT32 Gap;
1716
1717 MainEditor.MouseAccumulatorY += GuidY;
1718 Gap = (MainEditor.MouseAccumulatorY * (INT32) MainEditor.ScreenSize.Row) / (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionY);
1719 MainEditor.MouseAccumulatorY = (MainEditor.MouseAccumulatorY * (INT32) MainEditor.ScreenSize.Row) % (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionY);
1720 MainEditor.MouseAccumulatorY = MainEditor.MouseAccumulatorY / (INT32) MainEditor.ScreenSize.Row;
1721
1722 return Gap;
1723 }
1724
1725 /**
1726 Support mouse movement. Move the cursor.
1727
1728 @param[in] MouseState The current mouse state.
1729
1730 @retval EFI_SUCCESS The operation was successful.
1731 @retval EFI_NOT_FOUND There was no mouse support found.
1732 **/
1733 EFI_STATUS
1734 MainEditorHandleMouseInput (
1735 IN EFI_SIMPLE_POINTER_STATE MouseState
1736 )
1737 {
1738
1739 INT32 TextX;
1740 INT32 TextY;
1741 UINTN FRow;
1742 UINTN FCol;
1743
1744 LIST_ENTRY *Link;
1745 EFI_EDITOR_LINE *Line;
1746
1747 UINTN Index;
1748 BOOLEAN Action;
1749
1750 //
1751 // mouse action means:
1752 // mouse movement
1753 // mouse left button
1754 //
1755 Action = FALSE;
1756
1757 //
1758 // have mouse movement
1759 //
1760 if (MouseState.RelativeMovementX || MouseState.RelativeMovementY) {
1761 //
1762 // handle
1763 //
1764 TextX = GetTextX (MouseState.RelativeMovementX);
1765 TextY = GetTextY (MouseState.RelativeMovementY);
1766
1767 FileBufferAdjustMousePosition (TextX, TextY);
1768
1769 Action = TRUE;
1770
1771 }
1772
1773 //
1774 // if left button pushed down
1775 //
1776 if (MouseState.LeftButton) {
1777
1778 FCol = MainEditor.FileBuffer->MousePosition.Column - 1 + 1;
1779
1780 FRow = MainEditor.FileBuffer->FilePosition.Row +
1781 MainEditor.FileBuffer->MousePosition.Row -
1782 MainEditor.FileBuffer->DisplayPosition.Row;
1783
1784 //
1785 // beyond the file line length
1786 //
1787 if (MainEditor.FileBuffer->NumLines < FRow) {
1788 FRow = MainEditor.FileBuffer->NumLines;
1789 }
1790
1791 Link = MainEditor.FileBuffer->ListHead->ForwardLink;
1792 for (Index = 0; Index < FRow - 1; Index++) {
1793 Link = Link->ForwardLink;
1794 }
1795
1796 Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
1797
1798 //
1799 // beyond the line's column length
1800 //
1801 if (FCol > Line->Size + 1) {
1802 FCol = Line->Size + 1;
1803 }
1804
1805 FileBufferMovePosition (FRow, FCol);
1806
1807 MainEditor.FileBuffer->MousePosition.Row = MainEditor.FileBuffer->DisplayPosition.Row;
1808
1809 MainEditor.FileBuffer->MousePosition.Column = MainEditor.FileBuffer->DisplayPosition.Column;
1810
1811 Action = TRUE;
1812 }
1813 //
1814 // mouse has action
1815 //
1816 if (Action) {
1817 return EFI_SUCCESS;
1818 }
1819
1820 //
1821 // no mouse action
1822 //
1823 return EFI_NOT_FOUND;
1824 }
1825
1826 /**
1827 Handle user key input. This routes to other functions for the actions.
1828
1829 @retval EFI_SUCCESS The operation was successful.
1830 @retval EFI_LOAD_ERROR A load error occured.
1831 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1832 **/
1833 EFI_STATUS
1834 MainEditorKeyInput (
1835 VOID
1836 )
1837 {
1838 EFI_KEY_DATA KeyData;
1839 EFI_STATUS Status;
1840 EFI_SIMPLE_POINTER_STATE MouseState;
1841 UINTN EventIndex;
1842 BOOLEAN NoShiftState;
1843
1844 do {
1845
1846 Status = EFI_SUCCESS;
1847 EditorMouseAction = FALSE;
1848
1849 //
1850 // backup some key elements, so that can aVOID some refresh work
1851 //
1852 MainEditorBackup ();
1853
1854 //
1855 // change priority of checking mouse/keyboard activity dynamically
1856 // so prevent starvation of keyboard.
1857 // if last time, mouse moves then this time check keyboard
1858 //
1859 if (MainEditor.MouseSupported) {
1860 Status = MainEditor.MouseInterface->GetState (
1861 MainEditor.MouseInterface,
1862 &MouseState
1863 );
1864 if (!EFI_ERROR (Status)) {
1865
1866 Status = MainEditorHandleMouseInput (MouseState);
1867
1868 if (!EFI_ERROR (Status)) {
1869 EditorMouseAction = TRUE;
1870 FileBufferMouseNeedRefresh = TRUE;
1871 } else if (Status == EFI_LOAD_ERROR) {
1872 StatusBarSetStatusString (L"Invalid Mouse Movement ");
1873 }
1874 }
1875 }
1876
1877 Status = gBS->WaitForEvent (1, &MainEditor.TextInputEx->WaitForKeyEx, &EventIndex);
1878 if (!EFI_ERROR (Status) && EventIndex == 0) {
1879 Status = MainEditor.TextInputEx->ReadKeyStrokeEx (MainEditor.TextInputEx, &KeyData);
1880 if (!EFI_ERROR (Status)) {
1881 //
1882 // dispatch to different components' key handling function
1883 // so not everywhere has to set this variable
1884 //
1885 FileBufferMouseNeedRefresh = TRUE;
1886 //
1887 // clear previous status string
1888 //
1889 StatusBarSetRefresh();
1890 //
1891 // NoShiftState: TRUE when no shift key is pressed.
1892 //
1893 NoShiftState = ((KeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) == 0) || (KeyData.KeyState.KeyShiftState == EFI_SHIFT_STATE_VALID);
1894 //
1895 // dispatch to different components' key handling function
1896 //
1897 if (EFI_NOT_FOUND != MenuBarDispatchControlHotKey(&KeyData)) {
1898 Status = EFI_SUCCESS;
1899 } else if (NoShiftState && ((KeyData.Key.ScanCode == SCAN_NULL) || ((KeyData.Key.ScanCode >= SCAN_UP) && (KeyData.Key.ScanCode <= SCAN_PAGE_DOWN)))) {
1900 Status = FileBufferHandleInput (&KeyData.Key);
1901 } else if (NoShiftState && (KeyData.Key.ScanCode >= SCAN_F1) && (KeyData.Key.ScanCode <= SCAN_F12)) {
1902 Status = MenuBarDispatchFunctionKey (&KeyData.Key);
1903 } else {
1904 StatusBarSetStatusString (L"Unknown Command");
1905 FileBufferMouseNeedRefresh = FALSE;
1906 }
1907
1908 if (Status != EFI_SUCCESS && Status != EFI_OUT_OF_RESOURCES) {
1909 //
1910 // not already has some error status
1911 //
1912 if (StatusBarGetString() != NULL && StrCmp (L"", StatusBarGetString()) == 0) {
1913 StatusBarSetStatusString (L"Disk Error. Try Again");
1914 }
1915 }
1916
1917 }
1918 //
1919 // after handling, refresh editor
1920 //
1921 MainEditorRefresh ();
1922 }
1923
1924 } while (Status != EFI_OUT_OF_RESOURCES && !EditorExit);
1925
1926 return Status;
1927 }
1928
1929 /**
1930 Set clipboard
1931
1932 @param[in] Line A pointer to the line to be set to clipboard
1933
1934 @retval EFI_SUCCESS The operation was successful.
1935 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1936 **/
1937 EFI_STATUS
1938 MainEditorSetCutLine (
1939 EFI_EDITOR_LINE *Line
1940 )
1941 {
1942 if (Line == NULL) {
1943 return EFI_SUCCESS;
1944 }
1945
1946 if (MainEditor.CutLine != NULL) {
1947 //
1948 // free the old clipboard
1949 //
1950 LineFree (MainEditor.CutLine);
1951 }
1952 //
1953 // duplicate the line to clipboard
1954 //
1955 MainEditor.CutLine = LineDup (Line);
1956 if (MainEditor.CutLine == NULL) {
1957 return EFI_OUT_OF_RESOURCES;
1958 }
1959
1960 return EFI_SUCCESS;
1961 }
1962
1963 /**
1964 Backup function for MainEditor
1965
1966 @retval EFI_SUCCESS The operation was successful.
1967 **/
1968 EFI_STATUS
1969 MainEditorBackup (
1970 VOID
1971 )
1972 {
1973 FileBufferBackup ();
1974
1975 return EFI_SUCCESS;
1976 }