/** @file | |
Implements editor interface functions. | |
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved. <BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "TextEditor.h" | |
#include "EditStatusBar.h" | |
#include "EditInputBar.h" | |
#include "EditMenuBar.h" | |
// | |
// the first time editor launch | |
// | |
BOOLEAN EditorFirst; | |
// | |
// it's time editor should exit | |
// | |
BOOLEAN EditorExit; | |
BOOLEAN EditorMouseAction; | |
extern EFI_EDITOR_FILE_BUFFER FileBuffer; | |
extern BOOLEAN FileBufferNeedRefresh; | |
extern BOOLEAN FileBufferOnlyLineNeedRefresh; | |
extern BOOLEAN FileBufferMouseNeedRefresh; | |
extern EFI_EDITOR_FILE_BUFFER FileBufferBackupVar; | |
EFI_EDITOR_GLOBAL_EDITOR MainEditor; | |
/** | |
Load a file from disk to editor | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
**/ | |
EFI_STATUS | |
MainCommandOpenFile ( | |
VOID | |
); | |
/** | |
Switch a file from ASCII to UNICODE or vise-versa. | |
@retval EFI_SUCCESS The switch was ok or a warning was presented. | |
**/ | |
EFI_STATUS | |
MainCommandSwitchFileType ( | |
VOID | |
); | |
/** | |
move cursor to specified lines | |
@retval EFI_SUCCESS The operation was successful. | |
**/ | |
EFI_STATUS | |
MainCommandGotoLine ( | |
VOID | |
); | |
/** | |
Save current file to disk, you can save to current file name or | |
save to another file name. | |
@retval EFI_SUCCESS The file was saved correctly. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
@retval EFI_LOAD_ERROR A file access error occurred. | |
**/ | |
EFI_STATUS | |
MainCommandSaveFile ( | |
VOID | |
); | |
/** | |
Show help information for the editor. | |
@retval EFI_SUCCESS The operation was successful. | |
**/ | |
EFI_STATUS | |
MainCommandDisplayHelp ( | |
VOID | |
); | |
/** | |
exit editor | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
**/ | |
EFI_STATUS | |
MainCommandExit ( | |
VOID | |
); | |
/** | |
search string in file buffer | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
**/ | |
EFI_STATUS | |
MainCommandSearch ( | |
VOID | |
); | |
/** | |
search string in file buffer, and replace it with another str | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
**/ | |
EFI_STATUS | |
MainCommandSearchReplace ( | |
VOID | |
); | |
/** | |
cut current line to clipboard | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
**/ | |
EFI_STATUS | |
MainCommandCutLine ( | |
VOID | |
); | |
/** | |
paste line to file buffer. | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
**/ | |
EFI_STATUS | |
MainCommandPasteLine ( | |
VOID | |
); | |
/** | |
Help info that will be displayed. | |
**/ | |
EFI_STRING_ID MainMenuHelpInfo[] = { | |
STRING_TOKEN (STR_EDIT_HELP_TITLE), | |
STRING_TOKEN (STR_EDIT_HELP_BLANK), | |
STRING_TOKEN (STR_EDIT_HELP_LIST_TITLE), | |
STRING_TOKEN (STR_EDIT_HELP_DIV), | |
STRING_TOKEN (STR_EDIT_HELP_GO_TO_LINE), | |
STRING_TOKEN (STR_EDIT_HELP_SAVE_FILE), | |
STRING_TOKEN (STR_EDIT_HELP_EXIT), | |
STRING_TOKEN (STR_EDIT_HELP_SEARCH), | |
STRING_TOKEN (STR_EDIT_HELP_SEARCH_REPLACE), | |
STRING_TOKEN (STR_EDIT_HELP_CUT_LINE), | |
STRING_TOKEN (STR_EDIT_HELP_PASTE_LINE), | |
STRING_TOKEN (STR_EDIT_HELP_OPEN_FILE), | |
STRING_TOKEN (STR_EDIT_HELP_FILE_TYPE), | |
STRING_TOKEN (STR_EDIT_HELP_BLANK), | |
STRING_TOKEN (STR_EDIT_HELP_EXIT_HELP), | |
STRING_TOKEN (STR_EDIT_HELP_BLANK), | |
STRING_TOKEN (STR_EDIT_HELP_BLANK), | |
STRING_TOKEN (STR_EDIT_HELP_BLANK), | |
STRING_TOKEN (STR_EDIT_HELP_BLANK), | |
STRING_TOKEN (STR_EDIT_HELP_BLANK), | |
STRING_TOKEN (STR_EDIT_HELP_BLANK), | |
STRING_TOKEN (STR_EDIT_HELP_BLANK), | |
STRING_TOKEN (STR_EDIT_HELP_DIV), | |
0 | |
}; | |
MENU_ITEM_FUNCTION MainControlBasedMenuFunctions[] = { | |
NULL, | |
NULL, /* Ctrl - A */ | |
NULL, /* Ctrl - B */ | |
NULL, /* Ctrl - C */ | |
NULL, /* Ctrl - D */ | |
MainCommandDisplayHelp, /* Ctrl - E */ | |
MainCommandSearch, /* Ctrl - F */ | |
MainCommandGotoLine, /* Ctrl - G */ | |
NULL, /* Ctrl - H */ | |
NULL, /* Ctrl - I */ | |
NULL, /* Ctrl - J */ | |
MainCommandCutLine, /* Ctrl - K */ | |
NULL, /* Ctrl - L */ | |
NULL, /* Ctrl - M */ | |
NULL, /* Ctrl - N */ | |
MainCommandOpenFile, /* Ctrl - O */ | |
NULL, /* Ctrl - P */ | |
MainCommandExit, /* Ctrl - Q */ | |
MainCommandSearchReplace, /* Ctrl - R */ | |
MainCommandSaveFile, /* Ctrl - S */ | |
MainCommandSwitchFileType, /* Ctrl - T */ | |
MainCommandPasteLine, /* Ctrl - U */ | |
NULL, /* Ctrl - V */ | |
NULL, /* Ctrl - W */ | |
NULL, /* Ctrl - X */ | |
NULL, /* Ctrl - Y */ | |
NULL, /* Ctrl - Z */ | |
}; | |
EDITOR_MENU_ITEM MainMenuItems[] = { | |
{ | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_GO_TO_LINE), | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_F1), | |
MainCommandGotoLine | |
}, | |
{ | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_SAVE_FILE), | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_F2), | |
MainCommandSaveFile | |
}, | |
{ | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_EXIT), | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_F3), | |
MainCommandExit | |
}, | |
{ | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_SEARCH), | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_F4), | |
MainCommandSearch | |
}, | |
{ | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_SEARCH_REPLACE), | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_F5), | |
MainCommandSearchReplace | |
}, | |
{ | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_CUT_LINE), | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_F6), | |
MainCommandCutLine | |
}, | |
{ | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_PASTE_LINE), | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_F7), | |
MainCommandPasteLine | |
}, | |
{ | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_OPEN_FILE), | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_F8), | |
MainCommandOpenFile | |
}, | |
{ | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_FILE_TYPE), | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_F9), | |
MainCommandSwitchFileType | |
}, | |
{ | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_FILE_TYPE), | |
STRING_TOKEN (STR_EDIT_LIBMENUBAR_F11), | |
MainCommandSwitchFileType | |
}, | |
{ | |
0, | |
0, | |
NULL | |
} | |
}; | |
/** | |
Load a file from disk to editor | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
**/ | |
EFI_STATUS | |
MainCommandOpenFile ( | |
VOID | |
) | |
{ | |
BOOLEAN Done; | |
EFI_STATUS Status; | |
// | |
// This command will open a file from current working directory. | |
// Read-only file can also be opened. But it can not be modified. | |
// Below is the scenario of Open File command: | |
// 1.IF currently opened file has not been modIFied, directly go to step . | |
// IF currently opened file has been modified, | |
// an Input Bar will be prompted as : | |
// "File Modified. Save ( Yes/No/Cancel) ?" | |
// IF user press 'y' or 'Y', currently opened file will be saved. | |
// IF user press 'n' or 'N', currently opened file will | |
// not be saved. | |
// IF user press 'c' or 'C' or ESC, Open File command ends and | |
// currently opened file is still opened. | |
// | |
// 2. An Input Bar will be prompted as : "File Name to Open: " | |
// IF user press ESC, Open File command ends and | |
// currently opened file is still opened. | |
// Any other inputs with a Return will | |
// cause currently opened file close. | |
// | |
// 3. IF user input file name is an existing file , this file will be read | |
// and opened. | |
// IF user input file name is a new file, this file will be created | |
// and opened. This file's type ( UNICODE or ASCII ) is the same | |
// with the old file. | |
// if current file is modified, so you need to choose | |
// whether to save it first. | |
// | |
if (MainEditor.FileBuffer->FileModified) { | |
Status = InputBarSetPrompt (L"File modified. Save (Yes/No/Cancel) ? "); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// the answer is just one character | |
// | |
Status = InputBarSetStringSize (1); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// loop for user's answer | |
// valid answer is just 'y' 'Y', 'n' 'N', 'c' 'C' | |
// | |
Done = FALSE; | |
while (!Done) { | |
Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); | |
StatusBarSetRefresh (); | |
// | |
// ESC pressed | |
// | |
if (Status == EFI_NOT_READY) { | |
return EFI_SUCCESS; | |
} | |
switch (InputBarGetString ()[0]) { | |
case L'y': | |
case L'Y': | |
// | |
// want to save this file first | |
// | |
Status = FileBufferSave (MainEditor.FileBuffer->FileName); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row, 0, 0); | |
FileBufferRestorePosition (); | |
Done = TRUE; | |
break; | |
case L'n': | |
case L'N': | |
// | |
// the file won't be saved | |
// | |
Done = TRUE; | |
break; | |
case L'c': | |
case L'C': | |
return EFI_SUCCESS; | |
} | |
} | |
} | |
// | |
// TO get the open file name | |
// | |
Status = InputBarSetPrompt (L"File Name to Open: "); | |
if (EFI_ERROR (Status)) { | |
FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); | |
return Status; | |
} | |
Status = InputBarSetStringSize (100); | |
if (EFI_ERROR (Status)) { | |
FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); | |
return Status; | |
} | |
while (1) { | |
Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); | |
StatusBarSetRefresh (); | |
// | |
// ESC pressed | |
// | |
if (Status == EFI_NOT_READY) { | |
return EFI_SUCCESS; | |
} | |
// | |
// The input string length should > 0 | |
// | |
if (StrLen (InputBarGetString ()) > 0) { | |
// | |
// CHECK if filename is valid | |
// | |
if (!IsValidFileName (InputBarGetString ())) { | |
FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); | |
StatusBarSetStatusString (L"Invalid File Name"); | |
return EFI_SUCCESS; | |
} | |
break; | |
} | |
} | |
// | |
// read from disk | |
// | |
Status = FileBufferRead (InputBarGetString (), FALSE); | |
if (EFI_ERROR (Status)) { | |
FileBufferRead (MainEditor.FileBuffer->FileName, TRUE); | |
return EFI_LOAD_ERROR; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Switch a file from ASCII to UNICODE or vise-versa. | |
@retval EFI_SUCCESS The switch was ok or a warning was presented. | |
**/ | |
EFI_STATUS | |
MainCommandSwitchFileType ( | |
VOID | |
) | |
{ | |
// | |
// Below is the scenario of File Type command: | |
// After File Type is executed, file type will be changed to another type | |
// if file is read-only, can not be modified | |
// | |
if (MainEditor.FileBuffer->ReadOnly) { | |
StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); | |
return EFI_SUCCESS; | |
} | |
if (MainEditor.FileBuffer->FileType == FileTypeUnicode) { | |
MainEditor.FileBuffer->FileType = FileTypeAscii; | |
} else { | |
MainEditor.FileBuffer->FileType = FileTypeUnicode; | |
} | |
MainEditor.FileBuffer->FileModified = TRUE; | |
return EFI_SUCCESS; | |
} | |
/** | |
cut current line to clipboard | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
**/ | |
EFI_STATUS | |
MainCommandCutLine ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_EDITOR_LINE *Line; | |
// | |
// This command will cut current line ( where cursor is on ) to clip board. | |
// And cursor will move to the beginning of next line. | |
// Below is the scenario of Cut Line command: | |
// 1. IF cursor is on valid line, current line will be cut to clip board. | |
// IF cursor is not on valid line, an Status String will be prompted : | |
// "Nothing to Cut". | |
// | |
Line = NULL; | |
Status = FileBufferCutLine (&Line); | |
if (Status == EFI_NOT_FOUND) { | |
return EFI_SUCCESS; | |
} | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
MainEditor.CutLine = Line; | |
return EFI_SUCCESS; | |
} | |
/** | |
paste line to file buffer. | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
**/ | |
EFI_STATUS | |
MainCommandPasteLine ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Below is the scenario of Paste Line command: | |
// 1. IF nothing is on clipboard, a Status String will be prompted : | |
// "No Line to Paste" and Paste Line command ends. | |
// IF something is on clipboard, insert it above current line. | |
// nothing on clipboard | |
// | |
if (MainEditor.CutLine == NULL) { | |
StatusBarSetStatusString (L"No Line to Paste"); | |
return EFI_SUCCESS; | |
} | |
Status = FileBufferPasteLine (); | |
return Status; | |
} | |
/** | |
search string in file buffer | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
**/ | |
EFI_STATUS | |
MainCommandSearch ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
CHAR16 *Buffer; | |
BOOLEAN Done; | |
UINTN Offset; | |
// | |
// Below is the scenario of Search command: | |
// 1. An Input Bar will be prompted : "Enter Search String:". | |
// IF user press ESC, Search command ends. | |
// IF user just press Enter, Search command ends. | |
// IF user inputs the search string, do Step 2. | |
// | |
// 2. IF input search string is found, cursor will move to the first | |
// occurrence and do Step 3. | |
// IF input search string is not found, a Status String | |
// "Search String Not Found" will be prompted and Search command ends. | |
// | |
// 3. An Input Bar will be prompted: "Find Next (Yes/No/Cancel ) ?". | |
// IF user press ESC, Search command ends. | |
// IF user press 'y' or 'Y', do Step 2. | |
// IF user press 'n' or 'N', Search command ends. | |
// IF user press 'c' or 'C', Search command ends. | |
// | |
Status = InputBarSetPrompt (L"Enter Search String: "); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = InputBarSetStringSize (40); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); | |
StatusBarSetRefresh (); | |
// | |
// ESC | |
// | |
if (Status == EFI_NOT_READY) { | |
return EFI_SUCCESS; | |
} | |
// | |
// just enter pressed | |
// | |
if (StrLen (InputBarGetString ()) == 0) { | |
return EFI_SUCCESS; | |
} | |
Buffer = CatSPrint (NULL, L"%s", InputBarGetString ()); | |
if (Buffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// the first time , search from current position | |
// | |
Offset = 0; | |
do { | |
// | |
// since search may be continued to search multiple times | |
// so we need to backup editor each time | |
// | |
MainEditorBackup (); | |
Status = FileBufferSearch (Buffer, Offset); | |
if (Status == EFI_NOT_FOUND) { | |
break; | |
} | |
// | |
// Find next | |
// | |
Status = InputBarSetPrompt (L"Find Next (Yes/No) ?"); | |
if (EFI_ERROR (Status)) { | |
FreePool (Buffer); | |
return Status; | |
} | |
Status = InputBarSetStringSize (1); | |
if (EFI_ERROR (Status)) { | |
FreePool (Buffer); | |
return Status; | |
} | |
Done = FALSE; | |
while (!Done) { | |
Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); | |
StatusBarSetRefresh (); | |
// | |
// ESC pressed | |
// | |
if (Status == EFI_NOT_READY) { | |
FreePool (Buffer); | |
return EFI_SUCCESS; | |
} | |
switch (InputBarGetString ()[0]) { | |
case L'y': | |
case L'Y': | |
Done = TRUE; | |
break; | |
case L'n': | |
case L'N': | |
FreePool (Buffer); | |
return EFI_SUCCESS; | |
} | |
// | |
// end of which | |
// | |
} | |
// | |
// end of while !Done | |
// for search second, third time, search from current position + strlen | |
// | |
Offset = StrLen (Buffer); | |
} while (1); | |
// | |
// end of do | |
// | |
FreePool (Buffer); | |
StatusBarSetStatusString (L"Search String Not Found"); | |
return EFI_SUCCESS; | |
} | |
/** | |
Search string in file buffer, and replace it with another str. | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
**/ | |
EFI_STATUS | |
MainCommandSearchReplace ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
CHAR16 *Search; | |
CHAR16 *Replace; | |
BOOLEAN Done; | |
BOOLEAN First; | |
BOOLEAN ReplaceOption; | |
UINTN SearchLen; | |
UINTN ReplaceLen; | |
BOOLEAN ReplaceAll; | |
ReplaceOption = FALSE; | |
// | |
// Below is the scenario of Search/Replace command: | |
// 1. An Input Bar is prompted : "Enter Search String:". | |
// IF user press ESC, Search/Replace command ends. | |
// IF user just press Enter, Search/Replace command ends. | |
// IF user inputs the search string S, do Step 2. | |
// | |
// 2. An Input Bar is prompted: "Replace With:". | |
// IF user press ESC, Search/Replace command ends. | |
// IF user inputs the replace string R, do Step 3. | |
// | |
// 3. IF input search string is not found, an Status String | |
// "Search String Not Found" will be prompted | |
// and Search/Replace command ends | |
// IF input search string is found, do Step 4. | |
// | |
// 4. An Input Bar will be prompted: "Replace ( Yes/No/All/Cancel )?" | |
// IF user press 'y' or 'Y', S will be replaced with R and do Step 5 | |
// IF user press 'n' or 'N', S will not be replaced and do Step 5. | |
// IF user press 'a' or 'A', all the S from file current position on | |
// will be replaced with R and Search/Replace command ends. | |
// IF user press 'c' or 'C' or ESC, Search/Replace command ends. | |
// | |
// 5. An Input Bar will be prompted: "Find Next (Yes/No/Cancel) ?". | |
// IF user press ESC, Search/Replace command ends. | |
// IF user press 'y' or 'Y', do Step 3. | |
// IF user press 'n' or 'N', Search/Replace command ends. | |
// IF user press 'c' or 'C', Search/Replace command ends. | |
// input search string | |
// | |
Status = InputBarSetPrompt (L"Enter Search String: "); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = InputBarSetStringSize (40); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); | |
StatusBarSetRefresh (); | |
// | |
// ESC | |
// | |
if (Status == EFI_NOT_READY) { | |
return EFI_SUCCESS; | |
} | |
// | |
// if just pressed enter | |
// | |
if (StrLen (InputBarGetString ()) == 0) { | |
return EFI_SUCCESS; | |
} | |
Search = CatSPrint (NULL, L"%s", InputBarGetString ()); | |
if (Search == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
SearchLen = StrLen (Search); | |
// | |
// input replace string | |
// | |
Status = InputBarSetPrompt (L"Replace With: "); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = InputBarSetStringSize (40); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); | |
StatusBarSetRefresh (); | |
// | |
// ESC | |
// | |
if (Status == EFI_NOT_READY) { | |
return EFI_SUCCESS; | |
} | |
Replace = CatSPrint (NULL, L"%s", InputBarGetString ()); | |
if (Replace == NULL) { | |
FreePool (Search); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
ReplaceLen = StrLen (Replace); | |
First = TRUE; | |
ReplaceAll = FALSE; | |
do { | |
// | |
// since search may be continued to search multiple times | |
// so we need to backup editor each time | |
// | |
MainEditorBackup (); | |
if (First) { | |
Status = FileBufferSearch (Search, 0); | |
} else { | |
// | |
// if just replace, so skip this replace string | |
// if replace string is an empty string, so skip to next character | |
// | |
if (ReplaceOption) { | |
Status = FileBufferSearch (Search, (ReplaceLen == 0) ? 1 : ReplaceLen); | |
} else { | |
Status = FileBufferSearch (Search, SearchLen); | |
} | |
} | |
if (Status == EFI_NOT_FOUND) { | |
break; | |
} | |
// | |
// replace or not? | |
// | |
Status = InputBarSetPrompt (L"Replace (Yes/No/All/Cancel) ?"); | |
if (EFI_ERROR (Status)) { | |
FreePool (Search); | |
FreePool (Replace); | |
return Status; | |
} | |
Status = InputBarSetStringSize (1); | |
if (EFI_ERROR (Status)) { | |
FreePool (Search); | |
FreePool (Replace); | |
return Status; | |
} | |
Done = FALSE; | |
while (!Done) { | |
Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); | |
StatusBarSetRefresh (); | |
// | |
// ESC pressed | |
// | |
if (Status == EFI_NOT_READY) { | |
FreePool (Search); | |
FreePool (Replace); | |
return EFI_SUCCESS; | |
} | |
switch (InputBarGetString ()[0]) { | |
case L'y': | |
case L'Y': | |
Done = TRUE; | |
ReplaceOption = TRUE; | |
break; | |
case L'n': | |
case L'N': | |
Done = TRUE; | |
ReplaceOption = FALSE; | |
break; | |
case L'a': | |
case L'A': | |
Done = TRUE; | |
ReplaceOption = TRUE; | |
ReplaceAll = TRUE; | |
break; | |
case L'c': | |
case L'C': | |
FreePool (Search); | |
FreePool (Replace); | |
return EFI_SUCCESS; | |
} | |
// | |
// end of which | |
// | |
} | |
// | |
// end of while !Done | |
// Decide to Replace | |
// | |
if (ReplaceOption) { | |
// | |
// file is read-only | |
// | |
if (MainEditor.FileBuffer->ReadOnly) { | |
StatusBarSetStatusString (L"Read Only File Can Not Be Modified"); | |
return EFI_SUCCESS; | |
} | |
// | |
// replace all | |
// | |
if (ReplaceAll) { | |
Status = FileBufferReplaceAll (Search, Replace, 0); | |
FreePool (Search); | |
FreePool (Replace); | |
return Status; | |
} | |
// | |
// replace | |
// | |
Status = FileBufferReplace (Replace, SearchLen); | |
if (EFI_ERROR (Status)) { | |
FreePool (Search); | |
FreePool (Replace); | |
return Status; | |
} | |
} | |
// | |
// Find next | |
// | |
Status = InputBarSetPrompt (L"Find Next (Yes/No) ?"); | |
if (EFI_ERROR (Status)) { | |
FreePool (Search); | |
FreePool (Replace); | |
return Status; | |
} | |
Status = InputBarSetStringSize (1); | |
if (EFI_ERROR (Status)) { | |
FreePool (Search); | |
FreePool (Replace); | |
return Status; | |
} | |
Done = FALSE; | |
while (!Done) { | |
Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); | |
StatusBarSetRefresh (); | |
// | |
// ESC pressed | |
// | |
if (Status == EFI_NOT_READY) { | |
FreePool (Search); | |
FreePool (Replace); | |
return EFI_SUCCESS; | |
} | |
switch (InputBarGetString ()[0]) { | |
case L'y': | |
case L'Y': | |
Done = TRUE; | |
break; | |
case L'n': | |
case L'N': | |
FreePool (Search); | |
FreePool (Replace); | |
return EFI_SUCCESS; | |
} | |
// | |
// end of which | |
// | |
} | |
// | |
// end of while !Done | |
// | |
First = FALSE; | |
} while (1); | |
// | |
// end of do | |
// | |
FreePool (Search); | |
FreePool (Replace); | |
StatusBarSetStatusString (L"Search String Not Found"); | |
return EFI_SUCCESS; | |
} | |
/** | |
exit editor | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
**/ | |
EFI_STATUS | |
MainCommandExit ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Below is the scenario of Exit command: | |
// 1. IF currently opened file is not modified, exit the editor and | |
// Exit command ends. | |
// IF currently opened file is modified, do Step 2 | |
// | |
// 2. An Input Bar will be prompted: | |
// "File modified. Save ( Yes/No/Cancel )?" | |
// IF user press 'y' or 'Y', currently opened file will be saved | |
// and Editor exits | |
// IF user press 'n' or 'N', currently opened file will not be saved | |
// and Editor exits. | |
// IF user press 'c' or 'C' or ESC, Exit command ends. | |
// if file has been modified, so will prompt user whether to save the changes | |
// | |
if (MainEditor.FileBuffer->FileModified) { | |
Status = InputBarSetPrompt (L"File modified. Save (Yes/No/Cancel) ? "); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = InputBarSetStringSize (1); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
while (1) { | |
Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); | |
StatusBarSetRefresh (); | |
// | |
// ESC pressed | |
// | |
if (Status == EFI_NOT_READY) { | |
return EFI_SUCCESS; | |
} | |
switch (InputBarGetString ()[0]) { | |
case L'y': | |
case L'Y': | |
// | |
// write file back to disk | |
// | |
Status = FileBufferSave (MainEditor.FileBuffer->FileName); | |
if (!EFI_ERROR (Status)) { | |
EditorExit = TRUE; | |
} | |
return Status; | |
case L'n': | |
case L'N': | |
EditorExit = TRUE; | |
return EFI_SUCCESS; | |
case L'c': | |
case L'C': | |
return EFI_SUCCESS; | |
} | |
} | |
} | |
EditorExit = TRUE; | |
return EFI_SUCCESS; | |
} | |
/** | |
move cursor to specified lines | |
@retval EFI_SUCCESS The operation was successful. | |
**/ | |
EFI_STATUS | |
MainCommandGotoLine ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN Row; | |
// | |
// Below is the scenario of Go To Line command: | |
// 1. An Input Bar will be prompted : "Go To Line:". | |
// IF user press ESC, Go To Line command ends. | |
// IF user just press Enter, cursor remains unchanged. | |
// IF user inputs line number, do Step 2. | |
// | |
// 2. IF input line number is valid, move cursor to the beginning | |
// of specified line and Go To Line command ends. | |
// IF input line number is invalid, a Status String will be prompted: | |
// "No Such Line" and Go To Line command ends. | |
// | |
Status = InputBarSetPrompt (L"Go To Line: "); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// line number's digit <= 6 | |
// | |
Status = InputBarSetStringSize (6); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); | |
StatusBarSetRefresh (); | |
// | |
// press ESC | |
// | |
if (Status == EFI_NOT_READY) { | |
return EFI_SUCCESS; | |
} | |
// | |
// if JUST press enter | |
// | |
if (StrLen (InputBarGetString ()) == 0) { | |
return EFI_SUCCESS; | |
} | |
Row = ShellStrToUintn (InputBarGetString ()); | |
// | |
// invalid line number | |
// | |
if ((Row > MainEditor.FileBuffer->NumLines) || (Row <= 0)) { | |
StatusBarSetStatusString (L"No Such Line"); | |
return EFI_SUCCESS; | |
} | |
// | |
// move cursor to that line's start | |
// | |
FileBufferMovePosition (Row, 1); | |
return EFI_SUCCESS; | |
} | |
/** | |
Save current file to disk, you can save to current file name or | |
save to another file name. | |
@retval EFI_SUCCESS The file was saved correctly. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
@retval EFI_LOAD_ERROR A file access error occurred. | |
**/ | |
EFI_STATUS | |
MainCommandSaveFile ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
CHAR16 *FileName; | |
BOOLEAN OldFile; | |
CHAR16 *Str; | |
SHELL_FILE_HANDLE FileHandle; | |
EFI_FILE_INFO *Info; | |
// | |
// This command will save currently opened file to disk. | |
// You can choose save to another file name or just save to | |
// current file name. | |
// Below is the scenario of Save File command: | |
// ( Suppose the old file name is A ) | |
// 1. An Input Bar will be prompted: "File To Save: [ old file name]" | |
// IF user press ESC, Save File command ends . | |
// IF user press Enter, input file name will be A. | |
// IF user inputs a new file name B, input file name will be B. | |
// | |
// 2. IF input file name is A, go to do Step 3. | |
// IF input file name is B, go to do Step 4. | |
// | |
// 3. IF A is read only, Status Bar will show "Access Denied" and | |
// Save File commands ends. | |
// IF A is not read only, save file buffer to disk and remove modified | |
// flag in Title Bar , then Save File command ends. | |
// | |
// 4. IF B does not exist, create this file and save file buffer to it. | |
// Go to do Step 7. | |
// IF B exits, do Step 5. | |
// | |
// 5.An Input Bar will be prompted: | |
// "File Exists. Overwrite ( Yes/No/Cancel )?" | |
// IF user press 'y' or 'Y', do Step 6. | |
// IF user press 'n' or 'N', Save File commands ends. | |
// IF user press 'c' or 'C' or ESC, Save File commands ends. | |
// | |
// 6. IF B is a read-only file, Status Bar will show "Access Denied" and | |
// Save File commands ends. | |
// IF B can be read and write, save file buffer to B. | |
// | |
// 7. Update File Name field in Title Bar to B and remove the modified | |
// flag in Title Bar. | |
// | |
Str = CatSPrint (NULL, L"File to Save: [%s]", MainEditor.FileBuffer->FileName); | |
if (Str == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
if (StrLen (Str) >= 50) { | |
// | |
// replace the long file name with "..." | |
// | |
Str[46] = L'.'; | |
Str[47] = L'.'; | |
Str[48] = L'.'; | |
Str[49] = L']'; | |
Str[50] = CHAR_NULL; | |
} | |
Status = InputBarSetPrompt (Str); | |
FreePool (Str); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = InputBarSetStringSize (100); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// get new file name | |
// | |
Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); | |
StatusBarSetRefresh (); | |
// | |
// if user pressed ESC | |
// | |
if (Status == EFI_NOT_READY) { | |
return EFI_SUCCESS; | |
} | |
// | |
// if just enter pressed, so think save to current file name | |
// | |
if (StrLen (InputBarGetString ()) == 0) { | |
FileName = CatSPrint (NULL, L"%s", MainEditor.FileBuffer->FileName); | |
} else { | |
FileName = CatSPrint (NULL, L"%s", InputBarGetString ()); | |
} | |
if (FileName == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
if (!IsValidFileName (FileName)) { | |
StatusBarSetStatusString (L"Invalid File Name"); | |
FreePool (FileName); | |
return EFI_SUCCESS; | |
} | |
OldFile = FALSE; | |
// | |
// save to the old file | |
// | |
if (StringNoCaseCompare (&FileName, &MainEditor.FileBuffer->FileName) == 0) { | |
OldFile = TRUE; | |
} | |
if (OldFile) { | |
// | |
// if the file is read only, so can not write back to it. | |
// | |
if (MainEditor.FileBuffer->ReadOnly == TRUE) { | |
StatusBarSetStatusString (L"Access Denied"); | |
FreePool (FileName); | |
return EFI_SUCCESS; | |
} | |
} else { | |
// | |
// if the file exists | |
// | |
if (ShellFileExists (FileName) != EFI_NOT_FOUND) { | |
// | |
// check for read only | |
// | |
Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ, 0); | |
if (EFI_ERROR (Status)) { | |
StatusBarSetStatusString (L"Open Failed"); | |
FreePool (FileName); | |
return EFI_SUCCESS; | |
} | |
Info = ShellGetFileInfo (FileHandle); | |
if (Info == NULL) { | |
StatusBarSetStatusString (L"Access Denied"); | |
FreePool (FileName); | |
return (EFI_SUCCESS); | |
} | |
if (Info->Attribute & EFI_FILE_READ_ONLY) { | |
StatusBarSetStatusString (L"Access Denied - Read Only"); | |
FreePool (Info); | |
FreePool (FileName); | |
return (EFI_SUCCESS); | |
} | |
FreePool (Info); | |
// | |
// ask user whether to overwrite this file | |
// | |
Status = InputBarSetPrompt (L"File exists. Overwrite (Yes/No/Cancel) ? "); | |
if (EFI_ERROR (Status)) { | |
SHELL_FREE_NON_NULL (FileName); | |
return Status; | |
} | |
Status = InputBarSetStringSize (1); | |
if (EFI_ERROR (Status)) { | |
SHELL_FREE_NON_NULL (FileName); | |
return Status; | |
} | |
while (TRUE) { | |
Status = InputBarRefresh (MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column); | |
StatusBarSetRefresh (); | |
// | |
// ESC pressed | |
// | |
if (Status == EFI_NOT_READY) { | |
SHELL_FREE_NON_NULL (FileName); | |
return EFI_SUCCESS; | |
} | |
switch (InputBarGetString ()[0]) { | |
case L'y': | |
case L'Y': | |
break; | |
case L'n': | |
case L'N': | |
case L'c': | |
case L'C': | |
SHELL_FREE_NON_NULL (FileName); | |
return EFI_SUCCESS; | |
} // end switch | |
} // while (!done) | |
} // file does exist | |
} // if old file name same | |
// | |
// save file to disk with specified name | |
// | |
FileBufferSetModified (); | |
Status = FileBufferSave (FileName); | |
SHELL_FREE_NON_NULL (FileName); | |
return Status; | |
} | |
/** | |
Show help information for the editor. | |
@retval EFI_SUCCESS The operation was successful. | |
**/ | |
EFI_STATUS | |
MainCommandDisplayHelp ( | |
VOID | |
) | |
{ | |
INT32 CurrentLine; | |
CHAR16 *InfoString; | |
EFI_KEY_DATA KeyData; | |
EFI_STATUS Status; | |
UINTN EventIndex; | |
// | |
// print helpInfo | |
// | |
for (CurrentLine = 0; 0 != MainMenuHelpInfo[CurrentLine]; CurrentLine++) { | |
InfoString = HiiGetString (gShellDebug1HiiHandle, MainMenuHelpInfo[CurrentLine], NULL); | |
ShellPrintEx (0, CurrentLine+1, L"%E%s%N", InfoString); | |
} | |
// | |
// scan for ctrl+w | |
// | |
while (TRUE) { | |
Status = gBS->WaitForEvent (1, &MainEditor.TextInputEx->WaitForKeyEx, &EventIndex); | |
if (EFI_ERROR (Status) || (EventIndex != 0)) { | |
continue; | |
} | |
Status = MainEditor.TextInputEx->ReadKeyStrokeEx (MainEditor.TextInputEx, &KeyData); | |
if (EFI_ERROR (Status)) { | |
continue; | |
} | |
if (((KeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) == 0) || | |
(KeyData.KeyState.KeyShiftState == EFI_SHIFT_STATE_VALID)) | |
{ | |
// | |
// For consoles that don't support/report shift state, | |
// CTRL+W is translated to L'W' - L'A' + 1. | |
// | |
if (KeyData.Key.UnicodeChar == L'W' - L'A' + 1) { | |
break; | |
} | |
} else if (((KeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) && | |
((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) && | |
((KeyData.KeyState.KeyShiftState & ~(EFI_SHIFT_STATE_VALID | EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) == 0)) | |
{ | |
// | |
// For consoles that supports/reports shift state, | |
// make sure that only CONTROL shift key is pressed. | |
// | |
if ((KeyData.Key.UnicodeChar == 'w') || (KeyData.Key.UnicodeChar == 'W')) { | |
break; | |
} | |
} | |
} | |
// | |
// update screen with file buffer's info | |
// | |
FileBufferRestorePosition (); | |
FileBufferNeedRefresh = TRUE; | |
FileBufferOnlyLineNeedRefresh = FALSE; | |
FileBufferRefresh (); | |
return EFI_SUCCESS; | |
} | |
EFI_EDITOR_COLOR_ATTRIBUTES OriginalColors; | |
INTN OriginalMode; | |
// | |
// basic initialization for MainEditor | |
// | |
EFI_EDITOR_GLOBAL_EDITOR MainEditorConst = { | |
&FileBuffer, | |
{ | |
{ 0, 0} | |
}, | |
{ | |
0, | |
0 | |
}, | |
NULL, | |
NULL, | |
FALSE, | |
NULL | |
}; | |
/** | |
The initialization function for MainEditor. | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
**/ | |
EFI_STATUS | |
MainEditorInit ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HANDLE *HandleBuffer; | |
UINTN HandleCount; | |
UINTN Index; | |
// | |
// basic initialization | |
// | |
CopyMem (&MainEditor, &MainEditorConst, sizeof (MainEditor)); | |
// | |
// set screen attributes | |
// | |
MainEditor.ColorAttributes.Colors.Foreground = gST->ConOut->Mode->Attribute & 0x000000ff; | |
MainEditor.ColorAttributes.Colors.Background = (UINT8)(gST->ConOut->Mode->Attribute >> 4); | |
OriginalColors = MainEditor.ColorAttributes.Colors; | |
OriginalMode = gST->ConOut->Mode->Mode; | |
// | |
// query screen size | |
// | |
gST->ConOut->QueryMode ( | |
gST->ConOut, | |
gST->ConOut->Mode->Mode, | |
&(MainEditor.ScreenSize.Column), | |
&(MainEditor.ScreenSize.Row) | |
); | |
// | |
// Find TextInEx in System Table ConsoleInHandle | |
// Per UEFI Spec, TextInEx is required for a console capable platform. | |
// | |
Status = gBS->HandleProtocol ( | |
gST->ConsoleInHandle, | |
&gEfiSimpleTextInputExProtocolGuid, | |
(VOID **)&MainEditor.TextInputEx | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Find mouse in System Table ConsoleInHandle | |
// | |
Status = gBS->HandleProtocol ( | |
gST->ConsoleInHandle, | |
&gEfiSimplePointerProtocolGuid, | |
(VOID **)&MainEditor.MouseInterface | |
); | |
if (EFI_ERROR (Status)) { | |
// | |
// If there is no Simple Pointer Protocol on System Table | |
// | |
HandleBuffer = NULL; | |
MainEditor.MouseInterface = NULL; | |
Status = gBS->LocateHandleBuffer ( | |
ByProtocol, | |
&gEfiSimplePointerProtocolGuid, | |
NULL, | |
&HandleCount, | |
&HandleBuffer | |
); | |
if (!EFI_ERROR (Status) && (HandleCount > 0)) { | |
// | |
// Try to find the first available mouse device | |
// | |
for (Index = 0; Index < HandleCount; Index++) { | |
Status = gBS->HandleProtocol ( | |
HandleBuffer[Index], | |
&gEfiSimplePointerProtocolGuid, | |
(VOID **)&MainEditor.MouseInterface | |
); | |
if (!EFI_ERROR (Status)) { | |
break; | |
} | |
} | |
} | |
if (HandleBuffer != NULL) { | |
FreePool (HandleBuffer); | |
} | |
} | |
if (!EFI_ERROR (Status) && (MainEditor.MouseInterface != NULL)) { | |
MainEditor.MouseAccumulatorX = 0; | |
MainEditor.MouseAccumulatorY = 0; | |
MainEditor.MouseSupported = TRUE; | |
} | |
// | |
// below will call the five components' init function | |
// | |
Status = MainTitleBarInit (L"UEFI EDIT"); | |
if (EFI_ERROR (Status)) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_EDIT_LIBEDITOR_TITLEBAR), gShellDebug1HiiHandle); | |
return EFI_LOAD_ERROR; | |
} | |
Status = ControlHotKeyInit (MainControlBasedMenuFunctions); | |
Status = MenuBarInit (MainMenuItems); | |
if (EFI_ERROR (Status)) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_EDIT_LIBEDITOR_MAINMENU), gShellDebug1HiiHandle); | |
return EFI_LOAD_ERROR; | |
} | |
Status = StatusBarInit (); | |
if (EFI_ERROR (Status)) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_EDIT_LIBEDITOR_STATUSBAR), gShellDebug1HiiHandle); | |
return EFI_LOAD_ERROR; | |
} | |
InputBarInit (MainEditor.TextInputEx); | |
Status = FileBufferInit (); | |
if (EFI_ERROR (Status)) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_EDIT_LIBEDITOR_FILEBUFFER), gShellDebug1HiiHandle); | |
return EFI_LOAD_ERROR; | |
} | |
// | |
// clear whole screen and enable cursor | |
// | |
gST->ConOut->ClearScreen (gST->ConOut); | |
gST->ConOut->EnableCursor (gST->ConOut, TRUE); | |
// | |
// initialize EditorFirst and EditorExit | |
// | |
EditorFirst = TRUE; | |
EditorExit = FALSE; | |
EditorMouseAction = FALSE; | |
return EFI_SUCCESS; | |
} | |
/** | |
The cleanup function for MainEditor. | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
**/ | |
EFI_STATUS | |
MainEditorCleanup ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// call the five components' cleanup function | |
// if error, do not exit | |
// just print some warning | |
// | |
MainTitleBarCleanup (); | |
StatusBarCleanup (); | |
InputBarCleanup (); | |
MenuBarCleanup (); | |
Status = FileBufferCleanup (); | |
if (EFI_ERROR (Status)) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_EDIT_LIBEDITOR_FILEBUFFER_CLEANUP), gShellDebug1HiiHandle); | |
} | |
// | |
// restore old mode | |
// | |
if (OriginalMode != gST->ConOut->Mode->Mode) { | |
gST->ConOut->SetMode (gST->ConOut, OriginalMode); | |
} | |
// | |
// restore old screen color | |
// | |
gST->ConOut->SetAttribute ( | |
gST->ConOut, | |
EFI_TEXT_ATTR (OriginalColors.Foreground, OriginalColors.Background) | |
); | |
gST->ConOut->ClearScreen (gST->ConOut); | |
return EFI_SUCCESS; | |
} | |
/** | |
Refresh the main editor component. | |
**/ | |
VOID | |
MainEditorRefresh ( | |
VOID | |
) | |
{ | |
// | |
// The Stall value is from experience. NOT from spec. avoids 'flicker' | |
// | |
gBS->Stall (50); | |
// | |
// call the components refresh function | |
// | |
if ( EditorFirst | |
|| (StrCmp (FileBufferBackupVar.FileName, FileBuffer.FileName) != 0) | |
|| (FileBufferBackupVar.FileType != FileBuffer.FileType) | |
|| (FileBufferBackupVar.FileModified != FileBuffer.FileModified) | |
|| (FileBufferBackupVar.ReadOnly != FileBuffer.ReadOnly)) | |
{ | |
MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row, 0, 0); | |
FileBufferRestorePosition (); | |
} | |
if ( EditorFirst | |
|| (FileBufferBackupVar.FilePosition.Row != FileBuffer.FilePosition.Row) | |
|| (FileBufferBackupVar.FilePosition.Column != FileBuffer.FilePosition.Column) | |
|| (FileBufferBackupVar.ModeInsert != FileBuffer.ModeInsert) | |
|| StatusBarGetRefresh ()) | |
{ | |
StatusBarRefresh (EditorFirst, MainEditor.ScreenSize.Row, MainEditor.ScreenSize.Column, MainEditor.FileBuffer->FilePosition.Row, MainEditor.FileBuffer->FilePosition.Column, MainEditor.FileBuffer->ModeInsert); | |
FileBufferRestorePosition (); | |
} | |
if (EditorFirst) { | |
FileBufferRestorePosition (); | |
} | |
FileBufferRefresh (); | |
// | |
// EditorFirst is now set to FALSE | |
// | |
EditorFirst = FALSE; | |
} | |
/** | |
Get's the resultant location of the cursor based on the relative movement of the Mouse. | |
@param[in] GuidX The relative mouse movement. | |
@return The X location of the mouse. | |
**/ | |
INT32 | |
GetTextX ( | |
IN INT32 GuidX | |
) | |
{ | |
INT32 Gap; | |
MainEditor.MouseAccumulatorX += GuidX; | |
Gap = (MainEditor.MouseAccumulatorX * (INT32)MainEditor.ScreenSize.Column) / (INT32)(50 * (INT32)MainEditor.MouseInterface->Mode->ResolutionX); | |
MainEditor.MouseAccumulatorX = (MainEditor.MouseAccumulatorX * (INT32)MainEditor.ScreenSize.Column) % (INT32)(50 * (INT32)MainEditor.MouseInterface->Mode->ResolutionX); | |
MainEditor.MouseAccumulatorX = MainEditor.MouseAccumulatorX / (INT32)MainEditor.ScreenSize.Column; | |
return Gap; | |
} | |
/** | |
Get's the resultant location of the cursor based on the relative movement of the Mouse. | |
@param[in] GuidY The relative mouse movement. | |
@return The Y location of the mouse. | |
**/ | |
INT32 | |
GetTextY ( | |
IN INT32 GuidY | |
) | |
{ | |
INT32 Gap; | |
MainEditor.MouseAccumulatorY += GuidY; | |
Gap = (MainEditor.MouseAccumulatorY * (INT32)MainEditor.ScreenSize.Row) / (INT32)(50 * (INT32)MainEditor.MouseInterface->Mode->ResolutionY); | |
MainEditor.MouseAccumulatorY = (MainEditor.MouseAccumulatorY * (INT32)MainEditor.ScreenSize.Row) % (INT32)(50 * (INT32)MainEditor.MouseInterface->Mode->ResolutionY); | |
MainEditor.MouseAccumulatorY = MainEditor.MouseAccumulatorY / (INT32)MainEditor.ScreenSize.Row; | |
return Gap; | |
} | |
/** | |
Support mouse movement. Move the cursor. | |
@param[in] MouseState The current mouse state. | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_NOT_FOUND There was no mouse support found. | |
**/ | |
EFI_STATUS | |
MainEditorHandleMouseInput ( | |
IN EFI_SIMPLE_POINTER_STATE MouseState | |
) | |
{ | |
INT32 TextX; | |
INT32 TextY; | |
UINTN FRow; | |
UINTN FCol; | |
LIST_ENTRY *Link; | |
EFI_EDITOR_LINE *Line; | |
UINTN Index; | |
BOOLEAN Action; | |
// | |
// mouse action means: | |
// mouse movement | |
// mouse left button | |
// | |
Action = FALSE; | |
// | |
// have mouse movement | |
// | |
if (MouseState.RelativeMovementX || MouseState.RelativeMovementY) { | |
// | |
// handle | |
// | |
TextX = GetTextX (MouseState.RelativeMovementX); | |
TextY = GetTextY (MouseState.RelativeMovementY); | |
FileBufferAdjustMousePosition (TextX, TextY); | |
Action = TRUE; | |
} | |
// | |
// if left button pushed down | |
// | |
if (MouseState.LeftButton) { | |
FCol = MainEditor.FileBuffer->MousePosition.Column - 1 + 1; | |
FRow = MainEditor.FileBuffer->FilePosition.Row + | |
MainEditor.FileBuffer->MousePosition.Row - | |
MainEditor.FileBuffer->DisplayPosition.Row; | |
// | |
// beyond the file line length | |
// | |
if (MainEditor.FileBuffer->NumLines < FRow) { | |
FRow = MainEditor.FileBuffer->NumLines; | |
} | |
Link = MainEditor.FileBuffer->ListHead->ForwardLink; | |
for (Index = 0; Index < FRow - 1; Index++) { | |
Link = Link->ForwardLink; | |
} | |
Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE); | |
// | |
// beyond the line's column length | |
// | |
if (FCol > Line->Size + 1) { | |
FCol = Line->Size + 1; | |
} | |
FileBufferMovePosition (FRow, FCol); | |
MainEditor.FileBuffer->MousePosition.Row = MainEditor.FileBuffer->DisplayPosition.Row; | |
MainEditor.FileBuffer->MousePosition.Column = MainEditor.FileBuffer->DisplayPosition.Column; | |
Action = TRUE; | |
} | |
// | |
// mouse has action | |
// | |
if (Action) { | |
return EFI_SUCCESS; | |
} | |
// | |
// no mouse action | |
// | |
return EFI_NOT_FOUND; | |
} | |
/** | |
Handle user key input. This routes to other functions for the actions. | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_LOAD_ERROR A load error occurred. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
**/ | |
EFI_STATUS | |
MainEditorKeyInput ( | |
VOID | |
) | |
{ | |
EFI_KEY_DATA KeyData; | |
EFI_STATUS Status; | |
EFI_SIMPLE_POINTER_STATE MouseState; | |
BOOLEAN NoShiftState; | |
do { | |
Status = EFI_SUCCESS; | |
EditorMouseAction = FALSE; | |
// | |
// backup some key elements, so that can aVOID some refresh work | |
// | |
MainEditorBackup (); | |
// | |
// change priority of checking mouse/keyboard activity dynamically | |
// so prevent starvation of keyboard. | |
// if last time, mouse moves then this time check keyboard | |
// | |
if (MainEditor.MouseSupported) { | |
Status = MainEditor.MouseInterface->GetState ( | |
MainEditor.MouseInterface, | |
&MouseState | |
); | |
if (!EFI_ERROR (Status)) { | |
Status = MainEditorHandleMouseInput (MouseState); | |
if (!EFI_ERROR (Status)) { | |
EditorMouseAction = TRUE; | |
FileBufferMouseNeedRefresh = TRUE; | |
} else if (Status == EFI_LOAD_ERROR) { | |
StatusBarSetStatusString (L"Invalid Mouse Movement "); | |
} | |
} | |
} | |
// | |
// CheckEvent() returns Success when non-partial key is pressed. | |
// | |
Status = gBS->CheckEvent (MainEditor.TextInputEx->WaitForKeyEx); | |
if (!EFI_ERROR (Status)) { | |
Status = MainEditor.TextInputEx->ReadKeyStrokeEx (MainEditor.TextInputEx, &KeyData); | |
if (!EFI_ERROR (Status)) { | |
// | |
// dispatch to different components' key handling function | |
// so not everywhere has to set this variable | |
// | |
FileBufferMouseNeedRefresh = TRUE; | |
// | |
// clear previous status string | |
// | |
StatusBarSetRefresh (); | |
// | |
// NoShiftState: TRUE when no shift key is pressed. | |
// | |
NoShiftState = ((KeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) == 0) || (KeyData.KeyState.KeyShiftState == EFI_SHIFT_STATE_VALID); | |
// | |
// dispatch to different components' key handling function | |
// | |
if (EFI_NOT_FOUND != MenuBarDispatchControlHotKey (&KeyData)) { | |
Status = EFI_SUCCESS; | |
} else if (NoShiftState && ((KeyData.Key.ScanCode == SCAN_NULL) || ((KeyData.Key.ScanCode >= SCAN_UP) && (KeyData.Key.ScanCode <= SCAN_PAGE_DOWN)))) { | |
Status = FileBufferHandleInput (&KeyData.Key); | |
} else if (NoShiftState && (KeyData.Key.ScanCode >= SCAN_F1) && (KeyData.Key.ScanCode <= SCAN_F12)) { | |
Status = MenuBarDispatchFunctionKey (&KeyData.Key); | |
} else { | |
StatusBarSetStatusString (L"Unknown Command"); | |
FileBufferMouseNeedRefresh = FALSE; | |
} | |
if ((Status != EFI_SUCCESS) && (Status != EFI_OUT_OF_RESOURCES)) { | |
// | |
// not already has some error status | |
// | |
if ((StatusBarGetString () != NULL) && (StrCmp (L"", StatusBarGetString ()) == 0)) { | |
StatusBarSetStatusString (L"Disk Error. Try Again"); | |
} | |
} | |
} | |
} | |
// | |
// after handling, refresh editor | |
// | |
MainEditorRefresh (); | |
} while (Status != EFI_OUT_OF_RESOURCES && !EditorExit); | |
return Status; | |
} | |
/** | |
Set clipboard | |
@param[in] Line A pointer to the line to be set to clipboard | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
**/ | |
EFI_STATUS | |
MainEditorSetCutLine ( | |
EFI_EDITOR_LINE *Line | |
) | |
{ | |
if (Line == NULL) { | |
return EFI_SUCCESS; | |
} | |
if (MainEditor.CutLine != NULL) { | |
// | |
// free the old clipboard | |
// | |
LineFree (MainEditor.CutLine); | |
} | |
// | |
// duplicate the line to clipboard | |
// | |
MainEditor.CutLine = LineDup (Line); | |
if (MainEditor.CutLine == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Backup function for MainEditor | |
@retval EFI_SUCCESS The operation was successful. | |
**/ | |
EFI_STATUS | |
MainEditorBackup ( | |
VOID | |
) | |
{ | |
FileBufferBackup (); | |
return EFI_SUCCESS; | |
} |