2 Implements editor interface functions.
4 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved. <BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "TextEditor.h"
10 #include "EditStatusBar.h"
11 #include "EditInputBar.h"
12 #include "EditMenuBar.h"
15 // the first time editor launch
20 // it's time editor should exit
24 BOOLEAN EditorMouseAction
;
26 extern EFI_EDITOR_FILE_BUFFER FileBuffer
;
28 extern BOOLEAN FileBufferNeedRefresh
;
30 extern BOOLEAN FileBufferOnlyLineNeedRefresh
;
32 extern BOOLEAN FileBufferMouseNeedRefresh
;
34 extern EFI_EDITOR_FILE_BUFFER FileBufferBackupVar
;
36 EFI_EDITOR_GLOBAL_EDITOR MainEditor
;
39 Load a file from disk to editor
41 @retval EFI_SUCCESS The operation was successful.
42 @retval EFI_LOAD_ERROR A load error occurred.
43 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
51 Switch a file from ASCII to UNICODE or vise-versa.
53 @retval EFI_SUCCESS The switch was ok or a warning was presented.
56 MainCommandSwitchFileType (
61 move cursor to specified lines
63 @retval EFI_SUCCESS The operation was successful.
71 Save current file to disk, you can save to current file name or
72 save to another file name.
74 @retval EFI_SUCCESS The file was saved correctly.
75 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
76 @retval EFI_LOAD_ERROR A file access error occurred.
84 Show help information for the editor.
86 @retval EFI_SUCCESS The operation was successful.
89 MainCommandDisplayHelp (
96 @retval EFI_SUCCESS The operation was successful.
97 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
98 @retval EFI_LOAD_ERROR A load error occurred.
106 search string in file buffer
108 @retval EFI_SUCCESS The operation was successful.
109 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
110 @retval EFI_LOAD_ERROR A load error occurred.
118 search string in file buffer, and replace it with another str
120 @retval EFI_SUCCESS The operation was successful.
121 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
122 @retval EFI_LOAD_ERROR A load error occurred.
125 MainCommandSearchReplace (
130 cut current line to clipboard
132 @retval EFI_SUCCESS The operation was successful.
133 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
134 @retval EFI_LOAD_ERROR A load error occurred.
142 paste line to file buffer.
144 @retval EFI_SUCCESS The operation was successful.
145 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
146 @retval EFI_LOAD_ERROR A load error occurred.
149 MainCommandPasteLine (
154 Help info that will be displayed.
156 EFI_STRING_ID MainMenuHelpInfo
[] = {
157 STRING_TOKEN (STR_EDIT_HELP_TITLE
),
158 STRING_TOKEN (STR_EDIT_HELP_BLANK
),
159 STRING_TOKEN (STR_EDIT_HELP_LIST_TITLE
),
160 STRING_TOKEN (STR_EDIT_HELP_DIV
),
161 STRING_TOKEN (STR_EDIT_HELP_GO_TO_LINE
),
162 STRING_TOKEN (STR_EDIT_HELP_SAVE_FILE
),
163 STRING_TOKEN (STR_EDIT_HELP_EXIT
),
164 STRING_TOKEN (STR_EDIT_HELP_SEARCH
),
165 STRING_TOKEN (STR_EDIT_HELP_SEARCH_REPLACE
),
166 STRING_TOKEN (STR_EDIT_HELP_CUT_LINE
),
167 STRING_TOKEN (STR_EDIT_HELP_PASTE_LINE
),
168 STRING_TOKEN (STR_EDIT_HELP_OPEN_FILE
),
169 STRING_TOKEN (STR_EDIT_HELP_FILE_TYPE
),
170 STRING_TOKEN (STR_EDIT_HELP_BLANK
),
171 STRING_TOKEN (STR_EDIT_HELP_EXIT_HELP
),
172 STRING_TOKEN (STR_EDIT_HELP_BLANK
),
173 STRING_TOKEN (STR_EDIT_HELP_BLANK
),
174 STRING_TOKEN (STR_EDIT_HELP_BLANK
),
175 STRING_TOKEN (STR_EDIT_HELP_BLANK
),
176 STRING_TOKEN (STR_EDIT_HELP_BLANK
),
177 STRING_TOKEN (STR_EDIT_HELP_BLANK
),
178 STRING_TOKEN (STR_EDIT_HELP_BLANK
),
179 STRING_TOKEN (STR_EDIT_HELP_DIV
),
183 MENU_ITEM_FUNCTION MainControlBasedMenuFunctions
[] = {
189 MainCommandDisplayHelp
, /* Ctrl - E */
190 MainCommandSearch
, /* Ctrl - F */
191 MainCommandGotoLine
, /* Ctrl - G */
195 MainCommandCutLine
, /* Ctrl - K */
199 MainCommandOpenFile
, /* Ctrl - O */
201 MainCommandExit
, /* Ctrl - Q */
202 MainCommandSearchReplace
, /* Ctrl - R */
203 MainCommandSaveFile
, /* Ctrl - S */
204 MainCommandSwitchFileType
, /* Ctrl - T */
205 MainCommandPasteLine
, /* Ctrl - U */
213 EDITOR_MENU_ITEM MainMenuItems
[] = {
215 STRING_TOKEN (STR_EDIT_LIBMENUBAR_GO_TO_LINE
),
216 STRING_TOKEN (STR_EDIT_LIBMENUBAR_F1
),
220 STRING_TOKEN (STR_EDIT_LIBMENUBAR_SAVE_FILE
),
221 STRING_TOKEN (STR_EDIT_LIBMENUBAR_F2
),
225 STRING_TOKEN (STR_EDIT_LIBMENUBAR_EXIT
),
226 STRING_TOKEN (STR_EDIT_LIBMENUBAR_F3
),
231 STRING_TOKEN (STR_EDIT_LIBMENUBAR_SEARCH
),
232 STRING_TOKEN (STR_EDIT_LIBMENUBAR_F4
),
236 STRING_TOKEN (STR_EDIT_LIBMENUBAR_SEARCH_REPLACE
),
237 STRING_TOKEN (STR_EDIT_LIBMENUBAR_F5
),
238 MainCommandSearchReplace
241 STRING_TOKEN (STR_EDIT_LIBMENUBAR_CUT_LINE
),
242 STRING_TOKEN (STR_EDIT_LIBMENUBAR_F6
),
246 STRING_TOKEN (STR_EDIT_LIBMENUBAR_PASTE_LINE
),
247 STRING_TOKEN (STR_EDIT_LIBMENUBAR_F7
),
252 STRING_TOKEN (STR_EDIT_LIBMENUBAR_OPEN_FILE
),
253 STRING_TOKEN (STR_EDIT_LIBMENUBAR_F8
),
257 STRING_TOKEN (STR_EDIT_LIBMENUBAR_FILE_TYPE
),
258 STRING_TOKEN (STR_EDIT_LIBMENUBAR_F9
),
259 MainCommandSwitchFileType
262 STRING_TOKEN (STR_EDIT_LIBMENUBAR_FILE_TYPE
),
263 STRING_TOKEN (STR_EDIT_LIBMENUBAR_F11
),
264 MainCommandSwitchFileType
275 Load a file from disk to editor
277 @retval EFI_SUCCESS The operation was successful.
278 @retval EFI_LOAD_ERROR A load error occurred.
279 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
282 MainCommandOpenFile (
290 // This command will open a file from current working directory.
291 // Read-only file can also be opened. But it can not be modified.
292 // Below is the scenario of Open File command:
293 // 1.IF currently opened file has not been modIFied, directly go to step .
294 // IF currently opened file has been modified,
295 // an Input Bar will be prompted as :
296 // "File Modified. Save ( Yes/No/Cancel) ?"
297 // IF user press 'y' or 'Y', currently opened file will be saved.
298 // IF user press 'n' or 'N', currently opened file will
300 // IF user press 'c' or 'C' or ESC, Open File command ends and
301 // currently opened file is still opened.
303 // 2. An Input Bar will be prompted as : "File Name to Open: "
304 // IF user press ESC, Open File command ends and
305 // currently opened file is still opened.
306 // Any other inputs with a Return will
307 // cause currently opened file close.
309 // 3. IF user input file name is an existing file , this file will be read
311 // IF user input file name is a new file, this file will be created
312 // and opened. This file's type ( UNICODE or ASCII ) is the same
313 // with the old file.
314 // if current file is modified, so you need to choose
315 // whether to save it first.
317 if (MainEditor
.FileBuffer
->FileModified
) {
318 Status
= InputBarSetPrompt (L
"File modified. Save (Yes/No/Cancel) ? ");
319 if (EFI_ERROR (Status
)) {
324 // the answer is just one character
326 Status
= InputBarSetStringSize (1);
327 if (EFI_ERROR (Status
)) {
332 // loop for user's answer
333 // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C'
337 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
338 StatusBarSetRefresh ();
343 if (Status
== EFI_NOT_READY
) {
347 switch (InputBarGetString ()[0]) {
351 // want to save this file first
353 Status
= FileBufferSave (MainEditor
.FileBuffer
->FileName
);
354 if (EFI_ERROR (Status
)) {
358 MainTitleBarRefresh (MainEditor
.FileBuffer
->FileName
, MainEditor
.FileBuffer
->FileType
, MainEditor
.FileBuffer
->ReadOnly
, MainEditor
.FileBuffer
->FileModified
, MainEditor
.ScreenSize
.Column
, MainEditor
.ScreenSize
.Row
, 0, 0);
359 FileBufferRestorePosition ();
366 // the file won't be saved
379 // TO get the open file name
381 Status
= InputBarSetPrompt (L
"File Name to Open: ");
382 if (EFI_ERROR (Status
)) {
383 FileBufferRead (MainEditor
.FileBuffer
->FileName
, TRUE
);
387 Status
= InputBarSetStringSize (100);
388 if (EFI_ERROR (Status
)) {
389 FileBufferRead (MainEditor
.FileBuffer
->FileName
, TRUE
);
394 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
395 StatusBarSetRefresh ();
400 if (Status
== EFI_NOT_READY
) {
405 // The input string length should > 0
407 if (StrLen (InputBarGetString ()) > 0) {
409 // CHECK if filename is valid
411 if (!IsValidFileName (InputBarGetString ())) {
412 FileBufferRead (MainEditor
.FileBuffer
->FileName
, TRUE
);
413 StatusBarSetStatusString (L
"Invalid File Name");
424 Status
= FileBufferRead (InputBarGetString (), FALSE
);
426 if (EFI_ERROR (Status
)) {
427 FileBufferRead (MainEditor
.FileBuffer
->FileName
, TRUE
);
428 return EFI_LOAD_ERROR
;
435 Switch a file from ASCII to UNICODE or vise-versa.
437 @retval EFI_SUCCESS The switch was ok or a warning was presented.
440 MainCommandSwitchFileType (
445 // Below is the scenario of File Type command:
446 // After File Type is executed, file type will be changed to another type
447 // if file is read-only, can not be modified
449 if (MainEditor
.FileBuffer
->ReadOnly
) {
450 StatusBarSetStatusString (L
"Read Only File Can Not Be Modified");
454 if (MainEditor
.FileBuffer
->FileType
== FileTypeUnicode
) {
455 MainEditor
.FileBuffer
->FileType
= FileTypeAscii
;
457 MainEditor
.FileBuffer
->FileType
= FileTypeUnicode
;
460 MainEditor
.FileBuffer
->FileModified
= TRUE
;
466 cut current line to clipboard
468 @retval EFI_SUCCESS The operation was successful.
469 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
470 @retval EFI_LOAD_ERROR A load error occurred.
478 EFI_EDITOR_LINE
*Line
;
481 // This command will cut current line ( where cursor is on ) to clip board.
482 // And cursor will move to the beginning of next line.
483 // Below is the scenario of Cut Line command:
484 // 1. IF cursor is on valid line, current line will be cut to clip board.
485 // IF cursor is not on valid line, an Status String will be prompted :
489 Status
= FileBufferCutLine (&Line
);
490 if (Status
== EFI_NOT_FOUND
) {
494 if (EFI_ERROR (Status
)) {
498 MainEditor
.CutLine
= Line
;
504 paste line to file buffer.
506 @retval EFI_SUCCESS The operation was successful.
507 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
508 @retval EFI_LOAD_ERROR A load error occurred.
511 MainCommandPasteLine (
518 // Below is the scenario of Paste Line command:
519 // 1. IF nothing is on clipboard, a Status String will be prompted :
520 // "No Line to Paste" and Paste Line command ends.
521 // IF something is on clipboard, insert it above current line.
522 // nothing on clipboard
524 if (MainEditor
.CutLine
== NULL
) {
525 StatusBarSetStatusString (L
"No Line to Paste");
529 Status
= FileBufferPasteLine ();
535 search string in file buffer
537 @retval EFI_SUCCESS The operation was successful.
538 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
539 @retval EFI_LOAD_ERROR A load error occurred.
552 // Below is the scenario of Search command:
553 // 1. An Input Bar will be prompted : "Enter Search String:".
554 // IF user press ESC, Search command ends.
555 // IF user just press Enter, Search command ends.
556 // IF user inputs the search string, do Step 2.
558 // 2. IF input search string is found, cursor will move to the first
559 // occurrence and do Step 3.
560 // IF input search string is not found, a Status String
561 // "Search String Not Found" will be prompted and Search command ends.
563 // 3. An Input Bar will be prompted: "Find Next (Yes/No/Cancel ) ?".
564 // IF user press ESC, Search command ends.
565 // IF user press 'y' or 'Y', do Step 2.
566 // IF user press 'n' or 'N', Search command ends.
567 // IF user press 'c' or 'C', Search command ends.
569 Status
= InputBarSetPrompt (L
"Enter Search String: ");
570 if (EFI_ERROR (Status
)) {
574 Status
= InputBarSetStringSize (40);
575 if (EFI_ERROR (Status
)) {
579 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
580 StatusBarSetRefresh ();
585 if (Status
== EFI_NOT_READY
) {
590 // just enter pressed
592 if (StrLen (InputBarGetString ()) == 0) {
596 Buffer
= CatSPrint (NULL
, L
"%s", InputBarGetString ());
597 if (Buffer
== NULL
) {
598 return EFI_OUT_OF_RESOURCES
;
602 // the first time , search from current position
607 // since search may be continued to search multiple times
608 // so we need to backup editor each time
612 Status
= FileBufferSearch (Buffer
, Offset
);
614 if (Status
== EFI_NOT_FOUND
) {
621 Status
= InputBarSetPrompt (L
"Find Next (Yes/No) ?");
622 if (EFI_ERROR (Status
)) {
627 Status
= InputBarSetStringSize (1);
628 if (EFI_ERROR (Status
)) {
635 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
636 StatusBarSetRefresh ();
641 if (Status
== EFI_NOT_READY
) {
646 switch (InputBarGetString ()[0]) {
664 // end of while !Done
665 // for search second, third time, search from current position + strlen
667 Offset
= StrLen (Buffer
);
674 StatusBarSetStatusString (L
"Search String Not Found");
680 Search string in file buffer, and replace it with another str.
682 @retval EFI_SUCCESS The operation was successful.
683 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
684 @retval EFI_LOAD_ERROR A load error occurred.
687 MainCommandSearchReplace (
696 BOOLEAN ReplaceOption
;
701 ReplaceOption
= FALSE
;
704 // Below is the scenario of Search/Replace command:
705 // 1. An Input Bar is prompted : "Enter Search String:".
706 // IF user press ESC, Search/Replace command ends.
707 // IF user just press Enter, Search/Replace command ends.
708 // IF user inputs the search string S, do Step 2.
710 // 2. An Input Bar is prompted: "Replace With:".
711 // IF user press ESC, Search/Replace command ends.
712 // IF user inputs the replace string R, do Step 3.
714 // 3. IF input search string is not found, an Status String
715 // "Search String Not Found" will be prompted
716 // and Search/Replace command ends
717 // IF input search string is found, do Step 4.
719 // 4. An Input Bar will be prompted: "Replace ( Yes/No/All/Cancel )?"
720 // IF user press 'y' or 'Y', S will be replaced with R and do Step 5
721 // IF user press 'n' or 'N', S will not be replaced and do Step 5.
722 // IF user press 'a' or 'A', all the S from file current position on
723 // will be replaced with R and Search/Replace command ends.
724 // IF user press 'c' or 'C' or ESC, Search/Replace command ends.
726 // 5. An Input Bar will be prompted: "Find Next (Yes/No/Cancel) ?".
727 // IF user press ESC, Search/Replace command ends.
728 // IF user press 'y' or 'Y', do Step 3.
729 // IF user press 'n' or 'N', Search/Replace command ends.
730 // IF user press 'c' or 'C', Search/Replace command ends.
731 // input search string
733 Status
= InputBarSetPrompt (L
"Enter Search String: ");
734 if (EFI_ERROR (Status
)) {
738 Status
= InputBarSetStringSize (40);
739 if (EFI_ERROR (Status
)) {
743 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
744 StatusBarSetRefresh ();
749 if (Status
== EFI_NOT_READY
) {
754 // if just pressed enter
756 if (StrLen (InputBarGetString ()) == 0) {
760 Search
= CatSPrint (NULL
, L
"%s", InputBarGetString ());
761 if (Search
== NULL
) {
762 return EFI_OUT_OF_RESOURCES
;
765 SearchLen
= StrLen (Search
);
768 // input replace string
770 Status
= InputBarSetPrompt (L
"Replace With: ");
771 if (EFI_ERROR (Status
)) {
775 Status
= InputBarSetStringSize (40);
776 if (EFI_ERROR (Status
)) {
780 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
781 StatusBarSetRefresh ();
786 if (Status
== EFI_NOT_READY
) {
790 Replace
= CatSPrint (NULL
, L
"%s", InputBarGetString ());
791 if (Replace
== NULL
) {
793 return EFI_OUT_OF_RESOURCES
;
796 ReplaceLen
= StrLen (Replace
);
802 // since search may be continued to search multiple times
803 // so we need to backup editor each time
808 Status
= FileBufferSearch (Search
, 0);
811 // if just replace, so skip this replace string
812 // if replace string is an empty string, so skip to next character
815 Status
= FileBufferSearch (Search
, (ReplaceLen
== 0) ? 1 : ReplaceLen
);
817 Status
= FileBufferSearch (Search
, SearchLen
);
821 if (Status
== EFI_NOT_FOUND
) {
828 Status
= InputBarSetPrompt (L
"Replace (Yes/No/All/Cancel) ?");
830 if (EFI_ERROR (Status
)) {
836 Status
= InputBarSetStringSize (1);
837 if (EFI_ERROR (Status
)) {
845 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
846 StatusBarSetRefresh ();
851 if (Status
== EFI_NOT_READY
) {
857 switch (InputBarGetString ()[0]) {
861 ReplaceOption
= TRUE
;
867 ReplaceOption
= FALSE
;
873 ReplaceOption
= TRUE
;
890 // end of while !Done
897 if (MainEditor
.FileBuffer
->ReadOnly
) {
898 StatusBarSetStatusString (L
"Read Only File Can Not Be Modified");
906 Status
= FileBufferReplaceAll (Search
, Replace
, 0);
915 Status
= FileBufferReplace (Replace
, SearchLen
);
916 if (EFI_ERROR (Status
)) {
926 Status
= InputBarSetPrompt (L
"Find Next (Yes/No) ?");
927 if (EFI_ERROR (Status
)) {
933 Status
= InputBarSetStringSize (1);
934 if (EFI_ERROR (Status
)) {
942 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
943 StatusBarSetRefresh ();
948 if (Status
== EFI_NOT_READY
) {
954 switch (InputBarGetString ()[0]) {
973 // end of while !Done
984 StatusBarSetStatusString (L
"Search String Not Found");
992 @retval EFI_SUCCESS The operation was successful.
993 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
994 @retval EFI_LOAD_ERROR A load error occurred.
1004 // Below is the scenario of Exit command:
1005 // 1. IF currently opened file is not modified, exit the editor and
1006 // Exit command ends.
1007 // IF currently opened file is modified, do Step 2
1009 // 2. An Input Bar will be prompted:
1010 // "File modified. Save ( Yes/No/Cancel )?"
1011 // IF user press 'y' or 'Y', currently opened file will be saved
1013 // IF user press 'n' or 'N', currently opened file will not be saved
1014 // and Editor exits.
1015 // IF user press 'c' or 'C' or ESC, Exit command ends.
1016 // if file has been modified, so will prompt user whether to save the changes
1018 if (MainEditor
.FileBuffer
->FileModified
) {
1019 Status
= InputBarSetPrompt (L
"File modified. Save (Yes/No/Cancel) ? ");
1020 if (EFI_ERROR (Status
)) {
1024 Status
= InputBarSetStringSize (1);
1025 if (EFI_ERROR (Status
)) {
1030 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
1031 StatusBarSetRefresh ();
1036 if (Status
== EFI_NOT_READY
) {
1040 switch (InputBarGetString ()[0]) {
1044 // write file back to disk
1046 Status
= FileBufferSave (MainEditor
.FileBuffer
->FileName
);
1047 if (!EFI_ERROR (Status
)) {
1070 move cursor to specified lines
1072 @retval EFI_SUCCESS The operation was successful.
1075 MainCommandGotoLine (
1083 // Below is the scenario of Go To Line command:
1084 // 1. An Input Bar will be prompted : "Go To Line:".
1085 // IF user press ESC, Go To Line command ends.
1086 // IF user just press Enter, cursor remains unchanged.
1087 // IF user inputs line number, do Step 2.
1089 // 2. IF input line number is valid, move cursor to the beginning
1090 // of specified line and Go To Line command ends.
1091 // IF input line number is invalid, a Status String will be prompted:
1092 // "No Such Line" and Go To Line command ends.
1094 Status
= InputBarSetPrompt (L
"Go To Line: ");
1095 if (EFI_ERROR (Status
)) {
1100 // line number's digit <= 6
1102 Status
= InputBarSetStringSize (6);
1103 if (EFI_ERROR (Status
)) {
1107 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
1108 StatusBarSetRefresh ();
1113 if (Status
== EFI_NOT_READY
) {
1118 // if JUST press enter
1120 if (StrLen (InputBarGetString ()) == 0) {
1124 Row
= ShellStrToUintn (InputBarGetString ());
1127 // invalid line number
1129 if ((Row
> MainEditor
.FileBuffer
->NumLines
) || (Row
<= 0)) {
1130 StatusBarSetStatusString (L
"No Such Line");
1135 // move cursor to that line's start
1137 FileBufferMovePosition (Row
, 1);
1143 Save current file to disk, you can save to current file name or
1144 save to another file name.
1146 @retval EFI_SUCCESS The file was saved correctly.
1147 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1148 @retval EFI_LOAD_ERROR A file access error occurred.
1151 MainCommandSaveFile (
1159 SHELL_FILE_HANDLE FileHandle
;
1160 EFI_FILE_INFO
*Info
;
1163 // This command will save currently opened file to disk.
1164 // You can choose save to another file name or just save to
1165 // current file name.
1166 // Below is the scenario of Save File command:
1167 // ( Suppose the old file name is A )
1168 // 1. An Input Bar will be prompted: "File To Save: [ old file name]"
1169 // IF user press ESC, Save File command ends .
1170 // IF user press Enter, input file name will be A.
1171 // IF user inputs a new file name B, input file name will be B.
1173 // 2. IF input file name is A, go to do Step 3.
1174 // IF input file name is B, go to do Step 4.
1176 // 3. IF A is read only, Status Bar will show "Access Denied" and
1177 // Save File commands ends.
1178 // IF A is not read only, save file buffer to disk and remove modified
1179 // flag in Title Bar , then Save File command ends.
1181 // 4. IF B does not exist, create this file and save file buffer to it.
1183 // IF B exits, do Step 5.
1185 // 5.An Input Bar will be prompted:
1186 // "File Exists. Overwrite ( Yes/No/Cancel )?"
1187 // IF user press 'y' or 'Y', do Step 6.
1188 // IF user press 'n' or 'N', Save File commands ends.
1189 // IF user press 'c' or 'C' or ESC, Save File commands ends.
1191 // 6. IF B is a read-only file, Status Bar will show "Access Denied" and
1192 // Save File commands ends.
1193 // IF B can be read and write, save file buffer to B.
1195 // 7. Update File Name field in Title Bar to B and remove the modified
1196 // flag in Title Bar.
1198 Str
= CatSPrint (NULL
, L
"File to Save: [%s]", MainEditor
.FileBuffer
->FileName
);
1200 return EFI_OUT_OF_RESOURCES
;
1203 if (StrLen (Str
) >= 50) {
1205 // replace the long file name with "..."
1211 Str
[50] = CHAR_NULL
;
1214 Status
= InputBarSetPrompt (Str
);
1217 if (EFI_ERROR (Status
)) {
1221 Status
= InputBarSetStringSize (100);
1222 if (EFI_ERROR (Status
)) {
1227 // get new file name
1229 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
1230 StatusBarSetRefresh ();
1233 // if user pressed ESC
1235 if (Status
== EFI_NOT_READY
) {
1240 // if just enter pressed, so think save to current file name
1242 if (StrLen (InputBarGetString ()) == 0) {
1243 FileName
= CatSPrint (NULL
, L
"%s", MainEditor
.FileBuffer
->FileName
);
1245 FileName
= CatSPrint (NULL
, L
"%s", InputBarGetString ());
1248 if (FileName
== NULL
) {
1249 return EFI_OUT_OF_RESOURCES
;
1252 if (!IsValidFileName (FileName
)) {
1253 StatusBarSetStatusString (L
"Invalid File Name");
1254 FreePool (FileName
);
1261 // save to the old file
1263 if (StringNoCaseCompare (&FileName
, &MainEditor
.FileBuffer
->FileName
) == 0) {
1269 // if the file is read only, so can not write back to it.
1271 if (MainEditor
.FileBuffer
->ReadOnly
== TRUE
) {
1272 StatusBarSetStatusString (L
"Access Denied");
1273 FreePool (FileName
);
1278 // if the file exists
1280 if (ShellFileExists (FileName
) != EFI_NOT_FOUND
) {
1282 // check for read only
1284 Status
= ShellOpenFileByName (FileName
, &FileHandle
, EFI_FILE_MODE_READ
, 0);
1285 if (EFI_ERROR (Status
)) {
1286 StatusBarSetStatusString (L
"Open Failed");
1287 FreePool (FileName
);
1291 Info
= ShellGetFileInfo (FileHandle
);
1293 StatusBarSetStatusString (L
"Access Denied");
1294 FreePool (FileName
);
1295 return (EFI_SUCCESS
);
1298 if (Info
->Attribute
& EFI_FILE_READ_ONLY
) {
1299 StatusBarSetStatusString (L
"Access Denied - Read Only");
1301 FreePool (FileName
);
1302 return (EFI_SUCCESS
);
1308 // ask user whether to overwrite this file
1310 Status
= InputBarSetPrompt (L
"File exists. Overwrite (Yes/No/Cancel) ? ");
1311 if (EFI_ERROR (Status
)) {
1312 SHELL_FREE_NON_NULL (FileName
);
1316 Status
= InputBarSetStringSize (1);
1317 if (EFI_ERROR (Status
)) {
1318 SHELL_FREE_NON_NULL (FileName
);
1323 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
1324 StatusBarSetRefresh ();
1329 if (Status
== EFI_NOT_READY
) {
1330 SHELL_FREE_NON_NULL (FileName
);
1334 switch (InputBarGetString ()[0]) {
1343 SHELL_FREE_NON_NULL (FileName
);
1347 } // file does exist
1348 } // if old file name same
1351 // save file to disk with specified name
1353 FileBufferSetModified ();
1354 Status
= FileBufferSave (FileName
);
1355 SHELL_FREE_NON_NULL (FileName
);
1361 Show help information for the editor.
1363 @retval EFI_SUCCESS The operation was successful.
1366 MainCommandDisplayHelp (
1372 EFI_KEY_DATA KeyData
;
1379 for (CurrentLine
= 0; 0 != MainMenuHelpInfo
[CurrentLine
]; CurrentLine
++) {
1380 InfoString
= HiiGetString (gShellDebug1HiiHandle
, MainMenuHelpInfo
[CurrentLine
], NULL
);
1381 ShellPrintEx (0, CurrentLine
+1, L
"%E%s%N", InfoString
);
1388 Status
= gBS
->WaitForEvent (1, &MainEditor
.TextInputEx
->WaitForKeyEx
, &EventIndex
);
1389 if (EFI_ERROR (Status
) || (EventIndex
!= 0)) {
1393 Status
= MainEditor
.TextInputEx
->ReadKeyStrokeEx (MainEditor
.TextInputEx
, &KeyData
);
1394 if (EFI_ERROR (Status
)) {
1398 if (((KeyData
.KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) == 0) ||
1399 (KeyData
.KeyState
.KeyShiftState
== EFI_SHIFT_STATE_VALID
))
1402 // For consoles that don't support/report shift state,
1403 // CTRL+W is translated to L'W' - L'A' + 1.
1405 if (KeyData
.Key
.UnicodeChar
== L
'W' - L
'A' + 1) {
1408 } else if (((KeyData
.KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) != 0) &&
1409 ((KeyData
.KeyState
.KeyShiftState
& (EFI_LEFT_CONTROL_PRESSED
| EFI_RIGHT_CONTROL_PRESSED
)) != 0) &&
1410 ((KeyData
.KeyState
.KeyShiftState
& ~(EFI_SHIFT_STATE_VALID
| EFI_LEFT_CONTROL_PRESSED
| EFI_RIGHT_CONTROL_PRESSED
)) == 0))
1413 // For consoles that supports/reports shift state,
1414 // make sure that only CONTROL shift key is pressed.
1416 if ((KeyData
.Key
.UnicodeChar
== 'w') || (KeyData
.Key
.UnicodeChar
== 'W')) {
1423 // update screen with file buffer's info
1425 FileBufferRestorePosition ();
1426 FileBufferNeedRefresh
= TRUE
;
1427 FileBufferOnlyLineNeedRefresh
= FALSE
;
1428 FileBufferRefresh ();
1433 EFI_EDITOR_COLOR_ATTRIBUTES OriginalColors
;
1437 // basic initialization for MainEditor
1439 EFI_EDITOR_GLOBAL_EDITOR MainEditorConst
= {
1455 The initialization function for MainEditor.
1457 @retval EFI_SUCCESS The operation was successful.
1458 @retval EFI_LOAD_ERROR A load error occurred.
1466 EFI_HANDLE
*HandleBuffer
;
1471 // basic initialization
1473 CopyMem (&MainEditor
, &MainEditorConst
, sizeof (MainEditor
));
1476 // set screen attributes
1478 MainEditor
.ColorAttributes
.Colors
.Foreground
= gST
->ConOut
->Mode
->Attribute
& 0x000000ff;
1480 MainEditor
.ColorAttributes
.Colors
.Background
= (UINT8
)(gST
->ConOut
->Mode
->Attribute
>> 4);
1481 OriginalColors
= MainEditor
.ColorAttributes
.Colors
;
1483 OriginalMode
= gST
->ConOut
->Mode
->Mode
;
1486 // query screen size
1488 gST
->ConOut
->QueryMode (
1490 gST
->ConOut
->Mode
->Mode
,
1491 &(MainEditor
.ScreenSize
.Column
),
1492 &(MainEditor
.ScreenSize
.Row
)
1496 // Find TextInEx in System Table ConsoleInHandle
1497 // Per UEFI Spec, TextInEx is required for a console capable platform.
1499 Status
= gBS
->HandleProtocol (
1500 gST
->ConsoleInHandle
,
1501 &gEfiSimpleTextInputExProtocolGuid
,
1502 (VOID
**)&MainEditor
.TextInputEx
1504 if (EFI_ERROR (Status
)) {
1509 // Find mouse in System Table ConsoleInHandle
1511 Status
= gBS
->HandleProtocol (
1512 gST
->ConsoleInHandle
,
1513 &gEfiSimplePointerProtocolGuid
,
1514 (VOID
**)&MainEditor
.MouseInterface
1516 if (EFI_ERROR (Status
)) {
1518 // If there is no Simple Pointer Protocol on System Table
1520 HandleBuffer
= NULL
;
1521 MainEditor
.MouseInterface
= NULL
;
1522 Status
= gBS
->LocateHandleBuffer (
1524 &gEfiSimplePointerProtocolGuid
,
1529 if (!EFI_ERROR (Status
) && (HandleCount
> 0)) {
1531 // Try to find the first available mouse device
1533 for (Index
= 0; Index
< HandleCount
; Index
++) {
1534 Status
= gBS
->HandleProtocol (
1535 HandleBuffer
[Index
],
1536 &gEfiSimplePointerProtocolGuid
,
1537 (VOID
**)&MainEditor
.MouseInterface
1539 if (!EFI_ERROR (Status
)) {
1545 if (HandleBuffer
!= NULL
) {
1546 FreePool (HandleBuffer
);
1550 if (!EFI_ERROR (Status
) && (MainEditor
.MouseInterface
!= NULL
)) {
1551 MainEditor
.MouseAccumulatorX
= 0;
1552 MainEditor
.MouseAccumulatorY
= 0;
1553 MainEditor
.MouseSupported
= TRUE
;
1557 // below will call the five components' init function
1559 Status
= MainTitleBarInit (L
"UEFI EDIT");
1560 if (EFI_ERROR (Status
)) {
1561 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_EDIT_LIBEDITOR_TITLEBAR
), gShellDebug1HiiHandle
);
1562 return EFI_LOAD_ERROR
;
1565 Status
= ControlHotKeyInit (MainControlBasedMenuFunctions
);
1566 Status
= MenuBarInit (MainMenuItems
);
1567 if (EFI_ERROR (Status
)) {
1568 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_EDIT_LIBEDITOR_MAINMENU
), gShellDebug1HiiHandle
);
1569 return EFI_LOAD_ERROR
;
1572 Status
= StatusBarInit ();
1573 if (EFI_ERROR (Status
)) {
1574 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_EDIT_LIBEDITOR_STATUSBAR
), gShellDebug1HiiHandle
);
1575 return EFI_LOAD_ERROR
;
1578 InputBarInit (MainEditor
.TextInputEx
);
1580 Status
= FileBufferInit ();
1581 if (EFI_ERROR (Status
)) {
1582 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_EDIT_LIBEDITOR_FILEBUFFER
), gShellDebug1HiiHandle
);
1583 return EFI_LOAD_ERROR
;
1587 // clear whole screen and enable cursor
1589 gST
->ConOut
->ClearScreen (gST
->ConOut
);
1590 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
1593 // initialize EditorFirst and EditorExit
1597 EditorMouseAction
= FALSE
;
1603 The cleanup function for MainEditor.
1605 @retval EFI_SUCCESS The operation was successful.
1606 @retval EFI_LOAD_ERROR A load error occurred.
1616 // call the five components' cleanup function
1617 // if error, do not exit
1618 // just print some warning
1620 MainTitleBarCleanup ();
1621 StatusBarCleanup ();
1625 Status
= FileBufferCleanup ();
1626 if (EFI_ERROR (Status
)) {
1627 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_EDIT_LIBEDITOR_FILEBUFFER_CLEANUP
), gShellDebug1HiiHandle
);
1633 if (OriginalMode
!= gST
->ConOut
->Mode
->Mode
) {
1634 gST
->ConOut
->SetMode (gST
->ConOut
, OriginalMode
);
1638 // restore old screen color
1640 gST
->ConOut
->SetAttribute (
1642 EFI_TEXT_ATTR (OriginalColors
.Foreground
, OriginalColors
.Background
)
1645 gST
->ConOut
->ClearScreen (gST
->ConOut
);
1651 Refresh the main editor component.
1659 // The Stall value is from experience. NOT from spec. avoids 'flicker'
1664 // call the components refresh function
1667 || (StrCmp (FileBufferBackupVar
.FileName
, FileBuffer
.FileName
) != 0)
1668 || (FileBufferBackupVar
.FileType
!= FileBuffer
.FileType
)
1669 || (FileBufferBackupVar
.FileModified
!= FileBuffer
.FileModified
)
1670 || (FileBufferBackupVar
.ReadOnly
!= FileBuffer
.ReadOnly
))
1672 MainTitleBarRefresh (MainEditor
.FileBuffer
->FileName
, MainEditor
.FileBuffer
->FileType
, MainEditor
.FileBuffer
->ReadOnly
, MainEditor
.FileBuffer
->FileModified
, MainEditor
.ScreenSize
.Column
, MainEditor
.ScreenSize
.Row
, 0, 0);
1673 FileBufferRestorePosition ();
1677 || (FileBufferBackupVar
.FilePosition
.Row
!= FileBuffer
.FilePosition
.Row
)
1678 || (FileBufferBackupVar
.FilePosition
.Column
!= FileBuffer
.FilePosition
.Column
)
1679 || (FileBufferBackupVar
.ModeInsert
!= FileBuffer
.ModeInsert
)
1680 || StatusBarGetRefresh ())
1682 StatusBarRefresh (EditorFirst
, MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
, MainEditor
.FileBuffer
->FilePosition
.Row
, MainEditor
.FileBuffer
->FilePosition
.Column
, MainEditor
.FileBuffer
->ModeInsert
);
1683 FileBufferRestorePosition ();
1687 FileBufferRestorePosition ();
1690 FileBufferRefresh ();
1693 // EditorFirst is now set to FALSE
1695 EditorFirst
= FALSE
;
1699 Get's the resultant location of the cursor based on the relative movement of the Mouse.
1701 @param[in] GuidX The relative mouse movement.
1703 @return The X location of the mouse.
1712 MainEditor
.MouseAccumulatorX
+= GuidX
;
1713 Gap
= (MainEditor
.MouseAccumulatorX
* (INT32
)MainEditor
.ScreenSize
.Column
) / (INT32
)(50 * (INT32
)MainEditor
.MouseInterface
->Mode
->ResolutionX
);
1714 MainEditor
.MouseAccumulatorX
= (MainEditor
.MouseAccumulatorX
* (INT32
)MainEditor
.ScreenSize
.Column
) % (INT32
)(50 * (INT32
)MainEditor
.MouseInterface
->Mode
->ResolutionX
);
1715 MainEditor
.MouseAccumulatorX
= MainEditor
.MouseAccumulatorX
/ (INT32
)MainEditor
.ScreenSize
.Column
;
1720 Get's the resultant location of the cursor based on the relative movement of the Mouse.
1722 @param[in] GuidY The relative mouse movement.
1724 @return The Y location of the mouse.
1733 MainEditor
.MouseAccumulatorY
+= GuidY
;
1734 Gap
= (MainEditor
.MouseAccumulatorY
* (INT32
)MainEditor
.ScreenSize
.Row
) / (INT32
)(50 * (INT32
)MainEditor
.MouseInterface
->Mode
->ResolutionY
);
1735 MainEditor
.MouseAccumulatorY
= (MainEditor
.MouseAccumulatorY
* (INT32
)MainEditor
.ScreenSize
.Row
) % (INT32
)(50 * (INT32
)MainEditor
.MouseInterface
->Mode
->ResolutionY
);
1736 MainEditor
.MouseAccumulatorY
= MainEditor
.MouseAccumulatorY
/ (INT32
)MainEditor
.ScreenSize
.Row
;
1742 Support mouse movement. Move the cursor.
1744 @param[in] MouseState The current mouse state.
1746 @retval EFI_SUCCESS The operation was successful.
1747 @retval EFI_NOT_FOUND There was no mouse support found.
1750 MainEditorHandleMouseInput (
1751 IN EFI_SIMPLE_POINTER_STATE MouseState
1760 EFI_EDITOR_LINE
*Line
;
1766 // mouse action means:
1768 // mouse left button
1773 // have mouse movement
1775 if (MouseState
.RelativeMovementX
|| MouseState
.RelativeMovementY
) {
1779 TextX
= GetTextX (MouseState
.RelativeMovementX
);
1780 TextY
= GetTextY (MouseState
.RelativeMovementY
);
1782 FileBufferAdjustMousePosition (TextX
, TextY
);
1788 // if left button pushed down
1790 if (MouseState
.LeftButton
) {
1791 FCol
= MainEditor
.FileBuffer
->MousePosition
.Column
- 1 + 1;
1793 FRow
= MainEditor
.FileBuffer
->FilePosition
.Row
+
1794 MainEditor
.FileBuffer
->MousePosition
.Row
-
1795 MainEditor
.FileBuffer
->DisplayPosition
.Row
;
1798 // beyond the file line length
1800 if (MainEditor
.FileBuffer
->NumLines
< FRow
) {
1801 FRow
= MainEditor
.FileBuffer
->NumLines
;
1804 Link
= MainEditor
.FileBuffer
->ListHead
->ForwardLink
;
1805 for (Index
= 0; Index
< FRow
- 1; Index
++) {
1806 Link
= Link
->ForwardLink
;
1809 Line
= CR (Link
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
1812 // beyond the line's column length
1814 if (FCol
> Line
->Size
+ 1) {
1815 FCol
= Line
->Size
+ 1;
1818 FileBufferMovePosition (FRow
, FCol
);
1820 MainEditor
.FileBuffer
->MousePosition
.Row
= MainEditor
.FileBuffer
->DisplayPosition
.Row
;
1822 MainEditor
.FileBuffer
->MousePosition
.Column
= MainEditor
.FileBuffer
->DisplayPosition
.Column
;
1837 return EFI_NOT_FOUND
;
1841 Handle user key input. This routes to other functions for the actions.
1843 @retval EFI_SUCCESS The operation was successful.
1844 @retval EFI_LOAD_ERROR A load error occurred.
1845 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1848 MainEditorKeyInput (
1852 EFI_KEY_DATA KeyData
;
1854 EFI_SIMPLE_POINTER_STATE MouseState
;
1855 BOOLEAN NoShiftState
;
1858 Status
= EFI_SUCCESS
;
1859 EditorMouseAction
= FALSE
;
1862 // backup some key elements, so that can aVOID some refresh work
1864 MainEditorBackup ();
1867 // change priority of checking mouse/keyboard activity dynamically
1868 // so prevent starvation of keyboard.
1869 // if last time, mouse moves then this time check keyboard
1871 if (MainEditor
.MouseSupported
) {
1872 Status
= MainEditor
.MouseInterface
->GetState (
1873 MainEditor
.MouseInterface
,
1876 if (!EFI_ERROR (Status
)) {
1877 Status
= MainEditorHandleMouseInput (MouseState
);
1879 if (!EFI_ERROR (Status
)) {
1880 EditorMouseAction
= TRUE
;
1881 FileBufferMouseNeedRefresh
= TRUE
;
1882 } else if (Status
== EFI_LOAD_ERROR
) {
1883 StatusBarSetStatusString (L
"Invalid Mouse Movement ");
1889 // CheckEvent() returns Success when non-partial key is pressed.
1891 Status
= gBS
->CheckEvent (MainEditor
.TextInputEx
->WaitForKeyEx
);
1892 if (!EFI_ERROR (Status
)) {
1893 Status
= MainEditor
.TextInputEx
->ReadKeyStrokeEx (MainEditor
.TextInputEx
, &KeyData
);
1894 if (!EFI_ERROR (Status
)) {
1896 // dispatch to different components' key handling function
1897 // so not everywhere has to set this variable
1899 FileBufferMouseNeedRefresh
= TRUE
;
1901 // clear previous status string
1903 StatusBarSetRefresh ();
1905 // NoShiftState: TRUE when no shift key is pressed.
1907 NoShiftState
= ((KeyData
.KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) == 0) || (KeyData
.KeyState
.KeyShiftState
== EFI_SHIFT_STATE_VALID
);
1909 // dispatch to different components' key handling function
1911 if (EFI_NOT_FOUND
!= MenuBarDispatchControlHotKey (&KeyData
)) {
1912 Status
= EFI_SUCCESS
;
1913 } else if (NoShiftState
&& ((KeyData
.Key
.ScanCode
== SCAN_NULL
) || ((KeyData
.Key
.ScanCode
>= SCAN_UP
) && (KeyData
.Key
.ScanCode
<= SCAN_PAGE_DOWN
)))) {
1914 Status
= FileBufferHandleInput (&KeyData
.Key
);
1915 } else if (NoShiftState
&& (KeyData
.Key
.ScanCode
>= SCAN_F1
) && (KeyData
.Key
.ScanCode
<= SCAN_F12
)) {
1916 Status
= MenuBarDispatchFunctionKey (&KeyData
.Key
);
1918 StatusBarSetStatusString (L
"Unknown Command");
1919 FileBufferMouseNeedRefresh
= FALSE
;
1922 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_OUT_OF_RESOURCES
)) {
1924 // not already has some error status
1926 if ((StatusBarGetString () != NULL
) && (StrCmp (L
"", StatusBarGetString ()) == 0)) {
1927 StatusBarSetStatusString (L
"Disk Error. Try Again");
1934 // after handling, refresh editor
1936 MainEditorRefresh ();
1937 } while (Status
!= EFI_OUT_OF_RESOURCES
&& !EditorExit
);
1945 @param[in] Line A pointer to the line to be set to clipboard
1947 @retval EFI_SUCCESS The operation was successful.
1948 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1951 MainEditorSetCutLine (
1952 EFI_EDITOR_LINE
*Line
1959 if (MainEditor
.CutLine
!= NULL
) {
1961 // free the old clipboard
1963 LineFree (MainEditor
.CutLine
);
1967 // duplicate the line to clipboard
1969 MainEditor
.CutLine
= LineDup (Line
);
1970 if (MainEditor
.CutLine
== NULL
) {
1971 return EFI_OUT_OF_RESOURCES
;
1978 Backup function for MainEditor
1980 @retval EFI_SUCCESS The operation was successful.
1987 FileBufferBackup ();