mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-04 05:25:45 +01:00 
			
		
		
		
	Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Qiu Shumin <shumin.qiu@intel.com> Reviewed-by: Jaben Carsey <jaben.carsey@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17730 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			3372 lines
		
	
	
		
			78 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3372 lines
		
	
	
		
			78 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Implements filebuffer interface functions.
 | 
						|
 | 
						|
  Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved. <BR>
 | 
						|
  This program and the accompanying materials
 | 
						|
  are licensed and made available under the terms and conditions of the BSD License
 | 
						|
  which accompanies this distribution.  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "TextEditor.h"
 | 
						|
#include <Guid/FileSystemInfo.h>
 | 
						|
#include <Library/FileHandleLib.h>
 | 
						|
 | 
						|
EFI_EDITOR_FILE_BUFFER  FileBuffer;
 | 
						|
EFI_EDITOR_FILE_BUFFER  FileBufferBackupVar;
 | 
						|
 | 
						|
//
 | 
						|
// for basic initialization of FileBuffer
 | 
						|
//
 | 
						|
EFI_EDITOR_FILE_BUFFER  FileBufferConst = {
 | 
						|
  NULL,
 | 
						|
  FileTypeUnicode,
 | 
						|
  NULL,
 | 
						|
  NULL,
 | 
						|
  0,
 | 
						|
  {
 | 
						|
    0,
 | 
						|
    0
 | 
						|
  },
 | 
						|
  {
 | 
						|
    0,
 | 
						|
    0
 | 
						|
  },
 | 
						|
  {
 | 
						|
    0,
 | 
						|
    0
 | 
						|
  },
 | 
						|
  {
 | 
						|
    0,
 | 
						|
    0
 | 
						|
  },
 | 
						|
  FALSE,
 | 
						|
  TRUE,
 | 
						|
  FALSE,
 | 
						|
  NULL
 | 
						|
};
 | 
						|
 | 
						|
//
 | 
						|
// the whole edit area needs to be refreshed
 | 
						|
//
 | 
						|
BOOLEAN          FileBufferNeedRefresh;	
 | 
						|
 | 
						|
//
 | 
						|
// only the current line in edit area needs to be refresh
 | 
						|
//
 | 
						|
BOOLEAN                 FileBufferOnlyLineNeedRefresh;
 | 
						|
 | 
						|
BOOLEAN                 FileBufferMouseNeedRefresh;
 | 
						|
 | 
						|
extern BOOLEAN          EditorMouseAction;
 | 
						|
 | 
						|
/**
 | 
						|
  Initialization function for FileBuffer.
 | 
						|
 | 
						|
  @param EFI_SUCCESS            The initialization was successful.
 | 
						|
  @param EFI_LOAD_ERROR         A default name could not be created.
 | 
						|
  @param EFI_OUT_OF_RESOURCES   A memory allocation failed.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferInit (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // basically initialize the FileBuffer
 | 
						|
  //
 | 
						|
  CopyMem (&FileBuffer         , &FileBufferConst, sizeof (EFI_EDITOR_FILE_BUFFER));
 | 
						|
  CopyMem (&FileBufferBackupVar, &FileBufferConst, sizeof (EFI_EDITOR_FILE_BUFFER));
 | 
						|
 | 
						|
  //
 | 
						|
  // set default FileName
 | 
						|
  //
 | 
						|
  FileBuffer.FileName = EditGetDefaultFileName (L"txt");
 | 
						|
  if (FileBuffer.FileName == NULL) {
 | 
						|
    return EFI_LOAD_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  FileBuffer.ListHead = AllocateZeroPool (sizeof (LIST_ENTRY));
 | 
						|
  if (FileBuffer.ListHead == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  InitializeListHead (FileBuffer.ListHead);
 | 
						|
 | 
						|
  FileBuffer.DisplayPosition.Row    = 2;
 | 
						|
  FileBuffer.DisplayPosition.Column = 1;
 | 
						|
  FileBuffer.LowVisibleRange.Row    = 2;
 | 
						|
  FileBuffer.LowVisibleRange.Column = 1;
 | 
						|
 | 
						|
  FileBufferNeedRefresh             = FALSE;
 | 
						|
  FileBufferMouseNeedRefresh        = FALSE;
 | 
						|
  FileBufferOnlyLineNeedRefresh     = FALSE;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Backup function for FileBuffer.  Only backup the following items:
 | 
						|
      Mouse/Cursor position
 | 
						|
      File Name, Type, ReadOnly, Modified
 | 
						|
      Insert Mode
 | 
						|
 | 
						|
  This is for making the file buffer refresh as few as possible.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The backup operation was successful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferBackup (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  FileBufferBackupVar.MousePosition = FileBuffer.MousePosition;
 | 
						|
 | 
						|
  SHELL_FREE_NON_NULL (FileBufferBackupVar.FileName);
 | 
						|
  FileBufferBackupVar.FileName        = NULL;
 | 
						|
  FileBufferBackupVar.FileName        = StrnCatGrow (&FileBufferBackupVar.FileName, NULL, FileBuffer.FileName, 0);
 | 
						|
 | 
						|
  FileBufferBackupVar.ModeInsert      = FileBuffer.ModeInsert;
 | 
						|
  FileBufferBackupVar.FileType        = FileBuffer.FileType;
 | 
						|
 | 
						|
  FileBufferBackupVar.FilePosition    = FileBuffer.FilePosition;
 | 
						|
  FileBufferBackupVar.LowVisibleRange = FileBuffer.LowVisibleRange;
 | 
						|
 | 
						|
  FileBufferBackupVar.FileModified    = FileBuffer.FileModified;
 | 
						|
  FileBufferBackupVar.ReadOnly        = FileBuffer.ReadOnly;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Advance to the next Count lines
 | 
						|
  
 | 
						|
  @param[in] Count              The line number to advance by.
 | 
						|
  @param[in] CurrentLine        The pointer to the current line structure.
 | 
						|
  @param[in] LineList           The pointer to the linked list of lines.
 | 
						|
 | 
						|
  @retval NULL                  There was an error.
 | 
						|
  @return  The line structure after the advance.
 | 
						|
**/
 | 
						|
EFI_EDITOR_LINE *
 | 
						|
EFIAPI
 | 
						|
