| /** @file | |
| Implements editor interface functions. | |
| Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved. <BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #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 occured. | |
| @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 occured. | |
| **/ | |
| 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 occured. | |
| **/ | |
| 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 occured. | |
| **/ | |
| 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 occured. | |
| **/ | |
| 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 occured. | |
| **/ | |
| 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 occured. | |
| **/ | |
| 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 occured. | |
| @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 occured. | |
| **/ | |
| 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 occured. | |
| **/ | |
| 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 occured. | |
| **/ | |
| 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 occured. | |
| **/ | |
| 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 occured. | |
| **/ | |
| 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 occured. | |
| **/ | |
| 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_INPUT_KEY Key; | |
| // | |
| // 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 | |
| // | |
| do { | |
| gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); | |
| } while(SCAN_CONTROL_W != Key.UnicodeChar); | |
| // | |
| // 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, | |
| FALSE, | |
| NULL | |
| }; | |
| /** | |
| The initialization function for MainEditor. | |
| @retval EFI_SUCCESS The operation was successful. | |
| @retval EFI_LOAD_ERROR A load error occured. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| 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 mouse in System Table ConsoleInHandle | |
| // | |
| Status = gBS->HandleProtocol ( | |
| gST->ConIn, | |
| &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 (); | |
| 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 occured. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| 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 | |
| EFIAPI | |
| 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 | |
| EFIAPI | |
| 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 | |
| EFIAPI | |
| 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 | |
| EFIAPI | |
| 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 occured. | |
| @retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| MainEditorKeyInput ( | |
| VOID | |
| ) | |
| { | |
| EFI_INPUT_KEY Key; | |
| EFI_STATUS Status; | |
| EFI_SIMPLE_POINTER_STATE MouseState; | |
| 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 "); | |
| } | |
| } | |
| } | |
| Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); | |
| 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(); | |
| // | |
| // dispatch to different components' key handling function | |
| // | |
| if (EFI_NOT_FOUND != MenuBarDispatchControlHotKey(&Key)) { | |
| Status = EFI_SUCCESS; | |
| } else if ((Key.ScanCode == SCAN_NULL) || ((Key.ScanCode >= SCAN_UP) && (Key.ScanCode <= SCAN_PAGE_DOWN))) { | |
| Status = FileBufferHandleInput (&Key); | |
| } else if ((Key.ScanCode >= SCAN_F1) && (Key.ScanCode <= SCAN_F12)) { | |
| Status = MenuBarDispatchFunctionKey (&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 | |
| EFIAPI | |
| 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 | |
| EFIAPI | |
| MainEditorBackup ( | |
| VOID | |
| ) | |
| { | |
| FileBufferBackup (); | |
| return EFI_SUCCESS; | |
| } |