]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c
4eb7d9eee304dfc2937fcc169a981b5fc34d5c25
[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 EFIAPI
1422 MainEditorInit (
1423 VOID
1424 )
1425 {
1426 EFI_STATUS Status;
1427 EFI_HANDLE *HandleBuffer;
1428 UINTN HandleCount;
1429 UINTN Index;
1430
1431 //
1432 // basic initialization
1433 //
1434 CopyMem (&MainEditor, &MainEditorConst, sizeof (MainEditor));
1435
1436 //
1437 // set screen attributes
1438 //
1439 MainEditor.ColorAttributes.Colors.Foreground = gST->ConOut->Mode->Attribute & 0x000000ff;
1440
1441 MainEditor.ColorAttributes.Colors.Background = (UINT8) (gST->ConOut->Mode->Attribute >> 4);
1442 OriginalColors = MainEditor.ColorAttributes.Colors;
1443
1444 OriginalMode = gST->ConOut->Mode->Mode;
1445
1446 //
1447 // query screen size
1448 //
1449 gST->ConOut->QueryMode (
1450 gST->ConOut,
1451 gST->ConOut->Mode->Mode,
1452 &(MainEditor.ScreenSize.Column),
1453 &(MainEditor.ScreenSize.Row)
1454 );
1455
1456 //
1457 // Find mouse in System Table ConsoleInHandle
1458 //
1459 Status = gBS->HandleProtocol (
1460 gST->ConIn,
1461 &gEfiSimplePointerProtocolGuid,
1462 (VOID**)&MainEditor.MouseInterface
1463 );
1464 if (EFI_ERROR (Status)) {
1465 //
1466 // If there is no Simple Pointer Protocol on System Table
1467 //
1468 HandleBuffer = NULL;
1469 MainEditor.MouseInterface = NULL;
1470 Status = gBS->LocateHandleBuffer (
1471 ByProtocol,
1472 &gEfiSimplePointerProtocolGuid,
1473 NULL,
1474 &HandleCount,
1475 &HandleBuffer
1476 );
1477 if (!EFI_ERROR (Status) && HandleCount > 0) {
1478 //
1479 // Try to find the first available mouse device
1480 //
1481 for (Index = 0; Index < HandleCount; Index++) {
1482 Status = gBS->HandleProtocol (
1483 HandleBuffer[Index],
1484 &gEfiSimplePointerProtocolGuid,
1485 (VOID**)&MainEditor.MouseInterface
1486 );
1487 if (!EFI_ERROR (Status)) {
1488 break;
1489 }
1490 }
1491 }
1492 if (HandleBuffer != NULL) {
1493 FreePool (HandleBuffer);
1494 }
1495 }
1496
1497 if (!EFI_ERROR (Status) && MainEditor.MouseInterface != NULL) {
1498 MainEditor.MouseAccumulatorX = 0;
1499 MainEditor.MouseAccumulatorY = 0;
1500 MainEditor.MouseSupported = TRUE;
1501 }
1502
1503 //
1504 // below will call the five components' init function
1505 //
1506 Status = MainTitleBarInit (L"UEFI EDIT");
1507 if (EFI_ERROR (Status)) {
1508 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_TITLEBAR), gShellDebug1HiiHandle);
1509 return EFI_LOAD_ERROR;
1510 }
1511
1512 Status = ControlHotKeyInit (MainControlBasedMenuFunctions);
1513 Status = MenuBarInit (MainMenuItems);
1514 if (EFI_ERROR (Status)) {
1515 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_MAINMENU), gShellDebug1HiiHandle);
1516 return EFI_LOAD_ERROR;
1517 }
1518
1519 Status = StatusBarInit ();
1520 if (EFI_ERROR (Status)) {
1521 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_STATUSBAR), gShellDebug1HiiHandle);
1522 return EFI_LOAD_ERROR;
1523 }
1524
1525 InputBarInit ();
1526
1527 Status = FileBufferInit ();
1528 if (EFI_ERROR (Status)) {
1529 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER), gShellDebug1HiiHandle);
1530 return EFI_LOAD_ERROR;
1531 }
1532 //
1533 // clear whole screen and enable cursor
1534 //
1535 gST->ConOut->ClearScreen (gST->ConOut);
1536 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
1537
1538 //
1539 // initialize EditorFirst and EditorExit
1540 //
1541 EditorFirst = TRUE;
1542 EditorExit = FALSE;
1543 EditorMouseAction = FALSE;
1544
1545 return EFI_SUCCESS;
1546 }
1547
1548 /**
1549 The cleanup function for MainEditor.
1550
1551 @retval EFI_SUCCESS The operation was successful.
1552 @retval EFI_LOAD_ERROR A load error occured.
1553 **/
1554 EFI_STATUS
1555 EFIAPI
1556 MainEditorCleanup (
1557 VOID
1558 )
1559 {
1560 EFI_STATUS Status;
1561
1562 //
1563 // call the five components' cleanup function
1564 // if error, do not exit
1565 // just print some warning
1566 //
1567 MainTitleBarCleanup();
1568 StatusBarCleanup();
1569 InputBarCleanup();
1570 MenuBarCleanup ();
1571
1572 Status = FileBufferCleanup ();
1573 if (EFI_ERROR (Status)) {
1574 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER_CLEANUP), gShellDebug1HiiHandle);
1575 }
1576 //
1577 // restore old mode
1578 //
1579 if (OriginalMode != gST->ConOut->Mode->Mode) {
1580 gST->ConOut->SetMode (gST->ConOut, OriginalMode);
1581 }
1582 //
1583 // restore old screen color
1584 //
1585 gST->ConOut->SetAttribute (
1586 gST->ConOut,
1587 EFI_TEXT_ATTR (OriginalColors.Foreground, OriginalColors.Background)
1588 );
1589
1590 gST->ConOut->ClearScreen (gST->ConOut);
1591
1592 return EFI_SUCCESS;
1593 }
1594
1595 /**
1596 Refresh the main editor component.
1597 **/
1598 VOID
1599 EFIAPI
1600 MainEditorRefresh (
1601 VOID
1602 )
1603 {
1604 //
1605 // The Stall value is from experience. NOT from spec. avoids 'flicker'
1606 //
1607 gBS->Stall (50);
1608
1609 //
1610 // call the components refresh function
1611 //
1612 if (EditorFirst
1613 || StrCmp (FileBufferBackupVar.FileName, FileBuffer.FileName) != 0
1614 || FileBufferBackupVar.FileType != FileBuffer.FileType
1615 || FileBufferBackupVar.FileModified != FileBuffer.FileModified
1616 || FileBufferBackupVar.ReadOnly != FileBuffer.ReadOnly) {
1617
1618 MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row, 0, 0);
1619 FileBufferRestorePosition ();
1620 }
1621
1622 if (EditorFirst
1623 || FileBufferBackupVar.FilePosition.Row != FileBuffer.FilePosition.Row
1624 || FileBufferBackupVar.FilePosition.Column != FileBuffer.FilePosition.Column
1625 || FileBufferBackupVar.ModeInsert != FileBuffer.ModeInsert
1626 || StatusBarGetRefresh()) {
1627
1628 StatusBarRefresh (EditorFirst, MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column, MainEditor.FileBuffer->FilePosition.Row, MainEditor.FileBuffer->FilePosition.Column, MainEditor.FileBuffer->ModeInsert);
1629 FileBufferRestorePosition ();
1630 }
1631
1632 if (EditorFirst) {
1633 FileBufferRestorePosition ();
1634 }
1635
1636 FileBufferRefresh ();
1637
1638 //
1639 // EditorFirst is now set to FALSE
1640 //
1641 EditorFirst = FALSE;
1642 }
1643
1644 /**
1645 Get's the resultant location of the cursor based on the relative movement of the Mouse.
1646
1647 @param[in] GuidX The relative mouse movement.
1648
1649 @return The X location of the mouse.
1650 **/
1651 INT32
1652 EFIAPI
1653 GetTextX (
1654 IN INT32 GuidX
1655 )
1656 {
1657 INT32 Gap;
1658
1659 MainEditor.MouseAccumulatorX += GuidX;
1660 Gap = (MainEditor.MouseAccumulatorX * (INT32) MainEditor.ScreenSize.Column) / (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionX);
1661 MainEditor.MouseAccumulatorX = (MainEditor.MouseAccumulatorX * (INT32) MainEditor.ScreenSize.Column) % (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionX);
1662 MainEditor.MouseAccumulatorX = MainEditor.MouseAccumulatorX / (INT32) MainEditor.ScreenSize.Column;
1663 return Gap;
1664 }
1665
1666 /**
1667 Get's the resultant location of the cursor based on the relative movement of the Mouse.
1668
1669 @param[in] GuidY The relative mouse movement.
1670
1671 @return The Y location of the mouse.
1672 **/
1673 INT32
1674 EFIAPI
1675 GetTextY (
1676 IN INT32 GuidY
1677 )
1678 {
1679 INT32 Gap;
1680
1681 MainEditor.MouseAccumulatorY += GuidY;
1682 Gap = (MainEditor.MouseAccumulatorY * (INT32) MainEditor.ScreenSize.Row) / (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionY);
1683 MainEditor.MouseAccumulatorY = (MainEditor.MouseAccumulatorY * (INT32) MainEditor.ScreenSize.Row) % (INT32) (50 * (INT32) MainEditor.MouseInterface->Mode->ResolutionY);
1684 MainEditor.MouseAccumulatorY = MainEditor.MouseAccumulatorY / (INT32) MainEditor.ScreenSize.Row;
1685
1686 return Gap;
1687 }
1688
1689 /**
1690 Support mouse movement. Move the cursor.
1691
1692 @param[in] MouseState The current mouse state.
1693
1694 @retval EFI_SUCCESS The operation was successful.
1695 @retval EFI_NOT_FOUND There was no mouse support found.
1696 **/
1697 EFI_STATUS
1698 EFIAPI
1699 MainEditorHandleMouseInput (
1700 IN EFI_SIMPLE_POINTER_STATE MouseState
1701 )
1702 {
1703
1704 INT32 TextX;
1705 INT32 TextY;
1706 UINTN FRow;
1707 UINTN FCol;
1708
1709 LIST_ENTRY *Link;
1710 EFI_EDITOR_LINE *Line;
1711
1712 UINTN Index;
1713 BOOLEAN Action;
1714
1715 //
1716 // mouse action means:
1717 // mouse movement
1718 // mouse left button
1719 //
1720 Action = FALSE;
1721
1722 //
1723 // have mouse movement
1724 //
1725 if (MouseState.RelativeMovementX || MouseState.RelativeMovementY) {
1726 //
1727 // handle
1728 //
1729 TextX = GetTextX (MouseState.RelativeMovementX);
1730 TextY = GetTextY (MouseState.RelativeMovementY);
1731
1732 FileBufferAdjustMousePosition (TextX, TextY);
1733
1734 Action = TRUE;
1735
1736 }
1737
1738 //
1739 // if left button pushed down
1740 //
1741 if (MouseState.LeftButton) {
1742
1743 FCol = MainEditor.FileBuffer->MousePosition.Column - 1 + 1;
1744
1745 FRow = MainEditor.FileBuffer->FilePosition.Row +
1746 MainEditor.FileBuffer->MousePosition.Row -
1747 MainEditor.FileBuffer->DisplayPosition.Row;
1748
1749 //
1750 // beyond the file line length
1751 //
1752 if (MainEditor.FileBuffer->NumLines < FRow) {
1753 FRow = MainEditor.FileBuffer->NumLines;
1754 }
1755
1756 Link = MainEditor.FileBuffer->ListHead->ForwardLink;
1757 for (Index = 0; Index < FRow - 1; Index++) {
1758 Link = Link->ForwardLink;
1759 }
1760
1761 Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
1762
1763 //
1764 // beyond the line's column length
1765 //
1766 if (FCol > Line->Size + 1) {
1767 FCol = Line->Size + 1;
1768 }
1769
1770 FileBufferMovePosition (FRow, FCol);
1771
1772 MainEditor.FileBuffer->MousePosition.Row = MainEditor.FileBuffer->DisplayPosition.Row;
1773
1774 MainEditor.FileBuffer->MousePosition.Column = MainEditor.FileBuffer->DisplayPosition.Column;
1775
1776 Action = TRUE;
1777 }
1778 //
1779 // mouse has action
1780 //
1781 if (Action) {
1782 return EFI_SUCCESS;
1783 }
1784
1785 //
1786 // no mouse action
1787 //
1788 return EFI_NOT_FOUND;
1789 }
1790
1791 /**
1792 Handle user key input. This routes to other functions for the actions.
1793
1794 @retval EFI_SUCCESS The operation was successful.
1795 @retval EFI_LOAD_ERROR A load error occured.
1796 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1797 **/
1798 EFI_STATUS
1799 EFIAPI
1800 MainEditorKeyInput (
1801 VOID
1802 )
1803 {
1804 EFI_INPUT_KEY Key;
1805 EFI_STATUS Status;
1806 EFI_SIMPLE_POINTER_STATE MouseState;
1807
1808 do {
1809
1810 Status = EFI_SUCCESS;
1811 EditorMouseAction = FALSE;
1812
1813 //
1814 // backup some key elements, so that can aVOID some refresh work
1815 //
1816 MainEditorBackup ();
1817
1818 //
1819 // change priority of checking mouse/keyboard activity dynamically
1820 // so prevent starvation of keyboard.
1821 // if last time, mouse moves then this time check keyboard
1822 //
1823 if (MainEditor.MouseSupported) {
1824 Status = MainEditor.MouseInterface->GetState (
1825 MainEditor.MouseInterface,
1826 &MouseState
1827 );
1828 if (!EFI_ERROR (Status)) {
1829
1830 Status = MainEditorHandleMouseInput (MouseState);
1831
1832 if (!EFI_ERROR (Status)) {
1833 EditorMouseAction = TRUE;
1834 FileBufferMouseNeedRefresh = TRUE;
1835 } else if (Status == EFI_LOAD_ERROR) {
1836 StatusBarSetStatusString (L"Invalid Mouse Movement ");
1837 }
1838 }
1839 }
1840
1841 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
1842 if (!EFI_ERROR (Status)) {
1843 //
1844 // dispatch to different components' key handling function
1845 // so not everywhere has to set this variable
1846 //
1847 FileBufferMouseNeedRefresh = TRUE;
1848 //
1849 // clear previous status string
1850 //
1851 StatusBarSetRefresh();
1852
1853 //
1854 // dispatch to different components' key handling function
1855 //
1856 if (EFI_NOT_FOUND != MenuBarDispatchControlHotKey(&Key)) {
1857 Status = EFI_SUCCESS;
1858 } else if ((Key.ScanCode == SCAN_NULL) || ((Key.ScanCode >= SCAN_UP) && (Key.ScanCode <= SCAN_PAGE_DOWN))) {
1859 Status = FileBufferHandleInput (&Key);
1860 } else if ((Key.ScanCode >= SCAN_F1) && (Key.ScanCode <= SCAN_F12)) {
1861 Status = MenuBarDispatchFunctionKey (&Key);
1862 } else {
1863 StatusBarSetStatusString (L"Unknown Command");
1864 FileBufferMouseNeedRefresh = FALSE;
1865 }
1866
1867 if (Status != EFI_SUCCESS && Status != EFI_OUT_OF_RESOURCES) {
1868 //
1869 // not already has some error status
1870 //
1871 if (StatusBarGetString() != NULL && StrCmp (L"", StatusBarGetString()) == 0) {
1872 StatusBarSetStatusString (L"Disk Error. Try Again");
1873 }
1874 }
1875
1876 }
1877 //
1878 // after handling, refresh editor
1879 //
1880 MainEditorRefresh ();
1881
1882 } while (Status != EFI_OUT_OF_RESOURCES && !EditorExit);
1883
1884 return Status;
1885 }
1886
1887 /**
1888 Set clipboard
1889
1890 @param[in] Line A pointer to the line to be set to clipboard
1891
1892 @retval EFI_SUCCESS The operation was successful.
1893 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1894 **/
1895 EFI_STATUS
1896 EFIAPI
1897 MainEditorSetCutLine (
1898 EFI_EDITOR_LINE *Line
1899 )
1900 {
1901 if (Line == NULL) {
1902 return EFI_SUCCESS;
1903 }
1904
1905 if (MainEditor.CutLine != NULL) {
1906 //
1907 // free the old clipboard
1908 //
1909 LineFree (MainEditor.CutLine);
1910 }
1911 //
1912 // duplicate the line to clipboard
1913 //
1914 MainEditor.CutLine = LineDup (Line);
1915 if (MainEditor.CutLine == NULL) {
1916 return EFI_OUT_OF_RESOURCES;
1917 }
1918
1919 return EFI_SUCCESS;
1920 }
1921
1922 /**
1923 Backup function for MainEditor
1924
1925 @retval EFI_SUCCESS The operation was successful.
1926 **/
1927 EFI_STATUS
1928 EFIAPI
1929 MainEditorBackup (
1930 VOID
1931 )
1932 {
1933 FileBufferBackup ();
1934
1935 return EFI_SUCCESS;
1936 }