Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Chen A Chen <chen.a.chen@intel.com> Reviewed-by: Jaben Carsey <jaben.carsey@intel.com> Reviewed-by: Ruiyu Ni <Ruiyu.ni@intel.com>
		
			
				
	
	
		
			3326 lines
		
	
	
		
			77 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3326 lines
		
	
	
		
			77 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @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
 | |
| 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
 | |
| 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 *
 | |
| 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 *
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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 *
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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 *
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| FileBufferSetModified (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   FileBuffer.FileModified = TRUE;
 | |
| }
 | |
| 
 |