]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c
ShellPkg: Added the Ctrl based hot key and changed text editor's UI.
[mirror_edk2.git] / ShellPkg / Library / UefiShellDebug1CommandsLib / Edit / MainTextEditor.c
1 /** @file
2 Implements editor interface functions.
3
4 Copyright (c) 2005 - 2011, 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 menu.
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 Status = FileBufferCutLine (&Line);
493 if (Status == EFI_NOT_FOUND) {
494 return EFI_SUCCESS;
495 }
496
497 if (EFI_ERROR (Status)) {
498 return Status;
499 }
500
501 MainEditor.CutLine = Line;
502
503 return EFI_SUCCESS;
504 }
505
506 /**
507 paste line to file buffer.
508
509 @retval EFI_SUCCESS The operation was successful.
510 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
511 @retval EFI_LOAD_ERROR A load error occured.
512 **/
513 EFI_STATUS
514 MainCommandPasteLine (
515 VOID
516 )
517 {
518 EFI_STATUS Status;
519
520 //
521 // Below is the scenario of Paste Line command:
522 // 1. IF nothing is on clipboard, a Status String will be prompted :
523 // "No Line to Paste" and Paste Line command ends.
524 // IF something is on clipboard, insert it above current line.
525 // nothing on clipboard
526 //
527 if (MainEditor.CutLine == NULL) {
528 StatusBarSetStatusString (L"No Line to Paste");
529 return EFI_SUCCESS;
530 }
531
532 Status = FileBufferPasteLine ();
533
534 return Status;
535 }
536
537
538 /**
539 search string in file buffer
540
541 @retval EFI_SUCCESS The operation was successful.
542 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
543 @retval EFI_LOAD_ERROR A load error occured.
544 **/
545 EFI_STATUS
546 MainCommandSearch (
547 VOID
548 )
549 {
550 EFI_STATUS Status;
551 CHAR16 *Buffer;
552 BOOLEAN Done;
553 UINTN Offset;
554
555 //
556 // Below is the scenario of Search command:
557 // 1. An Input Bar will be prompted : "Enter Search String:".
558 // IF user press ESC, Search command ends.
559 // IF user just press Enter, Search command ends.
560 // IF user inputs the search string, do Step 2.
561 //
562 // 2. IF input search string is found, cursor will move to the first
563 // occurrence and do Step 3.
564 // IF input search string is not found, a Status String
565 // "Search String Not Found" will be prompted and Search command ends.
566 //
567 // 3. An Input Bar will be prompted: "Find Next (Yes/No/Cancel ) ?".
568 // IF user press ESC, Search command ends.
569 // IF user press 'y' or 'Y', do Step 2.
570 // IF user press 'n' or 'N', Search command ends.
571 // IF user press 'c' or 'C', Search command ends.
572 //
573 Status = InputBarSetPrompt (L"Enter Search String: ");
574 if (EFI_ERROR (Status)) {
575 return Status;
576 }
577
578 Status = InputBarSetStringSize (40);
579 if (EFI_ERROR (Status)) {
580 return Status;
581 }
582
583 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
584 StatusBarSetRefresh();
585
586 //
587 // ESC
588 //
589 if (Status == EFI_NOT_READY) {
590 return EFI_SUCCESS;
591 }
592 //
593 // just enter pressed
594 //
595 if (StrLen (InputBarGetString()) == 0) {
596 return EFI_SUCCESS;
597 }
598
599 Buffer = CatSPrint (NULL, L"%s", InputBarGetString());
600 if (Buffer == NULL) {
601 return EFI_OUT_OF_RESOURCES;
602 }
603 //
604 // the first time , search from current position
605 //
606 Offset = 0;
607 do {
608 //
609 // since search may be continued to search multiple times
610 // so we need to backup editor each time
611 //
612 MainEditorBackup ();
613
614 Status = FileBufferSearch (Buffer, Offset);
615
616 if (Status == EFI_NOT_FOUND) {
617 break;
618 }
619 //
620 // Find next
621 //
622 Status = InputBarSetPrompt (L"Find Next (Yes/No) ?");
623 if (EFI_ERROR (Status)) {
624 FreePool (Buffer);
625 return Status;
626 }
627
628 Status = InputBarSetStringSize (1);
629 if (EFI_ERROR (Status)) {
630 FreePool (Buffer);
631 return Status;
632 }
633
634 Done = FALSE;
635 while (!Done) {
636 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
637 StatusBarSetRefresh();
638
639 //
640 // ESC pressed
641 //
642 if (Status == EFI_NOT_READY) {
643 FreePool (Buffer);
644 return EFI_SUCCESS;
645 }
646
647 switch (InputBarGetString()[0]) {
648 case L'y':
649 case L'Y':
650 Done = TRUE;
651 break;
652
653 case L'n':
654 case L'N':
655 FreePool (Buffer);
656 return EFI_SUCCESS;
657
658 }
659 //
660 // end of which
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
669 } while (1);
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 occured.
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 // if just pressed enter
754 //
755 if (StrLen (InputBarGetString()) == 0) {
756 return EFI_SUCCESS;
757 }
758
759 Search = CatSPrint (NULL, L"%s", InputBarGetString());
760 if (Search == NULL) {
761 return EFI_OUT_OF_RESOURCES;
762 }
763
764 SearchLen = StrLen (Search);
765
766 //
767 // input replace string
768 //
769 Status = InputBarSetPrompt (L"Replace With: ");
770 if (EFI_ERROR (Status)) {
771 return Status;
772 }
773
774 Status = InputBarSetStringSize (40);
775 if (EFI_ERROR (Status)) {
776 return Status;
777 }
778
779 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
780 StatusBarSetRefresh();
781
782 //
783 // ESC
784 //
785 if (Status == EFI_NOT_READY) {
786 return EFI_SUCCESS;
787 }
788
789 Replace = CatSPrint (NULL, L"%s", InputBarGetString());
790 if (Replace == NULL) {
791 FreePool (Search);
792 return EFI_OUT_OF_RESOURCES;
793 }
794
795 ReplaceLen = StrLen (Replace);
796
797 First = TRUE;
798 ReplaceAll = FALSE;
799 do {
800 //
801 // since search may be continued to search multiple times
802 // so we need to backup editor each time
803 //
804 MainEditorBackup ();
805
806 if (First) {
807 Status = FileBufferSearch (Search, 0);
808 } else {
809 //
810 // if just replace, so skip this replace string
811 // if replace string is an empty string, so skip to next character
812 //
813 if (ReplaceOption) {
814 Status = FileBufferSearch (Search, (ReplaceLen == 0) ? 1 : ReplaceLen);
815 } else {
816 Status = FileBufferSearch (Search, SearchLen);
817 }
818 }
819
820 if (Status == EFI_NOT_FOUND) {
821 break;
822 }
823 //
824 // replace or not?
825 //
826 Status = InputBarSetPrompt (L"Replace (Yes/No/All/Cancel) ?");
827
828 if (EFI_ERROR (Status)) {
829 FreePool (Search);
830 FreePool (Replace);
831 return Status;
832 }
833
834 Status = InputBarSetStringSize (1);
835 if (EFI_ERROR (Status)) {
836 FreePool (Search);
837 FreePool (Replace);
838 return Status;
839 }
840
841 Done = FALSE;
842 while (!Done) {
843 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
844 StatusBarSetRefresh();
845
846 //
847 // ESC pressed
848 //
849 if (Status == EFI_NOT_READY) {
850 FreePool (Search);
851 FreePool (Replace);
852 return EFI_SUCCESS;
853 }
854
855 switch (InputBarGetString()[0]) {
856 case L'y':
857 case L'Y':
858 Done = TRUE;
859 ReplaceOption = TRUE;
860 break;
861
862 case L'n':
863 case L'N':
864 Done = TRUE;
865 ReplaceOption = FALSE;
866 break;
867
868 case L'a':
869 case L'A':
870 Done = TRUE;
871 ReplaceOption = TRUE;
872 ReplaceAll = TRUE;
873 break;
874
875 case L'c':
876 case L'C':
877 FreePool (Search);
878 FreePool (Replace);
879 return EFI_SUCCESS;
880
881 }
882 //
883 // end of which
884 //
885 }
886 //
887 // end of while !Done
888 // Decide to Replace
889 //
890 if (ReplaceOption) {
891 //
892 // file is read-only
893 //
894 if (MainEditor.FileBuffer->ReadOnly) {
895 StatusBarSetStatusString (L"Read Only File Can Not Be Modified");
896 return EFI_SUCCESS;
897 }
898 //
899 // replace all
900 //
901 if (ReplaceAll) {
902 Status = FileBufferReplaceAll (Search, Replace, 0);
903 FreePool (Search);
904 FreePool (Replace);
905 return Status;
906 }
907 //
908 // replace
909 //
910 Status = FileBufferReplace (Replace, SearchLen);
911 if (EFI_ERROR (Status)) {
912 FreePool (Search);
913 FreePool (Replace);
914 return Status;
915 }
916 }
917 //
918 // Find next
919 //
920 Status = InputBarSetPrompt (L"Find Next (Yes/No) ?");
921 if (EFI_ERROR (Status)) {
922 FreePool (Search);
923 FreePool (Replace);
924 return Status;
925 }
926
927 Status = InputBarSetStringSize (1);
928 if (EFI_ERROR (Status)) {
929 FreePool (Search);
930 FreePool (Replace);
931 return Status;
932 }
933
934 Done = FALSE;
935 while (!Done) {
936 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
937 StatusBarSetRefresh();
938
939 //
940 // ESC pressed
941 //
942 if (Status == EFI_NOT_READY) {
943 FreePool (Search);
944 FreePool (Replace);
945 return EFI_SUCCESS;
946 }
947
948 switch (InputBarGetString()[0]) {
949 case L'y':
950 case L'Y':
951 Done = TRUE;
952 break;
953
954 case L'n':
955 case L'N':
956 FreePool (Search);
957 FreePool (Replace);
958 return EFI_SUCCESS;
959
960 }
961 //
962 // end of which
963 //
964 }
965 //
966 // end of while !Done
967 //
968 First = FALSE;
969
970 } while (1);
971 //
972 // end of do
973 //
974 FreePool (Search);
975 FreePool (Replace);
976
977 StatusBarSetStatusString (L"Search String Not Found");
978
979 return EFI_SUCCESS;
980 }
981
982 /**
983 exit editor
984
985 @retval EFI_SUCCESS The operation was successful.
986 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
987 @retval EFI_LOAD_ERROR A load error occured.
988 **/
989 EFI_STATUS
990 MainCommandExit (
991 VOID
992 )
993 {
994 EFI_STATUS Status;
995
996 //
997 // Below is the scenario of Exit command:
998 // 1. IF currently opened file is not modified, exit the editor and
999 // Exit command ends.
1000 // IF currently opened file is modified, do Step 2
1001 //
1002 // 2. An Input Bar will be prompted:
1003 // "File modified. Save ( Yes/No/Cancel )?"
1004 // IF user press 'y' or 'Y', currently opened file will be saved
1005 // and Editor exits
1006 // IF user press 'n' or 'N', currently opened file will not be saved
1007 // and Editor exits.
1008 // IF user press 'c' or 'C' or ESC, Exit command ends.
1009 // if file has been modified, so will prompt user whether to save the changes
1010 //
1011 if (MainEditor.FileBuffer->FileModified) {
1012
1013 Status = InputBarSetPrompt (L"File modified. Save (Yes/No/Cancel) ? ");
1014 if (EFI_ERROR (Status)) {
1015 return Status;
1016 }
1017
1018 Status = InputBarSetStringSize (1);
1019 if (EFI_ERROR (Status)) {
1020 return Status;
1021 }
1022
1023 while (1) {
1024 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
1025 StatusBarSetRefresh();
1026
1027 //
1028 // ESC pressed
1029 //
1030 if (Status == EFI_NOT_READY) {
1031 return EFI_SUCCESS;
1032 }
1033
1034 switch (InputBarGetString()[0]) {
1035 case L'y':
1036 case L'Y':
1037 //
1038 // write file back to disk
1039 //
1040 Status = FileBufferSave (MainEditor.FileBuffer->FileName);
1041 if (!EFI_ERROR (Status)) {
1042 EditorExit = TRUE;
1043 }
1044
1045 return Status;
1046
1047 case L'n':
1048 case L'N':
1049 EditorExit = TRUE;
1050 return EFI_SUCCESS;
1051
1052 case L'c':
1053 case L'C':
1054 return EFI_SUCCESS;
1055
1056 }
1057 }
1058 }
1059
1060 EditorExit = TRUE;
1061 return EFI_SUCCESS;
1062
1063 }
1064
1065 /**
1066 move cursor to specified lines
1067
1068 @retval EFI_SUCCESS The operation was successful.
1069 **/
1070 EFI_STATUS
1071 MainCommandGotoLine (
1072 VOID
1073 )
1074 {
1075 EFI_STATUS Status;
1076 UINTN Row;
1077
1078 //
1079 // Below is the scenario of Go To Line command:
1080 // 1. An Input Bar will be prompted : "Go To Line:".
1081 // IF user press ESC, Go To Line command ends.
1082 // IF user just press Enter, cursor remains unchanged.
1083 // IF user inputs line number, do Step 2.
1084 //
1085 // 2. IF input line number is valid, move cursor to the beginning
1086 // of specified line and Go To Line command ends.
1087 // IF input line number is invalid, a Status String will be prompted:
1088 // "No Such Line" and Go To Line command ends.
1089 //
1090 Status = InputBarSetPrompt (L"Go To Line: ");
1091 if (EFI_ERROR (Status)) {
1092 return Status;
1093 }
1094 //
1095 // line number's digit <= 6
1096 //
1097 Status = InputBarSetStringSize (6);
1098 if (EFI_ERROR (Status)) {
1099 return Status;
1100 }
1101
1102 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
1103 StatusBarSetRefresh();
1104
1105 //
1106 // press ESC
1107 //
1108 if (Status == EFI_NOT_READY) {
1109 return EFI_SUCCESS;
1110 }
1111 //
1112 // if JUST press enter
1113 //
1114 if (StrLen (InputBarGetString()) == 0) {
1115 return EFI_SUCCESS;
1116 }
1117
1118 Row = ShellStrToUintn (InputBarGetString());
1119
1120 //
1121 // invalid line number
1122 //
1123 if (Row > MainEditor.FileBuffer->NumLines || Row <= 0) {
1124 StatusBarSetStatusString (L"No Such Line");
1125 return EFI_SUCCESS;
1126 }
1127 //
1128 // move cursor to that line's start
1129 //
1130 FileBufferMovePosition (Row, 1);
1131
1132 return EFI_SUCCESS;
1133 }
1134
1135 /**
1136 Save current file to disk, you can save to current file name or
1137 save to another file name.
1138
1139 @retval EFI_SUCCESS The file was saved correctly.
1140 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1141 @retval EFI_LOAD_ERROR A file access error occured.
1142 **/
1143 EFI_STATUS
1144 MainCommandSaveFile (
1145 VOID
1146 )
1147 {
1148 EFI_STATUS Status;
1149 CHAR16 *FileName;
1150 BOOLEAN OldFile;
1151 CHAR16 *Str;
1152 SHELL_FILE_HANDLE FileHandle;
1153 EFI_FILE_INFO *Info;
1154
1155 //
1156 // This command will save currently opened file to disk.
1157 // You can choose save to another file name or just save to
1158 // current file name.
1159 // Below is the scenario of Save File command:
1160 // ( Suppose the old file name is A )
1161 // 1. An Input Bar will be prompted: "File To Save: [ old file name]"
1162 // IF user press ESC, Save File command ends .
1163 // IF user press Enter, input file name will be A.
1164 // IF user inputs a new file name B, input file name will be B.
1165 //
1166 // 2. IF input file name is A, go to do Step 3.
1167 // IF input file name is B, go to do Step 4.
1168 //
1169 // 3. IF A is read only, Status Bar will show "Access Denied" and
1170 // Save File commands ends.
1171 // IF A is not read only, save file buffer to disk and remove modified
1172 // flag in Title Bar , then Save File command ends.
1173 //
1174 // 4. IF B does not exist, create this file and save file buffer to it.
1175 // Go to do Step 7.
1176 // IF B exits, do Step 5.
1177 //
1178 // 5.An Input Bar will be prompted:
1179 // "File Exists. Overwrite ( Yes/No/Cancel )?"
1180 // IF user press 'y' or 'Y', do Step 6.
1181 // IF user press 'n' or 'N', Save File commands ends.
1182 // IF user press 'c' or 'C' or ESC, Save File commands ends.
1183 //
1184 // 6. IF B is a read-only file, Status Bar will show "Access Denied" and
1185 // Save File commands ends.
1186 // IF B can be read and write, save file buffer to B.
1187 //
1188 // 7. Update File Name field in Title Bar to B and remove the modified
1189 // flag in Title Bar.
1190 //
1191 Str = CatSPrint (NULL, L"File to Save: [%s]", MainEditor.FileBuffer->FileName);
1192 if (Str == NULL) {
1193 return EFI_OUT_OF_RESOURCES;
1194 }
1195
1196 if (StrLen (Str) >= 50) {
1197 //
1198 // replace the long file name with "..."
1199 //
1200 Str[46] = L'.';
1201 Str[47] = L'.';
1202 Str[48] = L'.';
1203 Str[49] = L']';
1204 Str[50] = CHAR_NULL;
1205 }
1206
1207 Status = InputBarSetPrompt (Str);
1208 FreePool(Str);
1209
1210 if (EFI_ERROR (Status)) {
1211 return Status;
1212 }
1213
1214
1215 Status = InputBarSetStringSize (100);
1216 if (EFI_ERROR (Status)) {
1217 return Status;
1218 }
1219 //
1220 // get new file name
1221 //
1222 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
1223 StatusBarSetRefresh();
1224
1225 //
1226 // if user pressed ESC
1227 //
1228 if (Status == EFI_NOT_READY) {
1229 return EFI_SUCCESS;
1230 }
1231
1232 //
1233 // if just enter pressed, so think save to current file name
1234 //
1235 if (StrLen (InputBarGetString()) == 0) {
1236 FileName = CatSPrint (NULL, L"%s", MainEditor.FileBuffer->FileName);
1237 } else {
1238 FileName = CatSPrint (NULL, L"%s", InputBarGetString());
1239 }
1240
1241 if (FileName == NULL) {
1242 return EFI_OUT_OF_RESOURCES;
1243 }
1244
1245 if (!IsValidFileName (FileName)) {
1246 StatusBarSetStatusString (L"Invalid File Name");
1247 FreePool (FileName);
1248 return EFI_SUCCESS;
1249 }
1250
1251 OldFile = FALSE;
1252
1253 //
1254 // save to the old file
1255 //
1256 if (StringNoCaseCompare (&FileName, &MainEditor.FileBuffer->FileName) == 0) {
1257 OldFile = TRUE;
1258 }
1259
1260 if (OldFile) {
1261 //
1262 // if the file is read only, so can not write back to it.
1263 //
1264 if (MainEditor.FileBuffer->ReadOnly == TRUE) {
1265 StatusBarSetStatusString (L"Access Denied");
1266 FreePool (FileName);
1267 return EFI_SUCCESS;
1268 }
1269 } else {
1270 //
1271 // if the file exists
1272 //
1273 if (ShellFileExists(FileName) != EFI_NOT_FOUND) {
1274 //
1275 // check for read only
1276 //
1277 Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ, 0);
1278 if (EFI_ERROR(Status)) {
1279 StatusBarSetStatusString (L"Open Failed");
1280 FreePool (FileName);
1281 return EFI_SUCCESS;
1282 }
1283
1284 Info = ShellGetFileInfo(FileHandle);
1285 if (Info == NULL) {
1286 StatusBarSetStatusString (L"Access Denied");
1287 FreePool (FileName);
1288 return (EFI_SUCCESS);
1289 }
1290
1291 if (Info->Attribute & EFI_FILE_READ_ONLY) {
1292 StatusBarSetStatusString (L"Access Denied - Read Only");
1293 FreePool (Info);
1294 FreePool (FileName);
1295 return (EFI_SUCCESS);
1296 }
1297 FreePool (Info);
1298
1299 //
1300 // ask user whether to overwrite this file
1301 //
1302 Status = InputBarSetPrompt (L"File exists. Overwrite (Yes/No/Cancel) ? ");
1303 if (EFI_ERROR (Status)) {
1304 SHELL_FREE_NON_NULL (FileName);
1305 return Status;
1306 }
1307
1308 Status = InputBarSetStringSize (1);
1309 if (EFI_ERROR (Status)) {
1310 SHELL_FREE_NON_NULL (FileName);
1311 return Status;
1312 }
1313
1314 while (TRUE) {
1315 Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column);
1316 StatusBarSetRefresh();
1317
1318 //
1319 // ESC pressed
1320 //
1321 if (Status == EFI_NOT_READY) {
1322 SHELL_FREE_NON_NULL (FileName);
1323 return EFI_SUCCESS;
1324 }
1325
1326 switch (InputBarGetString()[0]) {
1327 case L'y':
1328 case L'Y':
1329 break;
1330
1331 case L'n':
1332 case L'N':
1333 case L'c':
1334 case L'C':
1335 SHELL_FREE_NON_NULL (FileName);
1336 return EFI_SUCCESS;
1337 } // end switch
1338 } // while (!done)
1339 } // file does exist
1340 } // if old file name same
1341
1342 //
1343 // save file to disk with specified name
1344 //
1345 FileBufferSetModified();
1346 Status = FileBufferSave (FileName);
1347 SHELL_FREE_NON_NULL (FileName);
1348
1349 return Status;
1350 }
1351
1352 /**
1353 show help menu.
1354
1355 @retval EFI_SUCCESS The operation was successful.
1356 **/
1357 EFI_STATUS
1358 MainCommandDisplayHelp (
1359 VOID
1360 )
1361 {
1362 INTN CurrentLine=0;
1363 CHAR16 * InfoString;
1364 EFI_INPUT_KEY Key;
1365
1366 // print helpInfo
1367 for (CurrentLine = 0; 0 != MainMenuHelpInfo[CurrentLine]; CurrentLine++) {
1368 InfoString = HiiGetString(gShellDebug1HiiHandle, MainMenuHelpInfo[CurrentLine], NULL);
1369 ShellPrintEx (0,CurrentLine+1,L"%E%s%N",InfoString);
1370 }
1371
1372 // scan for ctrl+w
1373 do {
1374 gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
1375 } while(SCAN_CONTROL_W != Key.UnicodeChar);
1376
1377 // update screen with file buffer's info
1378 FileBufferRestorePosition ();
1379 FileBufferNeedRefresh = TRUE;
1380 FileBufferOnlyLineNeedRefresh = FALSE;
1381 FileBufferRefresh ();
1382
1383 return EFI_SUCCESS;
1384 }
1385
1386 EFI_EDITOR_COLOR_ATTRIBUTES OriginalColors;
1387 INTN OriginalMode;
1388
1389
1390 //
1391 // basic initialization for MainEditor
1392 //
1393 EFI_EDITOR_GLOBAL_EDITOR MainEditorConst = {
1394 &FileBuffer,
1395 {
1396 0,
1397 0
1398 },
1399 {
1400 0,
1401 0
1402 },
1403 NULL,
1404 FALSE,
1405 NULL
1406 };
1407
1408 /**
1409 The initialization function for MainEditor.
1410
1411 @retval EFI_SUCCESS The operation was successful.
1412 @retval EFI_LOAD_ERROR A load error occured.
1413 **/
1414 EFI_STATUS
1415 EFIAPI
1416 MainEditorInit (
1417 VOID
1418 )
1419 {
1420 EFI_STATUS Status;
1421 EFI_HANDLE *HandleBuffer;
1422 UINTN HandleCount;
1423 UINTN Index;
1424
1425 //
1426 // basic initialization
1427 //
1428 CopyMem (&MainEditor, &MainEditorConst, sizeof (MainEditor));
1429
1430 //
1431 // set screen attributes
1432 //
1433 MainEditor.ColorAttributes.Colors.Foreground = gST->ConOut->Mode->Attribute & 0x000000ff;
1434
1435 MainEditor.ColorAttributes.Colors.Background = (UINT8) (gST->ConOut->Mode->Attribute >> 4);
1436 OriginalColors = MainEditor.ColorAttributes.Colors;
1437
1438 OriginalMode = gST->ConOut->Mode->Mode;
1439
1440 //
1441 // query screen size
1442 //
1443 gST->ConOut->QueryMode (
1444 gST->ConOut,
1445 gST->ConOut->Mode->Mode,
1446 &(MainEditor.ScreenSize.Column),
1447 &(MainEditor.ScreenSize.Row)
1448 );
1449
1450 //
1451 // Find mouse in System Table ConsoleInHandle
1452 //
1453 Status = gBS->HandleProtocol (
1454 gST->ConIn,
1455 &gEfiSimplePointerProtocolGuid,
1456 (VOID**)&MainEditor.MouseInterface
1457 );
1458 if (EFI_ERROR (Status)) {
1459 //
1460 // If there is no Simple Pointer Protocol on System Table
1461 //
1462 HandleBuffer = NULL;
1463 MainEditor.MouseInterface = NULL;
1464 Status = gBS->LocateHandleBuffer (
1465 ByProtocol,
1466 &gEfiSimplePointerProtocolGuid,
1467 NULL,
1468 &HandleCount,
1469 &HandleBuffer
1470 );
1471 if (!EFI_ERROR (Status) && HandleCount > 0) {
1472 //
1473 // Try to find the first available mouse device
1474 //
1475 for (Index = 0; Index < HandleCount; Index++) {
1476 Status = gBS->HandleProtocol (
1477 HandleBuffer[Index],
1478 &gEfiSimplePointerProtocolGuid,
1479 (VOID**)&MainEditor.MouseInterface
1480 );
1481 if (!EFI_ERROR (Status)) {
1482 break;
1483 }
1484 }
1485 }
1486 if (HandleBuffer != NULL) {
1487 FreePool (HandleBuffer);
1488 }
1489 }
1490
1491 if (!EFI_ERROR (Status) && MainEditor.MouseInterface != NULL) {
1492 MainEditor.MouseAccumulatorX = 0;
1493 MainEditor.MouseAccumulatorY = 0;
1494 MainEditor.MouseSupported = TRUE;
1495 }
1496
1497 //
1498 // below will call the five components' init function
1499 //
1500 Status = MainTitleBarInit (L"UEFI EDIT 2.0");
1501 if (EFI_ERROR (Status)) {
1502 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_TITLEBAR), gShellDebug1HiiHandle);
1503 return EFI_LOAD_ERROR;
1504 }
1505
1506 Status = ControlHotKeyInit (MainControlBasedMenuFunctions);
1507 Status = MenuBarInit (MainMenuItems);
1508 if (EFI_ERROR (Status)) {
1509 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_MAINMENU), gShellDebug1HiiHandle);
1510 return EFI_LOAD_ERROR;
1511 }
1512
1513 Status = StatusBarInit ();
1514 if (EFI_ERROR (Status)) {
1515 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_STATUSBAR), gShellDebug1HiiHandle);
1516 return EFI_LOAD_ERROR;
1517 }
1518
1519 InputBarInit ();
1520
1521 Status = FileBufferInit ();
1522 if (EFI_ERROR (Status)) {
1523 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER), gShellDebug1HiiHandle);
1524 return EFI_LOAD_ERROR;
1525 }
1526 //
1527 // clear whole screen and enable cursor
1528 //
1529 gST->ConOut->ClearScreen (gST->ConOut);
1530 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
1531
1532 //
1533 // initialize EditorFirst and EditorExit
1534 //
1535 EditorFirst = TRUE;
1536 EditorExit = FALSE;
1537 EditorMouseAction = FALSE;
1538
1539 return EFI_SUCCESS;
1540 }
1541
1542 /**
1543 The cleanup function for MainEditor.
1544
1545 @retval EFI_SUCCESS The operation was successful.
1546 @retval EFI_LOAD_ERROR A load error occured.
1547 **/
1548 EFI_STATUS
1549 EFIAPI
1550 MainEditorCleanup (
1551 VOID
1552 )
1553 {
1554 EFI_STATUS Status;
1555
1556 //
1557 // call the five components' cleanup function
1558 // if error, do not exit
1559 // just print some warning
1560 //
1561 MainTitleBarCleanup();
1562 StatusBarCleanup();
1563 InputBarCleanup();
1564 MenuBarCleanup ();
1565
1566 Status = FileBufferCleanup ();
1567 if (EFI_ERROR (Status)) {
1568 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER_CLEANUP), gShellDebug1HiiHandle);
1569 }
1570 //
1571 // restore old mode
1572 //
1573 if (OriginalMode != gST->ConOut->Mode->Mode) {
1574 gST->ConOut->SetMode (gST->ConOut, OriginalMode);
1575 }
1576 //
1577 // restore old screen color
1578 //
1579 gST->ConOut->SetAttribute (
1580 gST->ConOut,
1581 EFI_TEXT_ATTR (OriginalColors.Foreground, OriginalColors.Background)
1582 );
1583
1584 gST->ConOut->ClearScreen (gST->ConOut);
1585
1586 return EFI_SUCCESS;
1587 }
1588
1589 /**
1590 Refresh the main editor component.
1591 **/
1592 VOID
1593 EFIAPI
1594 MainEditorRefresh (
1595 VOID
1596 )
1597 {
1598 //
1599 // The Stall value is from experience. NOT from spec. avoids 'flicker'
1600 //
1601 gBS->Stall (50);
1602
1603 //
1604 // call the components refresh function
1605 //
1606 if (EditorFirst
1607 || StrCmp (FileBufferBackupVar.FileName, FileBuffer.FileName) != 0
1608 || FileBufferBackupVar.FileType != FileBuffer.FileType
1609 || FileBufferBackupVar.FileModified != FileBuffer.FileModified
1610 || FileBufferBackupVar.ReadOnly != FileBuffer.ReadOnly) {
1611
1612 MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row, 0, 0);
1613 FileBufferRestorePosition ();
1614 FileBufferRefresh ();
1615 }
1616 if (EditorFirst
1617 || FileBufferBackupVar.FilePosition.Row != FileBuffer.FilePosition.Row
1618 || FileBufferBackupVar.FilePosition.Column != FileBuffer.FilePosition.Column
1619 || FileBufferBackupVar.ModeInsert != FileBuffer.ModeInsert
1620 || StatusBarGetRefresh()) {
1621
1622 StatusBarRefresh (EditorFirst, MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column, MainEditor.FileBuffer->FilePosition.Row, MainEditor.FileBuffer->FilePosition.Column, MainEditor.FileBuffer->ModeInsert);
1623 FileBufferRestorePosition ();
1624 FileBufferRefresh ();
1625 }
1626
1627 if (EditorFirst) {
1628 FileBufferRestorePosition ();
1629 }
1630
1631 //
1632 // EditorFirst is now set to FALSE
1633 //
1634 EditorFirst = FALSE;
1635 }
1636
1637 /**
1638 Get's the resultant location of the cursor based on the relative movement of the Mouse.
1639
1640 @param[in] GuidX The relative mouse movement.
1641
1642 @return The X location of the mouse.
1643 **/
1644 INT32
1645 EFIAPI
1646 GetTextX (
1647 IN INT32 GuidX
1648 )
1649 {
1650 INT32 Gap;
1651
1652 MainEditor.MouseAccumulatorX += GuidX;
1653 Gap = (MainEditor.MouseAccumulatorX * (INT32) MainEditor.ScreenSize.Column) / (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionX);
1654 MainEditor.MouseAccumulatorX = (MainEditor.MouseAccumulatorX * (INT32) MainEditor.ScreenSize.Column) % (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionX);
1655 MainEditor.MouseAccumulatorX = MainEditor.MouseAccumulatorX / (INT32) MainEditor.ScreenSize.Column;
1656 return Gap;
1657 }
1658
1659 /**
1660 Get's the resultant location of the cursor based on the relative movement of the Mouse.
1661
1662 @param[in] GuidY The relative mouse movement.
1663
1664 @return The Y location of the mouse.
1665 **/
1666 INT32
1667 EFIAPI
1668 GetTextY (
1669 IN INT32 GuidY
1670 )
1671 {
1672 INT32 Gap;
1673
1674 MainEditor.MouseAccumulatorY += GuidY;
1675 Gap = (MainEditor.MouseAccumulatorY * (INT32) MainEditor.ScreenSize.Row) / (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionY);
1676 MainEditor.MouseAccumulatorY = (MainEditor.MouseAccumulatorY * (INT32) MainEditor.ScreenSize.Row) % (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionY);
1677 MainEditor.MouseAccumulatorY = MainEditor.MouseAccumulatorY / (INT32) MainEditor.ScreenSize.Row;
1678
1679 return Gap;
1680 }
1681
1682 /**
1683 Support mouse movement. Move the cursor.
1684
1685 @param[in] MouseState The current mouse state.
1686
1687 @retval EFI_SUCCESS The operation was successful.
1688 @retval EFI_NOT_FOUND There was no mouse support found.
1689 **/
1690 EFI_STATUS
1691 EFIAPI
1692 MainEditorHandleMouseInput (
1693 IN EFI_SIMPLE_POINTER_STATE MouseState
1694 )
1695 {
1696
1697 INT32 TextX;
1698 INT32 TextY;
1699 UINTN FRow;
1700 UINTN FCol;
1701
1702 LIST_ENTRY *Link;
1703 EFI_EDITOR_LINE *Line;
1704
1705 UINTN Index;
1706 BOOLEAN Action;
1707
1708 //
1709 // mouse action means:
1710 // mouse movement
1711 // mouse left button
1712 //
1713 Action = FALSE;
1714
1715 //
1716 // have mouse movement
1717 //
1718 if (MouseState.RelativeMovementX || MouseState.RelativeMovementY) {
1719 //
1720 // handle
1721 //
1722 TextX = GetTextX (MouseState.RelativeMovementX);
1723 TextY = GetTextY (MouseState.RelativeMovementY);
1724
1725 FileBufferAdjustMousePosition (TextX, TextY);
1726
1727 Action = TRUE;
1728
1729 }
1730
1731 //
1732 // if left button pushed down
1733 //
1734 if (MouseState.LeftButton) {
1735
1736 FCol = MainEditor.FileBuffer->MousePosition.Column - 1 + 1;
1737
1738 FRow = MainEditor.FileBuffer->FilePosition.Row +
1739 MainEditor.FileBuffer->MousePosition.Row -
1740 MainEditor.FileBuffer->DisplayPosition.Row;
1741
1742 //
1743 // beyond the file line length
1744 //
1745 if (MainEditor.FileBuffer->NumLines < FRow) {
1746 FRow = MainEditor.FileBuffer->NumLines;
1747 }
1748
1749 Link = MainEditor.FileBuffer->ListHead->ForwardLink;
1750 for (Index = 0; Index < FRow - 1; Index++) {
1751 Link = Link->ForwardLink;
1752 }
1753
1754 Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
1755
1756 //
1757 // beyond the line's column length
1758 //
1759 if (FCol > Line->Size + 1) {
1760 FCol = Line->Size + 1;
1761 }
1762
1763 FileBufferMovePosition (FRow, FCol);
1764
1765 MainEditor.FileBuffer->MousePosition.Row = MainEditor.FileBuffer->DisplayPosition.Row;
1766
1767 MainEditor.FileBuffer->MousePosition.Column = MainEditor.FileBuffer->DisplayPosition.Column;
1768
1769 Action = TRUE;
1770 }
1771 //
1772 // mouse has action
1773 //
1774 if (Action) {
1775 return EFI_SUCCESS;
1776 }
1777
1778 //
1779 // no mouse action
1780 //
1781 return EFI_NOT_FOUND;
1782 }
1783
1784 /**
1785 Handle user key input. This routes to other functions for the actions.
1786
1787 @retval EFI_SUCCESS The operation was successful.
1788 @retval EFI_LOAD_ERROR A load error occured.
1789 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1790 **/
1791 EFI_STATUS
1792 EFIAPI
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 EFIAPI
1890 MainEditorSetCutLine (
1891 EFI_EDITOR_LINE *Line
1892 )
1893 {
1894 if (Line == NULL) {
1895 return EFI_SUCCESS;
1896 }
1897
1898 if (MainEditor.CutLine != NULL) {
1899 //
1900 // free the old clipboard
1901 //
1902 LineFree (MainEditor.CutLine);
1903 }
1904 //
1905 // duplicate the line to clipboard
1906 //
1907 MainEditor.CutLine = LineDup (Line);
1908 if (MainEditor.CutLine == NULL) {
1909 return EFI_OUT_OF_RESOURCES;
1910 }
1911
1912 return EFI_SUCCESS;
1913 }
1914
1915 /**
1916 Backup function for MainEditor
1917
1918 @retval EFI_SUCCESS The operation was successful.
1919 **/
1920 EFI_STATUS
1921 EFIAPI
1922 MainEditorBackup (
1923 VOID
1924 )
1925 {
1926 FileBufferBackup ();
1927
1928 return EFI_SUCCESS;
1929 }