summaryrefslogtreecommitdiff
path: root/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit
diff options
context:
space:
mode:
Diffstat (limited to 'Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit')
-rw-r--r--Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Edit.c162
-rw-r--r--Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c3370
-rw-r--r--Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.h263
-rw-r--r--Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c1936
-rw-r--r--Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.h77
-rw-r--r--Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.c92
-rw-r--r--Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.h52
-rw-r--r--Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni75
-rw-r--r--Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditor.h32
-rw-r--r--Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditorTypes.h102
10 files changed, 6161 insertions, 0 deletions
diff --git a/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Edit.c b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Edit.c
new file mode 100644
index 0000000000..986b7e7b88
--- /dev/null
+++ b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Edit.c
@@ -0,0 +1,162 @@
+/** @file
+ Main file for Edit shell Debug1 function.
+
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
+ Copyright (c) 2005 - 2011, 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 "UefiShellDebug1CommandsLib.h"
+#include "TextEditor.h"
+
+/**
+ Function for 'edit' command.
+
+ @param[in] ImageHandle Handle to the Image (NULL if Internal).
+ @param[in] SystemTable Pointer to the System Table (NULL if Internal).
+**/
+SHELL_STATUS
+EFIAPI
+ShellCommandRunEdit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *Buffer;
+ CHAR16 *ProblemParam;
+ SHELL_STATUS ShellStatus;
+ LIST_ENTRY *Package;
+ CONST CHAR16 *Cwd;
+ CHAR16 *Nfs;
+ CHAR16 *Spot;
+ CONST CHAR16 *TempParam;
+// SHELL_FILE_HANDLE TempHandle;
+
+ Buffer = NULL;
+ ShellStatus = SHELL_SUCCESS;
+ Nfs = NULL;
+
+ //
+ // initialize the shell lib (we must be in non-auto-init...)
+ //
+ Status = ShellInitialize();
+ ASSERT_EFI_ERROR(Status);
+
+ Status = CommandInit();
+ ASSERT_EFI_ERROR(Status);
+
+ //
+ // parse the command line
+ //
+ Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE);
+ if (EFI_ERROR(Status)) {
+ if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"edit", ProblemParam);
+ FreePool(ProblemParam);
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ } else {
+ ASSERT(FALSE);
+ }
+ } else {
+ if (ShellCommandLineGetCount(Package) > 2) {
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"edit");
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ } else {
+ Cwd = gEfiShellProtocol->GetCurDir(NULL);
+ if (Cwd == NULL) {
+ Cwd = ShellGetEnvironmentVariable(L"path");
+ if (Cwd != NULL) {
+ Nfs = StrnCatGrow(&Nfs, NULL, Cwd+3, 0);
+ if (Nfs != NULL) {
+ Spot = StrStr(Nfs, L";");
+ if (Spot != NULL) {
+ *Spot = CHAR_NULL;
+ }
+ Spot = StrStr(Nfs, L"\\");
+ if (Spot != NULL) {
+ Spot[1] = CHAR_NULL;
+ }
+ gEfiShellProtocol->SetCurDir(NULL, Nfs);
+ FreePool(Nfs);
+ }
+ }
+ }
+
+ Status = MainEditorInit ();
+
+ if (EFI_ERROR (Status)) {
+ gST->ConOut->ClearScreen (gST->ConOut);
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_INIT_FAILED), gShellDebug1HiiHandle);
+ } else {
+ MainEditorBackup ();
+
+ //
+ // if editor launched with file named
+ //
+ if (ShellCommandLineGetCount(Package) == 2) {
+ TempParam = ShellCommandLineGetRawValue(Package, 1);
+ ASSERT(TempParam != NULL);
+ FileBufferSetFileName (TempParam);
+// if (EFI_ERROR(ShellFileExists(MainEditor.FileBuffer->FileName))) {
+// Status = ShellOpenFileByName(MainEditor.FileBuffer->FileName, &TempHandle, EFI_FILE_MODE_CREATE|EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0);
+// if (!EFI_ERROR(Status)) {
+// ShellCloseFile(&TempHandle);
+// }
+// }
+ }
+
+ Status = FileBufferRead (MainEditor.FileBuffer->FileName, FALSE);
+ if (!EFI_ERROR (Status)) {
+ MainEditorRefresh ();
+
+ Status = MainEditorKeyInput ();
+ }
+
+ if (Status != EFI_OUT_OF_RESOURCES) {
+ //
+ // back up the status string
+ //
+ Buffer = CatSPrint (NULL, L"%s", StatusBarGetString());
+ }
+
+ MainEditorCleanup ();
+
+ //
+ // print editor exit code on screen
+ //
+ if (Status == EFI_SUCCESS) {
+ } else if (Status == EFI_OUT_OF_RESOURCES) {
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_GEN_OUT_MEM), gShellDebug1HiiHandle, L"edit");
+ } else {
+ if (Buffer != NULL) {
+ if (StrCmp (Buffer, L"") != 0) {
+ //
+ // print out the status string
+ //
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_BUFFER), gShellDebug1HiiHandle, Buffer);
+ } else {
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_UNKNOWN_EDITOR_ERR), gShellDebug1HiiHandle);
+ }
+ } else {
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_MAIN_UNKNOWN_EDITOR_ERR), gShellDebug1HiiHandle);
+ }
+ }
+
+ if (Status != EFI_OUT_OF_RESOURCES) {
+ SHELL_FREE_NON_NULL (Buffer);
+ }
+ }
+ }
+ ShellCommandLineFreeVarList (Package);
+ }
+ return ShellStatus;
+}
diff --git a/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c
new file mode 100644
index 0000000000..efe0df0253
--- /dev/null
+++ b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.c
@@ -0,0 +1,3370 @@
+/** @file
+ Implements filebuffer 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 <Guid/FileSystemInfo.h>
+#include <Library/FileHandleLib.h>
+
+EFI_EDITOR_FILE_BUFFER FileBuffer;
+EFI_EDITOR_FILE_BUFFER FileBufferBackupVar;
+
+//
+// for basic initialization of FileBuffer
+//
+EFI_EDITOR_FILE_BUFFER FileBufferConst = {
+ NULL,
+ FileTypeUnicode,
+ NULL,
+ NULL,
+ 0,
+ {
+ 0,
+ 0
+ },
+ {
+ 0,
+ 0
+ },
+ {
+ 0,
+ 0
+ },
+ {
+ 0,
+ 0
+ },
+ FALSE,
+ TRUE,
+ FALSE,
+ NULL
+};
+
+//
+// the whole edit area needs to be refreshed
+//
+BOOLEAN FileBufferNeedRefresh;
+
+//
+// only the current line in edit area needs to be refresh
+//
+BOOLEAN FileBufferOnlyLineNeedRefresh;
+
+BOOLEAN FileBufferMouseNeedRefresh;
+
+extern BOOLEAN EditorMouseAction;
+
+/**
+ Initialization function for FileBuffer.
+
+ @param EFI_SUCCESS The initialization was successful.
+ @param EFI_LOAD_ERROR A default name could not be created.
+ @param EFI_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferInit (
+ VOID
+ )
+{
+ //
+ // basically initialize the FileBuffer
+ //
+ CopyMem (&FileBuffer , &FileBufferConst, sizeof (EFI_EDITOR_FILE_BUFFER));
+ CopyMem (&FileBufferBackupVar, &FileBufferConst, sizeof (EFI_EDITOR_FILE_BUFFER));
+
+ //
+ // set default FileName
+ //
+ FileBuffer.FileName = EditGetDefaultFileName (L"txt");
+ if (FileBuffer.FileName == NULL) {
+ return EFI_LOAD_ERROR;
+ }
+
+ FileBuffer.ListHead = AllocateZeroPool (sizeof (LIST_ENTRY));
+ if (FileBuffer.ListHead == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InitializeListHead (FileBuffer.ListHead);
+
+ FileBuffer.DisplayPosition.Row = 2;
+ FileBuffer.DisplayPosition.Column = 1;
+ FileBuffer.LowVisibleRange.Row = 2;
+ FileBuffer.LowVisibleRange.Column = 1;
+
+ FileBufferNeedRefresh = FALSE;
+ FileBufferMouseNeedRefresh = FALSE;
+ FileBufferOnlyLineNeedRefresh = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Backup function for FileBuffer. Only backup the following items:
+ Mouse/Cursor position
+ File Name, Type, ReadOnly, Modified
+ Insert Mode
+
+ This is for making the file buffer refresh as few as possible.
+
+ @retval EFI_SUCCESS The backup operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferBackup (
+ VOID
+ )
+{
+ FileBufferBackupVar.MousePosition = FileBuffer.MousePosition;
+
+ SHELL_FREE_NON_NULL (FileBufferBackupVar.FileName);
+ FileBufferBackupVar.FileName = NULL;
+ FileBufferBackupVar.FileName = StrnCatGrow (&FileBufferBackupVar.FileName, NULL, FileBuffer.FileName, 0);
+
+ FileBufferBackupVar.ModeInsert = FileBuffer.ModeInsert;
+ FileBufferBackupVar.FileType = FileBuffer.FileType;
+
+ FileBufferBackupVar.FilePosition = FileBuffer.FilePosition;
+ FileBufferBackupVar.LowVisibleRange = FileBuffer.LowVisibleRange;
+
+ FileBufferBackupVar.FileModified = FileBuffer.FileModified;
+ FileBufferBackupVar.ReadOnly = FileBuffer.ReadOnly;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Advance to the next Count lines
+
+ @param[in] Count The line number to advance by.
+ @param[in] CurrentLine The pointer to the current line structure.
+ @param[in] LineList The pointer to the linked list of lines.
+
+ @retval NULL There was an error.
+ @return The line structure after the advance.
+**/
+EFI_EDITOR_LINE *
+EFIAPI
+InternalEditorMiscLineAdvance (
+ IN CONST UINTN Count,
+ IN CONST EFI_EDITOR_LINE *CurrentLine,
+ IN CONST LIST_ENTRY *LineList
+ )
+
+{
+ UINTN Index;
+ CONST EFI_EDITOR_LINE *Line;
+
+ if (CurrentLine == NULL || LineList == NULL) {
+ return NULL;
+ }
+
+ for (Line = CurrentLine, Index = 0; Index < Count; Index++) {
+ //
+ // if already last line
+ //
+ if (Line->Link.ForwardLink == LineList) {
+ return NULL;
+ }
+
+ Line = CR (Line->Link.ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+ }
+
+ return ((EFI_EDITOR_LINE *)Line);
+}
+
+/**
+ Retreat to the previous Count lines.
+
+ @param[in] Count The line number to retreat by.
+ @param[in] CurrentLine The pointer to the current line structure.
+ @param[in] LineList The pointer to the linked list of lines.
+
+ @retval NULL There was an error.
+ @return The line structure after the retreat.
+**/
+EFI_EDITOR_LINE *
+EFIAPI
+InternalEditorMiscLineRetreat (
+ IN CONST UINTN Count,
+ IN CONST EFI_EDITOR_LINE *CurrentLine,
+ IN CONST LIST_ENTRY *LineList
+ )
+
+{
+ UINTN Index;
+ CONST EFI_EDITOR_LINE *Line;
+
+ if (CurrentLine == NULL || LineList == NULL) {
+ return NULL;
+ }
+
+ for (Line = CurrentLine, Index = 0; Index < Count; Index++) {
+ //
+ // already the first line
+ //
+ if (Line->Link.BackLink == LineList) {
+ return NULL;
+ }
+
+ Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+ }
+
+ return ((EFI_EDITOR_LINE *)Line);
+}
+
+/**
+ Advance/Retreat lines
+
+ @param[in] Count line number to advance/retreat
+ >0 : advance
+ <0 : retreat
+
+ @retval NULL An error occured.
+ @return The line after advance/retreat.
+**/
+EFI_EDITOR_LINE *
+MoveLine (
+ IN CONST INTN Count
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ UINTN AbsCount;
+
+ //
+ // if < 0, then retreat
+ // if > 0, the advance
+ //
+ if (Count <= 0) {
+ AbsCount = (UINTN)ABS(Count);
+ Line = InternalEditorMiscLineRetreat (AbsCount,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);
+ } else {
+ Line = InternalEditorMiscLineAdvance ((UINTN)Count,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);
+ }
+
+ return Line;
+}
+
+/**
+ Function to update the 'screen' to display the mouse position.
+
+ @retval EFI_SUCCESS The backup operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferRestoreMousePosition (
+ VOID
+ )
+{
+ EFI_EDITOR_COLOR_UNION Orig;
+ EFI_EDITOR_COLOR_UNION New;
+ UINTN FRow;
+ UINTN FColumn;
+ BOOLEAN HasCharacter;
+ EFI_EDITOR_LINE *CurrentLine;
+ EFI_EDITOR_LINE *Line;
+ CHAR16 Value;
+
+ //
+ // variable initialization
+ //
+ Line = NULL;
+
+ if (MainEditor.MouseSupported) {
+
+ if (FileBufferMouseNeedRefresh) {
+
+ FileBufferMouseNeedRefresh = FALSE;
+
+ //
+ // if mouse position not moved and only mouse action
+ // so do not need to refresh mouse position
+ //
+ if ((FileBuffer.MousePosition.Row == FileBufferBackupVar.MousePosition.Row &&
+ FileBuffer.MousePosition.Column == FileBufferBackupVar.MousePosition.Column)
+ && EditorMouseAction) {
+ return EFI_SUCCESS;
+ }
+ //
+ // backup the old screen attributes
+ //
+ Orig = MainEditor.ColorAttributes;
+ New.Data = 0;
+ New.Colors.Foreground = Orig.Colors.Background & 0xF;
+ New.Colors.Background = Orig.Colors.Foreground & 0x7;
+
+ //
+ // clear the old mouse position
+ //
+ FRow = FileBuffer.LowVisibleRange.Row + FileBufferBackupVar.MousePosition.Row - 2;
+
+ FColumn = FileBuffer.LowVisibleRange.Column + FileBufferBackupVar.MousePosition.Column - 1;
+
+ HasCharacter = TRUE;
+ if (FRow > FileBuffer.NumLines) {
+ HasCharacter = FALSE;
+ } else {
+ CurrentLine = FileBuffer.CurrentLine;
+ Line = MoveLine (FRow - FileBuffer.FilePosition.Row);
+
+ if (Line == NULL || FColumn > Line->Size) {
+ HasCharacter = FALSE;
+ }
+
+ FileBuffer.CurrentLine = CurrentLine;
+ }
+
+ ShellPrintEx (
+ (INT32)FileBufferBackupVar.MousePosition.Column - 1,
+ (INT32)FileBufferBackupVar.MousePosition.Row - 1,
+ L" "
+ );
+
+ if (HasCharacter) {
+ Value = (Line->Buffer[FColumn - 1]);
+ ShellPrintEx (
+ (INT32)FileBufferBackupVar.MousePosition.Column - 1,
+ (INT32)FileBufferBackupVar.MousePosition.Row - 1,
+ L"%c",
+ Value
+ );
+ }
+ //
+ // set the new mouse position
+ //
+ gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F);
+
+ //
+ // clear the old mouse position
+ //
+ FRow = FileBuffer.LowVisibleRange.Row + FileBuffer.MousePosition.Row - 2;
+ FColumn = FileBuffer.LowVisibleRange.Column + FileBuffer.MousePosition.Column - 1;
+
+ HasCharacter = TRUE;
+ if (FRow > FileBuffer.NumLines) {
+ HasCharacter = FALSE;
+ } else {
+ CurrentLine = FileBuffer.CurrentLine;
+ Line = MoveLine (FRow - FileBuffer.FilePosition.Row);
+
+ if (Line == NULL || FColumn > Line->Size) {
+ HasCharacter = FALSE;
+ }
+
+ FileBuffer.CurrentLine = CurrentLine;
+ }
+
+ ShellPrintEx (
+ (INT32)FileBuffer.MousePosition.Column - 1,
+ (INT32)FileBuffer.MousePosition.Row - 1,
+ L" "
+ );
+
+ if (HasCharacter) {
+ Value = Line->Buffer[FColumn - 1];
+ ShellPrintEx (
+ (INT32)FileBuffer.MousePosition.Column - 1,
+ (INT32)FileBuffer.MousePosition.Row - 1,
+ L"%c",
+ Value
+ );
+ }
+ //
+ // end of HasCharacter
+ //
+ gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);
+ }
+ //
+ // end of MouseNeedRefresh
+ //
+ }
+ //
+ // end of MouseSupported
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Free all the lines in FileBuffer
+ Fields affected:
+ Lines
+ CurrentLine
+ NumLines
+ ListHead
+
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferFreeLines (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_EDITOR_LINE *Line;
+
+ //
+ // free all the lines
+ //
+ if (FileBuffer.Lines != NULL) {
+
+ Line = FileBuffer.Lines;
+ Link = &(Line->Link);
+ do {
+ Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+ Link = Link->ForwardLink;
+
+ //
+ // free line's buffer and line itself
+ //
+ LineFree (Line);
+ } while (Link != FileBuffer.ListHead);
+ }
+ //
+ // clean the line list related structure
+ //
+ FileBuffer.Lines = NULL;
+ FileBuffer.CurrentLine = NULL;
+ FileBuffer.NumLines = 0;
+
+ FileBuffer.ListHead->ForwardLink = FileBuffer.ListHead;
+ FileBuffer.ListHead->BackLink = FileBuffer.ListHead;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Cleanup function for FileBuffer.
+
+ @retval EFI_SUCCESS The cleanup was successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferCleanup (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ SHELL_FREE_NON_NULL (FileBuffer.FileName);
+
+ //
+ // free all the lines
+ //
+ Status = FileBufferFreeLines ();
+
+ SHELL_FREE_NON_NULL (FileBuffer.ListHead);
+ FileBuffer.ListHead = NULL;
+
+ SHELL_FREE_NON_NULL (FileBufferBackupVar.FileName);
+ return Status;
+
+}
+
+/**
+ Print a line specified by Line on a row specified by Row of the screen.
+
+ @param[in] Line The line to print.
+ @param[in] Row The row on the screen to print onto (begin from 1).
+
+ @retval EFI_SUCCESS The printing was successful.
+**/
+EFI_STATUS
+FileBufferPrintLine (
+ IN CONST EFI_EDITOR_LINE *Line,
+ IN CONST UINTN Row
+ )
+{
+
+ CHAR16 *Buffer;
+ UINTN Limit;
+ CHAR16 *PrintLine;
+ CHAR16 *PrintLine2;
+ UINTN BufLen;
+
+ //
+ // print start from correct character
+ //
+ Buffer = Line->Buffer + FileBuffer.LowVisibleRange.Column - 1;
+
+ Limit = Line->Size - FileBuffer.LowVisibleRange.Column + 1;
+ if (Limit > Line->Size) {
+ Limit = 0;
+ }
+
+ BufLen = (MainEditor.ScreenSize.Column + 1) * sizeof (CHAR16);
+ PrintLine = AllocatePool (BufLen);
+ if (PrintLine != NULL) {
+ StrnCpyS (PrintLine, BufLen/sizeof(CHAR16), Buffer, MIN(Limit, MainEditor.ScreenSize.Column));
+ for (; Limit < MainEditor.ScreenSize.Column; Limit++) {
+ PrintLine[Limit] = L' ';
+ }
+
+ PrintLine[MainEditor.ScreenSize.Column] = CHAR_NULL;
+
+ PrintLine2 = AllocatePool (BufLen * 2);
+ if (PrintLine2 != NULL) {
+ ShellCopySearchAndReplace(PrintLine, PrintLine2, BufLen * 2, L"%", L"^%", FALSE, FALSE);
+
+ ShellPrintEx (
+ 0,
+ (INT32)Row - 1,
+ L"%s",
+ PrintLine2
+ );
+ FreePool (PrintLine2);
+ }
+ FreePool (PrintLine);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the cursor position according to FileBuffer.DisplayPosition.
+
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferRestorePosition (
+ VOID
+ )
+{
+ //
+ // set cursor position
+ //
+ return (gST->ConOut->SetCursorPosition (
+ gST->ConOut,
+ FileBuffer.DisplayPosition.Column - 1,
+ FileBuffer.DisplayPosition.Row - 1
+ ));
+}
+
+/**
+ Refresh the screen with whats in the buffer.
+
+ @retval EFI_SUCCESS The refresh was successful.
+ @retval EFI_LOAD_ERROR There was an error finding what to write.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferRefresh (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ EFI_EDITOR_LINE *Line;
+ UINTN Row;
+
+ //
+ // if it's the first time after editor launch, so should refresh
+ //
+ if (!EditorFirst) {
+ //
+ // no definite required refresh
+ // and file position displayed on screen has not been changed
+ //
+ if (!FileBufferNeedRefresh &&
+ !FileBufferOnlyLineNeedRefresh &&
+ FileBufferBackupVar.LowVisibleRange.Row == FileBuffer.LowVisibleRange.Row &&
+ FileBufferBackupVar.LowVisibleRange.Column == FileBuffer.LowVisibleRange.Column
+ ) {
+
+ FileBufferRestoreMousePosition ();
+ FileBufferRestorePosition ();
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+
+ //
+ // only need to refresh current line
+ //
+ if (FileBufferOnlyLineNeedRefresh &&
+ FileBufferBackupVar.LowVisibleRange.Row == FileBuffer.LowVisibleRange.Row &&
+ FileBufferBackupVar.LowVisibleRange.Column == FileBuffer.LowVisibleRange.Column
+ ) {
+
+ EditorClearLine (FileBuffer.DisplayPosition.Row, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row);
+ FileBufferPrintLine (
+ FileBuffer.CurrentLine,
+ FileBuffer.DisplayPosition.Row
+ );
+ } else {
+ //
+ // the whole edit area need refresh
+ //
+
+ //
+ // no line
+ //
+ if (FileBuffer.Lines == NULL) {
+ FileBufferRestoreMousePosition ();
+ FileBufferRestorePosition ();
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);
+
+ return EFI_SUCCESS;
+ }
+ //
+ // get the first line that will be displayed
+ //
+ Line = MoveLine (FileBuffer.LowVisibleRange.Row - FileBuffer.FilePosition.Row);
+ if (Line == NULL) {
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);
+
+ return EFI_LOAD_ERROR;
+ }
+
+ Link = &(Line->Link);
+ Row = 2;
+ do {
+ Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+
+ //
+ // print line at row
+ //
+ FileBufferPrintLine (Line, Row);
+
+ Link = Link->ForwardLink;
+ Row++;
+ } while (Link != FileBuffer.ListHead && Row <= (MainEditor.ScreenSize.Row - 1));
+ //
+ // while not file end and not screen full
+ //
+ while (Row <= (MainEditor.ScreenSize.Row - 1)) {
+ EditorClearLine (Row, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row);
+ Row++;
+ }
+ }
+
+ FileBufferRestoreMousePosition ();
+ FileBufferRestorePosition ();
+
+ FileBufferNeedRefresh = FALSE;
+ FileBufferOnlyLineNeedRefresh = FALSE;
+
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a new line and append it to the line list.
+ Fields affected:
+ NumLines
+ Lines
+
+ @retval NULL The create line failed.
+ @return The line created.
+**/
+EFI_EDITOR_LINE *
+EFIAPI
+FileBufferCreateLine (
+ VOID
+ )
+{
+ EFI_EDITOR_LINE *Line;
+
+ //
+ // allocate a line structure
+ //
+ Line = AllocateZeroPool (sizeof (EFI_EDITOR_LINE));
+ if (Line == NULL) {
+ return NULL;
+ }
+ //
+ // initialize the structure
+ //
+ Line->Signature = LINE_LIST_SIGNATURE;
+ Line->Size = 0;
+ Line->TotalSize = 0;
+ Line->Type = NewLineTypeDefault;
+
+ //
+ // initial buffer of the line is "\0"
+ //
+ ASSERT(CHAR_NULL == CHAR_NULL);
+ Line->Buffer = CatSPrint (NULL, L"\0");
+ if (Line->Buffer == NULL) {
+ return NULL;
+ }
+
+ FileBuffer.NumLines++;
+
+ //
+ // insert the line into line list
+ //
+ InsertTailList (FileBuffer.ListHead, &Line->Link);
+
+ if (FileBuffer.Lines == NULL) {
+ FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+ }
+
+ return Line;
+}
+
+/**
+ Set FileName field in FileBuffer.
+
+ @param Str The file name to set.
+
+ @retval EFI_SUCCESS The filename was successfully set.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+ @retval EFI_INVALID_PARAMETER Str is not a valid filename.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferSetFileName (
+ IN CONST CHAR16 *Str
+ )
+{
+ //
+ // Verify the parameters
+ //
+ if (!IsValidFileName(Str)) {
+ return (EFI_INVALID_PARAMETER);
+ }
+ //
+ // free the old file name
+ //
+ SHELL_FREE_NON_NULL (FileBuffer.FileName);
+
+ //
+ // Allocate and set the new name
+ //
+ FileBuffer.FileName = CatSPrint (NULL, L"%s", Str);
+ if (FileBuffer.FileName == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ Free the existing file lines and reset the modified flag.
+
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferFree (
+ VOID
+ )
+{
+ //
+ // free all the lines
+ //
+ FileBufferFreeLines ();
+ FileBuffer.FileModified = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Read a file from disk into the FileBuffer.
+
+ @param[in] FileName The filename to read.
+ @param[in] Recover TRUE if is for recover mode, no information printouts.
+
+ @retval EFI_SUCCESS The load was successful.
+ @retval EFI_LOAD_ERROR The load failed.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+ @retval EFI_INVALID_PARAMETER FileName is a directory.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferRead (
+ IN CONST CHAR16 *FileName,
+ IN CONST BOOLEAN Recover
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ EE_NEWLINE_TYPE Type;
+ UINTN LoopVar1;
+ UINTN LoopVar2;
+ UINTN LineSize;
+ VOID *Buffer;
+ CHAR16 *UnicodeBuffer;
+ UINT8 *AsciiBuffer;
+ UINTN FileSize;
+ SHELL_FILE_HANDLE FileHandle;
+ BOOLEAN CreateFile;
+ EFI_STATUS Status;
+ UINTN LineSizeBackup;
+ EFI_FILE_INFO *Info;
+
+ Line = NULL;
+ LoopVar1 = 0;
+ FileSize = 0;
+ UnicodeBuffer = NULL;
+ Type = NewLineTypeDefault;
+ FileHandle = NULL;
+ CreateFile = FALSE;
+
+ //
+ // in this function, when you return error ( except EFI_OUT_OF_RESOURCES )
+ // you should set status string via StatusBarSetStatusString(L"blah")
+ // since this function maybe called before the editorhandleinput loop
+ // so any error will cause editor return
+ // so if you want to print the error status
+ // you should set the status string
+ //
+
+ //
+ // try to open the file
+ //
+ Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ, 0);
+
+ if (!EFI_ERROR(Status)) {
+ CreateFile = FALSE;
+ if (FileHandle == NULL) {
+ StatusBarSetStatusString (L"Disk Error");
+ return EFI_LOAD_ERROR;
+ }
+
+ Info = ShellGetFileInfo(FileHandle);
+
+ if (Info->Attribute & EFI_FILE_DIRECTORY) {
+ StatusBarSetStatusString (L"Directory Can Not Be Edited");
+ FreePool (Info);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Info->Attribute & EFI_FILE_READ_ONLY) {
+ FileBuffer.ReadOnly = TRUE;
+ } else {
+ FileBuffer.ReadOnly = FALSE;
+ }
+ //
+ // get file size
+ //
+ FileSize = (UINTN) Info->FileSize;
+
+ FreePool (Info);
+ } else if (Status == EFI_NOT_FOUND) {
+ //
+ // file not exists. add create and try again
+ //
+ Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_WRITE_PROTECTED ||
+ Status == EFI_ACCESS_DENIED ||
+ Status == EFI_NO_MEDIA ||
+ Status == EFI_MEDIA_CHANGED
+ ) {
+ StatusBarSetStatusString (L"Access Denied");
+ } else if (Status == EFI_DEVICE_ERROR || Status == EFI_VOLUME_CORRUPTED || Status == EFI_VOLUME_FULL) {
+ StatusBarSetStatusString (L"Disk Error");
+ } else {
+ StatusBarSetStatusString (L"Invalid File Name or Current-working-directory");
+ }
+
+ return Status;
+ } else {
+ //
+ // it worked. now delete it and move on with the name (now validated)
+ //
+ Status = ShellDeleteFile (&FileHandle);
+ if (Status == EFI_WARN_DELETE_FAILURE) {
+ Status = EFI_ACCESS_DENIED;
+ }
+ FileHandle = NULL;
+ if (EFI_ERROR (Status)) {
+ StatusBarSetStatusString (L"Access Denied");
+ return Status;
+ }
+ }
+ //
+ // file doesn't exist, so set CreateFile to TRUE
+ //
+ CreateFile = TRUE;
+ FileBuffer.ReadOnly = FALSE;
+
+ //
+ // all the check ends
+ // so now begin to set file name, free lines
+ //
+ if (StrCmp (FileName, FileBuffer.FileName) != 0) {
+ FileBufferSetFileName (FileName);
+ }
+ //
+ // free the old lines
+ //
+ FileBufferFree ();
+
+ }
+ //
+ // the file exists
+ //
+ if (!CreateFile) {
+ //
+ // allocate buffer to read file
+ //
+ Buffer = AllocateZeroPool (FileSize);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // read file into Buffer
+ //
+ Status = ShellReadFile (FileHandle, &FileSize, Buffer);
+ ShellCloseFile(&FileHandle);
+ FileHandle = NULL;
+ if (EFI_ERROR (Status)) {
+ StatusBarSetStatusString (L"Read File Failed");
+ SHELL_FREE_NON_NULL (Buffer);
+ return EFI_LOAD_ERROR;
+ }
+ //
+ // nothing in this file
+ //
+ if (FileSize == 0) {
+ SHELL_FREE_NON_NULL (Buffer);
+ //
+ // since has no head, so only can be an ASCII file
+ //
+ FileBuffer.FileType = FileTypeAscii;
+
+ goto Done;
+ }
+
+ AsciiBuffer = Buffer;
+
+ if (FileSize < 2) {
+ //
+ // size < Unicode file header, so only can be ASCII file
+ //
+ FileBuffer.FileType = FileTypeAscii;
+ } else {
+ //
+ // Unicode file
+ //
+ if (*(UINT16 *) Buffer == EFI_UNICODE_BYTE_ORDER_MARK) {
+ //
+ // Unicode file's size should be even
+ //
+ if ((FileSize % 2) != 0) {
+ StatusBarSetStatusString (L"File Format Wrong");
+ SHELL_FREE_NON_NULL (Buffer);
+ return EFI_LOAD_ERROR;
+ }
+
+ FileSize /= 2;
+
+ FileBuffer.FileType = FileTypeUnicode;
+ UnicodeBuffer = Buffer;
+
+ //
+ // pass this 0xff and 0xfe
+ //
+ UnicodeBuffer++;
+ FileSize--;
+ } else {
+ FileBuffer.FileType = FileTypeAscii;
+ }
+ //
+ // end of AsciiBuffer ==
+ //
+ }
+ //
+ // end of FileSize < 2
+ // all the check ends
+ // so now begin to set file name, free lines
+ //
+ if (StrCmp (FileName, FileBuffer.FileName) != 0) {
+ FileBufferSetFileName (FileName);
+ }
+
+ //
+ // free the old lines
+ //
+ FileBufferFree ();
+
+ //
+ // parse file content line by line
+ //
+ for (LoopVar1 = 0; LoopVar1 < FileSize; LoopVar1++) {
+ Type = NewLineTypeUnknown;
+
+ for (LineSize = LoopVar1; LineSize < FileSize; LineSize++) {
+ if (FileBuffer.FileType == FileTypeAscii) {
+ if (AsciiBuffer[LineSize] == CHAR_CARRIAGE_RETURN) {
+ Type = NewLineTypeCarriageReturn;
+
+ //
+ // has LF following
+ //
+ if (LineSize < FileSize - 1) {
+ if (AsciiBuffer[LineSize + 1] == CHAR_LINEFEED) {
+ Type = NewLineTypeCarriageReturnLineFeed;
+ }
+ }
+
+ break;
+ } else if (AsciiBuffer[LineSize] == CHAR_LINEFEED) {
+ Type = NewLineTypeLineFeed;
+
+ //
+ // has CR following
+ //
+ if (LineSize < FileSize - 1) {
+ if (AsciiBuffer[LineSize + 1] == CHAR_CARRIAGE_RETURN) {
+ Type = NewLineTypeLineFeedCarriageReturn;
+ }
+ }
+
+ break;
+ }
+ } else {
+ if (UnicodeBuffer[LineSize] == CHAR_CARRIAGE_RETURN) {
+ Type = NewLineTypeCarriageReturn;
+
+ //
+ // has LF following
+ //
+ if (LineSize < FileSize - 1) {
+ if (UnicodeBuffer[LineSize + 1] == CHAR_LINEFEED) {
+ Type = NewLineTypeCarriageReturnLineFeed;
+ }
+ }
+
+ break;
+ } else if (UnicodeBuffer[LineSize] == CHAR_LINEFEED) {
+ Type = NewLineTypeLineFeed;
+
+ //
+ // has CR following
+ //
+ if (LineSize < FileSize - 1) {
+ if (UnicodeBuffer[LineSize + 1] == CHAR_CARRIAGE_RETURN) {
+ Type = NewLineTypeLineFeedCarriageReturn;
+ }
+ }
+
+ break;
+ }
+ }
+ //
+ // endif == ASCII
+ //
+ }
+ //
+ // end of for LineSize
+ //
+ // if the type is wrong, then exit
+ //
+ if (Type == NewLineTypeUnknown) {
+ //
+ // Now if Type is NewLineTypeUnknown, it should be file end
+ //
+ Type = NewLineTypeDefault;
+ }
+
+ LineSizeBackup = LineSize;
+
+ //
+ // create a new line
+ //
+ Line = FileBufferCreateLine ();
+ if (Line == NULL) {
+ SHELL_FREE_NON_NULL (Buffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // calculate file length
+ //
+ LineSize -= LoopVar1;
+
+ //
+ // Unicode and one CHAR_NULL
+ //
+ SHELL_FREE_NON_NULL (Line->Buffer);
+ Line->Buffer = AllocateZeroPool (LineSize * 2 + 2);
+
+ if (Line->Buffer == NULL) {
+ RemoveEntryList (&Line->Link);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // copy this line to Line->Buffer
+ //
+ for (LoopVar2 = 0; LoopVar2 < LineSize; LoopVar2++) {
+ if (FileBuffer.FileType == FileTypeAscii) {
+ Line->Buffer[LoopVar2] = (CHAR16) AsciiBuffer[LoopVar1];
+ } else {
+ Line->Buffer[LoopVar2] = UnicodeBuffer[LoopVar1];
+ }
+
+ LoopVar1++;
+ }
+ //
+ // LoopVar1 now points to where CHAR_CARRIAGE_RETURN or CHAR_LINEFEED;
+ //
+ Line->Buffer[LineSize] = 0;
+
+ Line->Size = LineSize;
+ Line->TotalSize = LineSize;
+ Line->Type = Type;
+
+ if (Type == NewLineTypeCarriageReturnLineFeed || Type == NewLineTypeLineFeedCarriageReturn) {
+ LoopVar1++;
+ }
+
+ //
+ // last character is a return, SO create a new line
+ //
+ if (((Type == NewLineTypeCarriageReturnLineFeed || Type == NewLineTypeLineFeedCarriageReturn) && LineSizeBackup == FileSize - 2) ||
+ ((Type == NewLineTypeLineFeed || Type == NewLineTypeCarriageReturn) && LineSizeBackup == FileSize - 1)
+ ) {
+ Line = FileBufferCreateLine ();
+ if (Line == NULL) {
+ SHELL_FREE_NON_NULL (Buffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ //
+ // end of if
+ //
+ }
+ //
+ // end of LoopVar1
+ //
+ SHELL_FREE_NON_NULL (Buffer);
+
+ }
+ //
+ // end of if CreateFile
+ //
+Done:
+
+ FileBuffer.DisplayPosition.Row = 2;
+ FileBuffer.DisplayPosition.Column = 1;
+ FileBuffer.LowVisibleRange.Row = 1;
+ FileBuffer.LowVisibleRange.Column = 1;
+ FileBuffer.FilePosition.Row = 1;
+ FileBuffer.FilePosition.Column = 1;
+ FileBuffer.MousePosition.Row = 2;
+ FileBuffer.MousePosition.Column = 1;
+
+ if (!Recover) {
+ UnicodeBuffer = CatSPrint (NULL, L"%d Lines Read", FileBuffer.NumLines);
+ if (UnicodeBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ StatusBarSetStatusString (UnicodeBuffer);
+ FreePool (UnicodeBuffer);
+ }
+/*
+ //
+ // check whether we have fs?: in filename
+ //
+ LoopVar1 = 0;
+ FSMappingPtr = NULL;
+ while (FileName[LoopVar1] != 0) {
+ if (FileName[LoopVar1] == L':') {
+ FSMappingPtr = &FileName[LoopVar1];
+ break;
+ }
+
+ LoopVar1++;
+ }
+
+ if (FSMappingPtr == NULL) {
+ CurDir = ShellGetCurrentDir (NULL);
+ } else {
+ LoopVar1 = 0;
+ LoopVar2 = 0;
+ while (FileName[LoopVar1] != 0) {
+ if (FileName[LoopVar1] == L':') {
+ break;
+ }
+
+ FSMapping[LoopVar2++] = FileName[LoopVar1];
+
+ LoopVar1++;
+ }
+
+ FSMapping[LoopVar2] = 0;
+ CurDir = ShellGetCurrentDir (FSMapping);
+ }
+
+ if (CurDir != NULL) {
+ for (LoopVar1 = 0; LoopVar1 < StrLen (CurDir) && CurDir[LoopVar1] != ':'; LoopVar1++);
+
+ CurDir[LoopVar1] = 0;
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) ShellGetMap (CurDir);
+ FreePool (CurDir);
+ } else {
+ return EFI_LOAD_ERROR;
+ }
+
+ Status = LibDevicePathToInterface (
+ &gEfiSimpleFileSystemProtocolGuid,
+ DevicePath,
+ (VOID **) &Vol
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_LOAD_ERROR;
+ }
+
+ Status = Vol->OpenVolume (Vol, &RootFs);
+ if (EFI_ERROR (Status)) {
+ return EFI_LOAD_ERROR;
+ }
+ //
+ // Get volume information of file system
+ //
+ Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + 100;
+ VolumeInfo = (EFI_FILE_SYSTEM_INFO *) AllocateZeroPool (Size);
+ Status = RootFs->GetInfo (RootFs, &gEfiFileSystemInfoGuid, &Size, VolumeInfo);
+ if (EFI_ERROR (Status)) {
+ RootFs->Close (RootFs);
+ return EFI_LOAD_ERROR;
+ }
+
+ if (VolumeInfo->ReadOnly) {
+ StatusBarSetStatusString (L"WARNING: Volume Read Only");
+ }
+
+ FreePool (VolumeInfo);
+ RootFs->Close (RootFs);
+ }
+//
+*/
+ //
+ // has line
+ //
+ if (FileBuffer.Lines != 0) {
+ FileBuffer.CurrentLine = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+ } else {
+ //
+ // create a dummy line
+ //
+ Line = FileBufferCreateLine ();
+ if (Line == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FileBuffer.CurrentLine = Line;
+ }
+
+ FileBuffer.FileModified = FALSE;
+ FileBufferNeedRefresh = TRUE;
+ FileBufferOnlyLineNeedRefresh = FALSE;
+ FileBufferMouseNeedRefresh = TRUE;
+
+
+ return EFI_SUCCESS;
+}
+
+/**
+ According to FileBuffer.NewLineType & FileBuffer.FileType,
+ get the return buffer and size.
+
+ @param[in] Type The type of line.
+ @param[out] Buffer The buffer to fill.
+ @param[out] Size The amount of the buffer used on return.
+**/
+VOID
+EFIAPI
+GetNewLine (
+ IN CONST EE_NEWLINE_TYPE Type,
+ OUT CHAR8 *Buffer,
+ OUT UINT8 *Size
+ )
+{
+ UINT8 NewLineSize;
+
+ //
+ // give new line buffer,
+ // and will judge unicode or ascii
+ //
+ NewLineSize = 0;
+
+ //
+ // not legal new line type
+ //
+ if (Type != NewLineTypeLineFeed && Type != NewLineTypeCarriageReturn && Type != NewLineTypeCarriageReturnLineFeed && Type != NewLineTypeLineFeedCarriageReturn) {
+ *Size = 0;
+ return ;
+ }
+ //
+ // use_cr: give 0x0d
+ //
+ if (Type == NewLineTypeCarriageReturn) {
+ if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {
+ Buffer[0] = 0x0d;
+ Buffer[1] = 0;
+ NewLineSize = 2;
+ } else {
+ Buffer[0] = 0x0d;
+ NewLineSize = 1;
+ }
+
+ *Size = NewLineSize;
+ return ;
+ }
+ //
+ // use_lf: give 0x0a
+ //
+ if (Type == NewLineTypeLineFeed) {
+ if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {
+ Buffer[0] = 0x0a;
+ Buffer[1] = 0;
+ NewLineSize = 2;
+ } else {
+ Buffer[0] = 0x0a;
+ NewLineSize = 1;
+ }
+
+ *Size = NewLineSize;
+ return ;
+ }
+ //
+ // use_crlf: give 0x0d 0x0a
+ //
+ if (Type == NewLineTypeCarriageReturnLineFeed) {
+ if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {
+ Buffer[0] = 0x0d;
+ Buffer[1] = 0;
+ Buffer[2] = 0x0a;
+ Buffer[3] = 0;
+
+ NewLineSize = 4;
+ } else {
+ Buffer[0] = 0x0d;
+ Buffer[1] = 0x0a;
+ NewLineSize = 2;
+ }
+
+ *Size = NewLineSize;
+ return ;
+ }
+ //
+ // use_lfcr: give 0x0a 0x0d
+ //
+ if (Type == NewLineTypeLineFeedCarriageReturn) {
+ if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {
+ Buffer[0] = 0x0a;
+ Buffer[1] = 0;
+ Buffer[2] = 0x0d;
+ Buffer[3] = 0;
+
+ NewLineSize = 4;
+ } else {
+ Buffer[0] = 0x0a;
+ Buffer[1] = 0x0d;
+ NewLineSize = 2;
+ }
+
+ *Size = NewLineSize;
+ return ;
+ }
+
+}
+
+/**
+ Change a Unicode string to an ASCII string.
+
+ @param[in] UStr The Unicode string.
+ @param[in] Length The maximum size of AStr.
+ @param[out] AStr ASCII string to pass out.
+
+ @return The actuall length.
+**/
+UINTN
+EFIAPI
+UnicodeToAscii (
+ IN CONST CHAR16 *UStr,
+ IN CONST UINTN Length,
+ OUT CHAR8 *AStr
+ )
+{
+ UINTN Index;
+
+ //
+ // just buffer copy, not character copy
+ //
+ for (Index = 0; Index < Length; Index++) {
+ *AStr++ = (CHAR8) *UStr++;
+ }
+
+ return Index;
+}
+
+/**
+ Save lines in FileBuffer to disk
+
+ @param[in] FileName The file name for writing.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_LOAD_ERROR
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to write the file.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferSave (
+ IN CONST CHAR16 *FileName
+ )
+{
+ SHELL_FILE_HANDLE FileHandle;
+ LIST_ENTRY *Link;
+ EFI_EDITOR_LINE *Line;
+ CHAR16 *Str;
+
+ EFI_STATUS Status;
+ UINTN Length;
+ UINTN NumLines;
+ CHAR8 NewLineBuffer[4];
+ UINT8 NewLineSize;
+
+ EFI_FILE_INFO *Info;
+
+ UINT64 Attribute;
+
+ EE_NEWLINE_TYPE Type;
+
+ UINTN TotalSize;
+ //
+ // 2M
+ //
+ CHAR8 *Cache;
+ UINTN LeftSize;
+ UINTN Size;
+ CHAR8 *Ptr;
+
+ Length = 0;
+ //
+ // 2M
+ //
+ TotalSize = 0x200000;
+
+ Attribute = 0;
+
+
+
+ //
+ // if is the old file
+ //
+ if (FileBuffer.FileName != NULL && StrCmp (FileName, FileBuffer.FileName) == 0) {
+ //
+ // file has not been modified
+ //
+ if (!FileBuffer.FileModified) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // if file is read-only, set error
+ //
+ if (FileBuffer.ReadOnly) {
+ StatusBarSetStatusString (L"Read Only File Can Not Be Saved");
+ return EFI_SUCCESS;
+ }
+ }
+
+ Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0);
+
+ if (!EFI_ERROR (Status)) {
+ Info = ShellGetFileInfo(FileHandle);
+
+ if (Info != NULL && Info->Attribute & EFI_FILE_DIRECTORY) {
+ StatusBarSetStatusString (L"Directory Can Not Be Saved");
+ ShellCloseFile(FileHandle);
+ FreePool(Info);
+ return EFI_LOAD_ERROR;
+ }
+
+ if (Info != NULL) {
+ Attribute = Info->Attribute & ~EFI_FILE_READ_ONLY;
+ FreePool(Info);
+ }
+
+ //
+ // if file exits, so delete it
+ //
+ Status = ShellDeleteFile (&FileHandle);
+ if (EFI_ERROR (Status) || Status == EFI_WARN_DELETE_FAILURE) {
+ StatusBarSetStatusString (L"Write File Failed");
+ return EFI_LOAD_ERROR;
+ }
+ }
+
+ Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, Attribute);
+
+ if (EFI_ERROR (Status)) {
+ StatusBarSetStatusString (L"Create File Failed");
+ return EFI_LOAD_ERROR;
+ }
+
+ //
+ // if file is Unicode file, write Unicode header to it.
+ //
+ if (FileBuffer.FileType == FileTypeUnicode) {
+ Length = 2;
+ Status = ShellWriteFile (FileHandle, &Length, (VOID*)&gUnicodeFileTag);
+ if (EFI_ERROR (Status)) {
+ ShellDeleteFile (&FileHandle);
+ return EFI_LOAD_ERROR;
+ }
+ }
+
+ Cache = AllocateZeroPool (TotalSize);
+ if (Cache == NULL) {
+ ShellDeleteFile (&FileHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // write all the lines back to disk
+ //
+ NumLines = 0;
+ Type = NewLineTypeCarriageReturnLineFeed;
+
+ Ptr = Cache;
+ LeftSize = TotalSize;
+
+ for (Link = FileBuffer.ListHead->ForwardLink; Link != FileBuffer.ListHead; Link = Link->ForwardLink) {
+ Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+
+ if (Line->Type != NewLineTypeDefault) {
+ Type = Line->Type;
+ }
+ //
+ // newline character is at most 4 bytes ( two Unicode characters )
+ //
+ Length = 4;
+ if (Line->Buffer != NULL && Line->Size != 0) {
+ if (FileBuffer.FileType == FileTypeAscii) {
+ Length += Line->Size;
+ } else {
+ Length += (Line->Size * 2);
+ }
+ //
+ // end if FileTypeAscii
+ //
+ }
+
+ //
+ // no cache room left, so write cache to disk
+ //
+ if (LeftSize < Length) {
+ Size = TotalSize - LeftSize;
+ Status = ShellWriteFile (FileHandle, &Size, Cache);
+ if (EFI_ERROR (Status)) {
+ ShellDeleteFile (&FileHandle);
+ FreePool (Cache);
+ return EFI_LOAD_ERROR;
+ }
+ Ptr = Cache;
+ LeftSize = TotalSize;
+ }
+
+ if (Line->Buffer != NULL && Line->Size != 0) {
+ if (FileBuffer.FileType == FileTypeAscii) {
+ UnicodeToAscii (Line->Buffer, Line->Size, Ptr);
+ Length = Line->Size;
+ } else {
+ Length = (Line->Size * 2);
+ CopyMem (Ptr, (CHAR8 *) Line->Buffer, Length);
+ }
+ //
+ // end if FileTypeAscii
+ //
+ Ptr += Length;
+ LeftSize -= Length;
+
+ }
+ //
+ // end of if Line -> Buffer != NULL && Line -> Size != 0
+ //
+ // if not the last line , write return buffer to disk
+ //
+ if (Link->ForwardLink != FileBuffer.ListHead) {
+ GetNewLine (Type, NewLineBuffer, &NewLineSize);
+ CopyMem (Ptr, (CHAR8 *) NewLineBuffer, NewLineSize);
+
+ Ptr += NewLineSize;
+ LeftSize -= NewLineSize;
+ }
+
+ NumLines++;
+ }
+
+ if (TotalSize != LeftSize) {
+ Size = TotalSize - LeftSize;
+ Status = ShellWriteFile (FileHandle, &Size, Cache);
+ if (EFI_ERROR (Status)) {
+ ShellDeleteFile (&FileHandle);
+ FreePool (Cache);
+ return EFI_LOAD_ERROR;
+ }
+ }
+
+ FreePool (Cache);
+
+ ShellCloseFile(&FileHandle);
+
+ FileBuffer.FileModified = FALSE;
+
+ //
+ // set status string
+ //
+ Str = CatSPrint (NULL, L"%d Lines Wrote", NumLines);
+ if (Str == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ StatusBarSetStatusString (Str);
+ SHELL_FREE_NON_NULL (Str);
+
+ //
+ // now everything is ready , you can set the new file name to filebuffer
+ //
+ if (FileName != NULL && FileBuffer.FileName != NULL && StrCmp (FileName, FileBuffer.FileName) != 0) {
+ //
+ // not the same
+ //
+ FileBufferSetFileName (FileName);
+ if (FileBuffer.FileName == NULL) {
+ ShellDeleteFile (&FileHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ FileBuffer.ReadOnly = FALSE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Scroll cursor to left 1 character position.
+
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferScrollLeft (
+ VOID
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ UINTN FRow;
+ UINTN FCol;
+
+ Line = FileBuffer.CurrentLine;
+
+ FRow = FileBuffer.FilePosition.Row;
+ FCol = FileBuffer.FilePosition.Column;
+
+ //
+ // if already at start of this line, so move to the end of previous line
+ //
+ if (FCol <= 1) {
+ //
+ // has previous line
+ //
+ if (Line->Link.BackLink != FileBuffer.ListHead) {
+ FRow--;
+ Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+ FCol = Line->Size + 1;
+ } else {
+ return EFI_SUCCESS;
+ }
+ } else {
+ //
+ // if not at start of this line, just move to previous column
+ //
+ FCol--;
+ }
+
+ FileBufferMovePosition (FRow, FCol);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete a char in line
+
+ @param[in, out] Line The line to delete in.
+ @param[in] Pos Position to delete the char at ( start from 0 ).
+**/
+VOID
+EFIAPI
+LineDeleteAt (
+ IN OUT EFI_EDITOR_LINE *Line,
+ IN UINTN Pos
+ )
+{
+ UINTN Index;
+
+ //
+ // move the latter characters front
+ //
+ for (Index = Pos - 1; Index < Line->Size; Index++) {
+ Line->Buffer[Index] = Line->Buffer[Index + 1];
+ }
+
+ Line->Size--;
+}
+
+/**
+ Concatenate Src into Dest.
+
+ @param[in, out] Dest Destination string
+ @param[in] Src Src String.
+**/
+VOID
+EFIAPI
+LineCat (
+ IN OUT EFI_EDITOR_LINE *Dest,
+ IN EFI_EDITOR_LINE *Src
+ )
+{
+ CHAR16 *Str;
+ UINTN Size;
+
+ Size = Dest->Size;
+
+ Dest->Buffer[Size] = 0;
+
+ //
+ // concatenate the two strings
+ //
+ Str = CatSPrint (NULL, L"%s%s", Dest->Buffer, Src->Buffer);
+ if (Str == NULL) {
+ Dest->Buffer = NULL;
+ return ;
+ }
+
+ Dest->Size = Size + Src->Size;
+ Dest->TotalSize = Dest->Size;
+
+ FreePool (Dest->Buffer);
+ FreePool (Src->Buffer);
+
+ //
+ // put str to dest->buffer
+ //
+ Dest->Buffer = Str;
+}
+
+/**
+ Delete the previous character.
+
+ @retval EFI_SUCCESS The delete was successful.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferDoBackspace (
+ VOID
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ EFI_EDITOR_LINE *End;
+ LIST_ENTRY *Link;
+ UINTN FileColumn;
+
+ FileColumn = FileBuffer.FilePosition.Column;
+
+ Line = FileBuffer.CurrentLine;
+
+ //
+ // the first column
+ //
+ if (FileColumn == 1) {
+ //
+ // the first row
+ //
+ if (FileBuffer.FilePosition.Row == 1) {
+ return EFI_SUCCESS;
+ }
+
+ FileBufferScrollLeft ();
+
+ Line = FileBuffer.CurrentLine;
+ Link = Line->Link.ForwardLink;
+ End = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+
+ //
+ // concatenate this line with previous line
+ //
+ LineCat (Line, End);
+ if (Line->Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // remove End from line list
+ //
+ RemoveEntryList (&End->Link);
+ FreePool (End);
+
+ FileBuffer.NumLines--;
+
+ FileBufferNeedRefresh = TRUE;
+ FileBufferOnlyLineNeedRefresh = FALSE;
+
+ } else {
+ //
+ // just delete the previous character
+ //
+ LineDeleteAt (Line, FileColumn - 1);
+ FileBufferScrollLeft ();
+ FileBufferOnlyLineNeedRefresh = TRUE;
+ }
+
+ if (!FileBuffer.FileModified) {
+ FileBuffer.FileModified = TRUE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Add a return into line at current position.
+
+ @retval EFI_SUCCESS The insetrion of the character was successful.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferDoReturn (
+ VOID
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ EFI_EDITOR_LINE *NewLine;
+ UINTN FileColumn;
+ UINTN Index;
+ CHAR16 *Buffer;
+ UINTN Row;
+ UINTN Col;
+
+ FileBufferNeedRefresh = TRUE;
+ FileBufferOnlyLineNeedRefresh = FALSE;
+
+ Line = FileBuffer.CurrentLine;
+
+ FileColumn = FileBuffer.FilePosition.Column;
+
+ NewLine = AllocateZeroPool (sizeof (EFI_EDITOR_LINE));
+ if (NewLine == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewLine->Signature = LINE_LIST_SIGNATURE;
+ NewLine->Size = Line->Size - FileColumn + 1;
+ NewLine->TotalSize = NewLine->Size;
+ NewLine->Buffer = CatSPrint (NULL, L"\0");
+ if (NewLine->Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewLine->Type = NewLineTypeDefault;
+
+ if (NewLine->Size > 0) {
+ //
+ // UNICODE + CHAR_NULL
+ //
+ Buffer = AllocateZeroPool (2 * (NewLine->Size + 1));
+ if (Buffer == NULL) {
+ FreePool (NewLine->Buffer);
+ FreePool (NewLine);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FreePool (NewLine->Buffer);
+
+ NewLine->Buffer = Buffer;
+
+ for (Index = 0; Index < NewLine->Size; Index++) {
+ NewLine->Buffer[Index] = Line->Buffer[Index + FileColumn - 1];
+ }
+
+ NewLine->Buffer[NewLine->Size] = CHAR_NULL;
+
+ Line->Buffer[FileColumn - 1] = CHAR_NULL;
+ Line->Size = FileColumn - 1;
+ }
+ //
+ // increase NumLines
+ //
+ FileBuffer.NumLines++;
+
+ //
+ // insert it into the correct position of line list
+ //
+ NewLine->Link.BackLink = &(Line->Link);
+ NewLine->Link.ForwardLink = Line->Link.ForwardLink;
+ Line->Link.ForwardLink->BackLink = &(NewLine->Link);
+ Line->Link.ForwardLink = &(NewLine->Link);
+
+ //
+ // move cursor to the start of next line
+ //
+ Row = FileBuffer.FilePosition.Row + 1;
+ Col = 1;
+
+ FileBufferMovePosition (Row, Col);
+
+ //
+ // set file is modified
+ //
+ if (!FileBuffer.FileModified) {
+ FileBuffer.FileModified = TRUE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete current character from current line. This is the effect caused
+ by the 'del' key.
+
+ @retval EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+FileBufferDoDelete (
+ VOID
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ EFI_EDITOR_LINE *Next;
+ LIST_ENTRY *Link;
+ UINTN FileColumn;
+
+ Line = FileBuffer.CurrentLine;
+ FileColumn = FileBuffer.FilePosition.Column;
+
+ //
+ // the last column
+ //
+ if (FileColumn >= Line->Size + 1) {
+ //
+ // the last line
+ //
+ if (Line->Link.ForwardLink == FileBuffer.ListHead) {
+ return EFI_SUCCESS;
+ }
+ //
+ // since last character,
+ // so will add the next line to this line
+ //
+ Link = Line->Link.ForwardLink;
+ Next = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+ LineCat (Line, Next);
+ if (Line->Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ RemoveEntryList (&Next->Link);
+ FreePool (Next);
+
+ FileBuffer.NumLines--;
+
+ FileBufferNeedRefresh = TRUE;
+ FileBufferOnlyLineNeedRefresh = FALSE;
+
+ } else {
+ //
+ // just delete current character
+ //
+ LineDeleteAt (Line, FileColumn);
+ FileBufferOnlyLineNeedRefresh = TRUE;
+ }
+
+ if (!FileBuffer.FileModified) {
+ FileBuffer.FileModified = TRUE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Scroll cursor to right 1 character.
+
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferScrollRight (
+ VOID
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ UINTN FRow;
+ UINTN FCol;
+
+ Line = FileBuffer.CurrentLine;
+ if (Line->Buffer == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ FRow = FileBuffer.FilePosition.Row;
+ FCol = FileBuffer.FilePosition.Column;
+
+ //
+ // if already at end of this line, scroll it to the start of next line
+ //
+ if (FCol > Line->Size) {
+ //
+ // has next line
+ //
+ if (Line->Link.ForwardLink != FileBuffer.ListHead) {
+ FRow++;
+ FCol = 1;
+ } else {
+ return EFI_SUCCESS;
+ }
+ } else {
+ //
+ // if not at end of this line, just move to next column
+ //
+ FCol++;
+ }
+
+ FileBufferMovePosition (FRow, FCol);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Insert a char into line
+
+
+ @param[in] Line The line to insert into.
+ @param[in] Char The char to insert.
+ @param[in] Pos The position to insert the char at ( start from 0 ).
+ @param[in] StrSize The current string size ( include CHAR_NULL ),unit is Unicode character.
+
+ @return The new string size ( include CHAR_NULL ) ( unit is Unicode character ).
+**/
+UINTN
+EFIAPI
+LineStrInsert (
+ IN EFI_EDITOR_LINE *Line,
+ IN CHAR16 Char,
+ IN UINTN Pos,
+ IN UINTN StrSize
+ )
+{
+ UINTN Index;
+ CHAR16 *TempStringPtr;
+ CHAR16 *Str;
+
+ Index = (StrSize) * 2;
+
+ Str = Line->Buffer;
+
+ //
+ // do not have free space
+ //
+ if (Line->TotalSize <= Line->Size) {
+ Str = ReallocatePool (Index, Index + 16, Str);
+ if (Str == NULL) {
+ return 0;
+ }
+
+ Line->TotalSize += 8;
+ }
+ //
+ // move the later part of the string one character right
+ //
+ TempStringPtr = Str;
+ for (Index = StrSize; Index > Pos; Index--) {
+ TempStringPtr[Index] = TempStringPtr[Index - 1];
+ }
+ //
+ // insert char into it.
+ //
+ TempStringPtr[Index] = Char;
+
+ Line->Buffer = Str;
+ Line->Size++;
+
+ return StrSize + 1;
+}
+
+/**
+ Add a character to the current line.
+
+ @param[in] Char The Character to input.
+
+ @retval EFI_SUCCESS The input was succesful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferAddChar (
+ IN CHAR16 Char
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ UINTN FilePos;
+
+ Line = FileBuffer.CurrentLine;
+
+ //
+ // only needs to refresh current line
+ //
+ FileBufferOnlyLineNeedRefresh = TRUE;
+
+ //
+ // when is insert mode, or cursor is at end of this line,
+ // so insert this character
+ // or replace the character.
+ //
+ FilePos = FileBuffer.FilePosition.Column - 1;
+ if (FileBuffer.ModeInsert || FilePos + 1 > Line->Size) {
+ LineStrInsert (Line, Char, FilePos, Line->Size + 1);
+ } else {
+ Line->Buffer[FilePos] = Char;
+ }
+ //
+ // move cursor to right
+ //
+ FileBufferScrollRight ();
+
+ if (!FileBuffer.FileModified) {
+ FileBuffer.FileModified = TRUE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Handles inputs from characters (ASCII key + Backspace + return)
+
+ @param[in] Char The input character.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_LOAD_ERROR There was an error.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferDoCharInput (
+ IN CONST CHAR16 Char
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ switch (Char) {
+ case CHAR_NULL:
+ break;
+
+ case CHAR_BACKSPACE:
+ Status = FileBufferDoBackspace ();
+ break;
+
+ case CHAR_TAB:
+ //
+ // Tabs are ignored
+ //
+ break;
+
+ case CHAR_LINEFEED:
+ case CHAR_CARRIAGE_RETURN:
+ Status = FileBufferDoReturn ();
+ break;
+
+ default:
+ //
+ // DEAL WITH ASCII CHAR, filter out thing like ctrl+f
+ //
+ if (Char > 127 || Char < 32) {
+ Status = StatusBarSetStatusString (L"Unknown Command");
+ } else {
+ Status = FileBufferAddChar (Char);
+ }
+
+ break;
+
+ }
+
+ return Status;
+}
+
+/**
+ Scroll cursor to the next line.
+
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferScrollDown (
+ VOID
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ UINTN FRow;
+ UINTN FCol;
+
+ Line = FileBuffer.CurrentLine;
+ if (Line->Buffer == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ FRow = FileBuffer.FilePosition.Row;
+ FCol = FileBuffer.FilePosition.Column;
+
+ //
+ // has next line
+ //
+ if (Line->Link.ForwardLink != FileBuffer.ListHead) {
+ FRow++;
+ Line = CR (Line->Link.ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+
+ //
+ // if the next line is not that long, so move to end of next line
+ //
+ if (FCol > Line->Size) {
+ FCol = Line->Size + 1;
+ }
+
+ } else {
+ return EFI_SUCCESS;
+ }
+
+ FileBufferMovePosition (FRow, FCol);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Scroll the cursor to previous line.
+
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferScrollUp (
+ VOID
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ UINTN FRow;
+ UINTN FCol;
+
+ Line = FileBuffer.CurrentLine;
+
+ FRow = FileBuffer.FilePosition.Row;
+ FCol = FileBuffer.FilePosition.Column;
+
+ //
+ // has previous line
+ //
+ if (Line->Link.BackLink != FileBuffer.ListHead) {
+ FRow--;
+ Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+
+ //
+ // if previous line is not that long, so move to the end of previous line
+ //
+ if (FCol > Line->Size) {
+ FCol = Line->Size + 1;
+ }
+
+ } else {
+ return EFI_SUCCESS;
+ }
+
+ FileBufferMovePosition (FRow, FCol);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Scroll cursor to next page.
+
+ @retval EFI_SUCCESS The operation wa successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferPageDown (
+ VOID
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ UINTN FRow;
+ UINTN FCol;
+ UINTN Gap;
+
+ Line = FileBuffer.CurrentLine;
+
+ FRow = FileBuffer.FilePosition.Row;
+ FCol = FileBuffer.FilePosition.Column;
+
+ //
+ // has next page
+ //
+ if (FileBuffer.NumLines >= FRow + (MainEditor.ScreenSize.Row - 2)) {
+ Gap = (MainEditor.ScreenSize.Row - 2);
+ } else {
+ //
+ // MOVE CURSOR TO LAST LINE
+ //
+ Gap = FileBuffer.NumLines - FRow;
+ }
+ //
+ // get correct line
+ //
+ Line = MoveLine (Gap);
+
+ //
+ // if that line, is not that long, so move to the end of that line
+ //
+ if (Line != NULL && FCol > Line->Size) {
+ FCol = Line->Size + 1;
+ }
+
+ FRow += Gap;
+
+ FileBufferMovePosition (FRow, FCol);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Scroll cursor to previous screen.
+
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferPageUp (
+ VOID
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ UINTN FRow;
+ UINTN FCol;
+ UINTN Gap;
+ INTN Retreat;
+
+ Line = FileBuffer.CurrentLine;
+
+ FRow = FileBuffer.FilePosition.Row;
+ FCol = FileBuffer.FilePosition.Column;
+
+ //
+ // has previous page
+ //
+ if (FRow > (MainEditor.ScreenSize.Row - 2)) {
+ Gap = (MainEditor.ScreenSize.Row - 2);
+ } else {
+ //
+ // the first line of file will displayed on the first line of screen
+ //
+ Gap = FRow - 1;
+ }
+
+ Retreat = Gap;
+ Retreat = -Retreat;
+
+ //
+ // get correct line
+ //
+ Line = MoveLine (Retreat);
+
+ //
+ // if that line is not that long, so move to the end of that line
+ //
+ if (Line != NULL && FCol > Line->Size) {
+ FCol = Line->Size + 1;
+ }
+
+ FRow -= Gap;
+
+ FileBufferMovePosition (FRow, FCol);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Scroll cursor to end of the current line.
+
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferEnd (
+ VOID
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ UINTN FRow;
+ UINTN FCol;
+
+ Line = FileBuffer.CurrentLine;
+
+ FRow = FileBuffer.FilePosition.Row;
+
+ //
+ // goto the last column of the line
+ //
+ FCol = Line->Size + 1;
+
+ FileBufferMovePosition (FRow, FCol);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Dispatch input to different handler
+ @param[in] Key The input key. One of:
+ ASCII KEY
+ Backspace/Delete
+ Return
+ Direction key: up/down/left/right/pgup/pgdn
+ Home/End
+ INS
+
+ @retval EFI_SUCCESS The dispatch was done successfully.
+ @retval EFI_LOAD_ERROR The dispatch was not successful.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferHandleInput (
+ IN CONST EFI_INPUT_KEY *Key
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ switch (Key->ScanCode) {
+ //
+ // ordinary key input
+ //
+ case SCAN_NULL:
+ if (!FileBuffer.ReadOnly) {
+ Status = FileBufferDoCharInput (Key->UnicodeChar);
+ } else {
+ Status = StatusBarSetStatusString (L"Read Only File Can Not Be Modified");
+ }
+
+ break;
+
+ //
+ // up arrow
+ //
+ case SCAN_UP:
+ Status = FileBufferScrollUp ();
+ break;
+
+ //
+ // down arrow
+ //
+ case SCAN_DOWN:
+ Status = FileBufferScrollDown ();
+ break;
+
+ //
+ // right arrow
+ //
+ case SCAN_RIGHT:
+ Status = FileBufferScrollRight ();
+ break;
+
+ //
+ // left arrow
+ //
+ case SCAN_LEFT:
+ Status = FileBufferScrollLeft ();
+ break;
+
+ //
+ // page up
+ //
+ case SCAN_PAGE_UP:
+ Status = FileBufferPageUp ();
+ break;
+
+ //
+ // page down
+ //
+ case SCAN_PAGE_DOWN:
+ Status = FileBufferPageDown ();
+ break;
+
+ //
+ // delete
+ //
+ case SCAN_DELETE:
+ if (!FileBuffer.ReadOnly) {
+ Status = FileBufferDoDelete ();
+ } else {
+ Status = StatusBarSetStatusString (L"Read Only File Can Not Be Modified");
+ }
+
+ break;
+
+ //
+ // home
+ //
+ case SCAN_HOME:
+ FileBufferMovePosition (FileBuffer.FilePosition.Row, 1);
+ Status = EFI_SUCCESS;
+ break;
+
+ //
+ // end
+ //
+ case SCAN_END:
+ Status = FileBufferEnd ();
+ break;
+
+ //
+ // insert
+ //
+ case SCAN_INSERT:
+ FileBuffer.ModeInsert = (BOOLEAN)!FileBuffer.ModeInsert;
+ Status = EFI_SUCCESS;
+ break;
+
+ default:
+ Status = StatusBarSetStatusString (L"Unknown Command");
+ break;
+ }
+
+ return Status;
+}
+
+/**
+ Check user specified FileRow is above current screen.
+
+ @param[in] FileRow The row of file position ( start from 1 ).
+
+ @retval TRUE It is above the current screen.
+ @retval FALSE It is not above the current screen.
+**/
+BOOLEAN
+EFIAPI
+AboveCurrentScreen (
+ IN UINTN FileRow
+ )
+{
+ //
+ // if is to the above of the screen
+ //
+ if (FileRow < FileBuffer.LowVisibleRange.Row) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check user specified FileRow is under current screen.
+
+ @param[in] FileRow The row of file position ( start from 1 ).
+
+ @retval TRUE It is under the current screen.
+ @retval FALSE It is not under the current screen.
+**/
+BOOLEAN
+EFIAPI
+UnderCurrentScreen (
+ IN UINTN FileRow
+ )
+{
+ //
+ // if is to the under of the screen
+ //
+ if (FileRow > FileBuffer.LowVisibleRange.Row + (MainEditor.ScreenSize.Row - 2) - 1) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check user specified FileCol is left to current screen.
+
+ @param[in] FileCol The column of file position ( start from 1 ).
+
+ @retval TRUE It is to the left.
+ @retval FALSE It is not to the left.
+**/
+BOOLEAN
+EFIAPI
+LeftCurrentScreen (
+ IN UINTN FileCol
+ )
+{
+ //
+ // if is to the left of the screen
+ //
+ if (FileCol < FileBuffer.LowVisibleRange.Column) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check user specified FileCol is right to current screen.
+
+ @param[in] FileCol The column of file position ( start from 1 ).
+
+ @retval TRUE It is to the right.
+ @retval FALSE It is not to the right.
+**/
+BOOLEAN
+EFIAPI
+RightCurrentScreen (
+ IN UINTN FileCol
+ )
+{
+ //
+ // if is to the right of the screen
+ //
+ if (FileCol > FileBuffer.LowVisibleRange.Column + MainEditor.ScreenSize.Column - 1) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Advance/Retreat lines and set CurrentLine in FileBuffer to it
+
+ @param[in] Count The line number to advance/retreat
+ >0 : advance
+ <0: retreat
+
+ @retval NULL An error occured.
+ @return The line after advance/retreat.
+**/
+EFI_EDITOR_LINE *
+EFIAPI
+MoveCurrentLine (
+ IN INTN Count
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ UINTN AbsCount;
+
+ if (Count <= 0) {
+ AbsCount = (UINTN)ABS(Count);
+ Line = InternalEditorMiscLineRetreat (AbsCount,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);
+ } else {
+ Line = InternalEditorMiscLineAdvance ((UINTN)Count,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);
+ }
+
+ if (Line == NULL) {
+ return NULL;
+ }
+
+ MainEditor.FileBuffer->CurrentLine = Line;
+
+ return Line;
+}
+
+/**
+ According to cursor's file position, adjust screen display
+
+ @param[in] NewFilePosRow The row of file position ( start from 1 ).
+ @param[in] NewFilePosCol The column of file position ( start from 1 ).
+**/
+VOID
+EFIAPI
+FileBufferMovePosition (
+ IN CONST UINTN NewFilePosRow,
+ IN CONST UINTN NewFilePosCol
+ )
+{
+ INTN RowGap;
+ INTN ColGap;
+ UINTN Abs;
+ BOOLEAN Above;
+ BOOLEAN Under;
+ BOOLEAN Right;
+ BOOLEAN Left;
+
+ //
+ // CALCULATE gap between current file position and new file position
+ //
+ RowGap = NewFilePosRow - FileBuffer.FilePosition.Row;
+ ColGap = NewFilePosCol - FileBuffer.FilePosition.Column;
+
+ Under = UnderCurrentScreen (NewFilePosRow);
+ Above = AboveCurrentScreen (NewFilePosRow);
+ //
+ // if is below current screen
+ //
+ if (Under) {
+ //
+ // display row will be unchanged
+ //
+ FileBuffer.FilePosition.Row = NewFilePosRow;
+ } else {
+ if (Above) {
+ //
+ // has enough above line, so display row unchanged
+ // not has enough above lines, so the first line is at the
+ // first display line
+ //
+ if (NewFilePosRow < (FileBuffer.DisplayPosition.Row - 1)) {
+ FileBuffer.DisplayPosition.Row = NewFilePosRow + 1;
+ }
+
+ FileBuffer.FilePosition.Row = NewFilePosRow;
+ } else {
+ //
+ // in current screen
+ //
+ FileBuffer.FilePosition.Row = NewFilePosRow;
+ if (RowGap < 0) {
+ Abs = (UINTN)ABS(RowGap);
+ FileBuffer.DisplayPosition.Row -= Abs;
+ } else {
+ FileBuffer.DisplayPosition.Row += RowGap;
+ }
+ }
+ }
+
+ FileBuffer.LowVisibleRange.Row = FileBuffer.FilePosition.Row - (FileBuffer.DisplayPosition.Row - 2);
+
+ Right = RightCurrentScreen (NewFilePosCol);
+ Left = LeftCurrentScreen (NewFilePosCol);
+
+ //
+ // if right to current screen
+ //
+ if (Right) {
+ //
+ // display column will be changed to end
+ //
+ FileBuffer.DisplayPosition.Column = MainEditor.ScreenSize.Column;
+ FileBuffer.FilePosition.Column = NewFilePosCol;
+ } else {
+ if (Left) {
+ //
+ // has enough left characters , so display row unchanged
+ // not has enough left characters,
+ // so the first character is at the first display column
+ //
+ if (NewFilePosCol < (FileBuffer.DisplayPosition.Column)) {
+ FileBuffer.DisplayPosition.Column = NewFilePosCol;
+ }
+
+ FileBuffer.FilePosition.Column = NewFilePosCol;
+ } else {
+ //
+ // in current screen
+ //
+ FileBuffer.FilePosition.Column = NewFilePosCol;
+ if (ColGap < 0) {
+ Abs = (UINTN)(-ColGap);
+ FileBuffer.DisplayPosition.Column -= Abs;
+ } else {
+ FileBuffer.DisplayPosition.Column += ColGap;
+ }
+ }
+ }
+
+ FileBuffer.LowVisibleRange.Column = FileBuffer.FilePosition.Column - (FileBuffer.DisplayPosition.Column - 1);
+
+ //
+ // let CurrentLine point to correct line;
+ //
+ FileBuffer.CurrentLine = MoveCurrentLine (RowGap);
+
+}
+
+/**
+ Cut current line out and return a pointer to it.
+
+ @param[out] CutLine Upon a successful return pointer to the pointer to
+ the allocated cut line.
+
+ @retval EFI_SUCCESS The cut was successful.
+ @retval EFI_NOT_FOUND There was no selection to cut.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferCutLine (
+ OUT EFI_EDITOR_LINE **CutLine
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ EFI_EDITOR_LINE *NewLine;
+ UINTN Row;
+ UINTN Col;
+
+ if (FileBuffer.ReadOnly) {
+ StatusBarSetStatusString (L"Read Only File Can Not Be Modified");
+ return EFI_SUCCESS;
+ }
+
+ Line = FileBuffer.CurrentLine;
+
+ //
+ // if is the last dummy line, SO CAN not cut
+ //
+ if (StrCmp (Line->Buffer, L"\0") == 0 && Line->Link.ForwardLink == FileBuffer.ListHead
+ //
+ // last line
+ //
+ ) {
+ //
+ // LAST LINE AND NOTHING ON THIS LINE, SO CUT NOTHING
+ //
+ StatusBarSetStatusString (L"Nothing to Cut");
+ return EFI_NOT_FOUND;
+ }
+ //
+ // if is the last line, so create a dummy line
+ //
+ if (Line->Link.ForwardLink == FileBuffer.ListHead) {
+ //
+ // last line
+ // create a new line
+ //
+ NewLine = FileBufferCreateLine ();
+ if (NewLine == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ FileBuffer.NumLines--;
+ Row = FileBuffer.FilePosition.Row;
+ Col = 1;
+ //
+ // move home
+ //
+ FileBuffer.CurrentLine = CR (
+ FileBuffer.CurrentLine->Link.ForwardLink,
+ EFI_EDITOR_LINE,
+ Link,
+ LINE_LIST_SIGNATURE
+ );
+
+ RemoveEntryList (&Line->Link);
+
+ FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+
+ FileBufferMovePosition (Row, Col);
+
+ FileBuffer.FileModified = TRUE;
+ FileBufferNeedRefresh = TRUE;
+ FileBufferOnlyLineNeedRefresh = FALSE;
+
+ *CutLine = Line;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Paste a line into line list.
+
+ @retval EFI_SUCCESS The paste was successful.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferPasteLine (
+ VOID
+ )
+{
+ EFI_EDITOR_LINE *Line;
+ EFI_EDITOR_LINE *NewLine;
+ UINTN Row;
+ UINTN Col;
+
+ //
+ // if nothing is on clip board
+ // then do nothing
+ //
+ if (MainEditor.CutLine == NULL) {
+ return EFI_SUCCESS;
+ }
+ //
+ // read only file can not be pasted on
+ //
+ if (FileBuffer.ReadOnly) {
+ StatusBarSetStatusString (L"Read Only File Can Not Be Modified");
+ return EFI_SUCCESS;
+ }
+
+ NewLine = LineDup (MainEditor.CutLine);
+ if (NewLine == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // insert it above current line
+ //
+ Line = FileBuffer.CurrentLine;
+ NewLine->Link.BackLink = Line->Link.BackLink;
+ NewLine->Link.ForwardLink = &Line->Link;
+
+ Line->Link.BackLink->ForwardLink = &NewLine->Link;
+ Line->Link.BackLink = &NewLine->Link;
+
+ FileBuffer.NumLines++;
+ FileBuffer.CurrentLine = NewLine;
+
+ FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+
+ Col = 1;
+ //
+ // move home
+ //
+ Row = FileBuffer.FilePosition.Row;
+
+ FileBufferMovePosition (Row, Col);
+
+ //
+ // after paste, set some value so that refresh knows to do something
+ //
+ FileBuffer.FileModified = TRUE;
+ FileBufferNeedRefresh = TRUE;
+ FileBufferOnlyLineNeedRefresh = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search string from current position on in file
+
+ @param[in] Str The search string.
+ @param[in] Offset The offset from current position.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_NOT_FOUND The string Str was not found.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferSearch (
+ IN CONST CHAR16 *Str,
+ IN CONST UINTN Offset
+ )
+{
+ CHAR16 *Current;
+ UINTN Position;
+ UINTN Row;
+ UINTN Column;
+ EFI_EDITOR_LINE *Line;
+ CHAR16 *CharPos;
+ LIST_ENTRY *Link;
+ BOOLEAN Found;
+
+ Column = 0;
+ Position = 0;
+
+ //
+ // search if in current line
+ //
+ Current = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1 + Offset;
+
+ if (Current >= (FileBuffer.CurrentLine->Buffer + FileBuffer.CurrentLine->Size)) {
+ //
+ // the end
+ //
+ Current = FileBuffer.CurrentLine->Buffer + FileBuffer.CurrentLine->Size;
+ }
+
+ Found = FALSE;
+
+ CharPos = StrStr (Current, Str);
+ if (CharPos != NULL) {
+ Position = CharPos - Current + 1;
+ Found = TRUE;
+ }
+
+ //
+ // found
+ //
+ if (Found) {
+ Column = (Position - 1) + FileBuffer.FilePosition.Column + Offset;
+ Row = FileBuffer.FilePosition.Row;
+ } else {
+ //
+ // not found so find through next lines
+ //
+ Link = FileBuffer.CurrentLine->Link.ForwardLink;
+
+ Row = FileBuffer.FilePosition.Row + 1;
+ while (Link != FileBuffer.ListHead) {
+ Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+// Position = StrStr (Line->Buffer, Str);
+ CharPos = StrStr (Line->Buffer, Str);
+ if (CharPos != NULL) {
+ Position = CharPos - Line->Buffer + 1;
+ Found = TRUE;
+ }
+
+ if (Found) {
+ //
+ // found
+ //
+ Column = Position;
+ break;
+ }
+
+ Row++;
+ Link = Link->ForwardLink;
+ }
+
+ if (Link == FileBuffer.ListHead) {
+ Found = FALSE;
+ } else {
+ Found = TRUE;
+ }
+ }
+
+ if (!Found) {
+ return EFI_NOT_FOUND;
+ }
+
+ FileBufferMovePosition (Row, Column);
+
+ //
+ // call refresh to fresh edit area,
+ // because the outer may loop to find multiply occurrence of this string
+ //
+ FileBufferRefresh ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Replace SearchLen characters from current position on with Replace.
+
+ This will modify the current buffer at the current position.
+
+ @param[in] Replace The string to replace.
+ @param[in] SearchLen Search string's length.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferReplace (
+ IN CONST CHAR16 *Replace,
+ IN CONST UINTN SearchLen
+ )
+{
+ UINTN ReplaceLen;
+ UINTN Index;
+ CHAR16 *Buffer;
+ UINTN NewSize;
+ UINTN OldSize;
+ UINTN Gap;
+
+ ReplaceLen = StrLen (Replace);
+
+ OldSize = FileBuffer.CurrentLine->Size + 1;
+ //
+ // include CHAR_NULL
+ //
+ NewSize = OldSize + (ReplaceLen - SearchLen);
+
+ if (ReplaceLen > SearchLen) {
+ //
+ // do not have the enough space
+ //
+ if (FileBuffer.CurrentLine->TotalSize + 1 <= NewSize) {
+ FileBuffer.CurrentLine->Buffer = ReallocatePool (
+ 2 * OldSize,
+ 2 * NewSize,
+ FileBuffer.CurrentLine->Buffer
+ );
+ FileBuffer.CurrentLine->TotalSize = NewSize - 1;
+ }
+
+ if (FileBuffer.CurrentLine->Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // the end CHAR_NULL character;
+ //
+ Buffer = FileBuffer.CurrentLine->Buffer + (NewSize - 1);
+ Gap = ReplaceLen - SearchLen;
+
+ //
+ // keep the latter part
+ //
+ for (Index = 0; Index < (FileBuffer.CurrentLine->Size - FileBuffer.FilePosition.Column - SearchLen + 2); Index++) {
+ *Buffer = *(Buffer - Gap);
+ Buffer--;
+ }
+ //
+ // set replace into it
+ //
+ Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1;
+ for (Index = 0; Index < ReplaceLen; Index++) {
+ Buffer[Index] = Replace[Index];
+ }
+ }
+
+ if (ReplaceLen < SearchLen) {
+ Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1;
+
+ for (Index = 0; Index < ReplaceLen; Index++) {
+ Buffer[Index] = Replace[Index];
+ }
+
+ Buffer += ReplaceLen;
+ Gap = SearchLen - ReplaceLen;
+
+ //
+ // set replace into it
+ //
+ for (Index = 0; Index < (FileBuffer.CurrentLine->Size - FileBuffer.FilePosition.Column - ReplaceLen + 2); Index++) {
+ *Buffer = *(Buffer + Gap);
+ Buffer++;
+ }
+ }
+
+ if (ReplaceLen == SearchLen) {
+ Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1;
+ for (Index = 0; Index < ReplaceLen; Index++) {
+ Buffer[Index] = Replace[Index];
+ }
+ }
+
+ FileBuffer.CurrentLine->Size += (ReplaceLen - SearchLen);
+
+ FileBufferOnlyLineNeedRefresh = TRUE;
+
+ FileBuffer.FileModified = TRUE;
+
+ MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row, 0, 0);
+ FileBufferRestorePosition ();
+ FileBufferRefresh ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Move the mouse cursor position.
+
+ @param[in] TextX The new x-coordinate.
+ @param[in] TextY The new y-coordinate.
+**/
+VOID
+EFIAPI
+FileBufferAdjustMousePosition (
+ IN CONST INT32 TextX,
+ IN CONST INT32 TextY
+ )
+{
+ UINTN CoordinateX;
+ UINTN CoordinateY;
+ UINTN AbsX;
+ UINTN AbsY;
+
+ //
+ // TextX and TextY is mouse movement data returned by mouse driver
+ // This function will change it to MousePosition
+ //
+ //
+ // get absolute value
+ //
+
+ AbsX = ABS(TextX);
+ AbsY = ABS(TextY);
+
+ CoordinateX = FileBuffer.MousePosition.Column;
+ CoordinateY = FileBuffer.MousePosition.Row;
+
+ if (TextX >= 0) {
+ CoordinateX += TextX;
+ } else {
+ if (CoordinateX >= AbsX) {
+ CoordinateX -= AbsX;
+ } else {
+ CoordinateX = 0;
+ }
+ }
+
+ if (TextY >= 0) {
+ CoordinateY += TextY;
+ } else {
+ if (CoordinateY >= AbsY) {
+ CoordinateY -= AbsY;
+ } else {
+ CoordinateY = 0;
+ }
+ }
+ //
+ // check whether new mouse column position is beyond screen
+ // if not, adjust it
+ //
+ if (CoordinateX >= 1 && CoordinateX <= MainEditor.ScreenSize.Column) {
+ FileBuffer.MousePosition.Column = CoordinateX;
+ } else if (CoordinateX < 1) {
+ FileBuffer.MousePosition.Column = 1;
+ } else if (CoordinateX > MainEditor.ScreenSize.Column) {
+ FileBuffer.MousePosition.Column = MainEditor.ScreenSize.Column;
+ }
+ //
+ // check whether new mouse row position is beyond screen
+ // if not, adjust it
+ //
+ if (CoordinateY >= 2 && CoordinateY <= (MainEditor.ScreenSize.Row - 1)) {
+ FileBuffer.MousePosition.Row = CoordinateY;
+ } else if (CoordinateY < 2) {
+ FileBuffer.MousePosition.Row = 2;
+ } else if (CoordinateY > (MainEditor.ScreenSize.Row - 1)) {
+ FileBuffer.MousePosition.Row = (MainEditor.ScreenSize.Row - 1);
+ }
+
+}
+
+/**
+ Search and replace operation.
+
+ @param[in] SearchStr The string to search for.
+ @param[in] ReplaceStr The string to replace with.
+ @param[in] Offset The column to start at.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferReplaceAll (
+ IN CHAR16 *SearchStr,
+ IN CHAR16 *ReplaceStr,
+ IN UINTN Offset
+ )
+{
+ CHAR16 *Buffer;
+ UINTN Position;
+ UINTN Column;
+ UINTN ReplaceLen;
+ UINTN SearchLen;
+ UINTN Index;
+ UINTN NewSize;
+ UINTN OldSize;
+ UINTN Gap;
+ EFI_EDITOR_LINE *Line;
+ LIST_ENTRY *Link;
+ CHAR16 *CharPos;
+
+ SearchLen = StrLen (SearchStr);
+ ReplaceLen = StrLen (ReplaceStr);
+
+ Column = FileBuffer.FilePosition.Column + Offset - 1;
+
+ if (Column > FileBuffer.CurrentLine->Size) {
+ Column = FileBuffer.CurrentLine->Size;
+ }
+
+ Link = &(FileBuffer.CurrentLine->Link);
+
+ while (Link != FileBuffer.ListHead) {
+ Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
+ CharPos = StrStr (Line->Buffer + Column, SearchStr);
+ if (CharPos != NULL) {
+ Position = CharPos - Line->Buffer;// + Column;
+ //
+ // found
+ //
+ if (ReplaceLen > SearchLen) {
+ OldSize = Line->Size + 1;
+ //
+ // include CHAR_NULL
+ //
+ NewSize = OldSize + (ReplaceLen - SearchLen);
+
+ //
+ // do not have the enough space
+ //
+ if (Line->TotalSize + 1 <= NewSize) {
+ Line->Buffer = ReallocatePool (
+ 2 * OldSize,
+ 2 * NewSize,
+ Line->Buffer
+ );
+ Line->TotalSize = NewSize - 1;
+ }
+
+ if (Line->Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // the end CHAR_NULL character;
+ //
+ Buffer = Line->Buffer + (NewSize - 1);
+ Gap = ReplaceLen - SearchLen;
+
+ //
+ // keep the latter part
+ //
+ for (Index = 0; Index < (Line->Size - Position - SearchLen + 1); Index++) {
+ *Buffer = *(Buffer - Gap);
+ Buffer--;
+ }
+
+ } else if (ReplaceLen < SearchLen){
+ Buffer = Line->Buffer + Position + ReplaceLen;
+ Gap = SearchLen - ReplaceLen;
+
+ for (Index = 0; Index < (Line->Size - Position - ReplaceLen + 1); Index++) {
+ *Buffer = *(Buffer + Gap);
+ Buffer++;
+ }
+ } else {
+ ASSERT(ReplaceLen == SearchLen);
+ }
+ //
+ // set replace into it
+ //
+ Buffer = Line->Buffer + Position;
+ for (Index = 0; Index < ReplaceLen; Index++) {
+ Buffer[Index] = ReplaceStr[Index];
+ }
+
+ Line->Size += (ReplaceLen - SearchLen);
+ Column += ReplaceLen;
+ } else {
+ //
+ // not found
+ //
+ Column = 0;
+ Link = Link->ForwardLink;
+ }
+ }
+ //
+ // call refresh to fresh edit area
+ //
+ FileBuffer.FileModified = TRUE;
+ FileBufferNeedRefresh = TRUE;
+ FileBufferRefresh ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the modified state to TRUE.
+**/
+VOID
+EFIAPI
+FileBufferSetModified (
+ VOID
+ )
+{
+ FileBuffer.FileModified = TRUE;
+}
+
diff --git a/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.h b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.h
new file mode 100644
index 0000000000..9d4a08d7a3
--- /dev/null
+++ b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/FileBuffer.h
@@ -0,0 +1,263 @@
+/** @file
+ Declares filebuffer interface functions.
+
+ Copyright (c) 2005 - 2011, 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.
+
+**/
+
+#ifndef _LIB_FILE_BUFFER_H_
+#define _LIB_FILE_BUFFER_H_
+
+#include "TextEditorTypes.h"
+
+/**
+ Initialization function for FileBuffer.
+
+ @param EFI_SUCCESS The initialization was successful.
+ @param EFI_LOAD_ERROR A default name could not be created.
+ @param EFI_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferInit (
+ VOID
+ );
+
+/**
+ Cleanup function for FileBuffer.
+
+ @retval EFI_SUCCESS The cleanup was successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferCleanup (
+ VOID
+ );
+
+/**
+ Refresh the screen with whats in the buffer.
+
+ @retval EFI_SUCCESS The refresh was successful.
+ @retval EFI_LOAD_ERROR There was an error finding what to write.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferRefresh (
+ VOID
+ );
+
+/**
+ Dispatch input to different handler
+ @param[in] Key The input key. One of:
+ ASCII KEY
+ Backspace/Delete
+ Return
+ Direction key: up/down/left/right/pgup/pgdn
+ Home/End
+ INS
+
+ @retval EFI_SUCCESS The dispatch was done successfully.
+ @retval EFI_LOAD_ERROR The dispatch was not successful.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferHandleInput (
+ IN CONST EFI_INPUT_KEY * Key
+ );
+
+/**
+ Backup function for FileBuffer. Only backup the following items:
+ Mouse/Cursor position
+ File Name, Type, ReadOnly, Modified
+ Insert Mode
+
+ This is for making the file buffer refresh as few as possible.
+
+ @retval EFI_SUCCESS The backup operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferBackup (
+ VOID
+ );
+
+/**
+ Set the cursor position according to FileBuffer.DisplayPosition.
+
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferRestorePosition (
+ VOID
+ );
+
+/**
+ Set FileName field in FileBuffer.
+
+ @param Str The file name to set.
+
+ @retval EFI_SUCCESS The filename was successfully set.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+ @retval EFI_INVALID_PARAMETER Str is not a valid filename.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferSetFileName (
+ IN CONST CHAR16 *Str
+ );
+
+/**
+ Read a file from disk into the FileBuffer.
+
+ @param[in] FileName The filename to read.
+ @param[in] Recover TRUE if is for recover mode, no information printouts.
+
+ @retval EFI_SUCCESS The load was successful.
+ @retval EFI_LOAD_ERROR The load failed.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+ @retval EFI_INVALID_PARAMETER FileName is a directory.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferRead (
+ IN CONST CHAR16 *FileName,
+ IN CONST BOOLEAN Recover
+ );
+
+/**
+ Save lines in FileBuffer to disk
+
+ @param[in] FileName The file name for writing.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_LOAD_ERROR
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to write the file.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferSave (
+ CONST CHAR16 *FileName
+ );
+
+/**
+ According to cursor's file position, adjust screen display
+
+ @param[in] NewFilePosRow The row of file position ( start from 1 ).
+ @param[in] NewFilePosCol The column of file position ( start from 1 ).
+**/
+VOID
+EFIAPI
+FileBufferMovePosition (
+ IN CONST UINTN NewFilePosRow,
+ IN CONST UINTN NewFilePosCol
+ );
+
+/**
+ Cut current line out and return a pointer to it.
+
+ @param[out] CutLine Upon a successful return pointer to the pointer to
+ the allocated cut line.
+
+ @retval EFI_SUCCESS The cut was successful.
+ @retval EFI_NOT_FOUND There was no selection to cut.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferCutLine (
+ OUT EFI_EDITOR_LINE **CutLine
+ );
+
+/**
+ Paste a line into line list.
+
+ @retval EFI_SUCCESS The paste was successful.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferPasteLine (
+ VOID
+ );
+
+/**
+ Search string from current position on in file
+
+ @param[in] Str The search string.
+ @param[in] Offset The offset from current position.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_NOT_FOUND The string Str was not found.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferSearch (
+ IN CONST CHAR16 *Str,
+ IN CONST UINTN Offset
+ );
+
+/**
+ Replace SearchLen characters from current position on with Replace.
+
+ This will modify the current buffer at the current position.
+
+ @param[in] Replace The string to replace.
+ @param[in] SearchLen Search string's length.
+
+ @retval EFI_SUCCESS The operation was successful.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferReplace (
+ IN CONST CHAR16 *Replace,
+ IN CONST UINTN SearchLen
+ );
+
+/**
+ Search and replace operation.
+
+ @param[in] SearchStr The string to search for.
+ @param[in] ReplaceStr The string to replace with.
+ @param[in] Offset The column to start at.
+**/
+EFI_STATUS
+EFIAPI
+FileBufferReplaceAll (
+ IN CHAR16 *SearchStr,
+ IN CHAR16 *ReplaceStr,
+ IN UINTN Offset
+ );
+
+/**
+ Move the mouse cursor position.
+
+ @param[in] TextX The new x-coordinate.
+ @param[in] TextY The new y-coordinate.
+**/
+VOID
+EFIAPI
+FileBufferAdjustMousePosition (
+ IN CONST INT32 TextX,
+ IN CONST INT32 TextY
+ );
+
+/**
+ Set the modified state to TRUE.
+**/
+VOID
+EFIAPI
+FileBufferSetModified (
+ VOID
+ );
+
+#endif
diff --git a/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c
new file mode 100644
index 0000000000..4eb7d9eee3
--- /dev/null
+++ b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.c
@@ -0,0 +1,1936 @@
+/** @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;
+}
diff --git a/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.h b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.h
new file mode 100644
index 0000000000..c45859deda
--- /dev/null
+++ b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/MainTextEditor.h
@@ -0,0 +1,77 @@
+/** @file
+ Declares editor interface functions.
+
+ Copyright (c) 2005 - 2011, 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.
+
+**/
+
+#ifndef _LIB_EDITOR_H_
+#define _LIB_EDITOR_H_
+
+#include "TextEditorTypes.h"
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ Refresh the main editor component.
+**/
+VOID
+EFIAPI
+MainEditorRefresh (
+ VOID
+ );
+
+/**
+ 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
+ );
+
+/**
+ Backup function for MainEditor
+
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+MainEditorBackup (
+ VOID
+ );
+
+#endif
diff --git a/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.c b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.c
new file mode 100644
index 0000000000..ade78b8f90
--- /dev/null
+++ b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.c
@@ -0,0 +1,92 @@
+/** @file
+ Implementation of various string and line routines.
+
+ Copyright (c) 2005 - 2011, 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 "Misc.h"
+
+/**
+ Duplicate a EFI_EDITOR_LINE structure.
+
+ @param Src The line structure to copy from.
+
+ @retval NULL A memory allocation failed.
+ @return a pointer to the newly allcoated line.
+**/
+EFI_EDITOR_LINE *
+EFIAPI
+LineDup (
+ IN EFI_EDITOR_LINE *Src
+ )
+{
+ EFI_EDITOR_LINE *Dest;
+
+ //
+ // allocate for the line structure
+ //
+ Dest = AllocateZeroPool (sizeof (EFI_EDITOR_LINE));
+ if (Dest == NULL) {
+ return NULL;
+ }
+ //
+ // allocate and set the line buffer
+ //
+ Dest->Buffer = CatSPrint (NULL, L"%s", Src->Buffer);
+ if (Dest->Buffer == NULL) {
+ FreePool (Dest);
+ return NULL;
+ }
+
+ //
+ // set the other structure members
+ //
+ Dest->Signature = LINE_LIST_SIGNATURE;
+ Dest->Size = Src->Size;
+ Dest->TotalSize = Dest->Size;
+ Dest->Type = Src->Type;
+ Dest->Link = Src->Link;
+
+ return Dest;
+}
+
+/**
+ Free a EFI_EDITOR_LINE structure.
+
+ @param Src The line structure to free.
+**/
+VOID
+EFIAPI
+LineFree (
+ IN EFI_EDITOR_LINE *Src
+ )
+{
+ if (Src == NULL) {
+ return ;
+ }
+ //
+ // free the line buffer and then the line structure itself
+ //
+ SHELL_FREE_NON_NULL (Src->Buffer);
+ SHELL_FREE_NON_NULL (Src);
+
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.h b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.h
new file mode 100644
index 0000000000..583de3b42c
--- /dev/null
+++ b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/Misc.h
@@ -0,0 +1,52 @@
+/** @file
+ Declares generic editor helper functions.
+
+ Copyright (c) 2005 - 2011, 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.
+
+**/
+
+#ifndef _LIB_MISC_H_
+#define _LIB_MISC_H_
+
+#include "TextEditorTypes.h"
+
+
+
+/**
+ Free a EFI_EDITOR_LINE structure.
+
+ @param Src The line structure to free.
+**/
+VOID
+EFIAPI
+LineFree (
+ IN EFI_EDITOR_LINE *Src
+ );
+
+/**
+ Duplicate a EFI_EDITOR_LINE structure.
+
+ @param Src The line structure to copy from.
+
+ @retval NULL A memory allocation failed.
+ @return a pointer to the newly allcoated line.
+**/
+EFI_EDITOR_LINE *
+EFIAPI
+LineDup (
+ IN EFI_EDITOR_LINE *Src
+ );
+
+
+
+
+
+
+#endif
diff --git a/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni
new file mode 100644
index 0000000000..f799148135
--- /dev/null
+++ b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditStrings.uni
@@ -0,0 +1,75 @@
+// /**
+//
+// Copyright (c) 2005 - 2011, 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.
+//
+// Abstract:
+//
+// Additional string definitions for UEFI Shell 2.0 Debug1 profile Edit command
+//
+//
+// **/
+
+/=#
+
+#langdef en-US "english"
+
+#string STR_EDIT_LIBEDITOR_TITLEBAR #language en-US "%EMainEditor init failed on TitleBar init\r\n%N"
+#string STR_EDIT_LIBEDITOR_MAINMENU #language en-US "%EMainEditor init was not successful on MainMenu init\r\n%N"
+#string STR_EDIT_LIBEDITOR_STATUSBAR #language en-US "%EMainEditor init was not successful on StatusBar init\r\n%N"
+#string STR_EDIT_LIBEDITOR_INPUTBAR #language en-US "%EMainEditor init was not successful on InputBar init\r\n%N"
+#string STR_EDIT_LIBEDITOR_FILEBUFFER #language en-US "%EMainEditor init was not successful on FileBuffer init\r\n%N"
+#string STR_EDIT_LIBEDITOR_TITLEBAR_CLEANUP #language en-US "TitleBar cleanup was not successful\r\n"
+#string STR_EDIT_LIBEDITOR_MENUBAR_CLEANUP #language en-US "MenuBar cleanup was not successful\r\n"
+#string STR_EDIT_LIBEDITOR_STATUSBAR_CLEANUP #language en-US "StatusBar cleanup was not successful\r\n"
+#string STR_EDIT_LIBEDITOR_INPUTBAR_CLEANUP #language en-US "InputBar cleanup was not successful\r\n"
+#string STR_EDIT_LIBEDITOR_FILEBUFFER_CLEANUP #language en-US "FileBuffer cleanup was not successful\r\n"
+#string STR_EDIT_LIBEDITOR_MAINEDITOR_INIT #language en-US "%EMainEditor init was not succesful on TitleBar init\r\n%N"
+#string STR_EDIT_LIBINPUTBAR_MAININPUTBAR #language en-US "%s"
+#string STR_EDIT_LIBMENUBAR_OPEN_FILE #language en-US "Open File"
+#string STR_EDIT_LIBMENUBAR_SAVE_FILE #language en-US "Save File"
+#string STR_EDIT_LIBMENUBAR_EXIT #language en-US "Exit"
+#string STR_EDIT_LIBMENUBAR_CUT_LINE #language en-US "Cut Line"
+#string STR_EDIT_LIBMENUBAR_PASTE_LINE #language en-US "Paste Line"
+#string STR_EDIT_LIBMENUBAR_GO_TO_LINE #language en-US "Go To Line"
+#string STR_EDIT_LIBMENUBAR_SEARCH #language en-US "Search"
+#string STR_EDIT_LIBMENUBAR_SEARCH_REPLACE #language en-US "Search/Replace"
+#string STR_EDIT_LIBMENUBAR_FILE_TYPE #language en-US "File Type"
+#string STR_EDIT_LIBMENUBAR_F1 #language en-US "F1"
+#string STR_EDIT_LIBMENUBAR_F2 #language en-US "F2"
+#string STR_EDIT_LIBMENUBAR_F3 #language en-US "F3"
+#string STR_EDIT_LIBMENUBAR_F4 #language en-US "F4"
+#string STR_EDIT_LIBMENUBAR_F5 #language en-US "F5"
+#string STR_EDIT_LIBMENUBAR_F6 #language en-US "F6"
+#string STR_EDIT_LIBMENUBAR_F7 #language en-US "F7"
+#string STR_EDIT_LIBMENUBAR_F8 #language en-US "F8"
+#string STR_EDIT_LIBMENUBAR_F9 #language en-US "F9"
+#string STR_EDIT_LIBMENUBAR_F10 #language en-US "F10"
+#string STR_EDIT_LIBMENUBAR_F11 #language en-US "F11"
+#string STR_EDIT_LIBMENUBAR_F12 #language en-US "F12"
+#string STR_EDIT_LIBMENUBAR_CTRL_E #language en-US "Ctrl+E"
+#string STR_EDIT_LIBMENUBAR_CTRL_W #language en-US "Ctrl+W"
+#string STR_EDIT_HELP_TITLE #language en-US "Help \n"
+#string STR_EDIT_HELP_BLANK #language en-US " \n"
+#string STR_EDIT_HELP_LIST_TITLE #language en-US "Control Key Function Key Command \n"
+#string STR_EDIT_HELP_DIV #language en-US "----------- ------------ ----------------- \n"
+#string STR_EDIT_HELP_GO_TO_LINE #language en-US "Ctrl-G F1 Go To Line \n"
+#string STR_EDIT_HELP_SAVE_FILE #language en-US "Ctrl-S F2 Save File \n"
+#string STR_EDIT_HELP_EXIT #language en-US "Ctrl-Q F3 Exit \n"
+#string STR_EDIT_HELP_SEARCH #language en-US "Ctrl-F F4 Search \n"
+#string STR_EDIT_HELP_SEARCH_REPLACE #language en-US "Ctrl-R F5 Search/Replace \n"
+#string STR_EDIT_HELP_CUT_LINE #language en-US "Ctrl-K F6 Cut Line \n"
+#string STR_EDIT_HELP_PASTE_LINE #language en-US "Ctrl-U F7 Paste Line \n"
+#string STR_EDIT_HELP_OPEN_FILE #language en-US "Ctrl-O F8 Open File \n"
+#string STR_EDIT_HELP_FILE_TYPE #language en-US "Ctrl-T F9 File Type \n"
+#string STR_EDIT_HELP_EXIT_HELP #language en-US "Use Ctrl-W to exit this help \n"
+#string STR_EDIT_MAIN_INVALID_FILE_NAME #language en-US "%Hedit%N: Invalid File Name\r\n"
+#string STR_EDIT_MAIN_INIT_FAILED #language en-US "%Hedit%N: Initialization was not successful\r\n"
+#string STR_EDIT_MAIN_BUFFER #language en-US "%Hedit%N: %s\r\n"
+#string STR_EDIT_MAIN_UNKNOWN_EDITOR_ERR #language en-US "%Hedit%N: Unknown Editor Error\r\n"
diff --git a/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditor.h b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditor.h
new file mode 100644
index 0000000000..774f01a291
--- /dev/null
+++ b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditor.h
@@ -0,0 +1,32 @@
+/** @file
+ Main include file for Edit shell Debug1 function.
+
+ Copyright (c) 2005 - 2011, 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.
+
+**/
+
+#ifndef _EFI_EDIT_H_
+#define _EFI_EDIT_H_
+
+#include "TextEditorTypes.h"
+
+#include "MainTextEditor.h"
+#include "FileBuffer.h"
+#include "EditTitleBar.h"
+#include "EditStatusBar.h"
+#include "EditInputBar.h"
+#include "EditMenuBar.h"
+#include "Misc.h"
+
+extern EFI_EDITOR_GLOBAL_EDITOR MainEditor;
+extern BOOLEAN EditorFirst;
+extern BOOLEAN EditorExit;
+
+#endif // _EFI_EDIT_H_
diff --git a/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditorTypes.h b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditorTypes.h
new file mode 100644
index 0000000000..dfd56dd9a6
--- /dev/null
+++ b/Core/ShellPkg/Library/UefiShellDebug1CommandsLib/Edit/TextEditorTypes.h
@@ -0,0 +1,102 @@
+/** @file
+ Declares editor types.
+
+ Copyright (c) 2005 - 2011, 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.
+
+**/
+
+#ifndef _EDITOR_TYPE_H_
+#define _EDITOR_TYPE_H_
+
+#include "UefiShellDebug1CommandsLib.h"
+#include "EditTitleBar.h"
+#include "EditMenuBar.h"
+
+#define MIN_POOL_SIZE 125
+#define MAX_STRING_LENGTH 127
+
+typedef struct {
+ UINTN Row;
+ UINTN Column;
+} EFI_EDITOR_POSITION;
+
+typedef
+EFI_STATUS
+(*EFI_MENU_ITEM_FUNCTION) (
+ VOID
+ );
+
+typedef enum {
+ NewLineTypeDefault,
+ NewLineTypeLineFeed,
+ NewLineTypeCarriageReturn,
+ NewLineTypeCarriageReturnLineFeed,
+ NewLineTypeLineFeedCarriageReturn,
+ NewLineTypeUnknown
+} EE_NEWLINE_TYPE;
+
+#define LINE_LIST_SIGNATURE SIGNATURE_32 ('e', 'e', 'l', 'l')
+typedef struct _EFI_EDITOR_LINE {
+ UINTN Signature;
+ CHAR16 *Buffer;
+ UINTN Size; // unit is Unicode
+ UINTN TotalSize; // unit is Unicode, exclude CHAR_NULL
+ EE_NEWLINE_TYPE Type;
+ LIST_ENTRY Link;
+} EFI_EDITOR_LINE;
+
+typedef struct {
+ UINT32 Foreground : 4;
+ UINT32 Background : 4;
+} EFI_EDITOR_COLOR_ATTRIBUTES;
+
+typedef union {
+ EFI_EDITOR_COLOR_ATTRIBUTES Colors;
+ UINTN Data;
+} EFI_EDITOR_COLOR_UNION;
+
+typedef struct {
+ UINTN Columns;
+ UINTN Rows;
+} EFI_EDITOR_TEXT_MODE;
+
+typedef struct {
+ CHAR16 *FileName; // file name current edited in editor
+ EDIT_FILE_TYPE FileType; // Unicode file or ASCII file
+ LIST_ENTRY *ListHead; // list head of lines
+ EFI_EDITOR_LINE *Lines; // lines of current file
+ UINTN NumLines; // total line numbers
+ EFI_EDITOR_POSITION DisplayPosition; // cursor position in screen
+ EFI_EDITOR_POSITION FilePosition; // cursor position in file
+ EFI_EDITOR_POSITION MousePosition; // mouse position in screen
+ // file position of first byte displayed on screen
+ //
+ EFI_EDITOR_POSITION LowVisibleRange;
+
+ BOOLEAN FileModified; // file is modified or not
+ BOOLEAN ModeInsert; // input mode INS or OVR
+ BOOLEAN ReadOnly; // file is read-only or not
+ EFI_EDITOR_LINE *CurrentLine; // current line cursor is at
+} EFI_EDITOR_FILE_BUFFER;
+
+typedef struct {
+ EFI_EDITOR_FILE_BUFFER *FileBuffer;
+
+ EFI_EDITOR_COLOR_UNION ColorAttributes;
+ EFI_EDITOR_POSITION ScreenSize; // row number and column number
+ EFI_EDITOR_LINE *CutLine; // clip board
+ BOOLEAN MouseSupported;
+ EFI_SIMPLE_POINTER_PROTOCOL *MouseInterface;
+ INT32 MouseAccumulatorX;
+ INT32 MouseAccumulatorY;
+
+} EFI_EDITOR_GLOBAL_EDITOR;
+
+#endif