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