2 Implements filebuffer interface functions.
4 Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved. <BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "TextEditor.h"
16 #include <Guid/FileSystemInfo.h>
17 #include <Library/FileHandleLib.h>
19 EFI_EDITOR_FILE_BUFFER FileBuffer
;
20 EFI_EDITOR_FILE_BUFFER FileBufferBackupVar
;
23 // for basic initialization of FileBuffer
25 EFI_EDITOR_FILE_BUFFER FileBufferConst
= {
54 // the whole edit area needs to be refreshed
56 BOOLEAN FileBufferNeedRefresh
;
59 // only the current line in edit area needs to be refresh
61 BOOLEAN FileBufferOnlyLineNeedRefresh
;
63 BOOLEAN FileBufferMouseNeedRefresh
;
65 extern BOOLEAN EditorMouseAction
;
68 Initialization function for FileBuffer.
70 @param EFI_SUCCESS The initialization was successful.
71 @param EFI_LOAD_ERROR A default name could not be created.
72 @param EFI_OUT_OF_RESOURCES A memory allocation failed.
81 // basically initialize the FileBuffer
83 CopyMem (&FileBuffer
, &FileBufferConst
, sizeof (EFI_EDITOR_FILE_BUFFER
));
84 CopyMem (&FileBufferBackupVar
, &FileBufferConst
, sizeof (EFI_EDITOR_FILE_BUFFER
));
87 // set default FileName
89 FileBuffer
.FileName
= EditGetDefaultFileName (L
"txt");
90 if (FileBuffer
.FileName
== NULL
) {
91 return EFI_LOAD_ERROR
;
94 FileBuffer
.ListHead
= AllocateZeroPool (sizeof (LIST_ENTRY
));
95 if (FileBuffer
.ListHead
== NULL
) {
96 return EFI_OUT_OF_RESOURCES
;
99 InitializeListHead (FileBuffer
.ListHead
);
101 FileBuffer
.DisplayPosition
.Row
= 2;
102 FileBuffer
.DisplayPosition
.Column
= 1;
103 FileBuffer
.LowVisibleRange
.Row
= 2;
104 FileBuffer
.LowVisibleRange
.Column
= 1;
106 FileBufferNeedRefresh
= FALSE
;
107 FileBufferMouseNeedRefresh
= FALSE
;
108 FileBufferOnlyLineNeedRefresh
= FALSE
;
114 Backup function for FileBuffer. Only backup the following items:
115 Mouse/Cursor position
116 File Name, Type, ReadOnly, Modified
119 This is for making the file buffer refresh as few as possible.
121 @retval EFI_SUCCESS The backup operation was successful.
129 FileBufferBackupVar
.MousePosition
= FileBuffer
.MousePosition
;
131 SHELL_FREE_NON_NULL (FileBufferBackupVar
.FileName
);
132 FileBufferBackupVar
.FileName
= NULL
;
133 FileBufferBackupVar
.FileName
= StrnCatGrow (&FileBufferBackupVar
.FileName
, NULL
, FileBuffer
.FileName
, 0);
135 FileBufferBackupVar
.ModeInsert
= FileBuffer
.ModeInsert
;
136 FileBufferBackupVar
.FileType
= FileBuffer
.FileType
;
138 FileBufferBackupVar
.FilePosition
= FileBuffer
.FilePosition
;
139 FileBufferBackupVar
.LowVisibleRange
= FileBuffer
.LowVisibleRange
;
141 FileBufferBackupVar
.FileModified
= FileBuffer
.FileModified
;
142 FileBufferBackupVar
.ReadOnly
= FileBuffer
.ReadOnly
;
148 Advance to the next Count lines
150 @param[in] Count The line number to advance by.
151 @param[in] CurrentLine The pointer to the current line structure.
152 @param[in] LineList The pointer to the linked list of lines.
154 @retval NULL There was an error.
155 @return The line structure after the advance.
159 InternalEditorMiscLineAdvance (
160 IN CONST UINTN Count
,
161 IN CONST EFI_EDITOR_LINE
*CurrentLine
,
162 IN CONST LIST_ENTRY
*LineList
167 CONST EFI_EDITOR_LINE
*Line
;
169 if (CurrentLine
== NULL
|| LineList
== NULL
) {
173 for (Line
= CurrentLine
, Index
= 0; Index
< Count
; Index
++) {
175 // if already last line
177 if (Line
->Link
.ForwardLink
== LineList
) {
181 Line
= CR (Line
->Link
.ForwardLink
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
184 return ((EFI_EDITOR_LINE
*)Line
);
188 Retreat to the previous Count lines.
190 @param[in] Count The line number to retreat by.
191 @param[in] CurrentLine The pointer to the current line structure.
192 @param[in] LineList The pointer to the linked list of lines.
194 @retval NULL There was an error.
195 @return The line structure after the retreat.
199 InternalEditorMiscLineRetreat (
200 IN CONST UINTN Count
,
201 IN CONST EFI_EDITOR_LINE
*CurrentLine
,
202 IN CONST LIST_ENTRY
*LineList
207 CONST EFI_EDITOR_LINE
*Line
;
209 if (CurrentLine
== NULL
|| LineList
== NULL
) {
213 for (Line
= CurrentLine
, Index
= 0; Index
< Count
; Index
++) {
215 // already the first line
217 if (Line
->Link
.BackLink
== LineList
) {
221 Line
= CR (Line
->Link
.BackLink
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
224 return ((EFI_EDITOR_LINE
*)Line
);
228 Advance/Retreat lines
230 @param[in] Count line number to advance/retreat
234 @retval NULL An error occured.
235 @return The line after advance/retreat.
242 EFI_EDITOR_LINE
*Line
;
246 // if < 0, then retreat
247 // if > 0, the advance
250 AbsCount
= (UINTN
)ABS(Count
);
251 Line
= InternalEditorMiscLineRetreat (AbsCount
,MainEditor
.FileBuffer
->CurrentLine
,MainEditor
.FileBuffer
->ListHead
);
253 Line
= InternalEditorMiscLineAdvance ((UINTN
)Count
,MainEditor
.FileBuffer
->CurrentLine
,MainEditor
.FileBuffer
->ListHead
);
260 Decide if a point is in the already selected area.
262 @param[in] MouseRow The row of the point to test.
263 @param[in] MouseCol The col of the point to test.
265 @retval TRUE The point is in the selected area.
266 @retval FALSE The point is not in the selected area.
269 FileBufferIsInSelectedArea (
283 // judge mouse position whether is in selected area
288 if (MainEditor
.SelectStart
== 0 || MainEditor
.SelectEnd
== 0) {
292 // calculate the select area
294 RowStart
= (MainEditor
.SelectStart
- 1) / SHELL_EDIT_MAX_LINE_SIZE
+ 1;
295 RowEnd
= (MainEditor
.SelectEnd
- 1) / SHELL_EDIT_MAX_LINE_SIZE
+ 1;
297 ColStart
= (MainEditor
.SelectStart
- 1) % SHELL_EDIT_MAX_LINE_SIZE
+ 1;
298 ColEnd
= (MainEditor
.SelectEnd
- 1) % SHELL_EDIT_MAX_LINE_SIZE
+ 1;
300 FRow
= FileBuffer
.LowVisibleRange
.Row
+ MouseRow
- 2;
301 if (FRow
< RowStart
|| FRow
> RowEnd
) {
305 if (FRow
> RowStart
) {
310 ColEnd
= SHELL_EDIT_MAX_LINE_SIZE
;
313 MouseColStart
= ColStart
;
315 MouseColEnd
= ColEnd
;
317 if (MouseCol
< MouseColStart
|| MouseCol
> MouseColEnd
) {
325 Function to update the 'screen' to display the mouse position.
327 @retval EFI_SUCCESS The backup operation was successful.
331 FileBufferRestoreMousePosition (
335 EFI_EDITOR_COLOR_UNION Orig
;
336 EFI_EDITOR_COLOR_UNION New
;
339 BOOLEAN HasCharacter
;
340 EFI_EDITOR_LINE
*CurrentLine
;
341 EFI_EDITOR_LINE
*Line
;
345 // variable initialization
349 if (MainEditor
.MouseSupported
) {
351 if (FileBufferMouseNeedRefresh
) {
353 FileBufferMouseNeedRefresh
= FALSE
;
356 // if mouse position not moved and only mouse action
357 // so do not need to refresh mouse position
359 if ((FileBuffer
.MousePosition
.Row
== FileBufferBackupVar
.MousePosition
.Row
&&
360 FileBuffer
.MousePosition
.Column
== FileBufferBackupVar
.MousePosition
.Column
)
361 && EditorMouseAction
) {
365 // backup the old screen attributes
367 Orig
= MainEditor
.ColorAttributes
;
369 New
.Colors
.Foreground
= Orig
.Colors
.Background
& 0xF;
370 New
.Colors
.Background
= Orig
.Colors
.Foreground
& 0x7;
373 // clear the old mouse position
375 FRow
= FileBuffer
.LowVisibleRange
.Row
+ FileBufferBackupVar
.MousePosition
.Row
- 2;
377 FColumn
= FileBuffer
.LowVisibleRange
.Column
+ FileBufferBackupVar
.MousePosition
.Column
- 1;
379 if (FRow
<= FileBuffer
.NumLines
) {
380 CurrentLine
= FileBuffer
.CurrentLine
;
381 Line
= MoveLine (FRow
- FileBuffer
.FilePosition
.Row
);
382 FileBuffer
.CurrentLine
= CurrentLine
;
386 // if in selected area,
387 // so do not need to refresh mouse
389 if (!FileBufferIsInSelectedArea (
390 FileBufferBackupVar
.MousePosition
.Row
,
391 FileBufferBackupVar
.MousePosition
.Column
393 (Line
== NULL
|| FColumn
> Line
->Size
)
395 gST
->ConOut
->SetAttribute (gST
->ConOut
, Orig
.Data
);
397 gST
->ConOut
->SetAttribute (gST
->ConOut
, New
.Data
& 0x7F);
403 if (FRow
> FileBuffer
.NumLines
) {
404 HasCharacter
= FALSE
;
406 CurrentLine
= FileBuffer
.CurrentLine
;
407 Line
= MoveLine (FRow
- FileBuffer
.FilePosition
.Row
);
409 if (Line
== NULL
|| FColumn
> Line
->Size
) {
410 HasCharacter
= FALSE
;
413 FileBuffer
.CurrentLine
= CurrentLine
;
417 (INT32
)FileBufferBackupVar
.MousePosition
.Column
- 1,
418 (INT32
)FileBufferBackupVar
.MousePosition
.Row
- 1,
423 Value
= (Line
->Buffer
[FColumn
- 1]);
425 (INT32
)FileBufferBackupVar
.MousePosition
.Column
- 1,
426 (INT32
)FileBufferBackupVar
.MousePosition
.Row
- 1,
432 // set the new mouse position
434 if (!FileBufferIsInSelectedArea (
435 FileBuffer
.MousePosition
.Row
,
436 FileBuffer
.MousePosition
.Column
439 gST
->ConOut
->SetAttribute (gST
->ConOut
, New
.Data
& 0x7F);
441 gST
->ConOut
->SetAttribute (gST
->ConOut
, Orig
.Data
);
444 // clear the old mouse position
446 FRow
= FileBuffer
.LowVisibleRange
.Row
+ FileBuffer
.MousePosition
.Row
- 2;
447 FColumn
= FileBuffer
.LowVisibleRange
.Column
+ FileBuffer
.MousePosition
.Column
- 1;
450 if (FRow
> FileBuffer
.NumLines
) {
451 HasCharacter
= FALSE
;
453 CurrentLine
= FileBuffer
.CurrentLine
;
454 Line
= MoveLine (FRow
- FileBuffer
.FilePosition
.Row
);
456 if (Line
== NULL
|| FColumn
> Line
->Size
) {
457 HasCharacter
= FALSE
;
460 FileBuffer
.CurrentLine
= CurrentLine
;
464 (INT32
)FileBuffer
.MousePosition
.Column
- 1,
465 (INT32
)FileBuffer
.MousePosition
.Row
- 1,
470 Value
= Line
->Buffer
[FColumn
- 1];
472 (INT32
)FileBuffer
.MousePosition
.Column
- 1,
473 (INT32
)FileBuffer
.MousePosition
.Row
- 1,
479 // end of HasCharacter
481 gST
->ConOut
->SetAttribute (gST
->ConOut
, Orig
.Data
);
484 // end of MouseNeedRefresh
488 // end of MouseSupported
494 Free all the lines in FileBuffer
501 @retval EFI_SUCCESS The operation was successful.
505 FileBufferFreeLines (
510 EFI_EDITOR_LINE
*Line
;
513 // free all the lines
515 if (FileBuffer
.Lines
!= NULL
) {
517 Line
= FileBuffer
.Lines
;
518 Link
= &(Line
->Link
);
520 Line
= CR (Link
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
521 Link
= Link
->ForwardLink
;
524 // free line's buffer and line itself
527 } while (Link
!= FileBuffer
.ListHead
);
530 // clean the line list related structure
532 FileBuffer
.Lines
= NULL
;
533 FileBuffer
.CurrentLine
= NULL
;
534 FileBuffer
.NumLines
= 0;
536 FileBuffer
.ListHead
->ForwardLink
= FileBuffer
.ListHead
;
537 FileBuffer
.ListHead
->BackLink
= FileBuffer
.ListHead
;
543 Cleanup function for FileBuffer.
545 @retval EFI_SUCCESS The cleanup was successful.
555 SHELL_FREE_NON_NULL (FileBuffer
.FileName
);
558 // free all the lines
560 Status
= FileBufferFreeLines ();
562 SHELL_FREE_NON_NULL (FileBuffer
.ListHead
);
563 FileBuffer
.ListHead
= NULL
;
565 SHELL_FREE_NON_NULL (FileBufferBackupVar
.FileName
);
574 @param[in] Line The lline to print.
575 @param[in] Row The row on screen ( begin from 1 ).
576 @param[in] FRow The FRow.
577 @param[in] Orig The original color.
578 @param[in] New The color to print with.
580 @retval EFI_SUCCESS The operation was successful.
583 FileBufferPrintLine (
584 IN CONST EFI_EDITOR_LINE
*Line
,
587 IN EFI_EDITOR_COLOR_UNION Orig
,
588 IN EFI_EDITOR_COLOR_UNION New
610 // print the selected area in opposite color
612 if (MainEditor
.SelectStart
!= 0 && MainEditor
.SelectEnd
!= 0) {
613 RowStart
= (MainEditor
.SelectStart
- 1) / SHELL_EDIT_MAX_LINE_SIZE
+ 1;
614 RowEnd
= (MainEditor
.SelectEnd
- 1) / SHELL_EDIT_MAX_LINE_SIZE
+ 1;
616 ColStart
= (MainEditor
.SelectStart
- 1) % SHELL_EDIT_MAX_LINE_SIZE
+ 1;
617 ColEnd
= (MainEditor
.SelectEnd
- 1) % SHELL_EDIT_MAX_LINE_SIZE
+ 1;
619 if (FRow
>= RowStart
&& FRow
<= RowEnd
) {
623 if (FRow
> RowStart
) {
628 ColEnd
= Line
->Size
+ 1;
634 // print start from correct character
636 Buffer
= Line
->Buffer
+ FileBuffer
.LowVisibleRange
.Column
- 1;
638 Limit
= Line
->Size
- FileBuffer
.LowVisibleRange
.Column
+ 1;
639 if (Limit
> Line
->Size
) {
643 BufLen
= (MainEditor
.ScreenSize
.Column
+ 1) * sizeof (CHAR16
);
644 PrintLine
= AllocatePool (BufLen
);
645 ASSERT (PrintLine
!= NULL
);
647 StrnCpyS (PrintLine
, BufLen
/sizeof(CHAR16
), Buffer
, MIN(Limit
, MainEditor
.ScreenSize
.Column
));
648 for (; Limit
< MainEditor
.ScreenSize
.Column
; Limit
++) {
649 PrintLine
[Limit
] = L
' ';
652 PrintLine
[MainEditor
.ScreenSize
.Column
] = CHAR_NULL
;
654 PrintLine2
= AllocatePool (BufLen
* 2);
655 ASSERT (PrintLine2
!= NULL
);
657 ShellCopySearchAndReplace(PrintLine
, PrintLine2
, BufLen
* 2, L
"%", L
"^%", FALSE
, FALSE
);
668 // If the current line is selected.
671 gST
->ConOut
->SetAttribute (gST
->ConOut
, Orig
.Data
& 0x7F);
672 TempString
= AllocateCopyPool ((ColStart
- 1) * sizeof(CHAR16
), PrintLine2
);
673 ASSERT (TempString
!= NULL
);
680 FreePool (TempString
);
683 gST
->ConOut
->SetAttribute (gST
->ConOut
, New
.Data
& 0x7F);
684 TempString
= AllocateCopyPool (
685 (ColEnd
- ColStart
+ 1) * sizeof(CHAR16
),
686 PrintLine2
+ ColStart
- 1
688 ASSERT (TempString
!= NULL
);
695 FreePool (TempString
);
697 if (ColEnd
!= SHELL_EDIT_MAX_LINE_SIZE
) {
698 gST
->ConOut
->SetAttribute (gST
->ConOut
, Orig
.Data
& 0x7F);
699 TempString
= AllocateCopyPool (
700 (SHELL_EDIT_MAX_LINE_SIZE
- ColEnd
+ 1) * sizeof(CHAR16
),
701 PrintLine2
+ ColEnd
- 1
703 ASSERT (TempString
!= NULL
);
710 FreePool (TempString
);
714 FreePool (PrintLine
);
715 FreePool (PrintLine2
);
716 gST
->ConOut
->SetAttribute (gST
->ConOut
, Orig
.Data
& 0x7F);
722 Set the cursor position according to FileBuffer.DisplayPosition.
724 @retval EFI_SUCCESS The operation was successful.
728 FileBufferRestorePosition (
733 // set cursor position
735 return (gST
->ConOut
->SetCursorPosition (
737 FileBuffer
.DisplayPosition
.Column
- 1,
738 FileBuffer
.DisplayPosition
.Row
- 1
743 Refresh the screen with whats in the buffer.
745 @retval EFI_SUCCESS The refresh was successful.
746 @retval EFI_LOAD_ERROR There was an error finding what to write.
755 EFI_EDITOR_LINE
*Line
;
757 EFI_EDITOR_COLOR_UNION Orig
;
758 EFI_EDITOR_COLOR_UNION New
;
765 Orig
= MainEditor
.ColorAttributes
;
767 New
.Colors
.Foreground
= Orig
.Colors
.Background
;
768 New
.Colors
.Background
= Orig
.Colors
.Foreground
;
771 // if it's the first time after editor launch, so should refresh
775 // no definite required refresh
776 // and file position displayed on screen has not been changed
778 if (!FileBufferNeedRefresh
&&
779 !FileBufferOnlyLineNeedRefresh
&&
780 FileBufferBackupVar
.LowVisibleRange
.Row
== FileBuffer
.LowVisibleRange
.Row
782 FileBufferRestoreMousePosition ();
783 FileBufferRestorePosition ();
788 gST
->ConOut
->EnableCursor (gST
->ConOut
, FALSE
);
791 // only need to refresh current line
793 if (FileBufferOnlyLineNeedRefresh
&&
794 FileBufferBackupVar
.LowVisibleRange
.Row
== FileBuffer
.LowVisibleRange
.Row
797 EditorClearLine (FileBuffer
.DisplayPosition
.Row
, MainEditor
.ScreenSize
.Column
, MainEditor
.ScreenSize
.Row
);
798 FileBufferPrintLine (
799 FileBuffer
.CurrentLine
,
800 FileBuffer
.DisplayPosition
.Row
,
801 FileBuffer
.FilePosition
.Row
,
807 // the whole edit area need refresh
809 if (EditorMouseAction
&& MainEditor
.SelectStart
!= 0 && MainEditor
.SelectEnd
!= 0) {
810 if (MainEditor
.SelectStart
!= MainEditorBackupVar
.SelectStart
) {
811 if (MainEditor
.SelectStart
>= MainEditorBackupVar
.SelectStart
&& MainEditorBackupVar
.SelectStart
!= 0) {
812 StartRow
= (MainEditorBackupVar
.SelectStart
- 1) / SHELL_EDIT_MAX_LINE_SIZE
+ 1;
814 StartRow
= (MainEditor
.SelectStart
- 1) / SHELL_EDIT_MAX_LINE_SIZE
+ 1;
817 StartRow
= (MainEditor
.SelectStart
- 1) / SHELL_EDIT_MAX_LINE_SIZE
+ 1;
820 if (MainEditor
.SelectEnd
<= MainEditorBackupVar
.SelectEnd
) {
821 EndRow
= (MainEditorBackupVar
.SelectEnd
- 1) / SHELL_EDIT_MAX_LINE_SIZE
+ 1;
823 EndRow
= (MainEditor
.SelectEnd
- 1) / SHELL_EDIT_MAX_LINE_SIZE
+ 1;
829 if (StartRow
> EndRow
) {
835 FStartRow
= StartRow
;
837 StartRow
= 2 + StartRow
- FileBuffer
.LowVisibleRange
.Row
;
838 EndRow
= 2 + EndRow
- FileBuffer
.LowVisibleRange
.Row
;
842 // not mouse selection actions
844 FStartRow
= FileBuffer
.LowVisibleRange
.Row
;
846 EndRow
= (MainEditor
.ScreenSize
.Row
- 1);
852 if (FileBuffer
.Lines
== NULL
) {
853 FileBufferRestoreMousePosition ();
854 FileBufferRestorePosition ();
855 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
860 // get the first line that will be displayed
862 Line
= MoveLine (FileBuffer
.LowVisibleRange
.Row
- FileBuffer
.FilePosition
.Row
);
864 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
866 return EFI_LOAD_ERROR
;
869 Link
= &(Line
->Link
);
872 Line
= CR (Link
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
877 FileBufferPrintLine (Line
,
879 FileBuffer
.LowVisibleRange
.Row
+ Row
- 2,
884 Link
= Link
->ForwardLink
;
886 } while (Link
!= FileBuffer
.ListHead
&& Row
<= EndRow
);
888 // while not file end and not screen full
890 while (Row
<= EndRow
) {
891 EditorClearLine (Row
, MainEditor
.ScreenSize
.Column
, MainEditor
.ScreenSize
.Row
);
896 FileBufferRestoreMousePosition ();
897 FileBufferRestorePosition ();
899 FileBufferNeedRefresh
= FALSE
;
900 FileBufferOnlyLineNeedRefresh
= FALSE
;
902 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
907 Create a new line and append it to the line list.
912 @retval NULL The create line failed.
913 @return The line created.
917 FileBufferCreateLine (
921 EFI_EDITOR_LINE
*Line
;
924 // allocate a line structure
926 Line
= AllocateZeroPool (sizeof (EFI_EDITOR_LINE
));
931 // initialize the structure
933 Line
->Signature
= LINE_LIST_SIGNATURE
;
936 Line
->Type
= NewLineTypeDefault
;
939 // initial buffer of the line is "\0"
941 ASSERT(CHAR_NULL
== CHAR_NULL
);
942 Line
->Buffer
= CatSPrint (NULL
, L
"\0");
943 if (Line
->Buffer
== NULL
) {
947 FileBuffer
.NumLines
++;
950 // insert the line into line list
952 InsertTailList (FileBuffer
.ListHead
, &Line
->Link
);
954 if (FileBuffer
.Lines
== NULL
) {
955 FileBuffer
.Lines
= CR (FileBuffer
.ListHead
->ForwardLink
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
962 Set FileName field in FileBuffer.
964 @param Str The file name to set.
966 @retval EFI_SUCCESS The filename was successfully set.
967 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
968 @retval EFI_INVALID_PARAMETER Str is not a valid filename.
972 FileBufferSetFileName (
977 // Verify the parameters
979 if (!IsValidFileName(Str
)) {
980 return (EFI_INVALID_PARAMETER
);
983 // free the old file name
985 SHELL_FREE_NON_NULL (FileBuffer
.FileName
);
988 // Allocate and set the new name
990 FileBuffer
.FileName
= CatSPrint (NULL
, L
"%s", Str
);
991 if (FileBuffer
.FileName
== NULL
) {
992 return EFI_OUT_OF_RESOURCES
;
998 Free the existing file lines and reset the modified flag.
1000 @retval EFI_SUCCESS The operation was successful.
1009 // free all the lines
1011 FileBufferFreeLines ();
1012 FileBuffer
.FileModified
= FALSE
;
1019 Read a file from disk into the FileBuffer.
1021 @param[in] FileName The filename to read.
1022 @param[in] Recover TRUE if is for recover mode, no information printouts.
1024 @retval EFI_SUCCESS The load was successful.
1025 @retval EFI_LOAD_ERROR The load failed.
1026 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1027 @retval EFI_INVALID_PARAMETER FileName is a directory.
1032 IN CONST CHAR16
*FileName
,
1033 IN CONST BOOLEAN Recover
1036 EFI_EDITOR_LINE
*Line
;
1037 EE_NEWLINE_TYPE Type
;
1042 CHAR16
*UnicodeBuffer
;
1045 SHELL_FILE_HANDLE FileHandle
;
1048 UINTN LineSizeBackup
;
1049 EFI_FILE_INFO
*Info
;
1054 UnicodeBuffer
= NULL
;
1055 Type
= NewLineTypeDefault
;
1060 // in this function, when you return error ( except EFI_OUT_OF_RESOURCES )
1061 // you should set status string via StatusBarSetStatusString(L"blah")
1062 // since this function maybe called before the editorhandleinput loop
1063 // so any error will cause editor return
1064 // so if you want to print the error status
1065 // you should set the status string
1069 // try to open the file
1071 Status
= ShellOpenFileByName (FileName
, &FileHandle
, EFI_FILE_MODE_READ
, 0);
1073 if (!EFI_ERROR(Status
)) {
1075 if (FileHandle
== NULL
) {
1076 StatusBarSetStatusString (L
"Disk Error");
1077 return EFI_LOAD_ERROR
;
1080 Info
= ShellGetFileInfo(FileHandle
);
1082 if (Info
->Attribute
& EFI_FILE_DIRECTORY
) {
1083 StatusBarSetStatusString (L
"Directory Can Not Be Edited");
1085 return EFI_INVALID_PARAMETER
;
1088 if (Info
->Attribute
& EFI_FILE_READ_ONLY
) {
1089 FileBuffer
.ReadOnly
= TRUE
;
1091 FileBuffer
.ReadOnly
= FALSE
;
1096 FileSize
= (UINTN
) Info
->FileSize
;
1099 } else if (Status
== EFI_NOT_FOUND
) {
1101 // file not exists. add create and try again
1103 Status
= ShellOpenFileByName (FileName
, &FileHandle
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_CREATE
, 0);
1104 if (EFI_ERROR (Status
)) {
1105 if (Status
== EFI_WRITE_PROTECTED
||
1106 Status
== EFI_ACCESS_DENIED
||
1107 Status
== EFI_NO_MEDIA
||
1108 Status
== EFI_MEDIA_CHANGED
1110 StatusBarSetStatusString (L
"Access Denied");
1111 } else if (Status
== EFI_DEVICE_ERROR
|| Status
== EFI_VOLUME_CORRUPTED
|| Status
== EFI_VOLUME_FULL
) {
1112 StatusBarSetStatusString (L
"Disk Error");
1114 StatusBarSetStatusString (L
"Invalid File Name or Current-working-directory");
1120 // it worked. now delete it and move on with the name (now validated)
1122 Status
= ShellDeleteFile (&FileHandle
);
1123 if (Status
== EFI_WARN_DELETE_FAILURE
) {
1124 Status
= EFI_ACCESS_DENIED
;
1127 if (EFI_ERROR (Status
)) {
1128 StatusBarSetStatusString (L
"Access Denied");
1133 // file doesn't exist, so set CreateFile to TRUE
1136 FileBuffer
.ReadOnly
= FALSE
;
1139 // all the check ends
1140 // so now begin to set file name, free lines
1142 if (StrCmp (FileName
, FileBuffer
.FileName
) != 0) {
1143 FileBufferSetFileName (FileName
);
1146 // free the old lines
1156 // allocate buffer to read file
1158 Buffer
= AllocateZeroPool (FileSize
);
1159 if (Buffer
== NULL
) {
1160 return EFI_OUT_OF_RESOURCES
;
1163 // read file into Buffer
1165 Status
= ShellReadFile (FileHandle
, &FileSize
, Buffer
);
1166 ShellCloseFile(&FileHandle
);
1168 if (EFI_ERROR (Status
)) {
1169 StatusBarSetStatusString (L
"Read File Failed");
1170 SHELL_FREE_NON_NULL (Buffer
);
1171 return EFI_LOAD_ERROR
;
1174 // nothing in this file
1176 if (FileSize
== 0) {
1177 SHELL_FREE_NON_NULL (Buffer
);
1179 // since has no head, so only can be an ASCII file
1181 FileBuffer
.FileType
= FileTypeAscii
;
1186 AsciiBuffer
= Buffer
;
1190 // size < Unicode file header, so only can be ASCII file
1192 FileBuffer
.FileType
= FileTypeAscii
;
1197 if (*(UINT16
*) Buffer
== EFI_UNICODE_BYTE_ORDER_MARK
) {
1199 // Unicode file's size should be even
1201 if ((FileSize
% 2) != 0) {
1202 StatusBarSetStatusString (L
"File Format Wrong");
1203 SHELL_FREE_NON_NULL (Buffer
);
1204 return EFI_LOAD_ERROR
;
1209 FileBuffer
.FileType
= FileTypeUnicode
;
1210 UnicodeBuffer
= Buffer
;
1213 // pass this 0xff and 0xfe
1218 FileBuffer
.FileType
= FileTypeAscii
;
1221 // end of AsciiBuffer ==
1225 // end of FileSize < 2
1226 // all the check ends
1227 // so now begin to set file name, free lines
1229 if (StrCmp (FileName
, FileBuffer
.FileName
) != 0) {
1230 FileBufferSetFileName (FileName
);
1234 // free the old lines
1239 // parse file content line by line
1241 for (LoopVar1
= 0; LoopVar1
< FileSize
; LoopVar1
++) {
1242 Type
= NewLineTypeUnknown
;
1244 for (LineSize
= LoopVar1
; LineSize
< FileSize
; LineSize
++) {
1245 if (FileBuffer
.FileType
== FileTypeAscii
) {
1246 if (AsciiBuffer
[LineSize
] == CHAR_CARRIAGE_RETURN
) {
1247 Type
= NewLineTypeCarriageReturn
;
1252 if (LineSize
< FileSize
- 1) {
1253 if (AsciiBuffer
[LineSize
+ 1] == CHAR_LINEFEED
) {
1254 Type
= NewLineTypeCarriageReturnLineFeed
;
1259 } else if (AsciiBuffer
[LineSize
] == CHAR_LINEFEED
) {
1260 Type
= NewLineTypeLineFeed
;
1265 if (LineSize
< FileSize
- 1) {
1266 if (AsciiBuffer
[LineSize
+ 1] == CHAR_CARRIAGE_RETURN
) {
1267 Type
= NewLineTypeLineFeedCarriageReturn
;
1274 if (UnicodeBuffer
[LineSize
] == CHAR_CARRIAGE_RETURN
) {
1275 Type
= NewLineTypeCarriageReturn
;
1280 if (LineSize
< FileSize
- 1) {
1281 if (UnicodeBuffer
[LineSize
+ 1] == CHAR_LINEFEED
) {
1282 Type
= NewLineTypeCarriageReturnLineFeed
;
1287 } else if (UnicodeBuffer
[LineSize
] == CHAR_LINEFEED
) {
1288 Type
= NewLineTypeLineFeed
;
1293 if (LineSize
< FileSize
- 1) {
1294 if (UnicodeBuffer
[LineSize
+ 1] == CHAR_CARRIAGE_RETURN
) {
1295 Type
= NewLineTypeLineFeedCarriageReturn
;
1307 // end of for LineSize
1309 // if the type is wrong, then exit
1311 if (Type
== NewLineTypeUnknown
) {
1313 // Now if Type is NewLineTypeUnknown, it should be file end
1315 Type
= NewLineTypeDefault
;
1318 LineSizeBackup
= LineSize
;
1321 // create a new line
1323 Line
= FileBufferCreateLine ();
1325 SHELL_FREE_NON_NULL (Buffer
);
1326 return EFI_OUT_OF_RESOURCES
;
1329 // calculate file length
1331 LineSize
-= LoopVar1
;
1334 // Unicode and one CHAR_NULL
1336 SHELL_FREE_NON_NULL (Line
->Buffer
);
1337 Line
->Buffer
= AllocateZeroPool (LineSize
* 2 + 2);
1339 if (Line
->Buffer
== NULL
) {
1340 RemoveEntryList (&Line
->Link
);
1341 return EFI_OUT_OF_RESOURCES
;
1344 // copy this line to Line->Buffer
1346 for (LoopVar2
= 0; LoopVar2
< LineSize
; LoopVar2
++) {
1347 if (FileBuffer
.FileType
== FileTypeAscii
) {
1348 Line
->Buffer
[LoopVar2
] = (CHAR16
) AsciiBuffer
[LoopVar1
];
1350 Line
->Buffer
[LoopVar2
] = UnicodeBuffer
[LoopVar1
];
1356 // LoopVar1 now points to where CHAR_CARRIAGE_RETURN or CHAR_LINEFEED;
1358 Line
->Buffer
[LineSize
] = 0;
1360 Line
->Size
= LineSize
;
1361 Line
->TotalSize
= LineSize
;
1364 if (Type
== NewLineTypeCarriageReturnLineFeed
|| Type
== NewLineTypeLineFeedCarriageReturn
) {
1369 // last character is a return, SO create a new line
1371 if (((Type
== NewLineTypeCarriageReturnLineFeed
|| Type
== NewLineTypeLineFeedCarriageReturn
) && LineSizeBackup
== FileSize
- 2) ||
1372 ((Type
== NewLineTypeLineFeed
|| Type
== NewLineTypeCarriageReturn
) && LineSizeBackup
== FileSize
- 1)
1374 Line
= FileBufferCreateLine ();
1376 SHELL_FREE_NON_NULL (Buffer
);
1377 return EFI_OUT_OF_RESOURCES
;
1387 SHELL_FREE_NON_NULL (Buffer
);
1391 // end of if CreateFile
1395 FileBuffer
.DisplayPosition
.Row
= 2;
1396 FileBuffer
.DisplayPosition
.Column
= 1;
1397 FileBuffer
.LowVisibleRange
.Row
= 1;
1398 FileBuffer
.LowVisibleRange
.Column
= 1;
1399 FileBuffer
.FilePosition
.Row
= 1;
1400 FileBuffer
.FilePosition
.Column
= 1;
1401 FileBuffer
.MousePosition
.Row
= 2;
1402 FileBuffer
.MousePosition
.Column
= 1;
1405 UnicodeBuffer
= CatSPrint (NULL
, L
"%d Lines Read", FileBuffer
.NumLines
);
1406 if (UnicodeBuffer
== NULL
) {
1407 return EFI_OUT_OF_RESOURCES
;
1410 StatusBarSetStatusString (UnicodeBuffer
);
1411 FreePool (UnicodeBuffer
);
1415 // check whether we have fs?: in filename
1418 FSMappingPtr = NULL;
1419 while (FileName[LoopVar1] != 0) {
1420 if (FileName[LoopVar1] == L':') {
1421 FSMappingPtr = &FileName[LoopVar1];
1428 if (FSMappingPtr == NULL) {
1429 CurDir = ShellGetCurrentDir (NULL);
1433 while (FileName[LoopVar1] != 0) {
1434 if (FileName[LoopVar1] == L':') {
1438 FSMapping[LoopVar2++] = FileName[LoopVar1];
1443 FSMapping[LoopVar2] = 0;
1444 CurDir = ShellGetCurrentDir (FSMapping);
1447 if (CurDir != NULL) {
1448 for (LoopVar1 = 0; LoopVar1 < StrLen (CurDir) && CurDir[LoopVar1] != ':'; LoopVar1++);
1450 CurDir[LoopVar1] = 0;
1451 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) ShellGetMap (CurDir);
1454 return EFI_LOAD_ERROR;
1457 Status = LibDevicePathToInterface (
1458 &gEfiSimpleFileSystemProtocolGuid,
1462 if (EFI_ERROR (Status)) {
1463 return EFI_LOAD_ERROR;
1466 Status = Vol->OpenVolume (Vol, &RootFs);
1467 if (EFI_ERROR (Status)) {
1468 return EFI_LOAD_ERROR;
1471 // Get volume information of file system
1473 Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + 100;
1474 VolumeInfo = (EFI_FILE_SYSTEM_INFO *) AllocateZeroPool (Size);
1475 Status = RootFs->GetInfo (RootFs, &gEfiFileSystemInfoGuid, &Size, VolumeInfo);
1476 if (EFI_ERROR (Status)) {
1477 RootFs->Close (RootFs);
1478 return EFI_LOAD_ERROR;
1481 if (VolumeInfo->ReadOnly) {
1482 StatusBarSetStatusString (L"WARNING: Volume Read Only");
1485 FreePool (VolumeInfo);
1486 RootFs->Close (RootFs);
1493 if (FileBuffer
.Lines
!= 0) {
1494 FileBuffer
.CurrentLine
= CR (FileBuffer
.ListHead
->ForwardLink
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
1497 // create a dummy line
1499 Line
= FileBufferCreateLine ();
1501 return EFI_OUT_OF_RESOURCES
;
1504 FileBuffer
.CurrentLine
= Line
;
1507 FileBuffer
.FileModified
= FALSE
;
1508 FileBufferNeedRefresh
= TRUE
;
1509 FileBufferOnlyLineNeedRefresh
= FALSE
;
1510 FileBufferMouseNeedRefresh
= TRUE
;
1517 According to FileBuffer.NewLineType & FileBuffer.FileType,
1518 get the return buffer and size.
1520 @param[in] Type The type of line.
1521 @param[out] Buffer The buffer to fill.
1522 @param[out] Size The amount of the buffer used on return.
1527 IN CONST EE_NEWLINE_TYPE Type
,
1535 // give new line buffer,
1536 // and will judge unicode or ascii
1541 // not legal new line type
1543 if (Type
!= NewLineTypeLineFeed
&& Type
!= NewLineTypeCarriageReturn
&& Type
!= NewLineTypeCarriageReturnLineFeed
&& Type
!= NewLineTypeLineFeedCarriageReturn
) {
1548 // use_cr: give 0x0d
1550 if (Type
== NewLineTypeCarriageReturn
) {
1551 if (MainEditor
.FileBuffer
->FileType
== FileTypeUnicode
) {
1560 *Size
= NewLineSize
;
1564 // use_lf: give 0x0a
1566 if (Type
== NewLineTypeLineFeed
) {
1567 if (MainEditor
.FileBuffer
->FileType
== FileTypeUnicode
) {
1576 *Size
= NewLineSize
;
1580 // use_crlf: give 0x0d 0x0a
1582 if (Type
== NewLineTypeCarriageReturnLineFeed
) {
1583 if (MainEditor
.FileBuffer
->FileType
== FileTypeUnicode
) {
1596 *Size
= NewLineSize
;
1600 // use_lfcr: give 0x0a 0x0d
1602 if (Type
== NewLineTypeLineFeedCarriageReturn
) {
1603 if (MainEditor
.FileBuffer
->FileType
== FileTypeUnicode
) {
1616 *Size
= NewLineSize
;
1623 Change a Unicode string to an ASCII string.
1625 @param[in] UStr The Unicode string.
1626 @param[in] Length The maximum size of AStr.
1627 @param[out] AStr ASCII string to pass out.
1629 @return The actuall length.
1634 IN CONST CHAR16
*UStr
,
1635 IN CONST UINTN Length
,
1642 // just buffer copy, not character copy
1644 for (Index
= 0; Index
< Length
; Index
++) {
1645 *AStr
++ = (CHAR8
) *UStr
++;
1652 Save lines in FileBuffer to disk
1654 @param[in] FileName The file name for writing.
1656 @retval EFI_SUCCESS Data was written.
1657 @retval EFI_LOAD_ERROR
1658 @retval EFI_OUT_OF_RESOURCES There were not enough resources to write the file.
1663 IN CONST CHAR16
*FileName
1666 SHELL_FILE_HANDLE FileHandle
;
1668 EFI_EDITOR_LINE
*Line
;
1674 CHAR8 NewLineBuffer
[4];
1677 EFI_FILE_INFO
*Info
;
1681 EE_NEWLINE_TYPE Type
;
1696 TotalSize
= 0x200000;
1703 // if is the old file
1705 if (FileBuffer
.FileName
!= NULL
&& StrCmp (FileName
, FileBuffer
.FileName
) == 0) {
1707 // file has not been modified
1709 if (!FileBuffer
.FileModified
) {
1714 // if file is read-only, set error
1716 if (FileBuffer
.ReadOnly
) {
1717 StatusBarSetStatusString (L
"Read Only File Can Not Be Saved");
1722 Status
= ShellOpenFileByName (FileName
, &FileHandle
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
, 0);
1724 if (!EFI_ERROR (Status
)) {
1725 Info
= ShellGetFileInfo(FileHandle
);
1727 if (Info
!= NULL
&& Info
->Attribute
& EFI_FILE_DIRECTORY
) {
1728 StatusBarSetStatusString (L
"Directory Can Not Be Saved");
1729 ShellCloseFile(FileHandle
);
1731 return EFI_LOAD_ERROR
;
1735 Attribute
= Info
->Attribute
& ~EFI_FILE_READ_ONLY
;
1740 // if file exits, so delete it
1742 Status
= ShellDeleteFile (&FileHandle
);
1743 if (EFI_ERROR (Status
) || Status
== EFI_WARN_DELETE_FAILURE
) {
1744 StatusBarSetStatusString (L
"Write File Failed");
1745 return EFI_LOAD_ERROR
;
1749 Status
= ShellOpenFileByName (FileName
, &FileHandle
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_CREATE
, Attribute
);
1751 if (EFI_ERROR (Status
)) {
1752 StatusBarSetStatusString (L
"Create File Failed");
1753 return EFI_LOAD_ERROR
;
1757 // if file is Unicode file, write Unicode header to it.
1759 if (FileBuffer
.FileType
== FileTypeUnicode
) {
1761 Status
= ShellWriteFile (FileHandle
, &Length
, (VOID
*)&gUnicodeFileTag
);
1762 if (EFI_ERROR (Status
)) {
1763 ShellDeleteFile (&FileHandle
);
1764 return EFI_LOAD_ERROR
;
1768 Cache
= AllocateZeroPool (TotalSize
);
1769 if (Cache
== NULL
) {
1770 ShellDeleteFile (&FileHandle
);
1771 return EFI_OUT_OF_RESOURCES
;
1775 // write all the lines back to disk
1778 Type
= NewLineTypeCarriageReturnLineFeed
;
1781 LeftSize
= TotalSize
;
1783 for (Link
= FileBuffer
.ListHead
->ForwardLink
; Link
!= FileBuffer
.ListHead
; Link
= Link
->ForwardLink
) {
1784 Line
= CR (Link
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
1786 if (Line
->Type
!= NewLineTypeDefault
) {
1790 // newline character is at most 4 bytes ( two Unicode characters )
1793 if (Line
->Buffer
!= NULL
&& Line
->Size
!= 0) {
1794 if (FileBuffer
.FileType
== FileTypeAscii
) {
1795 Length
+= Line
->Size
;
1797 Length
+= (Line
->Size
* 2);
1800 // end if FileTypeAscii
1805 // no cache room left, so write cache to disk
1807 if (LeftSize
< Length
) {
1808 Size
= TotalSize
- LeftSize
;
1809 Status
= ShellWriteFile (FileHandle
, &Size
, Cache
);
1810 if (EFI_ERROR (Status
)) {
1811 ShellDeleteFile (&FileHandle
);
1813 return EFI_LOAD_ERROR
;
1816 LeftSize
= TotalSize
;
1819 if (Line
->Buffer
!= NULL
&& Line
->Size
!= 0) {
1820 if (FileBuffer
.FileType
== FileTypeAscii
) {
1821 UnicodeToAscii (Line
->Buffer
, Line
->Size
, Ptr
);
1822 Length
= Line
->Size
;
1824 Length
= (Line
->Size
* 2);
1825 CopyMem (Ptr
, (CHAR8
*) Line
->Buffer
, Length
);
1828 // end if FileTypeAscii
1835 // end of if Line -> Buffer != NULL && Line -> Size != 0
1837 // if not the last line , write return buffer to disk
1839 if (Link
->ForwardLink
!= FileBuffer
.ListHead
) {
1840 GetNewLine (Type
, NewLineBuffer
, &NewLineSize
);
1841 CopyMem (Ptr
, (CHAR8
*) NewLineBuffer
, NewLineSize
);
1844 LeftSize
-= NewLineSize
;
1850 if (TotalSize
!= LeftSize
) {
1851 Size
= TotalSize
- LeftSize
;
1852 Status
= ShellWriteFile (FileHandle
, &Size
, Cache
);
1853 if (EFI_ERROR (Status
)) {
1854 ShellDeleteFile (&FileHandle
);
1856 return EFI_LOAD_ERROR
;
1862 ShellCloseFile(&FileHandle
);
1864 FileBuffer
.FileModified
= FALSE
;
1867 // set status string
1869 Str
= CatSPrint (NULL
, L
"%d Lines Wrote", NumLines
);
1871 return EFI_OUT_OF_RESOURCES
;
1874 StatusBarSetStatusString (Str
);
1875 SHELL_FREE_NON_NULL (Str
);
1878 // now everything is ready , you can set the new file name to filebuffer
1880 if (FileName
!= NULL
&& FileBuffer
.FileName
!= NULL
&& StrCmp (FileName
, FileBuffer
.FileName
) != 0) {
1884 FileBufferSetFileName (FileName
);
1885 if (FileBuffer
.FileName
== NULL
) {
1886 ShellDeleteFile (&FileHandle
);
1887 return EFI_OUT_OF_RESOURCES
;
1891 FileBuffer
.ReadOnly
= FALSE
;
1896 Scroll cursor to left 1 character position.
1898 @retval EFI_SUCCESS The operation was successful.
1902 FileBufferScrollLeft (
1906 EFI_EDITOR_LINE
*Line
;
1910 Line
= FileBuffer
.CurrentLine
;
1912 FRow
= FileBuffer
.FilePosition
.Row
;
1913 FCol
= FileBuffer
.FilePosition
.Column
;
1916 // if already at start of this line, so move to the end of previous line
1920 // has previous line
1922 if (Line
->Link
.BackLink
!= FileBuffer
.ListHead
) {
1924 Line
= CR (Line
->Link
.BackLink
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
1925 FCol
= Line
->Size
+ 1;
1931 // if not at start of this line, just move to previous column
1936 FileBufferMovePosition (FRow
, FCol
);
1942 Delete a char in line
1944 @param[in, out] Line The line to delete in.
1945 @param[in] Pos Position to delete the char at ( start from 0 ).
1950 IN OUT EFI_EDITOR_LINE
*Line
,
1957 // move the latter characters front
1959 for (Index
= Pos
- 1; Index
< Line
->Size
; Index
++) {
1960 Line
->Buffer
[Index
] = Line
->Buffer
[Index
+ 1];
1967 Concatenate Src into Dest.
1969 @param[in, out] Dest Destination string
1970 @param[in] Src Src String.
1975 IN OUT EFI_EDITOR_LINE
*Dest
,
1976 IN EFI_EDITOR_LINE
*Src
1984 Dest
->Buffer
[Size
] = 0;
1987 // concatenate the two strings
1989 Str
= CatSPrint (NULL
, L
"%s%s", Dest
->Buffer
, Src
->Buffer
);
1991 Dest
->Buffer
= NULL
;
1995 Dest
->Size
= Size
+ Src
->Size
;
1996 Dest
->TotalSize
= Dest
->Size
;
1998 FreePool (Dest
->Buffer
);
1999 FreePool (Src
->Buffer
);
2002 // put str to dest->buffer
2008 Delete the previous character.
2010 @retval EFI_SUCCESS The delete was successful.
2011 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
2015 FileBufferDoBackspace (
2019 EFI_EDITOR_LINE
*Line
;
2020 EFI_EDITOR_LINE
*End
;
2024 FileColumn
= FileBuffer
.FilePosition
.Column
;
2026 Line
= FileBuffer
.CurrentLine
;
2031 if (FileColumn
== 1) {
2035 if (FileBuffer
.FilePosition
.Row
== 1) {
2039 FileBufferScrollLeft ();
2041 Line
= FileBuffer
.CurrentLine
;
2042 Link
= Line
->Link
.ForwardLink
;
2043 End
= CR (Link
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
2046 // concatenate this line with previous line
2048 LineCat (Line
, End
);
2049 if (Line
->Buffer
== NULL
) {
2050 return EFI_OUT_OF_RESOURCES
;
2053 // remove End from line list
2055 RemoveEntryList (&End
->Link
);
2058 FileBuffer
.NumLines
--;
2060 FileBufferNeedRefresh
= TRUE
;
2061 FileBufferOnlyLineNeedRefresh
= FALSE
;
2065 // just delete the previous character
2067 LineDeleteAt (Line
, FileColumn
- 1);
2068 FileBufferScrollLeft ();
2069 FileBufferOnlyLineNeedRefresh
= TRUE
;
2072 if (!FileBuffer
.FileModified
) {
2073 FileBuffer
.FileModified
= TRUE
;
2080 Add a return into line at current position.
2082 @retval EFI_SUCCESS The insetrion of the character was successful.
2083 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
2087 FileBufferDoReturn (
2091 EFI_EDITOR_LINE
*Line
;
2092 EFI_EDITOR_LINE
*NewLine
;
2099 FileBufferNeedRefresh
= TRUE
;
2100 FileBufferOnlyLineNeedRefresh
= FALSE
;
2102 Line
= FileBuffer
.CurrentLine
;
2104 FileColumn
= FileBuffer
.FilePosition
.Column
;
2106 NewLine
= AllocateZeroPool (sizeof (EFI_EDITOR_LINE
));
2107 if (NewLine
== NULL
) {
2108 return EFI_OUT_OF_RESOURCES
;
2111 NewLine
->Signature
= LINE_LIST_SIGNATURE
;
2112 NewLine
->Size
= Line
->Size
- FileColumn
+ 1;
2113 NewLine
->TotalSize
= NewLine
->Size
;
2114 NewLine
->Buffer
= CatSPrint (NULL
, L
"\0");
2115 if (NewLine
->Buffer
== NULL
) {
2116 return EFI_OUT_OF_RESOURCES
;
2119 NewLine
->Type
= NewLineTypeDefault
;
2121 if (NewLine
->Size
> 0) {
2123 // UNICODE + CHAR_NULL
2125 Buffer
= AllocateZeroPool (2 * (NewLine
->Size
+ 1));
2126 if (Buffer
== NULL
) {
2127 FreePool (NewLine
->Buffer
);
2129 return EFI_OUT_OF_RESOURCES
;
2132 FreePool (NewLine
->Buffer
);
2134 NewLine
->Buffer
= Buffer
;
2136 for (Index
= 0; Index
< NewLine
->Size
; Index
++) {
2137 NewLine
->Buffer
[Index
] = Line
->Buffer
[Index
+ FileColumn
- 1];
2140 NewLine
->Buffer
[NewLine
->Size
] = CHAR_NULL
;
2142 Line
->Buffer
[FileColumn
- 1] = CHAR_NULL
;
2143 Line
->Size
= FileColumn
- 1;
2146 // increase NumLines
2148 FileBuffer
.NumLines
++;
2151 // insert it into the correct position of line list
2153 NewLine
->Link
.BackLink
= &(Line
->Link
);
2154 NewLine
->Link
.ForwardLink
= Line
->Link
.ForwardLink
;
2155 Line
->Link
.ForwardLink
->BackLink
= &(NewLine
->Link
);
2156 Line
->Link
.ForwardLink
= &(NewLine
->Link
);
2159 // move cursor to the start of next line
2161 Row
= FileBuffer
.FilePosition
.Row
+ 1;
2164 FileBufferMovePosition (Row
, Col
);
2167 // set file is modified
2169 if (!FileBuffer
.FileModified
) {
2170 FileBuffer
.FileModified
= TRUE
;
2177 Delete current character from current line. This is the effect caused
2184 FileBufferDoDelete (
2188 EFI_EDITOR_LINE
*Line
;
2189 EFI_EDITOR_LINE
*Next
;
2193 Line
= FileBuffer
.CurrentLine
;
2194 FileColumn
= FileBuffer
.FilePosition
.Column
;
2199 if (FileColumn
>= Line
->Size
+ 1) {
2203 if (Line
->Link
.ForwardLink
== FileBuffer
.ListHead
) {
2207 // since last character,
2208 // so will add the next line to this line
2210 Link
= Line
->Link
.ForwardLink
;
2211 Next
= CR (Link
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
2212 LineCat (Line
, Next
);
2213 if (Line
->Buffer
== NULL
) {
2214 return EFI_OUT_OF_RESOURCES
;
2217 RemoveEntryList (&Next
->Link
);
2220 FileBuffer
.NumLines
--;
2222 FileBufferNeedRefresh
= TRUE
;
2223 FileBufferOnlyLineNeedRefresh
= FALSE
;
2227 // just delete current character
2229 LineDeleteAt (Line
, FileColumn
);
2230 FileBufferOnlyLineNeedRefresh
= TRUE
;
2233 if (!FileBuffer
.FileModified
) {
2234 FileBuffer
.FileModified
= TRUE
;
2241 Scroll cursor to right 1 character.
2243 @retval EFI_SUCCESS The operation was successful.
2247 FileBufferScrollRight (
2251 EFI_EDITOR_LINE
*Line
;
2255 Line
= FileBuffer
.CurrentLine
;
2256 if (Line
->Buffer
== NULL
) {
2260 FRow
= FileBuffer
.FilePosition
.Row
;
2261 FCol
= FileBuffer
.FilePosition
.Column
;
2264 // if already at end of this line, scroll it to the start of next line
2266 if (FCol
> Line
->Size
) {
2270 if (Line
->Link
.ForwardLink
!= FileBuffer
.ListHead
) {
2278 // if not at end of this line, just move to next column
2283 FileBufferMovePosition (FRow
, FCol
);
2289 Insert a char into line
2292 @param[in] Line The line to insert into.
2293 @param[in] Char The char to insert.
2294 @param[in] Pos The position to insert the char at ( start from 0 ).
2295 @param[in] StrSize The current string size ( include CHAR_NULL ),unit is Unicode character.
2297 @return The new string size ( include CHAR_NULL ) ( unit is Unicode character ).
2302 IN EFI_EDITOR_LINE
*Line
,
2309 CHAR16
*TempStringPtr
;
2312 Index
= (StrSize
) * 2;
2317 // do not have free space
2319 if (Line
->TotalSize
<= Line
->Size
) {
2320 Str
= ReallocatePool (Index
, Index
+ 16, Str
);
2325 Line
->TotalSize
+= 8;
2328 // move the later part of the string one character right
2330 TempStringPtr
= Str
;
2331 for (Index
= StrSize
; Index
> Pos
; Index
--) {
2332 TempStringPtr
[Index
] = TempStringPtr
[Index
- 1];
2335 // insert char into it.
2337 TempStringPtr
[Index
] = Char
;
2346 Add a character to the current line.
2348 @param[in] Char The Character to input.
2350 @retval EFI_SUCCESS The input was succesful.
2358 EFI_EDITOR_LINE
*Line
;
2361 Line
= FileBuffer
.CurrentLine
;
2364 // only needs to refresh current line
2366 FileBufferOnlyLineNeedRefresh
= TRUE
;
2369 // when is insert mode, or cursor is at end of this line,
2370 // so insert this character
2371 // or replace the character.
2373 FilePos
= FileBuffer
.FilePosition
.Column
- 1;
2374 if (FileBuffer
.ModeInsert
|| FilePos
+ 1 > Line
->Size
) {
2375 LineStrInsert (Line
, Char
, FilePos
, Line
->Size
+ 1);
2377 Line
->Buffer
[FilePos
] = Char
;
2380 // move cursor to right
2382 FileBufferScrollRight ();
2384 if (!FileBuffer
.FileModified
) {
2385 FileBuffer
.FileModified
= TRUE
;
2392 Handles inputs from characters (ASCII key + Backspace + return)
2394 @param[in] Char The input character.
2396 @retval EFI_SUCCESS The operation was successful.
2397 @retval EFI_LOAD_ERROR There was an error.
2398 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
2402 FileBufferDoCharInput (
2403 IN CONST CHAR16 Char
2408 Status
= EFI_SUCCESS
;
2414 case CHAR_BACKSPACE
:
2415 Status
= FileBufferDoBackspace ();
2425 case CHAR_CARRIAGE_RETURN
:
2426 Status
= FileBufferDoReturn ();
2431 // DEAL WITH ASCII CHAR, filter out thing like ctrl+f
2433 if (Char
> 127 || Char
< 32) {
2434 Status
= StatusBarSetStatusString (L
"Unknown Command");
2436 Status
= FileBufferAddChar (Char
);
2447 Scroll cursor to the next line.
2449 @retval EFI_SUCCESS The operation was successful.
2453 FileBufferScrollDown (
2457 EFI_EDITOR_LINE
*Line
;
2461 Line
= FileBuffer
.CurrentLine
;
2462 if (Line
->Buffer
== NULL
) {
2466 FRow
= FileBuffer
.FilePosition
.Row
;
2467 FCol
= FileBuffer
.FilePosition
.Column
;
2472 if (Line
->Link
.ForwardLink
!= FileBuffer
.ListHead
) {
2474 Line
= CR (Line
->Link
.ForwardLink
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
2477 // if the next line is not that long, so move to end of next line
2479 if (FCol
> Line
->Size
) {
2480 FCol
= Line
->Size
+ 1;
2487 FileBufferMovePosition (FRow
, FCol
);
2493 Scroll the cursor to previous line.
2495 @retval EFI_SUCCESS The operation was successful.
2499 FileBufferScrollUp (
2503 EFI_EDITOR_LINE
*Line
;
2507 Line
= FileBuffer
.CurrentLine
;
2509 FRow
= FileBuffer
.FilePosition
.Row
;
2510 FCol
= FileBuffer
.FilePosition
.Column
;
2513 // has previous line
2515 if (Line
->Link
.BackLink
!= FileBuffer
.ListHead
) {
2517 Line
= CR (Line
->Link
.BackLink
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
2520 // if previous line is not that long, so move to the end of previous line
2522 if (FCol
> Line
->Size
) {
2523 FCol
= Line
->Size
+ 1;
2530 FileBufferMovePosition (FRow
, FCol
);
2536 Scroll cursor to next page.
2538 @retval EFI_SUCCESS The operation wa successful.
2542 FileBufferPageDown (
2546 EFI_EDITOR_LINE
*Line
;
2551 Line
= FileBuffer
.CurrentLine
;
2553 FRow
= FileBuffer
.FilePosition
.Row
;
2554 FCol
= FileBuffer
.FilePosition
.Column
;
2559 if (FileBuffer
.NumLines
>= FRow
+ (MainEditor
.ScreenSize
.Row
- 2)) {
2560 Gap
= (MainEditor
.ScreenSize
.Row
- 2);
2563 // MOVE CURSOR TO LAST LINE
2565 Gap
= FileBuffer
.NumLines
- FRow
;
2570 Line
= MoveLine (Gap
);
2573 // if that line, is not that long, so move to the end of that line
2575 if (Line
!= NULL
&& FCol
> Line
->Size
) {
2576 FCol
= Line
->Size
+ 1;
2581 FileBufferMovePosition (FRow
, FCol
);
2587 Scroll cursor to previous screen.
2589 @retval EFI_SUCCESS The operation was successful.
2597 EFI_EDITOR_LINE
*Line
;
2603 Line
= FileBuffer
.CurrentLine
;
2605 FRow
= FileBuffer
.FilePosition
.Row
;
2606 FCol
= FileBuffer
.FilePosition
.Column
;
2609 // has previous page
2611 if (FRow
> (MainEditor
.ScreenSize
.Row
- 2)) {
2612 Gap
= (MainEditor
.ScreenSize
.Row
- 2);
2615 // the first line of file will displayed on the first line of screen
2626 Line
= MoveLine (Retreat
);
2629 // if that line is not that long, so move to the end of that line
2631 if (Line
!= NULL
&& FCol
> Line
->Size
) {
2632 FCol
= Line
->Size
+ 1;
2637 FileBufferMovePosition (FRow
, FCol
);
2643 Scroll cursor to end of the current line.
2645 @retval EFI_SUCCESS The operation was successful.
2653 EFI_EDITOR_LINE
*Line
;
2657 Line
= FileBuffer
.CurrentLine
;
2659 FRow
= FileBuffer
.FilePosition
.Row
;
2662 // goto the last column of the line
2664 FCol
= Line
->Size
+ 1;
2666 FileBufferMovePosition (FRow
, FCol
);
2672 Dispatch input to different handler
2673 @param[in] Key The input key. One of:
2677 Direction key: up/down/left/right/pgup/pgdn
2681 @retval EFI_SUCCESS The dispatch was done successfully.
2682 @retval EFI_LOAD_ERROR The dispatch was not successful.
2683 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
2687 FileBufferHandleInput (
2688 IN CONST EFI_INPUT_KEY
*Key
2693 Status
= EFI_SUCCESS
;
2695 switch (Key
->ScanCode
) {
2697 // ordinary key input
2700 if (!FileBuffer
.ReadOnly
) {
2701 Status
= FileBufferDoCharInput (Key
->UnicodeChar
);
2703 Status
= StatusBarSetStatusString (L
"Read Only File Can Not Be Modified");
2712 Status
= FileBufferScrollUp ();
2719 Status
= FileBufferScrollDown ();
2726 Status
= FileBufferScrollRight ();
2733 Status
= FileBufferScrollLeft ();
2740 Status
= FileBufferPageUp ();
2746 case SCAN_PAGE_DOWN
:
2747 Status
= FileBufferPageDown ();
2754 if (!FileBuffer
.ReadOnly
) {
2755 Status
= FileBufferDoDelete ();
2757 Status
= StatusBarSetStatusString (L
"Read Only File Can Not Be Modified");
2766 FileBufferMovePosition (FileBuffer
.FilePosition
.Row
, 1);
2767 Status
= EFI_SUCCESS
;
2774 Status
= FileBufferEnd ();
2781 FileBuffer
.ModeInsert
= (BOOLEAN
)!FileBuffer
.ModeInsert
;
2782 Status
= EFI_SUCCESS
;
2786 Status
= StatusBarSetStatusString (L
"Unknown Command");
2794 Check user specified FileRow is above current screen.
2796 @param[in] FileRow The row of file position ( start from 1 ).
2798 @retval TRUE It is above the current screen.
2799 @retval FALSE It is not above the current screen.
2803 AboveCurrentScreen (
2808 // if is to the above of the screen
2810 if (FileRow
< FileBuffer
.LowVisibleRange
.Row
) {
2818 Check user specified FileRow is under current screen.
2820 @param[in] FileRow The row of file position ( start from 1 ).
2822 @retval TRUE It is under the current screen.
2823 @retval FALSE It is not under the current screen.
2827 UnderCurrentScreen (
2832 // if is to the under of the screen
2834 if (FileRow
> FileBuffer
.LowVisibleRange
.Row
+ (MainEditor
.ScreenSize
.Row
- 2) - 1) {
2842 Check user specified FileCol is left to current screen.
2844 @param[in] FileCol The column of file position ( start from 1 ).
2846 @retval TRUE It is to the left.
2847 @retval FALSE It is not to the left.
2856 // if is to the left of the screen
2858 if (FileCol
< FileBuffer
.LowVisibleRange
.Column
) {
2866 Check user specified FileCol is right to current screen.
2868 @param[in] FileCol The column of file position ( start from 1 ).
2870 @retval TRUE It is to the right.
2871 @retval FALSE It is not to the right.
2875 RightCurrentScreen (
2880 // if is to the right of the screen
2882 if (FileCol
> FileBuffer
.LowVisibleRange
.Column
+ MainEditor
.ScreenSize
.Column
- 1) {
2890 Advance/Retreat lines and set CurrentLine in FileBuffer to it
2892 @param[in] Count The line number to advance/retreat
2896 @retval NULL An error occured.
2897 @return The line after advance/retreat.
2905 EFI_EDITOR_LINE
*Line
;
2909 AbsCount
= (UINTN
)ABS(Count
);
2910 Line
= InternalEditorMiscLineRetreat (AbsCount
,MainEditor
.FileBuffer
->CurrentLine
,MainEditor
.FileBuffer
->ListHead
);
2912 Line
= InternalEditorMiscLineAdvance ((UINTN
)Count
,MainEditor
.FileBuffer
->CurrentLine
,MainEditor
.FileBuffer
->ListHead
);
2919 MainEditor
.FileBuffer
->CurrentLine
= Line
;
2925 According to cursor's file position, adjust screen display
2927 @param[in] NewFilePosRow The row of file position ( start from 1 ).
2928 @param[in] NewFilePosCol The column of file position ( start from 1 ).
2932 FileBufferMovePosition (
2933 IN CONST UINTN NewFilePosRow
,
2934 IN CONST UINTN NewFilePosCol
2946 // CALCULATE gap between current file position and new file position
2948 RowGap
= NewFilePosRow
- FileBuffer
.FilePosition
.Row
;
2949 ColGap
= NewFilePosCol
- FileBuffer
.FilePosition
.Column
;
2951 Under
= UnderCurrentScreen (NewFilePosRow
);
2952 Above
= AboveCurrentScreen (NewFilePosRow
);
2954 // if is below current screen
2958 // display row will be unchanged
2960 FileBuffer
.FilePosition
.Row
= NewFilePosRow
;
2964 // has enough above line, so display row unchanged
2965 // not has enough above lines, so the first line is at the
2966 // first display line
2968 if (NewFilePosRow
< (FileBuffer
.DisplayPosition
.Row
- 1)) {
2969 FileBuffer
.DisplayPosition
.Row
= NewFilePosRow
+ 1;
2972 FileBuffer
.FilePosition
.Row
= NewFilePosRow
;
2975 // in current screen
2977 FileBuffer
.FilePosition
.Row
= NewFilePosRow
;
2979 Abs
= (UINTN
)ABS(RowGap
);
2980 FileBuffer
.DisplayPosition
.Row
-= Abs
;
2982 FileBuffer
.DisplayPosition
.Row
+= RowGap
;
2987 FileBuffer
.LowVisibleRange
.Row
= FileBuffer
.FilePosition
.Row
- (FileBuffer
.DisplayPosition
.Row
- 2);
2989 Right
= RightCurrentScreen (NewFilePosCol
);
2990 Left
= LeftCurrentScreen (NewFilePosCol
);
2993 // if right to current screen
2997 // display column will be changed to end
2999 FileBuffer
.DisplayPosition
.Column
= MainEditor
.ScreenSize
.Column
;
3000 FileBuffer
.FilePosition
.Column
= NewFilePosCol
;
3004 // has enough left characters , so display row unchanged
3005 // not has enough left characters,
3006 // so the first character is at the first display column
3008 if (NewFilePosCol
< (FileBuffer
.DisplayPosition
.Column
)) {
3009 FileBuffer
.DisplayPosition
.Column
= NewFilePosCol
;
3012 FileBuffer
.FilePosition
.Column
= NewFilePosCol
;
3015 // in current screen
3017 FileBuffer
.FilePosition
.Column
= NewFilePosCol
;
3019 Abs
= (UINTN
)(-ColGap
);
3020 FileBuffer
.DisplayPosition
.Column
-= Abs
;
3022 FileBuffer
.DisplayPosition
.Column
+= ColGap
;
3027 FileBuffer
.LowVisibleRange
.Column
= FileBuffer
.FilePosition
.Column
- (FileBuffer
.DisplayPosition
.Column
- 1);
3030 // let CurrentLine point to correct line;
3032 FileBuffer
.CurrentLine
= MoveCurrentLine (RowGap
);
3037 Cut current line out and return a pointer to it.
3039 @param[out] CutLine Upon a successful return pointer to the pointer to
3040 the allocated cut line.
3042 @retval EFI_SUCCESS The cut was successful.
3043 @retval EFI_NOT_FOUND There was no selection to cut.
3044 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
3049 OUT EFI_EDITOR_LINE
**CutLine
3052 EFI_EDITOR_LINE
*Line
;
3053 EFI_EDITOR_LINE
*NewLine
;
3057 if (FileBuffer
.ReadOnly
) {
3058 StatusBarSetStatusString (L
"Read Only File Can Not Be Modified");
3062 Line
= FileBuffer
.CurrentLine
;
3065 // if is the last dummy line, SO CAN not cut
3067 if (StrCmp (Line
->Buffer
, L
"\0") == 0 && Line
->Link
.ForwardLink
== FileBuffer
.ListHead
3073 // LAST LINE AND NOTHING ON THIS LINE, SO CUT NOTHING
3075 StatusBarSetStatusString (L
"Nothing to Cut");
3076 return EFI_NOT_FOUND
;
3079 // if is the last line, so create a dummy line
3081 if (Line
->Link
.ForwardLink
== FileBuffer
.ListHead
) {
3084 // create a new line
3086 NewLine
= FileBufferCreateLine ();
3087 if (NewLine
== NULL
) {
3088 return EFI_OUT_OF_RESOURCES
;
3092 FileBuffer
.NumLines
--;
3093 Row
= FileBuffer
.FilePosition
.Row
;
3098 FileBuffer
.CurrentLine
= CR (
3099 FileBuffer
.CurrentLine
->Link
.ForwardLink
,
3105 RemoveEntryList (&Line
->Link
);
3107 FileBuffer
.Lines
= CR (FileBuffer
.ListHead
->ForwardLink
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
3109 FileBufferMovePosition (Row
, Col
);
3111 FileBuffer
.FileModified
= TRUE
;
3112 FileBufferNeedRefresh
= TRUE
;
3113 FileBufferOnlyLineNeedRefresh
= FALSE
;
3121 Paste a line into line list.
3123 @retval EFI_SUCCESS The paste was successful.
3124 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
3128 FileBufferPasteLine (
3132 EFI_EDITOR_LINE
*Line
;
3133 EFI_EDITOR_LINE
*NewLine
;
3138 // if nothing is on clip board
3141 if (MainEditor
.CutLine
== NULL
) {
3145 // read only file can not be pasted on
3147 if (FileBuffer
.ReadOnly
) {
3148 StatusBarSetStatusString (L
"Read Only File Can Not Be Modified");
3152 NewLine
= LineDup (MainEditor
.CutLine
);
3153 if (NewLine
== NULL
) {
3154 return EFI_OUT_OF_RESOURCES
;
3157 // insert it above current line
3159 Line
= FileBuffer
.CurrentLine
;
3160 NewLine
->Link
.BackLink
= Line
->Link
.BackLink
;
3161 NewLine
->Link
.ForwardLink
= &Line
->Link
;
3163 Line
->Link
.BackLink
->ForwardLink
= &NewLine
->Link
;
3164 Line
->Link
.BackLink
= &NewLine
->Link
;
3166 FileBuffer
.NumLines
++;
3167 FileBuffer
.CurrentLine
= NewLine
;
3169 FileBuffer
.Lines
= CR (FileBuffer
.ListHead
->ForwardLink
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
3175 Row
= FileBuffer
.FilePosition
.Row
;
3177 FileBufferMovePosition (Row
, Col
);
3180 // after paste, set some value so that refresh knows to do something
3182 FileBuffer
.FileModified
= TRUE
;
3183 FileBufferNeedRefresh
= TRUE
;
3184 FileBufferOnlyLineNeedRefresh
= FALSE
;
3190 Search string from current position on in file
3192 @param[in] Str The search string.
3193 @param[in] Offset The offset from current position.
3195 @retval EFI_SUCCESS The operation was successful.
3196 @retval EFI_NOT_FOUND The string Str was not found.
3201 IN CONST CHAR16
*Str
,
3202 IN CONST UINTN Offset
3209 EFI_EDITOR_LINE
*Line
;
3218 // search if in current line
3220 Current
= FileBuffer
.CurrentLine
->Buffer
+ FileBuffer
.FilePosition
.Column
- 1 + Offset
;
3222 if (Current
>= (FileBuffer
.CurrentLine
->Buffer
+ FileBuffer
.CurrentLine
->Size
)) {
3226 Current
= FileBuffer
.CurrentLine
->Buffer
+ FileBuffer
.CurrentLine
->Size
;
3231 CharPos
= StrStr (Current
, Str
);
3232 if (CharPos
!= NULL
) {
3233 Position
= CharPos
- Current
+ 1;
3241 Column
= (Position
- 1) + FileBuffer
.FilePosition
.Column
+ Offset
;
3242 Row
= FileBuffer
.FilePosition
.Row
;
3245 // not found so find through next lines
3247 Link
= FileBuffer
.CurrentLine
->Link
.ForwardLink
;
3249 Row
= FileBuffer
.FilePosition
.Row
+ 1;
3250 while (Link
!= FileBuffer
.ListHead
) {
3251 Line
= CR (Link
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
3252 // Position = StrStr (Line->Buffer, Str);
3253 CharPos
= StrStr (Line
->Buffer
, Str
);
3254 if (CharPos
!= NULL
) {
3255 Position
= CharPos
- Line
->Buffer
+ 1;
3268 Link
= Link
->ForwardLink
;
3271 if (Link
== FileBuffer
.ListHead
) {
3279 return EFI_NOT_FOUND
;
3282 FileBufferMovePosition (Row
, Column
);
3285 // call refresh to fresh edit area,
3286 // because the outer may loop to find multiply occurrence of this string
3288 FileBufferRefresh ();
3294 Replace SearchLen characters from current position on with Replace.
3296 This will modify the current buffer at the current position.
3298 @param[in] Replace The string to replace.
3299 @param[in] SearchLen Search string's length.
3301 @retval EFI_SUCCESS The operation was successful.
3302 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
3307 IN CONST CHAR16
*Replace
,
3308 IN CONST UINTN SearchLen
3318 ReplaceLen
= StrLen (Replace
);
3320 OldSize
= FileBuffer
.CurrentLine
->Size
+ 1;
3322 // include CHAR_NULL
3324 NewSize
= OldSize
+ (ReplaceLen
- SearchLen
);
3326 if (ReplaceLen
> SearchLen
) {
3328 // do not have the enough space
3330 if (FileBuffer
.CurrentLine
->TotalSize
+ 1 <= NewSize
) {
3331 FileBuffer
.CurrentLine
->Buffer
= ReallocatePool (
3334 FileBuffer
.CurrentLine
->Buffer
3336 FileBuffer
.CurrentLine
->TotalSize
= NewSize
- 1;
3339 if (FileBuffer
.CurrentLine
->Buffer
== NULL
) {
3340 return EFI_OUT_OF_RESOURCES
;
3343 // the end CHAR_NULL character;
3345 Buffer
= FileBuffer
.CurrentLine
->Buffer
+ (NewSize
- 1);
3346 Gap
= ReplaceLen
- SearchLen
;
3349 // keep the latter part
3351 for (Index
= 0; Index
< (FileBuffer
.CurrentLine
->Size
- FileBuffer
.FilePosition
.Column
- SearchLen
+ 2); Index
++) {
3352 *Buffer
= *(Buffer
- Gap
);
3356 // set replace into it
3358 Buffer
= FileBuffer
.CurrentLine
->Buffer
+ FileBuffer
.FilePosition
.Column
- 1;
3359 for (Index
= 0; Index
< ReplaceLen
; Index
++) {
3360 Buffer
[Index
] = Replace
[Index
];
3364 if (ReplaceLen
< SearchLen
) {
3365 Buffer
= FileBuffer
.CurrentLine
->Buffer
+ FileBuffer
.FilePosition
.Column
- 1;
3367 for (Index
= 0; Index
< ReplaceLen
; Index
++) {
3368 Buffer
[Index
] = Replace
[Index
];
3371 Buffer
+= ReplaceLen
;
3372 Gap
= SearchLen
- ReplaceLen
;
3375 // set replace into it
3377 for (Index
= 0; Index
< (FileBuffer
.CurrentLine
->Size
- FileBuffer
.FilePosition
.Column
- ReplaceLen
+ 2); Index
++) {
3378 *Buffer
= *(Buffer
+ Gap
);
3383 if (ReplaceLen
== SearchLen
) {
3384 Buffer
= FileBuffer
.CurrentLine
->Buffer
+ FileBuffer
.FilePosition
.Column
- 1;
3385 for (Index
= 0; Index
< ReplaceLen
; Index
++) {
3386 Buffer
[Index
] = Replace
[Index
];
3390 FileBuffer
.CurrentLine
->Size
+= (ReplaceLen
- SearchLen
);
3392 FileBufferOnlyLineNeedRefresh
= TRUE
;
3394 FileBuffer
.FileModified
= TRUE
;
3396 MainTitleBarRefresh (MainEditor
.FileBuffer
->FileName
, MainEditor
.FileBuffer
->FileType
, MainEditor
.FileBuffer
->ReadOnly
, MainEditor
.FileBuffer
->FileModified
, MainEditor
.ScreenSize
.Column
, MainEditor
.ScreenSize
.Row
, 0, 0);
3397 FileBufferRestorePosition ();
3398 FileBufferRefresh ();
3404 Move the mouse cursor position.
3406 @param[in] TextX The new x-coordinate.
3407 @param[in] TextY The new y-coordinate.
3411 FileBufferAdjustMousePosition (
3412 IN CONST INT32 TextX
,
3413 IN CONST INT32 TextY
3422 // TextX and TextY is mouse movement data returned by mouse driver
3423 // This function will change it to MousePosition
3426 // get absolute value
3432 CoordinateX
= FileBuffer
.MousePosition
.Column
;
3433 CoordinateY
= FileBuffer
.MousePosition
.Row
;
3436 CoordinateX
+= TextX
;
3438 if (CoordinateX
>= AbsX
) {
3439 CoordinateX
-= AbsX
;
3446 CoordinateY
+= TextY
;
3448 if (CoordinateY
>= AbsY
) {
3449 CoordinateY
-= AbsY
;
3455 // check whether new mouse column position is beyond screen
3456 // if not, adjust it
3458 if (CoordinateX
>= 1 && CoordinateX
<= MainEditor
.ScreenSize
.Column
) {
3459 FileBuffer
.MousePosition
.Column
= CoordinateX
;
3460 } else if (CoordinateX
< 1) {
3461 FileBuffer
.MousePosition
.Column
= 1;
3462 } else if (CoordinateX
> MainEditor
.ScreenSize
.Column
) {
3463 FileBuffer
.MousePosition
.Column
= MainEditor
.ScreenSize
.Column
;
3466 // check whether new mouse row position is beyond screen
3467 // if not, adjust it
3469 if (CoordinateY
>= 2 && CoordinateY
<= (MainEditor
.ScreenSize
.Row
- 1)) {
3470 FileBuffer
.MousePosition
.Row
= CoordinateY
;
3471 } else if (CoordinateY
< 2) {
3472 FileBuffer
.MousePosition
.Row
= 2;
3473 } else if (CoordinateY
> (MainEditor
.ScreenSize
.Row
- 1)) {
3474 FileBuffer
.MousePosition
.Row
= (MainEditor
.ScreenSize
.Row
- 1);
3480 Search and replace operation.
3482 @param[in] SearchStr The string to search for.
3483 @param[in] ReplaceStr The string to replace with.
3484 @param[in] Offset The column to start at.
3488 FileBufferReplaceAll (
3489 IN CHAR16
*SearchStr
,
3490 IN CHAR16
*ReplaceStr
,
3503 EFI_EDITOR_LINE
*Line
;
3507 SearchLen
= StrLen (SearchStr
);
3508 ReplaceLen
= StrLen (ReplaceStr
);
3510 Column
= FileBuffer
.FilePosition
.Column
+ Offset
- 1;
3512 if (Column
> FileBuffer
.CurrentLine
->Size
) {
3513 Column
= FileBuffer
.CurrentLine
->Size
;
3516 Link
= &(FileBuffer
.CurrentLine
->Link
);
3518 while (Link
!= FileBuffer
.ListHead
) {
3519 Line
= CR (Link
, EFI_EDITOR_LINE
, Link
, LINE_LIST_SIGNATURE
);
3520 CharPos
= StrStr (Line
->Buffer
+ Column
, SearchStr
);
3521 if (CharPos
!= NULL
) {
3522 Position
= CharPos
- Line
->Buffer
;// + Column;
3526 if (ReplaceLen
> SearchLen
) {
3527 OldSize
= Line
->Size
+ 1;
3529 // include CHAR_NULL
3531 NewSize
= OldSize
+ (ReplaceLen
- SearchLen
);
3534 // do not have the enough space
3536 if (Line
->TotalSize
+ 1 <= NewSize
) {
3537 Line
->Buffer
= ReallocatePool (
3542 Line
->TotalSize
= NewSize
- 1;
3545 if (Line
->Buffer
== NULL
) {
3546 return EFI_OUT_OF_RESOURCES
;
3549 // the end CHAR_NULL character;
3551 Buffer
= Line
->Buffer
+ (NewSize
- 1);
3552 Gap
= ReplaceLen
- SearchLen
;
3555 // keep the latter part
3557 for (Index
= 0; Index
< (Line
->Size
- Position
- SearchLen
+ 1); Index
++) {
3558 *Buffer
= *(Buffer
- Gap
);
3562 } else if (ReplaceLen
< SearchLen
){
3563 Buffer
= Line
->Buffer
+ Position
+ ReplaceLen
;
3564 Gap
= SearchLen
- ReplaceLen
;
3566 for (Index
= 0; Index
< (Line
->Size
- Position
- ReplaceLen
+ 1); Index
++) {
3567 *Buffer
= *(Buffer
+ Gap
);
3571 ASSERT(ReplaceLen
== SearchLen
);
3574 // set replace into it
3576 Buffer
= Line
->Buffer
+ Position
;
3577 for (Index
= 0; Index
< ReplaceLen
; Index
++) {
3578 Buffer
[Index
] = ReplaceStr
[Index
];
3581 Line
->Size
+= (ReplaceLen
- SearchLen
);
3582 Column
+= ReplaceLen
;
3588 Link
= Link
->ForwardLink
;
3592 // call refresh to fresh edit area
3594 FileBuffer
.FileModified
= TRUE
;
3595 FileBufferNeedRefresh
= TRUE
;
3596 FileBufferRefresh ();
3602 Set the modified state to TRUE.
3606 FileBufferSetModified (
3610 FileBuffer
.FileModified
= TRUE
;
3615 Get the size of the open buffer.
3617 @retval The size in bytes.
3620 FileBufferGetTotalSize (
3626 EFI_EDITOR_LINE
*Line
;
3629 // calculate the total size of whole line list's buffer
3631 if (FileBuffer
.Lines
== NULL
) {
3636 FileBuffer
.ListHead
->BackLink
,
3642 // one line at most 0x50
3644 Size
= SHELL_EDIT_MAX_LINE_SIZE
* (FileBuffer
.NumLines
- 1) + Line
->Size
;