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