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