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
;
40 Load a file from disk to editor
42 @retval EFI_SUCCESS The operation was successful.
43 @retval EFI_LOAD_ERROR A load error occurred.
44 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
52 Switch a file from ASCII to UNICODE or vise-versa.
54 @retval EFI_SUCCESS The switch was ok or a warning was presented.
57 MainCommandSwitchFileType (
62 move cursor to specified lines
64 @retval EFI_SUCCESS The operation was successful.
72 Save current file to disk, you can save to current file name or
73 save to another file name.
75 @retval EFI_SUCCESS The file was saved correctly.
76 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
77 @retval EFI_LOAD_ERROR A file access error occurred.
85 Show help information for the editor.
87 @retval EFI_SUCCESS The operation was successful.
90 MainCommandDisplayHelp (
97 @retval EFI_SUCCESS The operation was successful.
98 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
99 @retval EFI_LOAD_ERROR A load error occurred.
107 search string in file buffer
109 @retval EFI_SUCCESS The operation was successful.
110 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
111 @retval EFI_LOAD_ERROR A load error occurred.
119 search string in file buffer, and replace it with another str
121 @retval EFI_SUCCESS The operation was successful.
122 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
123 @retval EFI_LOAD_ERROR A load error occurred.
126 MainCommandSearchReplace (
131 cut current line to clipboard
133 @retval EFI_SUCCESS The operation was successful.
134 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
135 @retval EFI_LOAD_ERROR A load error occurred.
143 paste line to file buffer.
145 @retval EFI_SUCCESS The operation was successful.
146 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
147 @retval EFI_LOAD_ERROR A load error occurred.
150 MainCommandPasteLine (
155 Help info that will be displayed.
157 EFI_STRING_ID MainMenuHelpInfo
[] = {
158 STRING_TOKEN(STR_EDIT_HELP_TITLE
),
159 STRING_TOKEN(STR_EDIT_HELP_BLANK
),
160 STRING_TOKEN(STR_EDIT_HELP_LIST_TITLE
),
161 STRING_TOKEN(STR_EDIT_HELP_DIV
),
162 STRING_TOKEN(STR_EDIT_HELP_GO_TO_LINE
),
163 STRING_TOKEN(STR_EDIT_HELP_SAVE_FILE
),
164 STRING_TOKEN(STR_EDIT_HELP_EXIT
),
165 STRING_TOKEN(STR_EDIT_HELP_SEARCH
),
166 STRING_TOKEN(STR_EDIT_HELP_SEARCH_REPLACE
),
167 STRING_TOKEN(STR_EDIT_HELP_CUT_LINE
),
168 STRING_TOKEN(STR_EDIT_HELP_PASTE_LINE
),
169 STRING_TOKEN(STR_EDIT_HELP_OPEN_FILE
),
170 STRING_TOKEN(STR_EDIT_HELP_FILE_TYPE
),
171 STRING_TOKEN(STR_EDIT_HELP_BLANK
),
172 STRING_TOKEN(STR_EDIT_HELP_EXIT_HELP
),
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_BLANK
),
180 STRING_TOKEN(STR_EDIT_HELP_DIV
),
184 MENU_ITEM_FUNCTION MainControlBasedMenuFunctions
[] = {
190 MainCommandDisplayHelp
, /* Ctrl - E */
191 MainCommandSearch
, /* Ctrl - F */
192 MainCommandGotoLine
, /* Ctrl - G */
196 MainCommandCutLine
, /* Ctrl - K */
200 MainCommandOpenFile
, /* Ctrl - O */
202 MainCommandExit
, /* Ctrl - Q */
203 MainCommandSearchReplace
, /* Ctrl - R */
204 MainCommandSaveFile
, /* Ctrl - S */
205 MainCommandSwitchFileType
, /* Ctrl - T */
206 MainCommandPasteLine
, /* Ctrl - U */
214 EDITOR_MENU_ITEM MainMenuItems
[] = {
216 STRING_TOKEN(STR_EDIT_LIBMENUBAR_GO_TO_LINE
),
217 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F1
),
221 STRING_TOKEN(STR_EDIT_LIBMENUBAR_SAVE_FILE
),
222 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F2
),
226 STRING_TOKEN(STR_EDIT_LIBMENUBAR_EXIT
),
227 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F3
),
232 STRING_TOKEN(STR_EDIT_LIBMENUBAR_SEARCH
),
233 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F4
),
237 STRING_TOKEN(STR_EDIT_LIBMENUBAR_SEARCH_REPLACE
),
238 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F5
),
239 MainCommandSearchReplace
242 STRING_TOKEN(STR_EDIT_LIBMENUBAR_CUT_LINE
),
243 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F6
),
247 STRING_TOKEN(STR_EDIT_LIBMENUBAR_PASTE_LINE
),
248 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F7
),
253 STRING_TOKEN(STR_EDIT_LIBMENUBAR_OPEN_FILE
),
254 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F8
),
258 STRING_TOKEN(STR_EDIT_LIBMENUBAR_FILE_TYPE
),
259 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F9
),
260 MainCommandSwitchFileType
263 STRING_TOKEN(STR_EDIT_LIBMENUBAR_FILE_TYPE
),
264 STRING_TOKEN(STR_EDIT_LIBMENUBAR_F11
),
265 MainCommandSwitchFileType
277 Load a file from disk to editor
279 @retval EFI_SUCCESS The operation was successful.
280 @retval EFI_LOAD_ERROR A load error occurred.
281 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
284 MainCommandOpenFile (
292 // This command will open a file from current working directory.
293 // Read-only file can also be opened. But it can not be modified.
294 // Below is the scenario of Open File command:
295 // 1.IF currently opened file has not been modIFied, directly go to step .
296 // IF currently opened file has been modified,
297 // an Input Bar will be prompted as :
298 // "File Modified. Save ( Yes/No/Cancel) ?"
299 // IF user press 'y' or 'Y', currently opened file will be saved.
300 // IF user press 'n' or 'N', currently opened file will
302 // IF user press 'c' or 'C' or ESC, Open File command ends and
303 // currently opened file is still opened.
305 // 2. An Input Bar will be prompted as : "File Name to Open: "
306 // IF user press ESC, Open File command ends and
307 // currently opened file is still opened.
308 // Any other inputs with a Return will
309 // cause currently opened file close.
311 // 3. IF user input file name is an existing file , this file will be read
313 // IF user input file name is a new file, this file will be created
314 // and opened. This file's type ( UNICODE or ASCII ) is the same
315 // with the old file.
316 // if current file is modified, so you need to choose
317 // whether to save it first.
319 if (MainEditor
.FileBuffer
->FileModified
) {
321 Status
= InputBarSetPrompt (L
"File modified. Save (Yes/No/Cancel) ? ");
322 if (EFI_ERROR (Status
)) {
326 // the answer is just one character
328 Status
= InputBarSetStringSize (1);
329 if (EFI_ERROR (Status
)) {
333 // loop for user's answer
334 // valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C'
338 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
339 StatusBarSetRefresh();
344 if (Status
== EFI_NOT_READY
) {
348 switch (InputBarGetString()[0]) {
352 // want to save this file first
354 Status
= FileBufferSave (MainEditor
.FileBuffer
->FileName
);
355 if (EFI_ERROR (Status
)) {
359 MainTitleBarRefresh (MainEditor
.FileBuffer
->FileName
, MainEditor
.FileBuffer
->FileType
, MainEditor
.FileBuffer
->ReadOnly
, MainEditor
.FileBuffer
->FileModified
, MainEditor
.ScreenSize
.Column
, MainEditor
.ScreenSize
.Row
, 0, 0);
360 FileBufferRestorePosition ();
367 // 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
) {
404 // The input string length should > 0
406 if (StrLen (InputBarGetString()) > 0) {
408 // CHECK if filename is valid
410 if (!IsValidFileName (InputBarGetString())) {
411 FileBufferRead (MainEditor
.FileBuffer
->FileName
, TRUE
);
412 StatusBarSetStatusString (L
"Invalid File Name");
422 Status
= FileBufferRead (InputBarGetString(), FALSE
);
424 if (EFI_ERROR (Status
)) {
425 FileBufferRead (MainEditor
.FileBuffer
->FileName
, TRUE
);
426 return EFI_LOAD_ERROR
;
433 Switch a file from ASCII to UNICODE or vise-versa.
435 @retval EFI_SUCCESS The switch was ok or a warning was presented.
438 MainCommandSwitchFileType (
443 // Below is the scenario of File Type command:
444 // After File Type is executed, file type will be changed to another type
445 // if file is read-only, can not be modified
447 if (MainEditor
.FileBuffer
->ReadOnly
) {
448 StatusBarSetStatusString (L
"Read Only File Can Not Be Modified");
452 if (MainEditor
.FileBuffer
->FileType
== FileTypeUnicode
) {
453 MainEditor
.FileBuffer
->FileType
= FileTypeAscii
;
455 MainEditor
.FileBuffer
->FileType
= FileTypeUnicode
;
458 MainEditor
.FileBuffer
->FileModified
= TRUE
;
464 cut current line to clipboard
466 @retval EFI_SUCCESS The operation was successful.
467 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
468 @retval EFI_LOAD_ERROR A load error occurred.
476 EFI_EDITOR_LINE
*Line
;
479 // This command will cut current line ( where cursor is on ) to clip board.
480 // And cursor will move to the beginning of next line.
481 // Below is the scenario of Cut Line command:
482 // 1. IF cursor is on valid line, current line will be cut to clip board.
483 // IF cursor is not on valid line, an Status String will be prompted :
487 Status
= FileBufferCutLine (&Line
);
488 if (Status
== EFI_NOT_FOUND
) {
492 if (EFI_ERROR (Status
)) {
496 MainEditor
.CutLine
= Line
;
502 paste line to file buffer.
504 @retval EFI_SUCCESS The operation was successful.
505 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
506 @retval EFI_LOAD_ERROR A load error occurred.
509 MainCommandPasteLine (
516 // Below is the scenario of Paste Line command:
517 // 1. IF nothing is on clipboard, a Status String will be prompted :
518 // "No Line to Paste" and Paste Line command ends.
519 // IF something is on clipboard, insert it above current line.
520 // nothing on clipboard
522 if (MainEditor
.CutLine
== NULL
) {
523 StatusBarSetStatusString (L
"No Line to Paste");
527 Status
= FileBufferPasteLine ();
534 search string in file buffer
536 @retval EFI_SUCCESS The operation was successful.
537 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
538 @retval EFI_LOAD_ERROR A load error occurred.
551 // Below is the scenario of Search command:
552 // 1. An Input Bar will be prompted : "Enter Search String:".
553 // IF user press ESC, Search command ends.
554 // IF user just press Enter, Search command ends.
555 // IF user inputs the search string, do Step 2.
557 // 2. IF input search string is found, cursor will move to the first
558 // occurrence and do Step 3.
559 // IF input search string is not found, a Status String
560 // "Search String Not Found" will be prompted and Search command ends.
562 // 3. An Input Bar will be prompted: "Find Next (Yes/No/Cancel ) ?".
563 // IF user press ESC, Search command ends.
564 // IF user press 'y' or 'Y', do Step 2.
565 // IF user press 'n' or 'N', Search command ends.
566 // IF user press 'c' or 'C', Search command ends.
568 Status
= InputBarSetPrompt (L
"Enter Search String: ");
569 if (EFI_ERROR (Status
)) {
573 Status
= InputBarSetStringSize (40);
574 if (EFI_ERROR (Status
)) {
578 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
579 StatusBarSetRefresh();
584 if (Status
== EFI_NOT_READY
) {
588 // just enter pressed
590 if (StrLen (InputBarGetString()) == 0) {
594 Buffer
= CatSPrint (NULL
, L
"%s", InputBarGetString());
595 if (Buffer
== NULL
) {
596 return EFI_OUT_OF_RESOURCES
;
599 // the first time , search from current position
604 // since search may be continued to search multiple times
605 // so we need to backup editor each time
609 Status
= FileBufferSearch (Buffer
, Offset
);
611 if (Status
== EFI_NOT_FOUND
) {
617 Status
= InputBarSetPrompt (L
"Find Next (Yes/No) ?");
618 if (EFI_ERROR (Status
)) {
623 Status
= InputBarSetStringSize (1);
624 if (EFI_ERROR (Status
)) {
631 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
632 StatusBarSetRefresh();
637 if (Status
== EFI_NOT_READY
) {
642 switch (InputBarGetString()[0]) {
659 // end of while !Done
660 // for search second, third time, search from current position + strlen
662 Offset
= StrLen (Buffer
);
669 StatusBarSetStatusString (L
"Search String Not Found");
675 Search string in file buffer, and replace it with another str.
677 @retval EFI_SUCCESS The operation was successful.
678 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
679 @retval EFI_LOAD_ERROR A load error occurred.
682 MainCommandSearchReplace (
691 BOOLEAN ReplaceOption
;
696 ReplaceOption
= FALSE
;
699 // Below is the scenario of Search/Replace command:
700 // 1. An Input Bar is prompted : "Enter Search String:".
701 // IF user press ESC, Search/Replace command ends.
702 // IF user just press Enter, Search/Replace command ends.
703 // IF user inputs the search string S, do Step 2.
705 // 2. An Input Bar is prompted: "Replace With:".
706 // IF user press ESC, Search/Replace command ends.
707 // IF user inputs the replace string R, do Step 3.
709 // 3. IF input search string is not found, an Status String
710 // "Search String Not Found" will be prompted
711 // and Search/Replace command ends
712 // IF input search string is found, do Step 4.
714 // 4. An Input Bar will be prompted: "Replace ( Yes/No/All/Cancel )?"
715 // IF user press 'y' or 'Y', S will be replaced with R and do Step 5
716 // IF user press 'n' or 'N', S will not be replaced and do Step 5.
717 // IF user press 'a' or 'A', all the S from file current position on
718 // will be replaced with R and Search/Replace command ends.
719 // IF user press 'c' or 'C' or ESC, Search/Replace command ends.
721 // 5. An Input Bar will be prompted: "Find Next (Yes/No/Cancel) ?".
722 // IF user press ESC, Search/Replace command ends.
723 // IF user press 'y' or 'Y', do Step 3.
724 // IF user press 'n' or 'N', Search/Replace command ends.
725 // IF user press 'c' or 'C', Search/Replace command ends.
726 // input search string
728 Status
= InputBarSetPrompt (L
"Enter Search String: ");
729 if (EFI_ERROR (Status
)) {
733 Status
= InputBarSetStringSize (40);
734 if (EFI_ERROR (Status
)) {
738 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
739 StatusBarSetRefresh();
744 if (Status
== EFI_NOT_READY
) {
748 // if just pressed enter
750 if (StrLen (InputBarGetString()) == 0) {
754 Search
= CatSPrint (NULL
, L
"%s", InputBarGetString());
755 if (Search
== NULL
) {
756 return EFI_OUT_OF_RESOURCES
;
759 SearchLen
= StrLen (Search
);
762 // input replace string
764 Status
= InputBarSetPrompt (L
"Replace With: ");
765 if (EFI_ERROR (Status
)) {
769 Status
= InputBarSetStringSize (40);
770 if (EFI_ERROR (Status
)) {
774 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
775 StatusBarSetRefresh();
780 if (Status
== EFI_NOT_READY
) {
784 Replace
= CatSPrint (NULL
, L
"%s", InputBarGetString());
785 if (Replace
== NULL
) {
787 return EFI_OUT_OF_RESOURCES
;
790 ReplaceLen
= StrLen (Replace
);
796 // since search may be continued to search multiple times
797 // so we need to backup editor each time
802 Status
= FileBufferSearch (Search
, 0);
805 // if just replace, so skip this replace string
806 // if replace string is an empty string, so skip to next character
809 Status
= FileBufferSearch (Search
, (ReplaceLen
== 0) ? 1 : ReplaceLen
);
811 Status
= FileBufferSearch (Search
, SearchLen
);
815 if (Status
== EFI_NOT_FOUND
) {
821 Status
= InputBarSetPrompt (L
"Replace (Yes/No/All/Cancel) ?");
823 if (EFI_ERROR (Status
)) {
829 Status
= InputBarSetStringSize (1);
830 if (EFI_ERROR (Status
)) {
838 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
839 StatusBarSetRefresh();
844 if (Status
== EFI_NOT_READY
) {
850 switch (InputBarGetString()[0]) {
854 ReplaceOption
= TRUE
;
860 ReplaceOption
= FALSE
;
866 ReplaceOption
= TRUE
;
882 // end of while !Done
889 if (MainEditor
.FileBuffer
->ReadOnly
) {
890 StatusBarSetStatusString (L
"Read Only File Can Not Be Modified");
897 Status
= FileBufferReplaceAll (Search
, Replace
, 0);
905 Status
= FileBufferReplace (Replace
, SearchLen
);
906 if (EFI_ERROR (Status
)) {
915 Status
= InputBarSetPrompt (L
"Find Next (Yes/No) ?");
916 if (EFI_ERROR (Status
)) {
922 Status
= InputBarSetStringSize (1);
923 if (EFI_ERROR (Status
)) {
931 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
932 StatusBarSetRefresh();
937 if (Status
== EFI_NOT_READY
) {
943 switch (InputBarGetString()[0]) {
961 // end of while !Done
972 StatusBarSetStatusString (L
"Search String Not Found");
980 @retval EFI_SUCCESS The operation was successful.
981 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
982 @retval EFI_LOAD_ERROR A load error occurred.
992 // Below is the scenario of Exit command:
993 // 1. IF currently opened file is not modified, exit the editor and
994 // Exit command ends.
995 // IF currently opened file is modified, do Step 2
997 // 2. An Input Bar will be prompted:
998 // "File modified. Save ( Yes/No/Cancel )?"
999 // IF user press 'y' or 'Y', currently opened file will be saved
1001 // IF user press 'n' or 'N', currently opened file will not be saved
1002 // and Editor exits.
1003 // IF user press 'c' or 'C' or ESC, Exit command ends.
1004 // if file has been modified, so will prompt user whether to save the changes
1006 if (MainEditor
.FileBuffer
->FileModified
) {
1008 Status
= InputBarSetPrompt (L
"File modified. Save (Yes/No/Cancel) ? ");
1009 if (EFI_ERROR (Status
)) {
1013 Status
= InputBarSetStringSize (1);
1014 if (EFI_ERROR (Status
)) {
1019 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
1020 StatusBarSetRefresh();
1025 if (Status
== EFI_NOT_READY
) {
1029 switch (InputBarGetString()[0]) {
1033 // write file back to disk
1035 Status
= FileBufferSave (MainEditor
.FileBuffer
->FileName
);
1036 if (!EFI_ERROR (Status
)) {
1061 move cursor to specified lines
1063 @retval EFI_SUCCESS The operation was successful.
1066 MainCommandGotoLine (
1074 // Below is the scenario of Go To Line command:
1075 // 1. An Input Bar will be prompted : "Go To Line:".
1076 // IF user press ESC, Go To Line command ends.
1077 // IF user just press Enter, cursor remains unchanged.
1078 // IF user inputs line number, do Step 2.
1080 // 2. IF input line number is valid, move cursor to the beginning
1081 // of specified line and Go To Line command ends.
1082 // IF input line number is invalid, a Status String will be prompted:
1083 // "No Such Line" and Go To Line command ends.
1085 Status
= InputBarSetPrompt (L
"Go To Line: ");
1086 if (EFI_ERROR (Status
)) {
1090 // line number's digit <= 6
1092 Status
= InputBarSetStringSize (6);
1093 if (EFI_ERROR (Status
)) {
1097 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
1098 StatusBarSetRefresh();
1103 if (Status
== EFI_NOT_READY
) {
1107 // if JUST press enter
1109 if (StrLen (InputBarGetString()) == 0) {
1113 Row
= ShellStrToUintn (InputBarGetString());
1116 // invalid line number
1118 if (Row
> MainEditor
.FileBuffer
->NumLines
|| Row
<= 0) {
1119 StatusBarSetStatusString (L
"No Such Line");
1123 // move cursor to that line's start
1125 FileBufferMovePosition (Row
, 1);
1131 Save current file to disk, you can save to current file name or
1132 save to another file name.
1134 @retval EFI_SUCCESS The file was saved correctly.
1135 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1136 @retval EFI_LOAD_ERROR A file access error occurred.
1139 MainCommandSaveFile (
1147 SHELL_FILE_HANDLE FileHandle
;
1148 EFI_FILE_INFO
*Info
;
1151 // This command will save currently opened file to disk.
1152 // You can choose save to another file name or just save to
1153 // current file name.
1154 // Below is the scenario of Save File command:
1155 // ( Suppose the old file name is A )
1156 // 1. An Input Bar will be prompted: "File To Save: [ old file name]"
1157 // IF user press ESC, Save File command ends .
1158 // IF user press Enter, input file name will be A.
1159 // IF user inputs a new file name B, input file name will be B.
1161 // 2. IF input file name is A, go to do Step 3.
1162 // IF input file name is B, go to do Step 4.
1164 // 3. IF A is read only, Status Bar will show "Access Denied" and
1165 // Save File commands ends.
1166 // IF A is not read only, save file buffer to disk and remove modified
1167 // flag in Title Bar , then Save File command ends.
1169 // 4. IF B does not exist, create this file and save file buffer to it.
1171 // IF B exits, do Step 5.
1173 // 5.An Input Bar will be prompted:
1174 // "File Exists. Overwrite ( Yes/No/Cancel )?"
1175 // IF user press 'y' or 'Y', do Step 6.
1176 // IF user press 'n' or 'N', Save File commands ends.
1177 // IF user press 'c' or 'C' or ESC, Save File commands ends.
1179 // 6. IF B is a read-only file, Status Bar will show "Access Denied" and
1180 // Save File commands ends.
1181 // IF B can be read and write, save file buffer to B.
1183 // 7. Update File Name field in Title Bar to B and remove the modified
1184 // flag in Title Bar.
1186 Str
= CatSPrint (NULL
, L
"File to Save: [%s]", MainEditor
.FileBuffer
->FileName
);
1188 return EFI_OUT_OF_RESOURCES
;
1191 if (StrLen (Str
) >= 50) {
1193 // replace the long file name with "..."
1199 Str
[50] = CHAR_NULL
;
1202 Status
= InputBarSetPrompt (Str
);
1205 if (EFI_ERROR (Status
)) {
1210 Status
= InputBarSetStringSize (100);
1211 if (EFI_ERROR (Status
)) {
1215 // get new file name
1217 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
1218 StatusBarSetRefresh();
1221 // if user pressed ESC
1223 if (Status
== EFI_NOT_READY
) {
1228 // if just enter pressed, so think save to current file name
1230 if (StrLen (InputBarGetString()) == 0) {
1231 FileName
= CatSPrint (NULL
, L
"%s", MainEditor
.FileBuffer
->FileName
);
1233 FileName
= CatSPrint (NULL
, L
"%s", InputBarGetString());
1236 if (FileName
== NULL
) {
1237 return EFI_OUT_OF_RESOURCES
;
1240 if (!IsValidFileName (FileName
)) {
1241 StatusBarSetStatusString (L
"Invalid File Name");
1242 FreePool (FileName
);
1249 // save to the old file
1251 if (StringNoCaseCompare (&FileName
, &MainEditor
.FileBuffer
->FileName
) == 0) {
1257 // if the file is read only, so can not write back to it.
1259 if (MainEditor
.FileBuffer
->ReadOnly
== TRUE
) {
1260 StatusBarSetStatusString (L
"Access Denied");
1261 FreePool (FileName
);
1266 // if the file exists
1268 if (ShellFileExists(FileName
) != EFI_NOT_FOUND
) {
1270 // check for read only
1272 Status
= ShellOpenFileByName(FileName
, &FileHandle
, EFI_FILE_MODE_READ
, 0);
1273 if (EFI_ERROR(Status
)) {
1274 StatusBarSetStatusString (L
"Open Failed");
1275 FreePool (FileName
);
1279 Info
= ShellGetFileInfo(FileHandle
);
1281 StatusBarSetStatusString (L
"Access Denied");
1282 FreePool (FileName
);
1283 return (EFI_SUCCESS
);
1286 if (Info
->Attribute
& EFI_FILE_READ_ONLY
) {
1287 StatusBarSetStatusString (L
"Access Denied - Read Only");
1289 FreePool (FileName
);
1290 return (EFI_SUCCESS
);
1295 // ask user whether to overwrite this file
1297 Status
= InputBarSetPrompt (L
"File exists. Overwrite (Yes/No/Cancel) ? ");
1298 if (EFI_ERROR (Status
)) {
1299 SHELL_FREE_NON_NULL (FileName
);
1303 Status
= InputBarSetStringSize (1);
1304 if (EFI_ERROR (Status
)) {
1305 SHELL_FREE_NON_NULL (FileName
);
1310 Status
= InputBarRefresh (MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
);
1311 StatusBarSetRefresh();
1316 if (Status
== EFI_NOT_READY
) {
1317 SHELL_FREE_NON_NULL (FileName
);
1321 switch (InputBarGetString()[0]) {
1330 SHELL_FREE_NON_NULL (FileName
);
1334 } // file does exist
1335 } // if old file name same
1338 // save file to disk with specified name
1340 FileBufferSetModified();
1341 Status
= FileBufferSave (FileName
);
1342 SHELL_FREE_NON_NULL (FileName
);
1348 Show help information for the editor.
1350 @retval EFI_SUCCESS The operation was successful.
1353 MainCommandDisplayHelp (
1359 EFI_KEY_DATA KeyData
;
1366 for (CurrentLine
= 0; 0 != MainMenuHelpInfo
[CurrentLine
]; CurrentLine
++) {
1367 InfoString
= HiiGetString(gShellDebug1HiiHandle
, MainMenuHelpInfo
[CurrentLine
], NULL
);
1368 ShellPrintEx (0, CurrentLine
+1, L
"%E%s%N", InfoString
);
1375 Status
= gBS
->WaitForEvent (1, &MainEditor
.TextInputEx
->WaitForKeyEx
, &EventIndex
);
1376 if (EFI_ERROR (Status
) || (EventIndex
!= 0)) {
1379 Status
= MainEditor
.TextInputEx
->ReadKeyStrokeEx (MainEditor
.TextInputEx
, &KeyData
);
1380 if (EFI_ERROR (Status
)) {
1384 if (((KeyData
.KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) == 0) ||
1385 (KeyData
.KeyState
.KeyShiftState
== EFI_SHIFT_STATE_VALID
)) {
1387 // For consoles that don't support/report shift state,
1388 // CTRL+W is translated to L'W' - L'A' + 1.
1390 if (KeyData
.Key
.UnicodeChar
== L
'W' - L
'A' + 1) {
1393 } else if (((KeyData
.KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) != 0) &&
1394 ((KeyData
.KeyState
.KeyShiftState
& (EFI_LEFT_CONTROL_PRESSED
| EFI_RIGHT_CONTROL_PRESSED
)) != 0) &&
1395 ((KeyData
.KeyState
.KeyShiftState
& ~(EFI_SHIFT_STATE_VALID
| EFI_LEFT_CONTROL_PRESSED
| EFI_RIGHT_CONTROL_PRESSED
)) == 0)) {
1397 // For consoles that supports/reports shift state,
1398 // make sure that only CONTROL shift key is pressed.
1400 if ((KeyData
.Key
.UnicodeChar
== 'w') || (KeyData
.Key
.UnicodeChar
== 'W')) {
1406 // update screen with file buffer's info
1408 FileBufferRestorePosition ();
1409 FileBufferNeedRefresh
= TRUE
;
1410 FileBufferOnlyLineNeedRefresh
= FALSE
;
1411 FileBufferRefresh ();
1416 EFI_EDITOR_COLOR_ATTRIBUTES OriginalColors
;
1421 // basic initialization for MainEditor
1423 EFI_EDITOR_GLOBAL_EDITOR MainEditorConst
= {
1439 The initialization function for MainEditor.
1441 @retval EFI_SUCCESS The operation was successful.
1442 @retval EFI_LOAD_ERROR A load error occurred.
1450 EFI_HANDLE
*HandleBuffer
;
1455 // basic initialization
1457 CopyMem (&MainEditor
, &MainEditorConst
, sizeof (MainEditor
));
1460 // set screen attributes
1462 MainEditor
.ColorAttributes
.Colors
.Foreground
= gST
->ConOut
->Mode
->Attribute
& 0x000000ff;
1464 MainEditor
.ColorAttributes
.Colors
.Background
= (UINT8
) (gST
->ConOut
->Mode
->Attribute
>> 4);
1465 OriginalColors
= MainEditor
.ColorAttributes
.Colors
;
1467 OriginalMode
= gST
->ConOut
->Mode
->Mode
;
1470 // query screen size
1472 gST
->ConOut
->QueryMode (
1474 gST
->ConOut
->Mode
->Mode
,
1475 &(MainEditor
.ScreenSize
.Column
),
1476 &(MainEditor
.ScreenSize
.Row
)
1480 // Find TextInEx in System Table ConsoleInHandle
1481 // Per UEFI Spec, TextInEx is required for a console capable platform.
1483 Status
= gBS
->HandleProtocol (
1484 gST
->ConsoleInHandle
,
1485 &gEfiSimpleTextInputExProtocolGuid
,
1486 (VOID
**)&MainEditor
.TextInputEx
1488 if (EFI_ERROR (Status
)) {
1493 // Find mouse in System Table ConsoleInHandle
1495 Status
= gBS
->HandleProtocol (
1496 gST
->ConsoleInHandle
,
1497 &gEfiSimplePointerProtocolGuid
,
1498 (VOID
**)&MainEditor
.MouseInterface
1500 if (EFI_ERROR (Status
)) {
1502 // If there is no Simple Pointer Protocol on System Table
1504 HandleBuffer
= NULL
;
1505 MainEditor
.MouseInterface
= NULL
;
1506 Status
= gBS
->LocateHandleBuffer (
1508 &gEfiSimplePointerProtocolGuid
,
1513 if (!EFI_ERROR (Status
) && HandleCount
> 0) {
1515 // Try to find the first available mouse device
1517 for (Index
= 0; Index
< HandleCount
; Index
++) {
1518 Status
= gBS
->HandleProtocol (
1519 HandleBuffer
[Index
],
1520 &gEfiSimplePointerProtocolGuid
,
1521 (VOID
**)&MainEditor
.MouseInterface
1523 if (!EFI_ERROR (Status
)) {
1528 if (HandleBuffer
!= NULL
) {
1529 FreePool (HandleBuffer
);
1533 if (!EFI_ERROR (Status
) && MainEditor
.MouseInterface
!= NULL
) {
1534 MainEditor
.MouseAccumulatorX
= 0;
1535 MainEditor
.MouseAccumulatorY
= 0;
1536 MainEditor
.MouseSupported
= TRUE
;
1540 // below will call the five components' init function
1542 Status
= MainTitleBarInit (L
"UEFI EDIT");
1543 if (EFI_ERROR (Status
)) {
1544 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN(STR_EDIT_LIBEDITOR_TITLEBAR
), gShellDebug1HiiHandle
);
1545 return EFI_LOAD_ERROR
;
1548 Status
= ControlHotKeyInit (MainControlBasedMenuFunctions
);
1549 Status
= MenuBarInit (MainMenuItems
);
1550 if (EFI_ERROR (Status
)) {
1551 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN(STR_EDIT_LIBEDITOR_MAINMENU
), gShellDebug1HiiHandle
);
1552 return EFI_LOAD_ERROR
;
1555 Status
= StatusBarInit ();
1556 if (EFI_ERROR (Status
)) {
1557 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN(STR_EDIT_LIBEDITOR_STATUSBAR
), gShellDebug1HiiHandle
);
1558 return EFI_LOAD_ERROR
;
1561 InputBarInit (MainEditor
.TextInputEx
);
1563 Status
= FileBufferInit ();
1564 if (EFI_ERROR (Status
)) {
1565 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER
), gShellDebug1HiiHandle
);
1566 return EFI_LOAD_ERROR
;
1569 // clear whole screen and enable cursor
1571 gST
->ConOut
->ClearScreen (gST
->ConOut
);
1572 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
1575 // initialize EditorFirst and EditorExit
1579 EditorMouseAction
= FALSE
;
1585 The cleanup function for MainEditor.
1587 @retval EFI_SUCCESS The operation was successful.
1588 @retval EFI_LOAD_ERROR A load error occurred.
1598 // call the five components' cleanup function
1599 // if error, do not exit
1600 // just print some warning
1602 MainTitleBarCleanup();
1607 Status
= FileBufferCleanup ();
1608 if (EFI_ERROR (Status
)) {
1609 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN(STR_EDIT_LIBEDITOR_FILEBUFFER_CLEANUP
), gShellDebug1HiiHandle
);
1614 if (OriginalMode
!= gST
->ConOut
->Mode
->Mode
) {
1615 gST
->ConOut
->SetMode (gST
->ConOut
, OriginalMode
);
1618 // restore old screen color
1620 gST
->ConOut
->SetAttribute (
1622 EFI_TEXT_ATTR (OriginalColors
.Foreground
, OriginalColors
.Background
)
1625 gST
->ConOut
->ClearScreen (gST
->ConOut
);
1631 Refresh the main editor component.
1639 // The Stall value is from experience. NOT from spec. avoids 'flicker'
1644 // call the components refresh function
1647 || StrCmp (FileBufferBackupVar
.FileName
, FileBuffer
.FileName
) != 0
1648 || FileBufferBackupVar
.FileType
!= FileBuffer
.FileType
1649 || FileBufferBackupVar
.FileModified
!= FileBuffer
.FileModified
1650 || FileBufferBackupVar
.ReadOnly
!= FileBuffer
.ReadOnly
) {
1652 MainTitleBarRefresh (MainEditor
.FileBuffer
->FileName
, MainEditor
.FileBuffer
->FileType
, MainEditor
.FileBuffer
->ReadOnly
, MainEditor
.FileBuffer
->FileModified
, MainEditor
.ScreenSize
.Column
, MainEditor
.ScreenSize
.Row
, 0, 0);
1653 FileBufferRestorePosition ();
1657 || FileBufferBackupVar
.FilePosition
.Row
!= FileBuffer
.FilePosition
.Row
1658 || FileBufferBackupVar
.FilePosition
.Column
!= FileBuffer
.FilePosition
.Column
1659 || FileBufferBackupVar
.ModeInsert
!= FileBuffer
.ModeInsert
1660 || StatusBarGetRefresh()) {
1662 StatusBarRefresh (EditorFirst
, MainEditor
.ScreenSize
.Row
, MainEditor
.ScreenSize
.Column
, MainEditor
.FileBuffer
->FilePosition
.Row
, MainEditor
.FileBuffer
->FilePosition
.Column
, MainEditor
.FileBuffer
->ModeInsert
);
1663 FileBufferRestorePosition ();
1667 FileBufferRestorePosition ();
1670 FileBufferRefresh ();
1673 // EditorFirst is now set to FALSE
1675 EditorFirst
= FALSE
;
1679 Get's the resultant location of the cursor based on the relative movement of the Mouse.
1681 @param[in] GuidX The relative mouse movement.
1683 @return The X location of the mouse.
1692 MainEditor
.MouseAccumulatorX
+= GuidX
;
1693 Gap
= (MainEditor
.MouseAccumulatorX
* (INT32
) MainEditor
.ScreenSize
.Column
) / (INT32
) (50 * (INT32
) MainEditor
.MouseInterface
->Mode
->ResolutionX
);
1694 MainEditor
.MouseAccumulatorX
= (MainEditor
.MouseAccumulatorX
* (INT32
) MainEditor
.ScreenSize
.Column
) % (INT32
) (50 * (INT32
) MainEditor
.MouseInterface
->Mode
->ResolutionX
);
1695 MainEditor
.MouseAccumulatorX
= MainEditor
.MouseAccumulatorX
/ (INT32
) MainEditor
.ScreenSize
.Column
;
1700 Get's the resultant location of the cursor based on the relative movement of the Mouse.
1702 @param[in] GuidY The relative mouse movement.
1704 @return The Y location of the mouse.
1713 MainEditor
.MouseAccumulatorY
+= GuidY
;
1714 Gap
= (MainEditor
.MouseAccumulatorY
* (INT32
) MainEditor
.ScreenSize
.Row
) / (INT32
) (50 * (INT32
) MainEditor
.MouseInterface
->Mode
->ResolutionY
);
1715 MainEditor
.MouseAccumulatorY
= (MainEditor
.MouseAccumulatorY
* (INT32
) MainEditor
.ScreenSize
.Row
) % (INT32
) (50 * (INT32
) MainEditor
.MouseInterface
->Mode
->ResolutionY
);
1716 MainEditor
.MouseAccumulatorY
= MainEditor
.MouseAccumulatorY
/ (INT32
) MainEditor
.ScreenSize
.Row
;
1722 Support mouse movement. Move the cursor.
1724 @param[in] MouseState The current mouse state.
1726 @retval EFI_SUCCESS The operation was successful.
1727 @retval EFI_NOT_FOUND There was no mouse support found.
1730 MainEditorHandleMouseInput (
1731 IN EFI_SIMPLE_POINTER_STATE MouseState
1741 EFI_EDITOR_LINE
*Line
;
1747 // mouse action means:
1749 // mouse left button
1754 // have mouse movement
1756 if (MouseState
.RelativeMovementX
|| MouseState
.RelativeMovementY
) {
1760 TextX
= GetTextX (MouseState
.RelativeMovementX
);
1761 TextY
= GetTextY (MouseState
.RelativeMovementY
);
1763 FileBufferAdjustMousePosition (TextX
, TextY
);
1770 // if left button pushed down
1772 if (MouseState
.LeftButton
) {
1774 FCol
= MainEditor
.FileBuffer
->MousePosition
.Column
- 1 + 1;
1776 FRow
= MainEditor
.FileBuffer
->FilePosition
.Row
+
1777 MainEditor
.FileBuffer
->MousePosition
.Row
-
1778 MainEditor
.FileBuffer
->DisplayPosition
.Row
;
1781 // beyond the file line length
1783 if (MainEditor
.FileBuffer
->NumLines
< FRow
) {
1784 FRow
= MainEditor
.FileBuffer
->NumLines
;
1787 Link
= MainEditor
.FileBuffer
->ListHead
->ForwardLink
;
1788 for (Index
= 0; Index
< FRow
- 1; Index
++) {
1789 Link
= Link
->ForwardLink
;
1792 Line
= CR (Link
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
1795 // beyond the line's column length
1797 if (FCol
> Line
->Size
+ 1) {
1798 FCol
= Line
->Size
+ 1;
1801 FileBufferMovePosition (FRow
, FCol
);
1803 MainEditor
.FileBuffer
->MousePosition
.Row
= MainEditor
.FileBuffer
->DisplayPosition
.Row
;
1805 MainEditor
.FileBuffer
->MousePosition
.Column
= MainEditor
.FileBuffer
->DisplayPosition
.Column
;
1819 return EFI_NOT_FOUND
;
1823 Handle user key input. This routes to other functions for the actions.
1825 @retval EFI_SUCCESS The operation was successful.
1826 @retval EFI_LOAD_ERROR A load error occurred.
1827 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1830 MainEditorKeyInput (
1834 EFI_KEY_DATA KeyData
;
1836 EFI_SIMPLE_POINTER_STATE MouseState
;
1837 BOOLEAN NoShiftState
;
1841 Status
= EFI_SUCCESS
;
1842 EditorMouseAction
= FALSE
;
1845 // backup some key elements, so that can aVOID some refresh work
1847 MainEditorBackup ();
1850 // change priority of checking mouse/keyboard activity dynamically
1851 // so prevent starvation of keyboard.
1852 // if last time, mouse moves then this time check keyboard
1854 if (MainEditor
.MouseSupported
) {
1855 Status
= MainEditor
.MouseInterface
->GetState (
1856 MainEditor
.MouseInterface
,
1859 if (!EFI_ERROR (Status
)) {
1861 Status
= MainEditorHandleMouseInput (MouseState
);
1863 if (!EFI_ERROR (Status
)) {
1864 EditorMouseAction
= TRUE
;
1865 FileBufferMouseNeedRefresh
= TRUE
;
1866 } else if (Status
== EFI_LOAD_ERROR
) {
1867 StatusBarSetStatusString (L
"Invalid Mouse Movement ");
1873 // CheckEvent() returns Success when non-partial key is pressed.
1875 Status
= gBS
->CheckEvent (MainEditor
.TextInputEx
->WaitForKeyEx
);
1876 if (!EFI_ERROR (Status
)) {
1877 Status
= MainEditor
.TextInputEx
->ReadKeyStrokeEx (MainEditor
.TextInputEx
, &KeyData
);
1878 if (!EFI_ERROR (Status
)) {
1880 // dispatch to different components' key handling function
1881 // so not everywhere has to set this variable
1883 FileBufferMouseNeedRefresh
= TRUE
;
1885 // clear previous status string
1887 StatusBarSetRefresh();
1889 // NoShiftState: TRUE when no shift key is pressed.
1891 NoShiftState
= ((KeyData
.KeyState
.KeyShiftState
& EFI_SHIFT_STATE_VALID
) == 0) || (KeyData
.KeyState
.KeyShiftState
== EFI_SHIFT_STATE_VALID
);
1893 // dispatch to different components' key handling function
1895 if (EFI_NOT_FOUND
!= MenuBarDispatchControlHotKey(&KeyData
)) {
1896 Status
= EFI_SUCCESS
;
1897 } else if (NoShiftState
&& ((KeyData
.Key
.ScanCode
== SCAN_NULL
) || ((KeyData
.Key
.ScanCode
>= SCAN_UP
) && (KeyData
.Key
.ScanCode
<= SCAN_PAGE_DOWN
)))) {
1898 Status
= FileBufferHandleInput (&KeyData
.Key
);
1899 } else if (NoShiftState
&& (KeyData
.Key
.ScanCode
>= SCAN_F1
) && (KeyData
.Key
.ScanCode
<= SCAN_F12
)) {
1900 Status
= MenuBarDispatchFunctionKey (&KeyData
.Key
);
1902 StatusBarSetStatusString (L
"Unknown Command");
1903 FileBufferMouseNeedRefresh
= FALSE
;
1906 if (Status
!= EFI_SUCCESS
&& Status
!= EFI_OUT_OF_RESOURCES
) {
1908 // not already has some error status
1910 if (StatusBarGetString() != NULL
&& StrCmp (L
"", StatusBarGetString()) == 0) {
1911 StatusBarSetStatusString (L
"Disk Error. Try Again");
1918 // after handling, refresh editor
1920 MainEditorRefresh ();
1922 } while (Status
!= EFI_OUT_OF_RESOURCES
&& !EditorExit
);
1930 @param[in] Line A pointer to the line to be set to clipboard
1932 @retval EFI_SUCCESS The operation was successful.
1933 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1936 MainEditorSetCutLine (
1937 EFI_EDITOR_LINE
*Line
1944 if (MainEditor
.CutLine
!= NULL
) {
1946 // free the old clipboard
1948 LineFree (MainEditor
.CutLine
);
1951 // duplicate the line to clipboard
1953 MainEditor
.CutLine
= LineDup (Line
);
1954 if (MainEditor
.CutLine
== NULL
) {
1955 return EFI_OUT_OF_RESOURCES
;
1962 Backup function for MainEditor
1964 @retval EFI_SUCCESS The operation was successful.
1971 FileBufferBackup ();