diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c | 1974 |
1 files changed, 1974 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c new file mode 100644 index 00000000..3c3c587d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c @@ -0,0 +1,1974 @@ +/** @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; +} |