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