InternalEditorMiscLineAdvance (
 | 
						|
  IN CONST UINTN            Count,
 | 
						|
  IN CONST EFI_EDITOR_LINE  *CurrentLine,
 | 
						|
  IN CONST LIST_ENTRY       *LineList
 | 
						|
  )
 | 
						|
 | 
						|
{
 | 
						|
  UINTN                 Index;
 | 
						|
  CONST EFI_EDITOR_LINE *Line;
 | 
						|
 | 
						|
  if (CurrentLine == NULL || LineList == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Line = CurrentLine, Index = 0; Index < Count; Index++) {
 | 
						|
    //
 | 
						|
    // if already last line
 | 
						|
    //
 | 
						|
    if (Line->Link.ForwardLink == LineList) {
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    Line = CR (Line->Link.ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
  }
 | 
						|
 | 
						|
  return ((EFI_EDITOR_LINE *)Line);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retreat to the previous Count lines.
 | 
						|
  
 | 
						|
  @param[in] Count              The line number to retreat by.
 | 
						|
  @param[in] CurrentLine        The pointer to the current line structure.
 | 
						|
  @param[in] LineList           The pointer to the linked list of lines.
 | 
						|
 | 
						|
  @retval NULL                  There was an error.
 | 
						|
  @return  The line structure after the retreat.
 | 
						|
**/
 | 
						|
EFI_EDITOR_LINE *
 | 
						|
EFIAPI
 | 
						|
InternalEditorMiscLineRetreat (
 | 
						|
  IN CONST UINTN            Count,
 | 
						|
  IN CONST EFI_EDITOR_LINE  *CurrentLine,
 | 
						|
  IN CONST LIST_ENTRY       *LineList
 | 
						|
  )
 | 
						|
 | 
						|
{
 | 
						|
  UINTN                 Index;
 | 
						|
  CONST EFI_EDITOR_LINE *Line;
 | 
						|
 | 
						|
  if (CurrentLine == NULL || LineList == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Line = CurrentLine, Index = 0; Index < Count; Index++) {
 | 
						|
    //
 | 
						|
    // already the first line
 | 
						|
    //
 | 
						|
    if (Line->Link.BackLink == LineList) {
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
  }
 | 
						|
 | 
						|
  return ((EFI_EDITOR_LINE *)Line);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Advance/Retreat lines
 | 
						|
  
 | 
						|
  @param[in] Count  line number to advance/retreat
 | 
						|
                       >0 : advance
 | 
						|
                       <0 : retreat
 | 
						|
 | 
						|
  @retval NULL An error occured.
 | 
						|
  @return The line after advance/retreat.
 | 
						|
**/
 | 
						|
EFI_EDITOR_LINE *
 | 
						|
MoveLine (
 | 
						|
  IN CONST INTN Count
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  UINTN           AbsCount;
 | 
						|
 | 
						|
  //
 | 
						|
  // if < 0, then retreat
 | 
						|
  // if > 0, the advance
 | 
						|
  //
 | 
						|
  if (Count <= 0) {
 | 
						|
    AbsCount  = (UINTN)ABS(Count);
 | 
						|
    Line      = InternalEditorMiscLineRetreat (AbsCount,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);
 | 
						|
  } else {
 | 
						|
    Line = InternalEditorMiscLineAdvance ((UINTN)Count,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);
 | 
						|
  }
 | 
						|
 | 
						|
  return Line;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function to update the 'screen' to display the mouse position.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The backup operation was successful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferRestoreMousePosition (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_COLOR_UNION  Orig;
 | 
						|
  EFI_EDITOR_COLOR_UNION  New;
 | 
						|
  UINTN                   FRow;
 | 
						|
  UINTN                   FColumn;
 | 
						|
  BOOLEAN                 HasCharacter;
 | 
						|
  EFI_EDITOR_LINE         *CurrentLine;
 | 
						|
  EFI_EDITOR_LINE         *Line;
 | 
						|
  CHAR16                  Value;
 | 
						|
 | 
						|
  //
 | 
						|
  // variable initialization
 | 
						|
  //
 | 
						|
  Line = NULL;
 | 
						|
 | 
						|
  if (MainEditor.MouseSupported) {
 | 
						|
 | 
						|
    if (FileBufferMouseNeedRefresh) {
 | 
						|
 | 
						|
      FileBufferMouseNeedRefresh = FALSE;
 | 
						|
 | 
						|
      //
 | 
						|
      // if mouse position not moved and only mouse action
 | 
						|
      // so do not need to refresh mouse position
 | 
						|
      //
 | 
						|
      if ((FileBuffer.MousePosition.Row == FileBufferBackupVar.MousePosition.Row &&
 | 
						|
          FileBuffer.MousePosition.Column == FileBufferBackupVar.MousePosition.Column)
 | 
						|
          && EditorMouseAction) {
 | 
						|
        return EFI_SUCCESS;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // backup the old screen attributes
 | 
						|
      //
 | 
						|
      Orig                  = MainEditor.ColorAttributes;
 | 
						|
      New.Data              = 0;
 | 
						|
      New.Colors.Foreground = Orig.Colors.Background & 0xF;
 | 
						|
      New.Colors.Background = Orig.Colors.Foreground & 0x7;
 | 
						|
 | 
						|
      //
 | 
						|
      // clear the old mouse position
 | 
						|
      //
 | 
						|
      FRow          = FileBuffer.LowVisibleRange.Row + FileBufferBackupVar.MousePosition.Row - 2;
 | 
						|
 | 
						|
      FColumn       = FileBuffer.LowVisibleRange.Column + FileBufferBackupVar.MousePosition.Column - 1;
 | 
						|
 | 
						|
      HasCharacter  = TRUE;
 | 
						|
      if (FRow > FileBuffer.NumLines) {
 | 
						|
        HasCharacter = FALSE;
 | 
						|
      } else {
 | 
						|
        CurrentLine = FileBuffer.CurrentLine;
 | 
						|
        Line        = MoveLine (FRow - FileBuffer.FilePosition.Row);
 | 
						|
 | 
						|
        if (Line == NULL || FColumn > Line->Size) {
 | 
						|
          HasCharacter = FALSE;
 | 
						|
        }
 | 
						|
 | 
						|
        FileBuffer.CurrentLine = CurrentLine;
 | 
						|
      }
 | 
						|
 | 
						|
      ShellPrintEx (
 | 
						|
        (INT32)FileBufferBackupVar.MousePosition.Column - 1,
 | 
						|
        (INT32)FileBufferBackupVar.MousePosition.Row - 1,
 | 
						|
        L" "
 | 
						|
        );
 | 
						|
 | 
						|
      if (HasCharacter) {
 | 
						|
        Value = (Line->Buffer[FColumn - 1]);
 | 
						|
        ShellPrintEx (
 | 
						|
          (INT32)FileBufferBackupVar.MousePosition.Column - 1,
 | 
						|
          (INT32)FileBufferBackupVar.MousePosition.Row - 1,
 | 
						|
          L"%c",
 | 
						|
          Value
 | 
						|
          );
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // set the new mouse position
 | 
						|
      //
 | 
						|
      gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F);
 | 
						|
 | 
						|
      //
 | 
						|
      // clear the old mouse position
 | 
						|
      //
 | 
						|
      FRow          = FileBuffer.LowVisibleRange.Row + FileBuffer.MousePosition.Row - 2;
 | 
						|
      FColumn       = FileBuffer.LowVisibleRange.Column + FileBuffer.MousePosition.Column - 1;
 | 
						|
 | 
						|
      HasCharacter  = TRUE;
 | 
						|
      if (FRow > FileBuffer.NumLines) {
 | 
						|
        HasCharacter = FALSE;
 | 
						|
      } else {
 | 
						|
        CurrentLine = FileBuffer.CurrentLine;
 | 
						|
        Line        = MoveLine (FRow - FileBuffer.FilePosition.Row);
 | 
						|
 | 
						|
        if (Line == NULL || FColumn > Line->Size) {
 | 
						|
          HasCharacter = FALSE;
 | 
						|
        }
 | 
						|
 | 
						|
        FileBuffer.CurrentLine = CurrentLine;
 | 
						|
      }
 | 
						|
 | 
						|
      ShellPrintEx (
 | 
						|
        (INT32)FileBuffer.MousePosition.Column - 1,
 | 
						|
        (INT32)FileBuffer.MousePosition.Row - 1,
 | 
						|
        L" "
 | 
						|
        );
 | 
						|
 | 
						|
      if (HasCharacter) {
 | 
						|
        Value = Line->Buffer[FColumn - 1];
 | 
						|
        ShellPrintEx (
 | 
						|
          (INT32)FileBuffer.MousePosition.Column - 1,
 | 
						|
          (INT32)FileBuffer.MousePosition.Row - 1,
 | 
						|
          L"%c",
 | 
						|
          Value
 | 
						|
          );
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // end of HasCharacter
 | 
						|
      //
 | 
						|
      gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // end of MouseNeedRefresh
 | 
						|
    //
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // end of MouseSupported
 | 
						|
  //
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Free all the lines in FileBuffer
 | 
						|
   Fields affected:
 | 
						|
     Lines
 | 
						|
     CurrentLine
 | 
						|
     NumLines
 | 
						|
     ListHead
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     The operation was successful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferFreeLines (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY  *Link;
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
 | 
						|
  //
 | 
						|
  // free all the lines
 | 
						|
  //
 | 
						|
  if (FileBuffer.Lines != NULL) {
 | 
						|
 | 
						|
    Line  = FileBuffer.Lines;
 | 
						|
    Link  = &(Line->Link);
 | 
						|
    do {
 | 
						|
      Line  = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
      Link  = Link->ForwardLink;
 | 
						|
 | 
						|
      //
 | 
						|
      // free line's buffer and line itself
 | 
						|
      //
 | 
						|
      LineFree (Line);
 | 
						|
    } while (Link != FileBuffer.ListHead);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // clean the line list related structure
 | 
						|
  //
 | 
						|
  FileBuffer.Lines            = NULL;
 | 
						|
  FileBuffer.CurrentLine      = NULL;
 | 
						|
  FileBuffer.NumLines         = 0;
 | 
						|
 | 
						|
  FileBuffer.ListHead->ForwardLink  = FileBuffer.ListHead;
 | 
						|
  FileBuffer.ListHead->BackLink  = FileBuffer.ListHead;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Cleanup function for FileBuffer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   The cleanup was successful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferCleanup (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  SHELL_FREE_NON_NULL (FileBuffer.FileName);
 | 
						|
 | 
						|
  //
 | 
						|
  // free all the lines
 | 
						|
  //
 | 
						|
  Status = FileBufferFreeLines ();
 | 
						|
 | 
						|
  SHELL_FREE_NON_NULL (FileBuffer.ListHead);
 | 
						|
  FileBuffer.ListHead = NULL;
 | 
						|
 | 
						|
  SHELL_FREE_NON_NULL (FileBufferBackupVar.FileName);
 | 
						|
  return Status;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Print a line specified by Line on a row specified by Row of the screen.
 | 
						|
 | 
						|
  @param[in] Line               The line to print.
 | 
						|
  @param[in] Row                The row on the screen to print onto (begin from 1).
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The printing was successful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FileBufferPrintLine (
 | 
						|
  IN CONST EFI_EDITOR_LINE  *Line,
 | 
						|
  IN CONST UINTN            Row
 | 
						|
  )
 | 
						|
{
 | 
						|
 | 
						|
  CHAR16  *Buffer;
 | 
						|
  UINTN   Limit;
 | 
						|
  CHAR16  *PrintLine;
 | 
						|
  CHAR16  *PrintLine2;
 | 
						|
  UINTN   BufLen; 
 | 
						|
 | 
						|
  //
 | 
						|
  // print start from correct character
 | 
						|
  //
 | 
						|
  Buffer  = Line->Buffer + FileBuffer.LowVisibleRange.Column - 1;
 | 
						|
 | 
						|
  Limit   = Line->Size - FileBuffer.LowVisibleRange.Column + 1;
 | 
						|
  if (Limit > Line->Size) {
 | 
						|
    Limit = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  BufLen = (MainEditor.ScreenSize.Column + 1) * sizeof (CHAR16);
 | 
						|
  PrintLine = AllocatePool (BufLen);
 | 
						|
  ASSERT (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);
 | 
						|
  ASSERT (PrintLine2 != NULL);
 | 
						|
 | 
						|
  ShellCopySearchAndReplace(PrintLine, PrintLine2, BufLen * 2, L"%", L"^%", FALSE, FALSE);
 | 
						|
 | 
						|
  ShellPrintEx (
 | 
						|
    0,
 | 
						|
    (INT32)Row - 1,
 | 
						|
    L"%s",
 | 
						|
    PrintLine2
 | 
						|
    );
 | 
						|
 | 
						|
  FreePool (PrintLine);
 | 
						|
  FreePool (PrintLine2);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set the cursor position according to FileBuffer.DisplayPosition.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The operation was successful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferRestorePosition (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // set cursor position
 | 
						|
  //
 | 
						|
  return (gST->ConOut->SetCursorPosition (
 | 
						|
        gST->ConOut,
 | 
						|
        FileBuffer.DisplayPosition.Column - 1,
 | 
						|
        FileBuffer.DisplayPosition.Row - 1
 | 
						|
        ));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Refresh the screen with whats in the buffer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     The refresh was successful.
 | 
						|
  @retval EFI_LOAD_ERROR  There was an error finding what to write.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferRefresh (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY  *Link;
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  UINTN           Row;
 | 
						|
 | 
						|
  //
 | 
						|
  // if it's the first time after editor launch, so should refresh
 | 
						|
  //
 | 
						|
  if (!EditorFirst) {
 | 
						|
    //
 | 
						|
    // no definite required refresh
 | 
						|
    // and file position displayed on screen has not been changed
 | 
						|
    //
 | 
						|
    if (!FileBufferNeedRefresh &&
 | 
						|
        !FileBufferOnlyLineNeedRefresh &&
 | 
						|
        FileBufferBackupVar.LowVisibleRange.Row == FileBuffer.LowVisibleRange.Row &&
 | 
						|
        FileBufferBackupVar.LowVisibleRange.Column == FileBuffer.LowVisibleRange.Column
 | 
						|
        ) {
 | 
						|
 | 
						|
      FileBufferRestoreMousePosition ();
 | 
						|
      FileBufferRestorePosition ();
 | 
						|
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  gST->ConOut->EnableCursor (gST->ConOut, FALSE);
 | 
						|
 | 
						|
  //
 | 
						|
  // only need to refresh current line
 | 
						|
  //
 | 
						|
  if (FileBufferOnlyLineNeedRefresh &&
 | 
						|
      FileBufferBackupVar.LowVisibleRange.Row == FileBuffer.LowVisibleRange.Row &&
 | 
						|
      FileBufferBackupVar.LowVisibleRange.Column == FileBuffer.LowVisibleRange.Column
 | 
						|
      ) {
 | 
						|
 | 
						|
    EditorClearLine (FileBuffer.DisplayPosition.Row, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row);
 | 
						|
    FileBufferPrintLine (
 | 
						|
      FileBuffer.CurrentLine,
 | 
						|
      FileBuffer.DisplayPosition.Row
 | 
						|
      );
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // the whole edit area need refresh
 | 
						|
    //
 | 
						|
 | 
						|
    //
 | 
						|
    // no line
 | 
						|
    //
 | 
						|
    if (FileBuffer.Lines == NULL) {
 | 
						|
      FileBufferRestoreMousePosition ();
 | 
						|
      FileBufferRestorePosition ();
 | 
						|
      gST->ConOut->EnableCursor (gST->ConOut, TRUE);
 | 
						|
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // get the first line that will be displayed
 | 
						|
    //
 | 
						|
    Line = MoveLine (FileBuffer.LowVisibleRange.Row - FileBuffer.FilePosition.Row);
 | 
						|
    if (Line == NULL) {
 | 
						|
      gST->ConOut->EnableCursor (gST->ConOut, TRUE);
 | 
						|
 | 
						|
      return EFI_LOAD_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    Link  = &(Line->Link);
 | 
						|
    Row   = 2;
 | 
						|
    do {
 | 
						|
      Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
 | 
						|
      //
 | 
						|
      // print line at row
 | 
						|
      //
 | 
						|
      FileBufferPrintLine (Line, Row);
 | 
						|
 | 
						|
      Link = Link->ForwardLink;
 | 
						|
      Row++;
 | 
						|
    } while (Link != FileBuffer.ListHead && Row <= (MainEditor.ScreenSize.Row - 1));
 | 
						|
    //
 | 
						|
    // while not file end and not screen full
 | 
						|
    //
 | 
						|
    while (Row <= (MainEditor.ScreenSize.Row - 1)) {
 | 
						|
      EditorClearLine (Row, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row);
 | 
						|
      Row++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  FileBufferRestoreMousePosition ();
 | 
						|
  FileBufferRestorePosition ();
 | 
						|
 | 
						|
  FileBufferNeedRefresh         = FALSE;
 | 
						|
  FileBufferOnlyLineNeedRefresh = FALSE;
 | 
						|
 | 
						|
  gST->ConOut->EnableCursor (gST->ConOut, TRUE);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create a new line and append it to the line list.
 | 
						|
    Fields affected:
 | 
						|
      NumLines
 | 
						|
      Lines
 | 
						|
 | 
						|
  @retval NULL    The create line failed.
 | 
						|
  @return         The line created.
 | 
						|
**/
 | 
						|
EFI_EDITOR_LINE *
 | 
						|
EFIAPI
 | 
						|
FileBufferCreateLine (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
 | 
						|
  //
 | 
						|
  // allocate a line structure
 | 
						|
  //
 | 
						|
  Line = AllocateZeroPool (sizeof (EFI_EDITOR_LINE));
 | 
						|
  if (Line == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // initialize the structure
 | 
						|
  //
 | 
						|
  Line->Signature = LINE_LIST_SIGNATURE;
 | 
						|
  Line->Size      = 0;
 | 
						|
  Line->TotalSize = 0;
 | 
						|
  Line->Type      = NewLineTypeDefault;
 | 
						|
 | 
						|
  //
 | 
						|
  // initial buffer of the line is "\0"
 | 
						|
  //
 | 
						|
  ASSERT(CHAR_NULL == CHAR_NULL);
 | 
						|
  Line->Buffer = CatSPrint (NULL, L"\0");
 | 
						|
  if (Line->Buffer == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  FileBuffer.NumLines++;
 | 
						|
 | 
						|
  //
 | 
						|
  // insert the line into line list
 | 
						|
  //
 | 
						|
  InsertTailList (FileBuffer.ListHead, &Line->Link);
 | 
						|
 | 
						|
  if (FileBuffer.Lines == NULL) {
 | 
						|
    FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
  }
 | 
						|
 | 
						|
  return Line;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set FileName field in FileBuffer.
 | 
						|
 | 
						|
  @param Str                    The file name to set.
 | 
						|
  
 | 
						|
  @retval EFI_SUCCESS           The filename was successfully set.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
 | 
						|
  @retval EFI_INVALID_PARAMETER Str is not a valid filename.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferSetFileName (
 | 
						|
  IN CONST CHAR16 *Str
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Verify the parameters
 | 
						|
  //
 | 
						|
  if (!IsValidFileName(Str)) {
 | 
						|
    return (EFI_INVALID_PARAMETER);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // free the old file name
 | 
						|
  //
 | 
						|
  SHELL_FREE_NON_NULL (FileBuffer.FileName);
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate and set the new name
 | 
						|
  //
 | 
						|
  FileBuffer.FileName = CatSPrint (NULL, L"%s", Str);
 | 
						|
  if (FileBuffer.FileName == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
/**
 | 
						|
  Free the existing file lines and reset the modified flag.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The operation was successful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferFree (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // free all the lines
 | 
						|
  //
 | 
						|
  FileBufferFreeLines ();
 | 
						|
  FileBuffer.FileModified = FALSE;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Read a file from disk into the FileBuffer.
 | 
						|
  
 | 
						|
  @param[in] FileName           The filename to read.
 | 
						|
  @param[in] Recover            TRUE if is for recover mode, no information printouts.
 | 
						|
  
 | 
						|
  @retval EFI_SUCCESS            The load was successful.
 | 
						|
  @retval EFI_LOAD_ERROR         The load failed.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   A memory allocation failed.
 | 
						|
  @retval EFI_INVALID_PARAMETER  FileName is a directory.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferRead (
 | 
						|
  IN CONST CHAR16  *FileName,
 | 
						|
  IN CONST BOOLEAN Recover
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE                 *Line;
 | 
						|
  EE_NEWLINE_TYPE                 Type;
 | 
						|
  UINTN                           LoopVar1;
 | 
						|
  UINTN                           LoopVar2;
 | 
						|
  UINTN                           LineSize;
 | 
						|
  VOID                            *Buffer;
 | 
						|
  CHAR16                          *UnicodeBuffer;
 | 
						|
  UINT8                           *AsciiBuffer;
 | 
						|
  UINTN                           FileSize;
 | 
						|
  SHELL_FILE_HANDLE               FileHandle;
 | 
						|
  BOOLEAN                         CreateFile;
 | 
						|
  EFI_STATUS                      Status;
 | 
						|
  UINTN                           LineSizeBackup;
 | 
						|
  EFI_FILE_INFO                   *Info;
 | 
						|
 | 
						|
  Line          = NULL;
 | 
						|
  LoopVar1      = 0;
 | 
						|
  FileSize      = 0;
 | 
						|
  UnicodeBuffer = NULL;
 | 
						|
  Type          = NewLineTypeDefault;
 | 
						|
  FileHandle    = NULL;
 | 
						|
  CreateFile    = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // in this function, when you return error ( except EFI_OUT_OF_RESOURCES )
 | 
						|
  // you should set status string via StatusBarSetStatusString(L"blah")
 | 
						|
  // since this function maybe called before the editorhandleinput loop
 | 
						|
  // so any error will cause editor return
 | 
						|
  // so if you want to print the error status
 | 
						|
  // you should set the status string
 | 
						|
  //
 | 
						|
 | 
						|
  //
 | 
						|
  // try to open the file
 | 
						|
  //
 | 
						|
  Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ, 0);
 | 
						|
 | 
						|
  if (!EFI_ERROR(Status)) {
 | 
						|
    CreateFile = FALSE;
 | 
						|
    if (FileHandle == NULL) {
 | 
						|
      StatusBarSetStatusString (L"Disk Error");
 | 
						|
      return EFI_LOAD_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    Info = ShellGetFileInfo(FileHandle);
 | 
						|
    
 | 
						|
    if (Info->Attribute & EFI_FILE_DIRECTORY) {
 | 
						|
      StatusBarSetStatusString (L"Directory Can Not Be Edited");
 | 
						|
      FreePool (Info);
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Info->Attribute & EFI_FILE_READ_ONLY) {
 | 
						|
      FileBuffer.ReadOnly = TRUE;
 | 
						|
    } else {
 | 
						|
      FileBuffer.ReadOnly = FALSE;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // get file size
 | 
						|
    //
 | 
						|
    FileSize = (UINTN) Info->FileSize;
 | 
						|
 | 
						|
    FreePool (Info);
 | 
						|
  } else if (Status == EFI_NOT_FOUND) {
 | 
						|
    //
 | 
						|
    // file not exists.  add create and try again
 | 
						|
    //
 | 
						|
    Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      if (Status == EFI_WRITE_PROTECTED ||
 | 
						|
          Status == EFI_ACCESS_DENIED ||
 | 
						|
          Status == EFI_NO_MEDIA ||
 | 
						|
          Status == EFI_MEDIA_CHANGED
 | 
						|
          ) {
 | 
						|
        StatusBarSetStatusString (L"Access Denied");
 | 
						|
      } else if (Status == EFI_DEVICE_ERROR || Status == EFI_VOLUME_CORRUPTED || Status == EFI_VOLUME_FULL) {
 | 
						|
        StatusBarSetStatusString (L"Disk Error");
 | 
						|
      } else {
 | 
						|
        StatusBarSetStatusString (L"Invalid File Name or Current-working-directory");
 | 
						|
      }
 | 
						|
 | 
						|
      return Status;
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // it worked.  now delete it and move on with the name (now validated)
 | 
						|
      //
 | 
						|
      Status = ShellDeleteFile (&FileHandle);
 | 
						|
      if (Status == EFI_WARN_DELETE_FAILURE) {
 | 
						|
        Status = EFI_ACCESS_DENIED;
 | 
						|
      }
 | 
						|
      FileHandle = NULL;
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        StatusBarSetStatusString (L"Access Denied");
 | 
						|
        return Status;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // file doesn't exist, so set CreateFile to TRUE
 | 
						|
    //
 | 
						|
    CreateFile          = TRUE;
 | 
						|
    FileBuffer.ReadOnly = FALSE;
 | 
						|
 | 
						|
    //
 | 
						|
    // all the check ends
 | 
						|
    // so now begin to set file name, free lines
 | 
						|
    //
 | 
						|
    if (StrCmp (FileName, FileBuffer.FileName) != 0) {
 | 
						|
      FileBufferSetFileName (FileName);
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // free the old lines
 | 
						|
    //
 | 
						|
    FileBufferFree ();
 | 
						|
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // the file exists
 | 
						|
  //
 | 
						|
  if (!CreateFile) {
 | 
						|
    //
 | 
						|
    // allocate buffer to read file
 | 
						|
    //
 | 
						|
    Buffer = AllocateZeroPool (FileSize);
 | 
						|
    if (Buffer == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // read file into Buffer
 | 
						|
    //
 | 
						|
    Status = ShellReadFile (FileHandle, &FileSize, Buffer);
 | 
						|
    ShellCloseFile(&FileHandle);
 | 
						|
    FileHandle = NULL;
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      StatusBarSetStatusString (L"Read File Failed");
 | 
						|
      SHELL_FREE_NON_NULL (Buffer);
 | 
						|
      return EFI_LOAD_ERROR;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // nothing in this file
 | 
						|
    //
 | 
						|
    if (FileSize == 0) {
 | 
						|
      SHELL_FREE_NON_NULL (Buffer);
 | 
						|
      //
 | 
						|
      // since has no head, so only can be an ASCII file
 | 
						|
      //
 | 
						|
      FileBuffer.FileType = FileTypeAscii;
 | 
						|
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
 | 
						|
    AsciiBuffer = Buffer;
 | 
						|
 | 
						|
    if (FileSize < 2) {
 | 
						|
      //
 | 
						|
      // size < Unicode file header, so only can be ASCII file
 | 
						|
      //
 | 
						|
      FileBuffer.FileType = FileTypeAscii;
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // Unicode file
 | 
						|
      //
 | 
						|
      if (*(UINT16 *) Buffer == EFI_UNICODE_BYTE_ORDER_MARK) {
 | 
						|
        //
 | 
						|
        // Unicode file's size should be even
 | 
						|
        //
 | 
						|
        if ((FileSize % 2) != 0) {
 | 
						|
          StatusBarSetStatusString (L"File Format Wrong");
 | 
						|
          SHELL_FREE_NON_NULL (Buffer);
 | 
						|
          return EFI_LOAD_ERROR;
 | 
						|
        }
 | 
						|
 | 
						|
        FileSize /= 2;
 | 
						|
 | 
						|
        FileBuffer.FileType = FileTypeUnicode;
 | 
						|
        UnicodeBuffer       = Buffer;
 | 
						|
 | 
						|
        //
 | 
						|
        // pass this 0xff and 0xfe
 | 
						|
        //
 | 
						|
        UnicodeBuffer++;
 | 
						|
        FileSize--;
 | 
						|
      } else {
 | 
						|
        FileBuffer.FileType = FileTypeAscii;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // end of AsciiBuffer ==
 | 
						|
      //
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // end of FileSize < 2
 | 
						|
    // all the check ends
 | 
						|
    // so now begin to set file name, free lines
 | 
						|
    //
 | 
						|
    if (StrCmp (FileName, FileBuffer.FileName) != 0) {
 | 
						|
      FileBufferSetFileName (FileName);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // free the old lines
 | 
						|
    //
 | 
						|
    FileBufferFree ();
 | 
						|
 | 
						|
    //
 | 
						|
    // parse file content line by line
 | 
						|
    //
 | 
						|
    for (LoopVar1 = 0; LoopVar1 < FileSize; LoopVar1++) {
 | 
						|
      Type = NewLineTypeUnknown;
 | 
						|
 | 
						|
      for (LineSize = LoopVar1; LineSize < FileSize; LineSize++) {
 | 
						|
        if (FileBuffer.FileType == FileTypeAscii) {
 | 
						|
          if (AsciiBuffer[LineSize] == CHAR_CARRIAGE_RETURN) {
 | 
						|
            Type = NewLineTypeCarriageReturn;
 | 
						|
 | 
						|
            //
 | 
						|
            // has LF following
 | 
						|
            //
 | 
						|
            if (LineSize < FileSize - 1) {
 | 
						|
              if (AsciiBuffer[LineSize + 1] == CHAR_LINEFEED) {
 | 
						|
                Type = NewLineTypeCarriageReturnLineFeed;
 | 
						|
              }
 | 
						|
            }
 | 
						|
 | 
						|
            break;
 | 
						|
          } else if (AsciiBuffer[LineSize] == CHAR_LINEFEED) {
 | 
						|
            Type = NewLineTypeLineFeed;
 | 
						|
 | 
						|
            //
 | 
						|
            // has CR following
 | 
						|
            //
 | 
						|
            if (LineSize < FileSize - 1) {
 | 
						|
              if (AsciiBuffer[LineSize + 1] == CHAR_CARRIAGE_RETURN) {
 | 
						|
                Type = NewLineTypeLineFeedCarriageReturn;
 | 
						|
              }
 | 
						|
            }
 | 
						|
 | 
						|
            break;
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          if (UnicodeBuffer[LineSize] == CHAR_CARRIAGE_RETURN) {
 | 
						|
            Type = NewLineTypeCarriageReturn;
 | 
						|
 | 
						|
            //
 | 
						|
            // has LF following
 | 
						|
            //
 | 
						|
            if (LineSize < FileSize - 1) {
 | 
						|
              if (UnicodeBuffer[LineSize + 1] == CHAR_LINEFEED) {
 | 
						|
                Type = NewLineTypeCarriageReturnLineFeed;
 | 
						|
              }
 | 
						|
            }
 | 
						|
 | 
						|
            break;
 | 
						|
          } else if (UnicodeBuffer[LineSize] == CHAR_LINEFEED) {
 | 
						|
            Type = NewLineTypeLineFeed;
 | 
						|
 | 
						|
            //
 | 
						|
            // has CR following
 | 
						|
            //
 | 
						|
            if (LineSize < FileSize - 1) {
 | 
						|
              if (UnicodeBuffer[LineSize + 1] == CHAR_CARRIAGE_RETURN) {
 | 
						|
                Type = NewLineTypeLineFeedCarriageReturn;
 | 
						|
              }
 | 
						|
            }
 | 
						|
 | 
						|
            break;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // endif == ASCII
 | 
						|
        //
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // end of for LineSize
 | 
						|
      //
 | 
						|
      // if the type is wrong, then exit
 | 
						|
      //
 | 
						|
      if (Type == NewLineTypeUnknown) {
 | 
						|
        //
 | 
						|
        // Now if Type is NewLineTypeUnknown, it should be file end
 | 
						|
        //
 | 
						|
        Type = NewLineTypeDefault;
 | 
						|
      }
 | 
						|
 | 
						|
      LineSizeBackup = LineSize;
 | 
						|
 | 
						|
      //
 | 
						|
      // create a new line
 | 
						|
      //
 | 
						|
      Line = FileBufferCreateLine ();
 | 
						|
      if (Line == NULL) {
 | 
						|
        SHELL_FREE_NON_NULL (Buffer);
 | 
						|
        return EFI_OUT_OF_RESOURCES;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // calculate file length
 | 
						|
      //
 | 
						|
      LineSize -= LoopVar1;
 | 
						|
 | 
						|
      //
 | 
						|
      // Unicode and one CHAR_NULL
 | 
						|
      //
 | 
						|
      SHELL_FREE_NON_NULL (Line->Buffer);
 | 
						|
      Line->Buffer = AllocateZeroPool (LineSize * 2 + 2);
 | 
						|
 | 
						|
      if (Line->Buffer == NULL) {
 | 
						|
        RemoveEntryList (&Line->Link);
 | 
						|
        return EFI_OUT_OF_RESOURCES;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // copy this line to Line->Buffer
 | 
						|
      //
 | 
						|
      for (LoopVar2 = 0; LoopVar2 < LineSize; LoopVar2++) {
 | 
						|
        if (FileBuffer.FileType == FileTypeAscii) {
 | 
						|
          Line->Buffer[LoopVar2] = (CHAR16) AsciiBuffer[LoopVar1];
 | 
						|
        } else {
 | 
						|
          Line->Buffer[LoopVar2] = UnicodeBuffer[LoopVar1];
 | 
						|
        }
 | 
						|
 | 
						|
        LoopVar1++;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // LoopVar1 now points to where CHAR_CARRIAGE_RETURN or CHAR_LINEFEED;
 | 
						|
      //
 | 
						|
      Line->Buffer[LineSize]  = 0;
 | 
						|
 | 
						|
      Line->Size              = LineSize;
 | 
						|
      Line->TotalSize         = LineSize;
 | 
						|
      Line->Type              = Type;
 | 
						|
 | 
						|
      if (Type == NewLineTypeCarriageReturnLineFeed || Type == NewLineTypeLineFeedCarriageReturn) {
 | 
						|
        LoopVar1++;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // last character is a return, SO create a new line
 | 
						|
      //
 | 
						|
      if (((Type == NewLineTypeCarriageReturnLineFeed || Type == NewLineTypeLineFeedCarriageReturn) && LineSizeBackup == FileSize - 2) ||
 | 
						|
          ((Type == NewLineTypeLineFeed || Type == NewLineTypeCarriageReturn) && LineSizeBackup == FileSize - 1)
 | 
						|
          ) {
 | 
						|
        Line = FileBufferCreateLine ();
 | 
						|
        if (Line == NULL) {
 | 
						|
          SHELL_FREE_NON_NULL (Buffer);
 | 
						|
          return EFI_OUT_OF_RESOURCES;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // end of if
 | 
						|
      //
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // end of LoopVar1
 | 
						|
    //
 | 
						|
    SHELL_FREE_NON_NULL (Buffer);
 | 
						|
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // end of if CreateFile
 | 
						|
  //
 | 
						|
Done:
 | 
						|
 | 
						|
  FileBuffer.DisplayPosition.Row    = 2;
 | 
						|
  FileBuffer.DisplayPosition.Column = 1;
 | 
						|
  FileBuffer.LowVisibleRange.Row    = 1;
 | 
						|
  FileBuffer.LowVisibleRange.Column = 1;
 | 
						|
  FileBuffer.FilePosition.Row       = 1;
 | 
						|
  FileBuffer.FilePosition.Column    = 1;
 | 
						|
  FileBuffer.MousePosition.Row      = 2;
 | 
						|
  FileBuffer.MousePosition.Column   = 1;
 | 
						|
 | 
						|
  if (!Recover) {
 | 
						|
    UnicodeBuffer = CatSPrint (NULL, L"%d Lines Read", FileBuffer.NumLines);
 | 
						|
    if (UnicodeBuffer == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    StatusBarSetStatusString (UnicodeBuffer);
 | 
						|
    FreePool (UnicodeBuffer);
 | 
						|
  }
 | 
						|
/*
 | 
						|
    //
 | 
						|
    // check whether we have fs?: in filename
 | 
						|
    //
 | 
						|
    LoopVar1             = 0;
 | 
						|
    FSMappingPtr  = NULL;
 | 
						|
    while (FileName[LoopVar1] != 0) {
 | 
						|
      if (FileName[LoopVar1] == L':') {
 | 
						|
        FSMappingPtr = &FileName[LoopVar1];
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      LoopVar1++;
 | 
						|
    }
 | 
						|
 | 
						|
    if (FSMappingPtr == NULL) {
 | 
						|
      CurDir = ShellGetCurrentDir (NULL);
 | 
						|
    } else {
 | 
						|
      LoopVar1 = 0;
 | 
						|
      LoopVar2 = 0;
 | 
						|
      while (FileName[LoopVar1] != 0) {
 | 
						|
        if (FileName[LoopVar1] == L':') {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        FSMapping[LoopVar2++] = FileName[LoopVar1];
 | 
						|
 | 
						|
        LoopVar1++;
 | 
						|
      }
 | 
						|
 | 
						|
      FSMapping[LoopVar2]  = 0;
 | 
						|
      CurDir        = ShellGetCurrentDir (FSMapping);
 | 
						|
    }
 | 
						|
 | 
						|
    if (CurDir != NULL) {
 | 
						|
      for (LoopVar1 = 0; LoopVar1 < StrLen (CurDir) && CurDir[LoopVar1] != ':'; LoopVar1++);
 | 
						|
 | 
						|
      CurDir[LoopVar1]   = 0;
 | 
						|
      DevicePath  = (EFI_DEVICE_PATH_PROTOCOL *) ShellGetMap (CurDir);
 | 
						|
      FreePool (CurDir);
 | 
						|
    } else {
 | 
						|
      return EFI_LOAD_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = LibDevicePathToInterface (
 | 
						|
              &gEfiSimpleFileSystemProtocolGuid,
 | 
						|
              DevicePath,
 | 
						|
              (VOID **) &Vol
 | 
						|
              );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_LOAD_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = Vol->OpenVolume (Vol, &RootFs);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_LOAD_ERROR;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Get volume information of file system
 | 
						|
    //
 | 
						|
    Size        = SIZE_OF_EFI_FILE_SYSTEM_INFO + 100;
 | 
						|
    VolumeInfo  = (EFI_FILE_SYSTEM_INFO *) AllocateZeroPool (Size);
 | 
						|
    Status      = RootFs->GetInfo (RootFs, &gEfiFileSystemInfoGuid, &Size, VolumeInfo);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      RootFs->Close (RootFs);
 | 
						|
      return EFI_LOAD_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    if (VolumeInfo->ReadOnly) {
 | 
						|
      StatusBarSetStatusString (L"WARNING: Volume Read Only");
 | 
						|
    }
 | 
						|
 | 
						|
    FreePool (VolumeInfo);
 | 
						|
    RootFs->Close (RootFs);
 | 
						|
  }
 | 
						|
//
 | 
						|
*/
 | 
						|
  //
 | 
						|
  // has line
 | 
						|
  //
 | 
						|
  if (FileBuffer.Lines != 0) {
 | 
						|
    FileBuffer.CurrentLine = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // create a dummy line
 | 
						|
    //
 | 
						|
    Line = FileBufferCreateLine ();
 | 
						|
    if (Line == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    FileBuffer.CurrentLine = Line;
 | 
						|
  }
 | 
						|
 | 
						|
  FileBuffer.FileModified       = FALSE;
 | 
						|
  FileBufferNeedRefresh         = TRUE;
 | 
						|
  FileBufferOnlyLineNeedRefresh = FALSE;
 | 
						|
  FileBufferMouseNeedRefresh    = TRUE;
 | 
						|
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  According to FileBuffer.NewLineType & FileBuffer.FileType,
 | 
						|
  get the return buffer and size.
 | 
						|
 | 
						|
  @param[in] Type               The type of line.
 | 
						|
  @param[out] Buffer            The buffer to fill.
 | 
						|
  @param[out] Size              The amount of the buffer used on return.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
GetNewLine (
 | 
						|
  IN CONST EE_NEWLINE_TYPE Type,
 | 
						|
  OUT CHAR8           *Buffer,
 | 
						|
  OUT UINT8           *Size
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8 NewLineSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // give new line buffer,
 | 
						|
  // and will judge unicode or ascii
 | 
						|
  //
 | 
						|
  NewLineSize = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // not legal new line type
 | 
						|
  //
 | 
						|
  if (Type != NewLineTypeLineFeed && Type != NewLineTypeCarriageReturn && Type != NewLineTypeCarriageReturnLineFeed && Type != NewLineTypeLineFeedCarriageReturn) {
 | 
						|
    *Size = 0;
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // use_cr: give 0x0d
 | 
						|
  //
 | 
						|
  if (Type == NewLineTypeCarriageReturn) {
 | 
						|
    if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {
 | 
						|
      Buffer[0]   = 0x0d;
 | 
						|
      Buffer[1]   = 0;
 | 
						|
      NewLineSize = 2;
 | 
						|
    } else {
 | 
						|
      Buffer[0]   = 0x0d;
 | 
						|
      NewLineSize = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    *Size = NewLineSize;
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // use_lf: give 0x0a
 | 
						|
  //
 | 
						|
  if (Type == NewLineTypeLineFeed) {
 | 
						|
    if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {
 | 
						|
      Buffer[0]   = 0x0a;
 | 
						|
      Buffer[1]   = 0;
 | 
						|
      NewLineSize = 2;
 | 
						|
    } else {
 | 
						|
      Buffer[0]   = 0x0a;
 | 
						|
      NewLineSize = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    *Size = NewLineSize;
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // use_crlf: give 0x0d 0x0a
 | 
						|
  //
 | 
						|
  if (Type == NewLineTypeCarriageReturnLineFeed) {
 | 
						|
    if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {
 | 
						|
      Buffer[0]   = 0x0d;
 | 
						|
      Buffer[1]   = 0;
 | 
						|
      Buffer[2]   = 0x0a;
 | 
						|
      Buffer[3]   = 0;
 | 
						|
 | 
						|
      NewLineSize = 4;
 | 
						|
    } else {
 | 
						|
      Buffer[0]   = 0x0d;
 | 
						|
      Buffer[1]   = 0x0a;
 | 
						|
      NewLineSize = 2;
 | 
						|
    }
 | 
						|
 | 
						|
    *Size = NewLineSize;
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // use_lfcr: give 0x0a 0x0d
 | 
						|
  //
 | 
						|
  if (Type == NewLineTypeLineFeedCarriageReturn) {
 | 
						|
    if (MainEditor.FileBuffer->FileType == FileTypeUnicode) {
 | 
						|
      Buffer[0]   = 0x0a;
 | 
						|
      Buffer[1]   = 0;
 | 
						|
      Buffer[2]   = 0x0d;
 | 
						|
      Buffer[3]   = 0;
 | 
						|
 | 
						|
      NewLineSize = 4;
 | 
						|
    } else {
 | 
						|
      Buffer[0]   = 0x0a;
 | 
						|
      Buffer[1]   = 0x0d;
 | 
						|
      NewLineSize = 2;
 | 
						|
    }
 | 
						|
 | 
						|
    *Size = NewLineSize;
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Change a Unicode string to an ASCII string.
 | 
						|
 | 
						|
  @param[in] UStr     The Unicode string.
 | 
						|
  @param[in] Length   The maximum size of AStr.
 | 
						|
  @param[out] AStr    ASCII string to pass out.
 | 
						|
 | 
						|
  @return The actuall length.
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
EFIAPI
 | 
						|
UnicodeToAscii (
 | 
						|
  IN CONST CHAR16   *UStr,
 | 
						|
  IN CONST UINTN    Length,
 | 
						|
  OUT CHAR8         *AStr
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // just buffer copy, not character copy
 | 
						|
  //
 | 
						|
  for (Index = 0; Index < Length; Index++) {
 | 
						|
    *AStr++ = (CHAR8) *UStr++;
 | 
						|
  }
 | 
						|
 | 
						|
  return Index;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Save lines in FileBuffer to disk
 | 
						|
 | 
						|
  @param[in] FileName           The file name for writing.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Data was written.
 | 
						|
  @retval EFI_LOAD_ERROR        
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  There were not enough resources to write the file.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferSave (
 | 
						|
  IN CONST CHAR16 *FileName
 | 
						|
  )
 | 
						|
{
 | 
						|
  SHELL_FILE_HANDLE FileHandle;
 | 
						|
  LIST_ENTRY        *Link;
 | 
						|
  EFI_EDITOR_LINE   *Line;
 | 
						|
  CHAR16            *Str;
 | 
						|
 | 
						|
  EFI_STATUS        Status;
 | 
						|
  UINTN             Length;
 | 
						|
  UINTN             NumLines;
 | 
						|
  CHAR8             NewLineBuffer[4];
 | 
						|
  UINT8             NewLineSize;
 | 
						|
 | 
						|
  EFI_FILE_INFO     *Info;
 | 
						|
 | 
						|
  UINT64            Attribute;
 | 
						|
 | 
						|
  EE_NEWLINE_TYPE   Type;
 | 
						|
 | 
						|
  UINTN             TotalSize;
 | 
						|
  //
 | 
						|
  // 2M
 | 
						|
  //
 | 
						|
  CHAR8             *Cache;
 | 
						|
  UINTN             LeftSize;
 | 
						|
  UINTN             Size;
 | 
						|
  CHAR8             *Ptr;
 | 
						|
 | 
						|
  Length    = 0;
 | 
						|
  //
 | 
						|
  // 2M
 | 
						|
  //
 | 
						|
  TotalSize = 0x200000;
 | 
						|
 | 
						|
  Attribute = 0;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
  //
 | 
						|
  // if is the old file
 | 
						|
  //
 | 
						|
  if (FileBuffer.FileName != NULL && StrCmp (FileName, FileBuffer.FileName) == 0) {
 | 
						|
    //
 | 
						|
    // file has not been modified
 | 
						|
    //
 | 
						|
    if (!FileBuffer.FileModified) {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // if file is read-only, set error
 | 
						|
    //
 | 
						|
    if (FileBuffer.ReadOnly) {
 | 
						|
      StatusBarSetStatusString (L"Read Only File Can Not Be Saved");
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0);
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    Info = ShellGetFileInfo(FileHandle);
 | 
						|
 | 
						|
    if (Info != NULL && Info->Attribute & EFI_FILE_DIRECTORY) {
 | 
						|
      StatusBarSetStatusString (L"Directory Can Not Be Saved");
 | 
						|
      ShellCloseFile(FileHandle);
 | 
						|
      FreePool(Info);
 | 
						|
      return EFI_LOAD_ERROR;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (Info != NULL) {
 | 
						|
      Attribute = Info->Attribute & ~EFI_FILE_READ_ONLY;
 | 
						|
      FreePool(Info);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // if file exits, so delete it
 | 
						|
    //
 | 
						|
    Status = ShellDeleteFile (&FileHandle);
 | 
						|
    if (EFI_ERROR (Status) || Status == EFI_WARN_DELETE_FAILURE) {
 | 
						|
      StatusBarSetStatusString (L"Write File Failed");
 | 
						|
      return EFI_LOAD_ERROR;
 | 
						|
    }
 | 
						|
 }
 | 
						|
 | 
						|
  Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, Attribute);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    StatusBarSetStatusString (L"Create File Failed");
 | 
						|
    return EFI_LOAD_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // if file is Unicode file, write Unicode header to it.
 | 
						|
  //
 | 
						|
  if (FileBuffer.FileType == FileTypeUnicode) {
 | 
						|
    Length  = 2;
 | 
						|
    Status  = ShellWriteFile (FileHandle, &Length, (VOID*)&gUnicodeFileTag);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      ShellDeleteFile (&FileHandle);
 | 
						|
      return EFI_LOAD_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Cache = AllocateZeroPool (TotalSize);
 | 
						|
  if (Cache == NULL) {
 | 
						|
    ShellDeleteFile (&FileHandle);
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // write all the lines back to disk
 | 
						|
  //
 | 
						|
  NumLines  = 0;
 | 
						|
  Type      = NewLineTypeCarriageReturnLineFeed;
 | 
						|
 | 
						|
  Ptr       = Cache;
 | 
						|
  LeftSize  = TotalSize;
 | 
						|
 | 
						|
  for (Link = FileBuffer.ListHead->ForwardLink; Link != FileBuffer.ListHead; Link = Link->ForwardLink) {
 | 
						|
    Line = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
 | 
						|
    if (Line->Type != NewLineTypeDefault) {
 | 
						|
      Type = Line->Type;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // newline character is at most 4 bytes ( two Unicode characters )
 | 
						|
    //
 | 
						|
    Length = 4;
 | 
						|
    if (Line->Buffer != NULL && Line->Size != 0) {
 | 
						|
      if (FileBuffer.FileType == FileTypeAscii) {
 | 
						|
        Length += Line->Size;
 | 
						|
      } else {
 | 
						|
        Length += (Line->Size * 2);
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // end if FileTypeAscii
 | 
						|
      //
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // no cache room left, so write cache to disk
 | 
						|
    //
 | 
						|
    if (LeftSize < Length) {
 | 
						|
      Size    = TotalSize - LeftSize;
 | 
						|
      Status  = ShellWriteFile (FileHandle, &Size, Cache);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        ShellDeleteFile (&FileHandle);        
 | 
						|
        FreePool (Cache);
 | 
						|
        return EFI_LOAD_ERROR;
 | 
						|
      }
 | 
						|
      Ptr       = Cache;
 | 
						|
      LeftSize  = TotalSize;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Line->Buffer != NULL && Line->Size != 0) {
 | 
						|
      if (FileBuffer.FileType == FileTypeAscii) {
 | 
						|
        UnicodeToAscii (Line->Buffer, Line->Size, Ptr);
 | 
						|
        Length = Line->Size;
 | 
						|
      } else {
 | 
						|
        Length = (Line->Size * 2);
 | 
						|
        CopyMem (Ptr, (CHAR8 *) Line->Buffer, Length);
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // end if FileTypeAscii
 | 
						|
      //
 | 
						|
      Ptr += Length;
 | 
						|
      LeftSize -= Length;
 | 
						|
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // end of if Line -> Buffer != NULL && Line -> Size != 0
 | 
						|
    //
 | 
						|
    // if not the last line , write return buffer to disk
 | 
						|
    //
 | 
						|
    if (Link->ForwardLink != FileBuffer.ListHead) {
 | 
						|
      GetNewLine (Type, NewLineBuffer, &NewLineSize);
 | 
						|
      CopyMem (Ptr, (CHAR8 *) NewLineBuffer, NewLineSize);
 | 
						|
 | 
						|
      Ptr += NewLineSize;
 | 
						|
      LeftSize -= NewLineSize;
 | 
						|
    }
 | 
						|
 | 
						|
    NumLines++;
 | 
						|
  }
 | 
						|
 | 
						|
  if (TotalSize != LeftSize) {
 | 
						|
    Size    = TotalSize - LeftSize;
 | 
						|
    Status  = ShellWriteFile (FileHandle, &Size, Cache);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      ShellDeleteFile (&FileHandle);
 | 
						|
      FreePool (Cache);
 | 
						|
      return EFI_LOAD_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (Cache);
 | 
						|
 | 
						|
  ShellCloseFile(&FileHandle);
 | 
						|
 | 
						|
  FileBuffer.FileModified = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // set status string
 | 
						|
  //
 | 
						|
  Str = CatSPrint (NULL, L"%d Lines Wrote", NumLines);
 | 
						|
  if (Str == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  StatusBarSetStatusString (Str);
 | 
						|
  SHELL_FREE_NON_NULL (Str);
 | 
						|
 | 
						|
  //
 | 
						|
  // now everything is ready , you can set the new file name to filebuffer
 | 
						|
  //
 | 
						|
  if (FileName != NULL && FileBuffer.FileName != NULL && StrCmp (FileName, FileBuffer.FileName) != 0) {
 | 
						|
    //
 | 
						|
    // not the same
 | 
						|
    //
 | 
						|
    FileBufferSetFileName (FileName);
 | 
						|
    if (FileBuffer.FileName == NULL) {
 | 
						|
      ShellDeleteFile (&FileHandle);
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  FileBuffer.ReadOnly = FALSE;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Scroll cursor to left 1 character position.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     The operation was successful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferScrollLeft (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  UINTN           FRow;
 | 
						|
  UINTN           FCol;
 | 
						|
 | 
						|
  Line  = FileBuffer.CurrentLine;
 | 
						|
 | 
						|
  FRow  = FileBuffer.FilePosition.Row;
 | 
						|
  FCol  = FileBuffer.FilePosition.Column;
 | 
						|
 | 
						|
  //
 | 
						|
  // if already at start of this line, so move to the end of previous line
 | 
						|
  //
 | 
						|
  if (FCol <= 1) {
 | 
						|
    //
 | 
						|
    // has previous line
 | 
						|
    //
 | 
						|
    if (Line->Link.BackLink != FileBuffer.ListHead) {
 | 
						|
      FRow--;
 | 
						|
      Line  = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
      FCol  = Line->Size + 1;
 | 
						|
    } else {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // if not at start of this line, just move to previous column
 | 
						|
    //
 | 
						|
    FCol--;
 | 
						|
  }
 | 
						|
 | 
						|
  FileBufferMovePosition (FRow, FCol);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Delete a char in line
 | 
						|
 | 
						|
  @param[in, out] Line   The line to delete in.
 | 
						|
  @param[in] Pos         Position to delete the char at ( start from 0 ).
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
LineDeleteAt (
 | 
						|
  IN  OUT EFI_EDITOR_LINE       *Line,
 | 
						|
  IN      UINTN                 Pos
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // move the latter characters front
 | 
						|
  //
 | 
						|
  for (Index = Pos - 1; Index < Line->Size; Index++) {
 | 
						|
    Line->Buffer[Index] = Line->Buffer[Index + 1];
 | 
						|
  }
 | 
						|
 | 
						|
  Line->Size--;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Concatenate Src into Dest.
 | 
						|
 | 
						|
  @param[in, out] Dest   Destination string
 | 
						|
  @param[in] Src         Src String.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
LineCat (
 | 
						|
  IN  OUT EFI_EDITOR_LINE *Dest,
 | 
						|
  IN      EFI_EDITOR_LINE *Src
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16  *Str;
 | 
						|
  UINTN   Size;
 | 
						|
 | 
						|
  Size                = Dest->Size;
 | 
						|
 | 
						|
  Dest->Buffer[Size]  = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // concatenate the two strings
 | 
						|
  //
 | 
						|
  Str = CatSPrint (NULL, L"%s%s", Dest->Buffer, Src->Buffer);
 | 
						|
  if (Str == NULL) {
 | 
						|
    Dest->Buffer = NULL;
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  Dest->Size      = Size + Src->Size;
 | 
						|
  Dest->TotalSize = Dest->Size;
 | 
						|
 | 
						|
  FreePool (Dest->Buffer);
 | 
						|
  FreePool (Src->Buffer);
 | 
						|
 | 
						|
  //
 | 
						|
  // put str to dest->buffer
 | 
						|
  //
 | 
						|
  Dest->Buffer = Str;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Delete the previous character.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The delete was successful.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferDoBackspace (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  EFI_EDITOR_LINE *End;
 | 
						|
  LIST_ENTRY  *Link;
 | 
						|
  UINTN           FileColumn;
 | 
						|
 | 
						|
  FileColumn  = FileBuffer.FilePosition.Column;
 | 
						|
 | 
						|
  Line        = FileBuffer.CurrentLine;
 | 
						|
 | 
						|
  //
 | 
						|
  // the first column
 | 
						|
  //
 | 
						|
  if (FileColumn == 1) {
 | 
						|
    //
 | 
						|
    // the first row
 | 
						|
    //
 | 
						|
    if (FileBuffer.FilePosition.Row == 1) {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
 | 
						|
    FileBufferScrollLeft ();
 | 
						|
 | 
						|
    Line  = FileBuffer.CurrentLine;
 | 
						|
    Link  = Line->Link.ForwardLink;
 | 
						|
    End   = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
 | 
						|
    //
 | 
						|
    // concatenate this line with previous line
 | 
						|
    //
 | 
						|
    LineCat (Line, End);
 | 
						|
    if (Line->Buffer == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // remove End from line list
 | 
						|
    //
 | 
						|
    RemoveEntryList (&End->Link);
 | 
						|
    FreePool (End);
 | 
						|
 | 
						|
    FileBuffer.NumLines--;
 | 
						|
 | 
						|
    FileBufferNeedRefresh         = TRUE;
 | 
						|
    FileBufferOnlyLineNeedRefresh = FALSE;
 | 
						|
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // just delete the previous character
 | 
						|
    //
 | 
						|
    LineDeleteAt (Line, FileColumn - 1);
 | 
						|
    FileBufferScrollLeft ();
 | 
						|
    FileBufferOnlyLineNeedRefresh = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!FileBuffer.FileModified) {
 | 
						|
    FileBuffer.FileModified = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Add a return into line at current position.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The insetrion of the character was successful.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferDoReturn (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  EFI_EDITOR_LINE *NewLine;
 | 
						|
  UINTN           FileColumn;
 | 
						|
  UINTN           Index;
 | 
						|
  CHAR16          *Buffer;
 | 
						|
  UINTN           Row;
 | 
						|
  UINTN           Col;
 | 
						|
 | 
						|
  FileBufferNeedRefresh         = TRUE;
 | 
						|
  FileBufferOnlyLineNeedRefresh = FALSE;
 | 
						|
 | 
						|
  Line                          = FileBuffer.CurrentLine;
 | 
						|
 | 
						|
  FileColumn                    = FileBuffer.FilePosition.Column;
 | 
						|
 | 
						|
  NewLine                       = AllocateZeroPool (sizeof (EFI_EDITOR_LINE));
 | 
						|
  if (NewLine == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  NewLine->Signature  = LINE_LIST_SIGNATURE;
 | 
						|
  NewLine->Size       = Line->Size - FileColumn + 1;
 | 
						|
  NewLine->TotalSize  = NewLine->Size;
 | 
						|
  NewLine->Buffer     = CatSPrint (NULL, L"\0");
 | 
						|
  if (NewLine->Buffer == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  NewLine->Type = NewLineTypeDefault;
 | 
						|
 | 
						|
  if (NewLine->Size > 0) {
 | 
						|
    //
 | 
						|
    // UNICODE + CHAR_NULL
 | 
						|
    //
 | 
						|
    Buffer = AllocateZeroPool (2 * (NewLine->Size + 1));
 | 
						|
    if (Buffer == NULL) {
 | 
						|
      FreePool (NewLine->Buffer);
 | 
						|
      FreePool (NewLine);
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    FreePool (NewLine->Buffer);
 | 
						|
 | 
						|
    NewLine->Buffer = Buffer;
 | 
						|
 | 
						|
    for (Index = 0; Index < NewLine->Size; Index++) {
 | 
						|
      NewLine->Buffer[Index] = Line->Buffer[Index + FileColumn - 1];
 | 
						|
    }
 | 
						|
 | 
						|
    NewLine->Buffer[NewLine->Size]  = CHAR_NULL;
 | 
						|
 | 
						|
    Line->Buffer[FileColumn - 1]    = CHAR_NULL;
 | 
						|
    Line->Size                      = FileColumn - 1;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // increase NumLines
 | 
						|
  //
 | 
						|
  FileBuffer.NumLines++;
 | 
						|
 | 
						|
  //
 | 
						|
  // insert it into the correct position of line list
 | 
						|
  //
 | 
						|
  NewLine->Link.BackLink     = &(Line->Link);
 | 
						|
  NewLine->Link.ForwardLink     = Line->Link.ForwardLink;
 | 
						|
  Line->Link.ForwardLink->BackLink = &(NewLine->Link);
 | 
						|
  Line->Link.ForwardLink        = &(NewLine->Link);
 | 
						|
 | 
						|
  //
 | 
						|
  // move cursor to the start of next line
 | 
						|
  //
 | 
						|
  Row = FileBuffer.FilePosition.Row + 1;
 | 
						|
  Col = 1;
 | 
						|
 | 
						|
  FileBufferMovePosition (Row, Col);
 | 
						|
 | 
						|
  //
 | 
						|
  // set file is modified
 | 
						|
  //
 | 
						|
  if (!FileBuffer.FileModified) {
 | 
						|
    FileBuffer.FileModified = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Delete current character from current line.  This is the effect caused 
 | 
						|
  by the 'del' key.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferDoDelete (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  EFI_EDITOR_LINE *Next;
 | 
						|
  LIST_ENTRY  *Link;
 | 
						|
  UINTN           FileColumn;
 | 
						|
 | 
						|
  Line        = FileBuffer.CurrentLine;
 | 
						|
  FileColumn  = FileBuffer.FilePosition.Column;
 | 
						|
 | 
						|
  //
 | 
						|
  // the last column
 | 
						|
  //
 | 
						|
  if (FileColumn >= Line->Size + 1) {
 | 
						|
    //
 | 
						|
    // the last line
 | 
						|
    //
 | 
						|
    if (Line->Link.ForwardLink == FileBuffer.ListHead) {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // since last character,
 | 
						|
    // so will add the next line to this line
 | 
						|
    //
 | 
						|
    Link  = Line->Link.ForwardLink;
 | 
						|
    Next  = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
    LineCat (Line, Next);
 | 
						|
    if (Line->Buffer == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    RemoveEntryList (&Next->Link);
 | 
						|
    FreePool (Next);
 | 
						|
 | 
						|
    FileBuffer.NumLines--;
 | 
						|
 | 
						|
    FileBufferNeedRefresh         = TRUE;
 | 
						|
    FileBufferOnlyLineNeedRefresh = FALSE;
 | 
						|
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // just delete current character
 | 
						|
    //
 | 
						|
    LineDeleteAt (Line, FileColumn);
 | 
						|
    FileBufferOnlyLineNeedRefresh = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!FileBuffer.FileModified) {
 | 
						|
    FileBuffer.FileModified = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Scroll cursor to right 1 character.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     The operation was successful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferScrollRight (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  UINTN           FRow;
 | 
						|
  UINTN           FCol;
 | 
						|
 | 
						|
  Line = FileBuffer.CurrentLine;
 | 
						|
  if (Line->Buffer == NULL) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  FRow  = FileBuffer.FilePosition.Row;
 | 
						|
  FCol  = FileBuffer.FilePosition.Column;
 | 
						|
 | 
						|
  //
 | 
						|
  // if already at end of this line, scroll it to the start of next line
 | 
						|
  //
 | 
						|
  if (FCol > Line->Size) {
 | 
						|
    //
 | 
						|
    // has next line
 | 
						|
    //
 | 
						|
    if (Line->Link.ForwardLink != FileBuffer.ListHead) {
 | 
						|
      FRow++;
 | 
						|
      FCol = 1;
 | 
						|
    } else {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // if not at end of this line, just move to next column
 | 
						|
    //
 | 
						|
    FCol++;
 | 
						|
  }
 | 
						|
 | 
						|
  FileBufferMovePosition (FRow, FCol);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Insert a char into line
 | 
						|
 | 
						|
  
 | 
						|
  @param[in] Line     The line to insert into.
 | 
						|
  @param[in] Char     The char to insert.
 | 
						|
  @param[in] Pos      The position to insert the char at ( start from 0 ).
 | 
						|
  @param[in] StrSize  The current string size ( include CHAR_NULL ),unit is Unicode character.
 | 
						|
 | 
						|
  @return The new string size ( include CHAR_NULL ) ( unit is Unicode character ).
 | 
						|
**/
 | 
						|
UINTN
 | 
						|
EFIAPI
 | 
						|
LineStrInsert (
 | 
						|
  IN      EFI_EDITOR_LINE  *Line,
 | 
						|
  IN      CHAR16           Char,
 | 
						|
  IN      UINTN            Pos,
 | 
						|
  IN      UINTN            StrSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN   Index;
 | 
						|
  CHAR16  *TempStringPtr;
 | 
						|
  CHAR16  *Str;
 | 
						|
 | 
						|
  Index = (StrSize) * 2;
 | 
						|
 | 
						|
  Str   = Line->Buffer;
 | 
						|
 | 
						|
  //
 | 
						|
  // do not have free space
 | 
						|
  //
 | 
						|
  if (Line->TotalSize <= Line->Size) {
 | 
						|
    Str = ReallocatePool (Index, Index + 16, Str);
 | 
						|
    if (Str == NULL) {
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    Line->TotalSize += 8;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // move the later part of the string one character right
 | 
						|
  //
 | 
						|
  TempStringPtr = Str;
 | 
						|
  for (Index = StrSize; Index > Pos; Index--) {
 | 
						|
    TempStringPtr[Index] = TempStringPtr[Index - 1];
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // insert char into it.
 | 
						|
  //
 | 
						|
  TempStringPtr[Index]      = Char;
 | 
						|
 | 
						|
  Line->Buffer  = Str;
 | 
						|
  Line->Size++;
 | 
						|
 | 
						|
  return StrSize + 1;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Add a character to the current line.
 | 
						|
 | 
						|
  @param[in] Char               The Character to input.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The input was succesful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferAddChar (
 | 
						|
  IN  CHAR16  Char
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  UINTN           FilePos;
 | 
						|
 | 
						|
  Line = FileBuffer.CurrentLine;
 | 
						|
 | 
						|
  //
 | 
						|
  // only needs to refresh current line
 | 
						|
  //
 | 
						|
  FileBufferOnlyLineNeedRefresh = TRUE;
 | 
						|
 | 
						|
  //
 | 
						|
  // when is insert mode, or cursor is at end of this line,
 | 
						|
  // so insert this character
 | 
						|
  // or replace the character.
 | 
						|
  //
 | 
						|
  FilePos = FileBuffer.FilePosition.Column - 1;
 | 
						|
  if (FileBuffer.ModeInsert || FilePos + 1 > Line->Size) {
 | 
						|
    LineStrInsert (Line, Char, FilePos, Line->Size + 1);
 | 
						|
  } else {
 | 
						|
    Line->Buffer[FilePos] = Char;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // move cursor to right
 | 
						|
  //
 | 
						|
  FileBufferScrollRight ();
 | 
						|
 | 
						|
  if (!FileBuffer.FileModified) {
 | 
						|
    FileBuffer.FileModified = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Handles inputs from characters (ASCII key + Backspace + return)
 | 
						|
 | 
						|
  @param[in] Char               The input character.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The operation was successful.
 | 
						|
  @retval EFI_LOAD_ERROR        There was an error.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferDoCharInput (
 | 
						|
  IN CONST CHAR16 Char
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  switch (Char) {
 | 
						|
  case CHAR_NULL:
 | 
						|
    break;
 | 
						|
 | 
						|
  case CHAR_BACKSPACE:
 | 
						|
    Status = FileBufferDoBackspace ();
 | 
						|
    break;
 | 
						|
 | 
						|
  case CHAR_TAB:
 | 
						|
    //
 | 
						|
    // Tabs are ignored
 | 
						|
    //
 | 
						|
    break;
 | 
						|
 | 
						|
  case CHAR_LINEFEED:
 | 
						|
  case CHAR_CARRIAGE_RETURN:
 | 
						|
    Status = FileBufferDoReturn ();
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
    //
 | 
						|
    // DEAL WITH ASCII CHAR, filter out thing like ctrl+f
 | 
						|
    //
 | 
						|
    if (Char > 127 || Char < 32) {
 | 
						|
      Status = StatusBarSetStatusString (L"Unknown Command");
 | 
						|
    } else {
 | 
						|
      Status = FileBufferAddChar (Char);
 | 
						|
    }
 | 
						|
 | 
						|
    break;
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Scroll cursor to the next line.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     The operation was successful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferScrollDown (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  UINTN           FRow;
 | 
						|
  UINTN           FCol;
 | 
						|
 | 
						|
  Line = FileBuffer.CurrentLine;
 | 
						|
  if (Line->Buffer == NULL) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  FRow  = FileBuffer.FilePosition.Row;
 | 
						|
  FCol  = FileBuffer.FilePosition.Column;
 | 
						|
 | 
						|
  //
 | 
						|
  // has next line
 | 
						|
  //
 | 
						|
  if (Line->Link.ForwardLink != FileBuffer.ListHead) {
 | 
						|
    FRow++;
 | 
						|
    Line = CR (Line->Link.ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
 | 
						|
    //
 | 
						|
    // if the next line is not that long, so move to end of next line
 | 
						|
    //
 | 
						|
    if (FCol > Line->Size) {
 | 
						|
      FCol = Line->Size + 1;
 | 
						|
    }
 | 
						|
 | 
						|
  } else {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  FileBufferMovePosition (FRow, FCol);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Scroll the cursor to previous line.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     The operation was successful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferScrollUp (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  UINTN           FRow;
 | 
						|
  UINTN           FCol;
 | 
						|
 | 
						|
  Line  = FileBuffer.CurrentLine;
 | 
						|
 | 
						|
  FRow  = FileBuffer.FilePosition.Row;
 | 
						|
  FCol  = FileBuffer.FilePosition.Column;
 | 
						|
 | 
						|
  //
 | 
						|
  // has previous line
 | 
						|
  //
 | 
						|
  if (Line->Link.BackLink != FileBuffer.ListHead) {
 | 
						|
    FRow--;
 | 
						|
    Line = CR (Line->Link.BackLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
 | 
						|
    //
 | 
						|
    // if previous line is not that long, so move to the end of previous line
 | 
						|
    //
 | 
						|
    if (FCol > Line->Size) {
 | 
						|
      FCol = Line->Size + 1;
 | 
						|
    }
 | 
						|
 | 
						|
  } else {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  FileBufferMovePosition (FRow, FCol);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Scroll cursor to next page.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     The operation wa successful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferPageDown (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  UINTN           FRow;
 | 
						|
  UINTN           FCol;
 | 
						|
  UINTN           Gap;
 | 
						|
 | 
						|
  Line  = FileBuffer.CurrentLine;
 | 
						|
 | 
						|
  FRow  = FileBuffer.FilePosition.Row;
 | 
						|
  FCol  = FileBuffer.FilePosition.Column;
 | 
						|
 | 
						|
  //
 | 
						|
  // has next page
 | 
						|
  //
 | 
						|
  if (FileBuffer.NumLines >= FRow + (MainEditor.ScreenSize.Row - 2)) {
 | 
						|
    Gap = (MainEditor.ScreenSize.Row - 2);
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // MOVE CURSOR TO LAST LINE
 | 
						|
    //
 | 
						|
    Gap = FileBuffer.NumLines - FRow;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // get correct line
 | 
						|
  //
 | 
						|
  Line = MoveLine (Gap);
 | 
						|
 | 
						|
  //
 | 
						|
  // if that line, is not that long, so move to the end of that line
 | 
						|
  //
 | 
						|
  if (Line != NULL && FCol > Line->Size) {
 | 
						|
    FCol = Line->Size + 1;
 | 
						|
  }
 | 
						|
 | 
						|
  FRow += Gap;
 | 
						|
 | 
						|
  FileBufferMovePosition (FRow, FCol);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Scroll cursor to previous screen.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS     The operation was successful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferPageUp (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  UINTN           FRow;
 | 
						|
  UINTN           FCol;
 | 
						|
  UINTN           Gap;
 | 
						|
  INTN            Retreat;
 | 
						|
 | 
						|
  Line  = FileBuffer.CurrentLine;
 | 
						|
 | 
						|
  FRow  = FileBuffer.FilePosition.Row;
 | 
						|
  FCol  = FileBuffer.FilePosition.Column;
 | 
						|
 | 
						|
  //
 | 
						|
  // has previous page
 | 
						|
  //
 | 
						|
  if (FRow > (MainEditor.ScreenSize.Row - 2)) {
 | 
						|
    Gap = (MainEditor.ScreenSize.Row - 2);
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // the first line of file will displayed on the first line of screen
 | 
						|
    //
 | 
						|
    Gap = FRow - 1;
 | 
						|
  }
 | 
						|
 | 
						|
  Retreat = Gap;
 | 
						|
  Retreat = -Retreat;
 | 
						|
 | 
						|
  //
 | 
						|
  // get correct line
 | 
						|
  //
 | 
						|
  Line = MoveLine (Retreat);
 | 
						|
 | 
						|
  //
 | 
						|
  // if that line is not that long, so move to the end of that line
 | 
						|
  //
 | 
						|
  if (Line != NULL && FCol > Line->Size) {
 | 
						|
    FCol = Line->Size + 1;
 | 
						|
  }
 | 
						|
 | 
						|
  FRow -= Gap;
 | 
						|
 | 
						|
  FileBufferMovePosition (FRow, FCol);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Scroll cursor to end of the current line.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       The operation was successful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferEnd (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  UINTN           FRow;
 | 
						|
  UINTN           FCol;
 | 
						|
 | 
						|
  Line  = FileBuffer.CurrentLine;
 | 
						|
 | 
						|
  FRow  = FileBuffer.FilePosition.Row;
 | 
						|
 | 
						|
  //
 | 
						|
  // goto the last column of the line
 | 
						|
  //
 | 
						|
  FCol = Line->Size + 1;
 | 
						|
 | 
						|
  FileBufferMovePosition (FRow, FCol);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/** 
 | 
						|
  Dispatch input to different handler
 | 
						|
  @param[in] Key                The input key.  One of:
 | 
						|
                                    ASCII KEY
 | 
						|
                                    Backspace/Delete
 | 
						|
                                    Return
 | 
						|
                                    Direction key: up/down/left/right/pgup/pgdn
 | 
						|
                                    Home/End
 | 
						|
                                    INS
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The dispatch was done successfully.
 | 
						|
  @retval EFI_LOAD_ERROR        The dispatch was not successful.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferHandleInput (
 | 
						|
  IN CONST EFI_INPUT_KEY *Key
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  switch (Key->ScanCode) {
 | 
						|
  //
 | 
						|
  // ordinary key input
 | 
						|
  //
 | 
						|
  case SCAN_NULL:
 | 
						|
    if (!FileBuffer.ReadOnly) {
 | 
						|
      Status = FileBufferDoCharInput (Key->UnicodeChar);
 | 
						|
    } else {
 | 
						|
      Status = StatusBarSetStatusString (L"Read Only File Can Not Be Modified");
 | 
						|
    }
 | 
						|
 | 
						|
    break;
 | 
						|
 | 
						|
  //
 | 
						|
  // up arrow
 | 
						|
  //
 | 
						|
  case SCAN_UP:
 | 
						|
    Status = FileBufferScrollUp ();
 | 
						|
    break;
 | 
						|
 | 
						|
  //
 | 
						|
  // down arrow
 | 
						|
  //
 | 
						|
  case SCAN_DOWN:
 | 
						|
    Status = FileBufferScrollDown ();
 | 
						|
    break;
 | 
						|
 | 
						|
  //
 | 
						|
  // right arrow
 | 
						|
  //
 | 
						|
  case SCAN_RIGHT:
 | 
						|
    Status = FileBufferScrollRight ();
 | 
						|
    break;
 | 
						|
 | 
						|
  //
 | 
						|
  // left arrow
 | 
						|
  //
 | 
						|
  case SCAN_LEFT:
 | 
						|
    Status = FileBufferScrollLeft ();
 | 
						|
    break;
 | 
						|
 | 
						|
  //
 | 
						|
  // page up
 | 
						|
  //
 | 
						|
  case SCAN_PAGE_UP:
 | 
						|
    Status = FileBufferPageUp ();
 | 
						|
    break;
 | 
						|
 | 
						|
  //
 | 
						|
  // page down
 | 
						|
  //
 | 
						|
  case SCAN_PAGE_DOWN:
 | 
						|
    Status = FileBufferPageDown ();
 | 
						|
    break;
 | 
						|
 | 
						|
  //
 | 
						|
  // delete
 | 
						|
  //
 | 
						|
  case SCAN_DELETE:
 | 
						|
    if (!FileBuffer.ReadOnly) {
 | 
						|
      Status = FileBufferDoDelete ();
 | 
						|
    } else {
 | 
						|
      Status = StatusBarSetStatusString (L"Read Only File Can Not Be Modified");
 | 
						|
    }
 | 
						|
 | 
						|
    break;
 | 
						|
 | 
						|
  //
 | 
						|
  // home
 | 
						|
  //
 | 
						|
  case SCAN_HOME:
 | 
						|
    FileBufferMovePosition (FileBuffer.FilePosition.Row, 1);
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
    break;
 | 
						|
 | 
						|
  //
 | 
						|
  // end
 | 
						|
  //
 | 
						|
  case SCAN_END:
 | 
						|
    Status = FileBufferEnd ();
 | 
						|
    break;
 | 
						|
 | 
						|
  //
 | 
						|
  // insert
 | 
						|
  //
 | 
						|
  case SCAN_INSERT:
 | 
						|
    FileBuffer.ModeInsert = (BOOLEAN)!FileBuffer.ModeInsert;
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
    Status = StatusBarSetStatusString (L"Unknown Command");
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check user specified FileRow is above current screen.
 | 
						|
 | 
						|
  @param[in] FileRow    The row of file position ( start from 1 ).
 | 
						|
 | 
						|
  @retval TRUE    It is above the current screen.
 | 
						|
  @retval FALSE   It is not above the current screen.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
AboveCurrentScreen (
 | 
						|
  IN UINTN FileRow
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // if is to the above of the screen
 | 
						|
  //
 | 
						|
  if (FileRow < FileBuffer.LowVisibleRange.Row) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check user specified FileRow is under current screen.
 | 
						|
 | 
						|
  @param[in] FileRow    The row of file position ( start from 1 ).
 | 
						|
 | 
						|
  @retval TRUE      It is under the current screen.
 | 
						|
  @retval FALSE     It is not under the current screen.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
UnderCurrentScreen (
 | 
						|
  IN UINTN FileRow
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // if is to the under of the screen
 | 
						|
  //
 | 
						|
  if (FileRow > FileBuffer.LowVisibleRange.Row + (MainEditor.ScreenSize.Row - 2) - 1) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check user specified FileCol is left to current screen.
 | 
						|
 | 
						|
  @param[in] FileCol    The column of file position ( start from 1 ).
 | 
						|
 | 
						|
  @retval TRUE    It is to the left.
 | 
						|
  @retval FALSE   It is not to the left.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
LeftCurrentScreen (
 | 
						|
  IN UINTN FileCol
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // if is to the left of the screen
 | 
						|
  //
 | 
						|
  if (FileCol < FileBuffer.LowVisibleRange.Column) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check user specified FileCol is right to current screen.
 | 
						|
 | 
						|
  @param[in] FileCol    The column of file position ( start from 1 ).
 | 
						|
 | 
						|
  @retval TRUE    It is to the right.
 | 
						|
  @retval FALSE   It is not to the right.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
RightCurrentScreen (
 | 
						|
  IN UINTN FileCol
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // if is to the right of the screen
 | 
						|
  //
 | 
						|
  if (FileCol > FileBuffer.LowVisibleRange.Column + MainEditor.ScreenSize.Column - 1) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Advance/Retreat lines and set CurrentLine in FileBuffer to it
 | 
						|
  
 | 
						|
  @param[in] Count The line number to advance/retreat
 | 
						|
                     >0 : advance
 | 
						|
                     <0: retreat
 | 
						|
 | 
						|
  @retval NULL An error occured.
 | 
						|
  @return The line after advance/retreat.
 | 
						|
**/
 | 
						|
EFI_EDITOR_LINE *
 | 
						|
EFIAPI
 | 
						|
MoveCurrentLine (
 | 
						|
  IN  INTN Count
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  UINTN           AbsCount;
 | 
						|
 | 
						|
  if (Count <= 0) {
 | 
						|
    AbsCount  = (UINTN)ABS(Count);
 | 
						|
    Line      = InternalEditorMiscLineRetreat (AbsCount,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);
 | 
						|
  } else {
 | 
						|
    Line = InternalEditorMiscLineAdvance ((UINTN)Count,MainEditor.FileBuffer->CurrentLine,MainEditor.FileBuffer->ListHead);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Line == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  MainEditor.FileBuffer->CurrentLine = Line;
 | 
						|
 | 
						|
  return Line;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  According to cursor's file position, adjust screen display
 | 
						|
 | 
						|
  @param[in] NewFilePosRow    The row of file position ( start from 1 ).
 | 
						|
  @param[in] NewFilePosCol    The column of file position ( start from 1 ).
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
FileBufferMovePosition (
 | 
						|
  IN CONST UINTN NewFilePosRow,
 | 
						|
  IN CONST UINTN NewFilePosCol
 | 
						|
  )
 | 
						|
{
 | 
						|
  INTN    RowGap;
 | 
						|
  INTN    ColGap;
 | 
						|
  UINTN   Abs;
 | 
						|
  BOOLEAN Above;
 | 
						|
  BOOLEAN Under;
 | 
						|
  BOOLEAN Right;
 | 
						|
  BOOLEAN Left;
 | 
						|
 | 
						|
  //
 | 
						|
  // CALCULATE gap between current file position and new file position
 | 
						|
  //
 | 
						|
  RowGap  = NewFilePosRow - FileBuffer.FilePosition.Row;
 | 
						|
  ColGap  = NewFilePosCol - FileBuffer.FilePosition.Column;
 | 
						|
 | 
						|
  Under   = UnderCurrentScreen (NewFilePosRow);
 | 
						|
  Above   = AboveCurrentScreen (NewFilePosRow);
 | 
						|
  //
 | 
						|
  // if is below current screen
 | 
						|
  //
 | 
						|
  if (Under) {
 | 
						|
    //
 | 
						|
    // display row will be unchanged
 | 
						|
    //
 | 
						|
    FileBuffer.FilePosition.Row = NewFilePosRow;
 | 
						|
  } else {
 | 
						|
    if (Above) {
 | 
						|
      //
 | 
						|
      // has enough above line, so display row unchanged
 | 
						|
      // not has enough above lines, so the first line is at the
 | 
						|
      // first display line
 | 
						|
      //
 | 
						|
      if (NewFilePosRow < (FileBuffer.DisplayPosition.Row - 1)) {
 | 
						|
        FileBuffer.DisplayPosition.Row = NewFilePosRow + 1;
 | 
						|
      }
 | 
						|
 | 
						|
      FileBuffer.FilePosition.Row = NewFilePosRow;
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // in current screen
 | 
						|
      //
 | 
						|
      FileBuffer.FilePosition.Row = NewFilePosRow;
 | 
						|
      if (RowGap < 0) {
 | 
						|
        Abs = (UINTN)ABS(RowGap);
 | 
						|
        FileBuffer.DisplayPosition.Row -= Abs;
 | 
						|
      } else {
 | 
						|
        FileBuffer.DisplayPosition.Row += RowGap;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  FileBuffer.LowVisibleRange.Row  = FileBuffer.FilePosition.Row - (FileBuffer.DisplayPosition.Row - 2);
 | 
						|
 | 
						|
  Right = RightCurrentScreen (NewFilePosCol);
 | 
						|
  Left = LeftCurrentScreen (NewFilePosCol);
 | 
						|
 | 
						|
  //
 | 
						|
  // if right to current screen
 | 
						|
  //
 | 
						|
  if (Right) {
 | 
						|
    //
 | 
						|
    // display column will be changed to end
 | 
						|
    //
 | 
						|
    FileBuffer.DisplayPosition.Column = MainEditor.ScreenSize.Column;
 | 
						|
    FileBuffer.FilePosition.Column    = NewFilePosCol;
 | 
						|
  } else {
 | 
						|
    if (Left) {
 | 
						|
      //
 | 
						|
      // has enough left characters , so display row unchanged
 | 
						|
      // not has enough left characters,
 | 
						|
      // so the first character is at the first display column
 | 
						|
      //
 | 
						|
      if (NewFilePosCol < (FileBuffer.DisplayPosition.Column)) {
 | 
						|
        FileBuffer.DisplayPosition.Column = NewFilePosCol;
 | 
						|
      }
 | 
						|
 | 
						|
      FileBuffer.FilePosition.Column = NewFilePosCol;
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // in current screen
 | 
						|
      //
 | 
						|
      FileBuffer.FilePosition.Column = NewFilePosCol;
 | 
						|
      if (ColGap < 0) {
 | 
						|
        Abs = (UINTN)(-ColGap);
 | 
						|
        FileBuffer.DisplayPosition.Column -= Abs;
 | 
						|
      } else {
 | 
						|
        FileBuffer.DisplayPosition.Column += ColGap;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  FileBuffer.LowVisibleRange.Column = FileBuffer.FilePosition.Column - (FileBuffer.DisplayPosition.Column - 1);
 | 
						|
 | 
						|
  //
 | 
						|
  // let CurrentLine point to correct line;
 | 
						|
  //
 | 
						|
  FileBuffer.CurrentLine = MoveCurrentLine (RowGap);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Cut current line out and return a pointer to it.
 | 
						|
 | 
						|
  @param[out] CutLine    Upon a successful return pointer to the pointer to 
 | 
						|
                        the allocated cut line.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             The cut was successful.
 | 
						|
  @retval EFI_NOT_FOUND           There was no selection to cut.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferCutLine (
 | 
						|
  OUT EFI_EDITOR_LINE **CutLine
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  EFI_EDITOR_LINE *NewLine;
 | 
						|
  UINTN           Row;
 | 
						|
  UINTN           Col;
 | 
						|
 | 
						|
  if (FileBuffer.ReadOnly) {
 | 
						|
    StatusBarSetStatusString (L"Read Only File Can Not Be Modified");
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  Line = FileBuffer.CurrentLine;
 | 
						|
 | 
						|
  //
 | 
						|
  // if is the last dummy line, SO CAN not cut
 | 
						|
  //
 | 
						|
  if (StrCmp (Line->Buffer, L"\0") == 0 && Line->Link.ForwardLink == FileBuffer.ListHead
 | 
						|
  //
 | 
						|
  // last line
 | 
						|
  //
 | 
						|
  ) {
 | 
						|
    //
 | 
						|
    // LAST LINE AND NOTHING ON THIS LINE, SO CUT NOTHING
 | 
						|
    //
 | 
						|
    StatusBarSetStatusString (L"Nothing to Cut");
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // if is the last line, so create a dummy line
 | 
						|
  //
 | 
						|
  if (Line->Link.ForwardLink == FileBuffer.ListHead) {
 | 
						|
    //
 | 
						|
    // last line
 | 
						|
    // create a new line
 | 
						|
    //
 | 
						|
    NewLine = FileBufferCreateLine ();
 | 
						|
    if (NewLine == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  FileBuffer.NumLines--;
 | 
						|
  Row = FileBuffer.FilePosition.Row;
 | 
						|
  Col = 1;
 | 
						|
  //
 | 
						|
  // move home
 | 
						|
  //
 | 
						|
  FileBuffer.CurrentLine = CR (
 | 
						|
                            FileBuffer.CurrentLine->Link.ForwardLink,
 | 
						|
                            EFI_EDITOR_LINE,
 | 
						|
                            Link,
 | 
						|
                            LINE_LIST_SIGNATURE
 | 
						|
                            );
 | 
						|
 | 
						|
  RemoveEntryList (&Line->Link);
 | 
						|
 | 
						|
  FileBuffer.Lines = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
 | 
						|
  FileBufferMovePosition (Row, Col);
 | 
						|
 | 
						|
  FileBuffer.FileModified       = TRUE;
 | 
						|
  FileBufferNeedRefresh         = TRUE;
 | 
						|
  FileBufferOnlyLineNeedRefresh = FALSE;
 | 
						|
 | 
						|
  *CutLine                      = Line;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Paste a line into line list.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             The paste was successful.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferPasteLine (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  EFI_EDITOR_LINE *NewLine;
 | 
						|
  UINTN           Row;
 | 
						|
  UINTN           Col;
 | 
						|
 | 
						|
  //
 | 
						|
  // if nothing is on clip board
 | 
						|
  // then do nothing
 | 
						|
  //
 | 
						|
  if (MainEditor.CutLine == NULL) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // read only file can not be pasted on
 | 
						|
  //
 | 
						|
  if (FileBuffer.ReadOnly) {
 | 
						|
    StatusBarSetStatusString (L"Read Only File Can Not Be Modified");
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  NewLine = LineDup (MainEditor.CutLine);
 | 
						|
  if (NewLine == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // insert it above current line
 | 
						|
  //
 | 
						|
  Line                    = FileBuffer.CurrentLine;
 | 
						|
  NewLine->Link.BackLink     = Line->Link.BackLink;
 | 
						|
  NewLine->Link.ForwardLink     = &Line->Link;
 | 
						|
 | 
						|
  Line->Link.BackLink->ForwardLink = &NewLine->Link;
 | 
						|
  Line->Link.BackLink        = &NewLine->Link;
 | 
						|
 | 
						|
  FileBuffer.NumLines++;
 | 
						|
  FileBuffer.CurrentLine  = NewLine;
 | 
						|
 | 
						|
  FileBuffer.Lines        = CR (FileBuffer.ListHead->ForwardLink, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
 | 
						|
  Col                     = 1;
 | 
						|
  //
 | 
						|
  // move home
 | 
						|
  //
 | 
						|
  Row = FileBuffer.FilePosition.Row;
 | 
						|
 | 
						|
  FileBufferMovePosition (Row, Col);
 | 
						|
 | 
						|
  //
 | 
						|
  // after paste, set some value so that refresh knows to do something
 | 
						|
  //
 | 
						|
  FileBuffer.FileModified       = TRUE;
 | 
						|
  FileBufferNeedRefresh         = TRUE;
 | 
						|
  FileBufferOnlyLineNeedRefresh = FALSE;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Search string from current position on in file
 | 
						|
 | 
						|
  @param[in] Str    The search string.
 | 
						|
  @param[in] Offset The offset from current position.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       The operation was successful.
 | 
						|
  @retval EFI_NOT_FOUND     The string Str was not found.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferSearch (
 | 
						|
  IN CONST CHAR16  *Str,
 | 
						|
  IN CONST UINTN Offset
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16          *Current;
 | 
						|
  UINTN           Position;
 | 
						|
  UINTN           Row;
 | 
						|
  UINTN           Column;
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  CHAR16          *CharPos;
 | 
						|
  LIST_ENTRY      *Link;
 | 
						|
  BOOLEAN         Found;
 | 
						|
 | 
						|
  Column = 0;
 | 
						|
  Position = 0;
 | 
						|
  
 | 
						|
  //
 | 
						|
  // search if in current line
 | 
						|
  //
 | 
						|
  Current = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1 + Offset;
 | 
						|
 | 
						|
  if (Current >= (FileBuffer.CurrentLine->Buffer + FileBuffer.CurrentLine->Size)) {
 | 
						|
    //
 | 
						|
    // the end
 | 
						|
    //
 | 
						|
    Current = FileBuffer.CurrentLine->Buffer + FileBuffer.CurrentLine->Size;
 | 
						|
  }
 | 
						|
 | 
						|
  Found = FALSE;
 | 
						|
 | 
						|
  CharPos  =  StrStr (Current, Str);
 | 
						|
  if (CharPos != NULL) {
 | 
						|
    Position = CharPos - Current + 1;
 | 
						|
    Found   = TRUE;
 | 
						|
  } 
 | 
						|
 | 
						|
  //
 | 
						|
  // found
 | 
						|
  //
 | 
						|
  if (Found) {
 | 
						|
    Column  = (Position - 1) + FileBuffer.FilePosition.Column + Offset;
 | 
						|
    Row     = FileBuffer.FilePosition.Row;
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // not found so find through next lines
 | 
						|
    //
 | 
						|
    Link  = FileBuffer.CurrentLine->Link.ForwardLink;
 | 
						|
 | 
						|
    Row   = FileBuffer.FilePosition.Row + 1;
 | 
						|
    while (Link != FileBuffer.ListHead) {
 | 
						|
      Line      = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
//      Position  = StrStr (Line->Buffer, Str);
 | 
						|
      CharPos  =  StrStr (Line->Buffer, Str);
 | 
						|
      if (CharPos != NULL) {
 | 
						|
        Position = CharPos - Line->Buffer + 1;
 | 
						|
        Found   = TRUE;
 | 
						|
      } 
 | 
						|
      
 | 
						|
      if (Found) {
 | 
						|
        //
 | 
						|
        // found
 | 
						|
        //
 | 
						|
        Column = Position;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      Row++;
 | 
						|
      Link = Link->ForwardLink;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Link == FileBuffer.ListHead) {
 | 
						|
      Found = FALSE;
 | 
						|
    } else {
 | 
						|
      Found = TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!Found) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  FileBufferMovePosition (Row, Column);
 | 
						|
 | 
						|
  //
 | 
						|
  // call refresh to fresh edit area,
 | 
						|
  // because the outer may loop to find multiply occurrence of this string
 | 
						|
  //
 | 
						|
  FileBufferRefresh ();
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Replace SearchLen characters from current position on with Replace.
 | 
						|
 | 
						|
  This will modify the current buffer at the current position.
 | 
						|
 | 
						|
  @param[in] Replace    The string to replace.
 | 
						|
  @param[in] SearchLen  Search string's length.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             The operation was successful.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferReplace (
 | 
						|
  IN CONST CHAR16   *Replace,
 | 
						|
  IN CONST UINTN    SearchLen
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN   ReplaceLen;
 | 
						|
  UINTN   Index;
 | 
						|
  CHAR16  *Buffer;
 | 
						|
  UINTN   NewSize;
 | 
						|
  UINTN   OldSize;
 | 
						|
  UINTN   Gap;
 | 
						|
 | 
						|
  ReplaceLen  = StrLen (Replace);
 | 
						|
 | 
						|
  OldSize     = FileBuffer.CurrentLine->Size + 1;
 | 
						|
  //
 | 
						|
  // include CHAR_NULL
 | 
						|
  //
 | 
						|
  NewSize = OldSize + (ReplaceLen - SearchLen);
 | 
						|
 | 
						|
  if (ReplaceLen > SearchLen) {
 | 
						|
    //
 | 
						|
    // do not have the enough space
 | 
						|
    //
 | 
						|
    if (FileBuffer.CurrentLine->TotalSize + 1 <= NewSize) {
 | 
						|
      FileBuffer.CurrentLine->Buffer = ReallocatePool (
 | 
						|
                                        2 * OldSize,
 | 
						|
                                        2 * NewSize,
 | 
						|
                                        FileBuffer.CurrentLine->Buffer
 | 
						|
                                        );
 | 
						|
      FileBuffer.CurrentLine->TotalSize = NewSize - 1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (FileBuffer.CurrentLine->Buffer == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // the end CHAR_NULL character;
 | 
						|
    //
 | 
						|
    Buffer  = FileBuffer.CurrentLine->Buffer + (NewSize - 1);
 | 
						|
    Gap     = ReplaceLen - SearchLen;
 | 
						|
 | 
						|
    //
 | 
						|
    // keep the latter part
 | 
						|
    //
 | 
						|
    for (Index = 0; Index < (FileBuffer.CurrentLine->Size - FileBuffer.FilePosition.Column - SearchLen + 2); Index++) {
 | 
						|
      *Buffer = *(Buffer - Gap);
 | 
						|
      Buffer--;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // set replace into it
 | 
						|
    //
 | 
						|
    Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1;
 | 
						|
    for (Index = 0; Index < ReplaceLen; Index++) {
 | 
						|
      Buffer[Index] = Replace[Index];
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (ReplaceLen < SearchLen) {
 | 
						|
    Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1;
 | 
						|
 | 
						|
    for (Index = 0; Index < ReplaceLen; Index++) {
 | 
						|
      Buffer[Index] = Replace[Index];
 | 
						|
    }
 | 
						|
 | 
						|
    Buffer += ReplaceLen;
 | 
						|
    Gap = SearchLen - ReplaceLen;
 | 
						|
 | 
						|
    //
 | 
						|
    // set replace into it
 | 
						|
    //
 | 
						|
    for (Index = 0; Index < (FileBuffer.CurrentLine->Size - FileBuffer.FilePosition.Column - ReplaceLen + 2); Index++) {
 | 
						|
      *Buffer = *(Buffer + Gap);
 | 
						|
      Buffer++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (ReplaceLen == SearchLen) {
 | 
						|
    Buffer = FileBuffer.CurrentLine->Buffer + FileBuffer.FilePosition.Column - 1;
 | 
						|
    for (Index = 0; Index < ReplaceLen; Index++) {
 | 
						|
      Buffer[Index] = Replace[Index];
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  FileBuffer.CurrentLine->Size += (ReplaceLen - SearchLen);
 | 
						|
 | 
						|
  FileBufferOnlyLineNeedRefresh = TRUE;
 | 
						|
 | 
						|
  FileBuffer.FileModified       = TRUE;
 | 
						|
 | 
						|
  MainTitleBarRefresh (MainEditor.FileBuffer->FileName, MainEditor.FileBuffer->FileType, MainEditor.FileBuffer->ReadOnly, MainEditor.FileBuffer->FileModified, MainEditor.ScreenSize.Column, MainEditor.ScreenSize.Row, 0, 0);
 | 
						|
  FileBufferRestorePosition ();
 | 
						|
  FileBufferRefresh ();
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Move the mouse cursor position.
 | 
						|
 | 
						|
  @param[in] TextX      The new x-coordinate.
 | 
						|
  @param[in] TextY      The new y-coordinate.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
FileBufferAdjustMousePosition (
 | 
						|
  IN CONST INT32 TextX,
 | 
						|
  IN CONST INT32 TextY
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN CoordinateX;
 | 
						|
  UINTN CoordinateY;
 | 
						|
  UINTN AbsX;
 | 
						|
  UINTN AbsY;
 | 
						|
 | 
						|
  //
 | 
						|
  // TextX and TextY is mouse movement data returned by mouse driver
 | 
						|
  // This function will change it to MousePosition
 | 
						|
  //
 | 
						|
  //
 | 
						|
  // get absolute value
 | 
						|
  //
 | 
						|
 | 
						|
  AbsX = ABS(TextX);
 | 
						|
  AbsY = ABS(TextY);
 | 
						|
 | 
						|
  CoordinateX = FileBuffer.MousePosition.Column;
 | 
						|
  CoordinateY = FileBuffer.MousePosition.Row;
 | 
						|
 | 
						|
  if (TextX >= 0) {
 | 
						|
    CoordinateX += TextX;
 | 
						|
  } else {
 | 
						|
    if (CoordinateX >= AbsX) {
 | 
						|
      CoordinateX -= AbsX;
 | 
						|
    } else {
 | 
						|
      CoordinateX = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (TextY >= 0) {
 | 
						|
    CoordinateY += TextY;
 | 
						|
  } else {
 | 
						|
    if (CoordinateY >= AbsY) {
 | 
						|
      CoordinateY -= AbsY;
 | 
						|
    } else {
 | 
						|
      CoordinateY = 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // check whether new mouse column position is beyond screen
 | 
						|
  // if not, adjust it
 | 
						|
  //
 | 
						|
  if (CoordinateX >= 1 && CoordinateX <= MainEditor.ScreenSize.Column) {
 | 
						|
    FileBuffer.MousePosition.Column = CoordinateX;
 | 
						|
  } else if (CoordinateX < 1) {
 | 
						|
    FileBuffer.MousePosition.Column = 1;
 | 
						|
  } else if (CoordinateX > MainEditor.ScreenSize.Column) {
 | 
						|
    FileBuffer.MousePosition.Column = MainEditor.ScreenSize.Column;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // check whether new mouse row position is beyond screen
 | 
						|
  // if not, adjust it
 | 
						|
  //
 | 
						|
  if (CoordinateY >= 2 && CoordinateY <= (MainEditor.ScreenSize.Row - 1)) {
 | 
						|
    FileBuffer.MousePosition.Row = CoordinateY;
 | 
						|
  } else if (CoordinateY < 2) {
 | 
						|
    FileBuffer.MousePosition.Row = 2;
 | 
						|
  } else if (CoordinateY > (MainEditor.ScreenSize.Row - 1)) {
 | 
						|
    FileBuffer.MousePosition.Row = (MainEditor.ScreenSize.Row - 1);
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Search and replace operation.
 | 
						|
 | 
						|
  @param[in] SearchStr    The string to search for.
 | 
						|
  @param[in] ReplaceStr   The string to replace with.
 | 
						|
  @param[in] Offset       The column to start at.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileBufferReplaceAll (
 | 
						|
  IN CHAR16 *SearchStr,
 | 
						|
  IN CHAR16 *ReplaceStr,
 | 
						|
  IN UINTN  Offset
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16          *Buffer;
 | 
						|
  UINTN           Position;
 | 
						|
  UINTN           Column;
 | 
						|
  UINTN           ReplaceLen;
 | 
						|
  UINTN           SearchLen;
 | 
						|
  UINTN           Index;
 | 
						|
  UINTN           NewSize;
 | 
						|
  UINTN           OldSize;
 | 
						|
  UINTN           Gap;
 | 
						|
  EFI_EDITOR_LINE *Line;
 | 
						|
  LIST_ENTRY      *Link;
 | 
						|
  CHAR16          *CharPos;
 | 
						|
 | 
						|
  SearchLen   = StrLen (SearchStr);
 | 
						|
  ReplaceLen  = StrLen (ReplaceStr);
 | 
						|
 | 
						|
  Column      = FileBuffer.FilePosition.Column + Offset - 1;
 | 
						|
 | 
						|
  if (Column > FileBuffer.CurrentLine->Size) {
 | 
						|
    Column = FileBuffer.CurrentLine->Size;
 | 
						|
  }
 | 
						|
 | 
						|
  Link = &(FileBuffer.CurrentLine->Link);
 | 
						|
 | 
						|
  while (Link != FileBuffer.ListHead) {
 | 
						|
    Line      = CR (Link, EFI_EDITOR_LINE, Link, LINE_LIST_SIGNATURE);
 | 
						|
    CharPos  =  StrStr (Line->Buffer + Column, SearchStr);
 | 
						|
    if (CharPos != NULL) {
 | 
						|
      Position = CharPos - Line->Buffer;// + Column;
 | 
						|
      //
 | 
						|
      // found
 | 
						|
      //
 | 
						|
      if (ReplaceLen > SearchLen) {
 | 
						|
        OldSize = Line->Size + 1;
 | 
						|
        //
 | 
						|
        // include CHAR_NULL
 | 
						|
        //
 | 
						|
        NewSize = OldSize + (ReplaceLen - SearchLen);
 | 
						|
 | 
						|
        //
 | 
						|
        // do not have the enough space
 | 
						|
        //
 | 
						|
        if (Line->TotalSize + 1 <= NewSize) {
 | 
						|
          Line->Buffer = ReallocatePool (
 | 
						|
                          2 * OldSize,
 | 
						|
                          2 * NewSize,
 | 
						|
                          Line->Buffer
 | 
						|
                          );
 | 
						|
          Line->TotalSize = NewSize - 1;
 | 
						|
        }
 | 
						|
 | 
						|
        if (Line->Buffer == NULL) {
 | 
						|
          return EFI_OUT_OF_RESOURCES;
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // the end CHAR_NULL character;
 | 
						|
        //
 | 
						|
        Buffer  = Line->Buffer + (NewSize - 1);
 | 
						|
        Gap     = ReplaceLen - SearchLen;
 | 
						|
 | 
						|
        //
 | 
						|
        // keep the latter part
 | 
						|
        //
 | 
						|
        for (Index = 0; Index < (Line->Size - Position - SearchLen + 1); Index++) {
 | 
						|
          *Buffer = *(Buffer - Gap);
 | 
						|
          Buffer--;
 | 
						|
        }
 | 
						|
 | 
						|
      } else if (ReplaceLen < SearchLen){
 | 
						|
        Buffer  = Line->Buffer + Position + ReplaceLen;
 | 
						|
        Gap     = SearchLen - ReplaceLen;
 | 
						|
 | 
						|
        for (Index = 0; Index < (Line->Size - Position - ReplaceLen + 1); Index++) {
 | 
						|
          *Buffer = *(Buffer + Gap);
 | 
						|
          Buffer++;
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        ASSERT(ReplaceLen == SearchLen);
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // set replace into it
 | 
						|
      //
 | 
						|
      Buffer = Line->Buffer + Position;
 | 
						|
      for (Index = 0; Index < ReplaceLen; Index++) {
 | 
						|
        Buffer[Index] = ReplaceStr[Index];
 | 
						|
      }
 | 
						|
 | 
						|
      Line->Size += (ReplaceLen - SearchLen);
 | 
						|
      Column += ReplaceLen;
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // not found
 | 
						|
      //
 | 
						|
      Column  = 0;
 | 
						|
      Link    = Link->ForwardLink;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // call refresh to fresh edit area
 | 
						|
  //
 | 
						|
  FileBuffer.FileModified = TRUE;
 | 
						|
  FileBufferNeedRefresh   = TRUE;
 | 
						|
  FileBufferRefresh ();
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set the modified state to TRUE.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
FileBufferSetModified (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  FileBuffer.FileModified = TRUE;
 | 
						|
}
 | 
						|
 |