/** @file Implements editor interface functions. Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
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; }